def pmuThread(pmuID, pmu_ip, port, buffer_size, setTS): pmu = Pmu(pmu_id=int(pmuID), port=int(port), ip=pmu_ip, buffer_size=int(buffer_size), set_timestamp=setTS) # pmu.logger.setLevel("DEBUG") pmu.set_configuration( cybergridCfg ) # This will load PMU configuration specified in IEEE C37.118.2 -Annex D (Table D.2) pmu.set_header() phaseAng1 = 0 phaseAng2 = 2.09439 phaseAng3 = -2.09439 pmu.run() # PMU starts listening for incoming connections while True: try: if pmu.clients: # Check if there is any connected PDCs sleep(1 / pmu.cfg2.get_data_rate()) cybergrid_data_sample.set_phasors([(120.0, phaseAng1), (120.0, phaseAng2), (120.0, phaseAng3)]) # pmu.send_data(phasors=[(120.0, 3.14), # (120.0, 3.14), # (120.0, 3.14)], # analog=[9.91], # digital=[0x0001]) pmu.send( cybergrid_data_sample ) # Sending sample data frame specified in IEEE C37.118.2 - Annex D (Table D.1) phaseAng1 = phaseIncrem(phaseAng1) phaseAng2 = phaseIncrem(phaseAng2) phaseAng3 = phaseIncrem(phaseAng3) except EnvironmentError as e: print(e) sys.exit() pmu.join()
60, # Nominal frequency 1, # Configuration change count 240) # Rate of phasor data transmission) hf = HeaderFrame( 7, # PMU_ID "Hello I'm nanoPMU!") # Header Message df = DataFrame( 7, # PMU_ID ("ok", True, "timestamp", False, False, False, 0, "<10", 0), # STAT WORD - Check DataFrame set_stat() [(14635, 0), (-7318, -12676), (-7318, 12675), (1092, 0)], # PHASORS (3 - v, 1 - i) 2500, # Frequency deviation from nominal in mHz 0, # Rate of Change of Frequency [100, 1000, 10000], # Analog Values [0x3c12], # Digital status word cfg) # Data Stream Configuration pmu.set_configuration(cfg) pmu.set_header(hf) pmu.run() while True: if pmu.clients: pmu.send(df) pmu.join()
[(ph_v_conversion, "v"), (ph_v_conversion, "v"), (ph_v_conversion, "v"), (ph_i_conversion, "i")], # Conversion factor for phasor channels [(1, "pow"), (1, "rms"), (1, "peak")], # Conversion factor for analog channels [(0x0000, 0xffff)], # Mask words for digital status words 60, # Nominal frequency 1, # Configuration change count 240) # Rate of phasor data transmission) hf = HeaderFrame(7, # PMU_ID "Hello I'm nanoPMU!") # Header Message df = DataFrame(7, # PMU_ID ("ok", True, "timestamp", False, False, False, 0, "<10", 0), # STAT WORD - Check DataFrame set_stat() [(14635, 0), (-7318, -12676), (-7318, 12675), (1092, 0)], # PHASORS (3 - v, 1 - i) 2500, # Frequency deviation from nominal in mHz 0, # Rate of Change of Frequency [100, 1000, 10000], # Analog Values [0x3c12], # Digital status word cfg) # Data Stream Configuration pmu.set_configuration(cfg) pmu.set_header(hf) pmu.run() while True: if pmu.clients: pmu.send(df) pmu.join()
class MyPmu: ''' Implements the communication protocol of the IEEE C37.118 synchrofphasor standard (IEC 61850) using "pypmu" lib (synchrophasor in the imports). This class acts like a wrapper interfacing the lib. Uses a callback function to handle the PPS as a trigger event on the GPIO 18 of the raspberry. ''' def __init__(self, channelNames, nFreq = 50): ''' channelNames = list of the Channels' Names nFreq = Nominal Frequency is needed for the configuration frame! ''' self.pmu = Pmu(ip="127.0.0.1", port=1411) self.pmu.logger.setLevel("DEBUG") self.nFreq = nFreq ph_v_conversion = [(100000, "v")]*len(channelNames) # Voltage phasor conversion factor self.cfg = ConfigFrame2(7, # PMU_ID 1000000, # TIME_BASE 1, # Number of PMUs included in data frame "Station A", # Station name 7734, # Data-stream ID(s) 15, # Data format - Check ConfigFrame2 set_data_format() len(channelNames), # Number of phasors 0, # Number of analog values 0, # Number of digital status words channelNames, # Channel Names ph_v_conversion, # Conversion factor for phasor channels [], # Conversion factor for analog channels [], # Mask words for digital status words nFreq, # Nominal frequency 1, # Configuration change count 1) # Rate of phasor data transmission) self.hf = HeaderFrame(7, # PMU_ID "Hello I'm MyPMU!") # Header Message self.current_dataframe = None self.pmu.set_configuration(self.cfg) self.pmu.set_header(self.hf) def run(self): ''' Create TCP socket, bind port and listen for incoming connections ''' self.pmu.run() while True: pass self.pmu.join() def set_dataframe(self, synchrophasors, soc): ''' Sets the new dataframe to be sent. ''' sph = [] rocof = [] freq_dev = [] for chan in synchrophasors: #for every chan is given a synchrophasor sph.append((synchrophasors[chan]['amplitude'], synchrophasors[chan]['phase'])) if abs(self.nFreq-synchrophasors[chan]['avg_freq']) > 32.767: rocof.append(0) else: rocof.append(synchrophasors[chan]['rocof']) #1 rocof for the whole datagram, the first is given freq_dev.append(synchrophasors[chan]['avg_freq']-self.nFreq)# average frequency deviation from nominal if len(freq_dev) == 0: freq_dev.append(0) self.current_dataframe = DataFrame(7, # PMU_ID ("ok", True, "timestamp", False, False, False, 0, "<10", 0), # STAT WORD - Check DataFrame set_stat() sph, # PHASORS np.average(freq_dev), # Frequency deviation from nominal in mHz np.average(rocof), # Rate of Change of Frequency [], # Analog Values [], # Digital status word self.cfg, # Data Stream Configuration soc=soc) def send(self, redlab, sph, timestamp): ''' This interface function for the lib sets the dataframe with the given arguments and if the PDC is connected start the communication. ''' myPmu.set_dataframe(sph, timestamp) if myPmu.pmu.clients: #if PDC asked for frame / is connected myPmu.pmu.send(myPmu.current_dataframe)