Source code for pymu.transferFrame

from struct import *
from .pmuLib import *
from .pmuEnum import *
from PyCRC.CRCCCITT import CRCCCITT
import time

[docs]class TransferFrame(): """ Custom class meant to create a message that can be passed to a socket connection. Only contains timestamp, phasor values, and ID for each phasor :param inputDataFrame: Populated data frame containing measurement values :type inputDataFrame: pmuDataFrame """ def __init__(self, inputDataFrame): self.header = "AAFF" self.length = 0 self.timestamp = None self.numOfPhasors = 0 self.phasors = [] self.crc = None self.fullFrameBytes = "" self.fullFrameHexStr = "" self.dataFrame = inputDataFrame self.parseDataSample() self.createFullFrame()
[docs] def parseDataSample(self): """Parse the input data sample""" self.length += len(self.header)/2 # Separator self.timestamp = self.dataFrame.soc.utcSec + (self.dataFrame.fracsec / self.dataFrame.configFrame.time_base.baseDecStr) self.parsePhasors() self.length += len(pack('d', self.timestamp)) # Double self.length += len(pack('H', self.numOfPhasors)) # Unsigned Short self.length += len(pack('I', int(self.length))) # Unsigned Int
[docs] def parsePhasors(self): """Parse the phasors in the data sample to extract measurements""" ident = 0 for p in range(0, self.dataFrame.configFrame.num_pmu): for ph in range(0, self.dataFrame.pmus[p].numOfPhsrs): units = self.dataFrame.configFrame.stations[p].phunits[ph].voltORcurr pField = PhasorField(self.dataFrame.pmus[p].phasors[ph], ident, units) self.length += len(pField.fullFrameHexStr)/2 self.phasors.append(pField) ident = ident + 1 self.numOfPhasors = len(self.phasors)
[docs] def genCrc(self): """Generate CRC-CCITT""" crcCalc = CRCCCITT('FFFF') frameInBytes = bytes.fromhex(self.fullFrameHexStr) theCrc = hex(crcCalc.calculate(frameInBytes))[2:].zfill(4) self.crc = theCrc.upper()
[docs] def createFullFrame(self): """Put all the pieces to together to create full transfer frame""" self.fullFrameHexStr += self.header self.fullFrameHexStr += intToHexStr(int(self.length)).zfill(8).upper() self.fullFrameHexStr += doubleToHexStr(self.timestamp).zfill(16).upper() self.fullFrameHexStr += intToHexStr(self.numOfPhasors).zfill(4).upper() for pf in self.phasors: self.fullFrameHexStr += pf.fullFrameHexStr # Removed CRC because it was slowing down transfer rates #self.genCrc() #self.fullFrameHexStr += self.crc self.fullFrameBytes = bytes.fromhex(self.fullFrameHexStr)
# # # # # # # Part of the frame that contains phasor values. # This field is repeated as needed in the frame # # # # # #
[docs]class PhasorField(): """Class to hold simplified phasor fields :param phasor: Phasor containing measurements :type phasor: Phasor :param idNum: Frame ID to use :type idNum: int :param theUnits: Volts or Amps :type theUnits: str """ def __init__(self, phasor, idNum, theUnits): self.options = None self.fullFrameHexStr = None self.length = 0 self.phasorFrame = phasor self.ident = idNum self.value = self.phasorFrame.mag self.angle = self.phasorFrame.rad self.units = theUnits self.parseOptions() self.createPhasorFieldFrame()
[docs] def parseOptions(self): """Parse options and create bytes as hex str""" if self.units == "VOLTAGE": self.options = intToHexStr(0).zfill(4) else: self.options = intToHexStr(2 ** 15)
[docs] def createPhasorFieldFrame(self): """Create phasor field frame inside full transfer frame""" fullFrameHexStr = "" fullFrameHexStr += intToHexStr(self.ident).zfill(4) fullFrameHexStr += doubleToHexStr(self.value) fullFrameHexStr += doubleToHexStr(self.angle) fullFrameHexStr += self.options self.fullFrameHexStr = fullFrameHexStr.upper() self.length = int(len(fullFrameHexStr)/2)