Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix v1.0.2 #40

Open
wants to merge 10 commits into
base: bugfix-v1.0.2
Choose a base branch
from
54 changes: 54 additions & 0 deletions examples/freq_float_PMU.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import random

from synchrophasor.frame import ConfigFrame2
from synchrophasor.pmu import Pmu


"""
randomPMU will listen on ip:port for incoming connections.
After request to start sending measurements - random
values for phasors will be sent.
"""

#This example is used to test data sending from PMU to PDC when FREQ is random floating point. All changes from original project can be seen in commits.


if __name__ == "__main__":

pmu = Pmu(ip="127.0.0.1", port=5080)
pmu.logger.setLevel("DEBUG")

cfg = ConfigFrame2(5080, # PMU_ID
1000000, # TIME_BASE
1, # Number of PMUs included in data frame
"Random Station", # Station name
5080, # Data-stream ID(s)
(True, True, True, True), # Data format - POLAR; PH - REAL; AN - REAL; FREQ - REAL;
3, # Number of phasors
1, # Number of analog values
1, # Number of digital status words
["VA", "VB", "VC", "ANALOG1", "BREAKER 1 STATUS",
"BREAKER 2 STATUS", "BREAKER 3 STATUS", "BREAKER 4 STATUS", "BREAKER 5 STATUS",
"BREAKER 6 STATUS", "BREAKER 7 STATUS", "BREAKER 8 STATUS", "BREAKER 9 STATUS",
"BREAKER A STATUS", "BREAKER B STATUS", "BREAKER C STATUS", "BREAKER D STATUS",
"BREAKER E STATUS", "BREAKER F STATUS", "BREAKER G STATUS"], # Channel Names
[(0, "v"), (0, "v"),
(0, "v")], # Conversion factor for phasor channels - (float representation, not important)
[(1, "pow")], # Conversion factor for analog channels
[(0x0000, 0xffff)], # Mask words for digital status words
50, # Nominal frequency
1, # Configuration change count
30) # Rate of phasor data transmission

pmu.set_configuration(cfg)
pmu.set_header("Hey! I'm randomPMU! Guess what? I'm sending random measurements values!")

pmu.run()

while True:
if pmu.clients:
pmu.send_data(phasors=[(random.uniform(215.0, 240.0), random.uniform(-0.1, 0.3)),
(random.uniform(215.0, 240.0), random.uniform(1.9, 2.2)),
(random.uniform(215.0, 240.0), random.uniform(3.0, 3.14))],
analog=[9.91],
digital=[0x0001], freq=random.uniform(49.49, 50.55))
56 changes: 56 additions & 0 deletions examples/freq_integer_PMU.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import random

from synchrophasor.frame import ConfigFrame2
from synchrophasor.pmu import Pmu


"""
randomPMU will listen on ip:port for incoming connections.
After request to start sending measurements - random
values for phasors will be sent.
"""

#This example is used to test data sending from PMU to PDC when FREQ is random short integer. All changes from original project can be seen in commits.


if __name__ == "__main__":

pmu = Pmu(ip="127.0.0.1", port=5080)
pmu.logger.setLevel("DEBUG")

cfg = ConfigFrame2(5080, # PMU_ID
1000000, # TIME_BASE
1, # Number of PMUs included in data frame
"Random Station", # Station name
5080, # Data-stream ID(s)
(True, True, True, False), # Data format - POLAR; PH - REAL; AN - REAL; FREQ - REAL;
3, # Number of phasors
1, # Number of analog values
1, # Number of digital status words
["VA", "VB", "VC", "ANALOG1", "BREAKER 1 STATUS",
"BREAKER 2 STATUS", "BREAKER 3 STATUS", "BREAKER 4 STATUS", "BREAKER 5 STATUS",
"BREAKER 6 STATUS", "BREAKER 7 STATUS", "BREAKER 8 STATUS", "BREAKER 9 STATUS",
"BREAKER A STATUS", "BREAKER B STATUS", "BREAKER C STATUS", "BREAKER D STATUS",
"BREAKER E STATUS", "BREAKER F STATUS", "BREAKER G STATUS"], # Channel Names
[(0, "v"), (0, "v"),
(0, "v")], # Conversion factor for phasor channels - (float representation, not important)
[(1, "pow")], # Conversion factor for analog channels
[(0x0000, 0xffff)], # Mask words for digital status words
50, # Nominal frequency
1, # Configuration change count
30) # Rate of phasor data transmission

pmu.set_configuration(cfg)
pmu.set_header("Hey! I'm randomPMU! Guess what? I'm sending random measurements values!")

pmu.run()

while True:
if pmu.clients:
pmu.send_data(phasors=[(random.uniform(215.0, 240.0), random.uniform(-0.1, 0.3)),
(random.uniform(215.0, 240.0), random.uniform(1.9, 2.2)),
(random.uniform(215.0, 240.0), random.uniform(3.0, 3.14))],
analog=[9.91],
digital=[0x0001], freq=random.randint(-4949, 5055))

pmu.join()
26 changes: 13 additions & 13 deletions synchrophasor/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,12 +226,12 @@ def set_time(self, soc=None, frasec=None):

t = time() # Get current timestamp

if soc:
if soc is not None:
self.set_soc(soc)
else:
self.set_soc(int(t)) # Get current timestamp

if frasec:
if frasec is not None:
if isinstance(frasec, collections.Sequence):
self.set_frasec(*frasec)
else:
Expand Down Expand Up @@ -392,7 +392,7 @@ def _int2frasec(frasec_int):
leap_occ = bool(leap_occ)
leap_pen = bool(leap_pen)

fr_seconds = frasec_int & (2**23-1)
fr_seconds = frasec_int & (2**24-1)

return fr_seconds, leap_dir, leap_occ, leap_pen, time_quality

Expand Down Expand Up @@ -1917,7 +1917,7 @@ def _stat2int(measurement_status="ok", sync=True, sorting="timestamp", trigger=F
if isinstance(trigger_reason, str):
trigger_reason = DataFrame.TRIGGER_REASON[trigger_reason]

stat = measurement_status << 2
stat = measurement_status << 1
if not sync:
stat |= 1

Expand Down Expand Up @@ -1952,7 +1952,7 @@ def _stat2int(measurement_status="ok", sync=True, sorting="timestamp", trigger=F
@staticmethod
def _int2stat(stat):

measurement_status = DataFrame.MEASUREMENT_STATUS_WORDS[stat >> 15]
measurement_status = DataFrame.MEASUREMENT_STATUS_WORDS[stat >> 14]
sync = bool(stat & 0x2000)

if stat & 0x1000:
Expand All @@ -1964,8 +1964,8 @@ def _int2stat(stat):
cfg_change = bool(stat & 0x400)
modified = bool(stat & 0x200)

time_quality = DataFrame.TIME_QUALITY_WORDS[stat & 0x1c0]
unlocked = DataFrame.UNLOCKED_TIME_WORDS[stat & 0x30]
time_quality = DataFrame.TIME_QUALITY_WORDS[(stat & 0x1c0) >> 6]
unlocked = DataFrame.UNLOCKED_TIME_WORDS[(stat & 0x30) >> 4]
trigger_reason = DataFrame.TRIGGER_REASON_WORDS[stat & 0xf]

return measurement_status, sync, sorting, trigger, cfg_change, modified, time_quality, unlocked, trigger_reason
Expand Down Expand Up @@ -2140,13 +2140,13 @@ def _freq2int(freq, data_format):
if isinstance(data_format, int):
data_format = DataFrame._int2format(data_format)

if data_format[3]: # FREQ/DFREQ floating point
if not -32.767 <= freq <= 32.767:
raise ValueError("FREQ must be in range -32.767 <= FREQ <= 32.767.")
if data_format[3]: # FREQ/DFREQ floating point, actual frequency value, input in Hz.
if not -32767 <= freq <= 32767:
raise ValueError("FREQ must be in range -32767 <= FREQ <= 32767.")

freq = unpack("!I", pack("!f", float(freq)))[0]
else:
if not -32767 <= freq <= 32767:
if not -32767 <= freq <= 32767: #FREQ 16-bit integer, should be frequency deviation from nominal(mHz). It is divided by 1000 and added to FNOM.
raise ValueError("FREQ must be 16-bit signed integer. -32767 <= FREQ <= 32767.")
freq = unpack("!H", pack("!h", freq))[0]

Expand Down Expand Up @@ -2357,7 +2357,7 @@ def get_measurements(self):
"phasors": self.get_phasors()[i],
"analog": self.get_analog()[i],
"digital": self.get_digital()[i],
"frequency": self.cfg.get_fnom()[i] + self.get_freq()[i] / 1000,
"frequency": (self.get_freq()[i]) if (self.cfg.get_data_format()[i])[3] else self.cfg.get_fnom()[i] + self.get_freq()[i] / 1000,
"rocof": self.get_dfreq()[i]}

measurements.append(measurement)
Expand All @@ -2368,7 +2368,7 @@ def get_measurements(self):
"phasors": self.get_phasors(),
"analog": self.get_analog(),
"digital": self.get_digital(),
"frequency": self.cfg.get_fnom() + self.get_freq() / 1000,
"frequency": (self.get_freq()) if (self.cfg.get_data_format())[3] else self.cfg.get_fnom() + self.get_freq() / 1000,
"rocof": self.get_dfreq()
})

Expand Down