/// <summary> /// Creates a new <see cref="FrequencyDefinition"/> from the specified parameters. /// </summary> /// <param name="parent">The <see cref="ConfigurationCell"/> parent of this <see cref="FrequencyDefinition"/>.</param> /// <param name="entryValue">The entry value from the INI based configuration file.</param> public FrequencyDefinition(ConfigurationCell parent, string entryValue) : base(parent) { string[] entry = entryValue.Split(','); int index = 0; FrequencyDefinition defaultFrequency = parent is null ? new FrequencyDefinition(null) : parent.Parent.DefaultFrequency; // If initial entry is an F - we just ignore this if (string.Compare(entry[index].Trim(), "F", StringComparison.OrdinalIgnoreCase) == 0) { index++; } ScalingValue = entry.Length > index?uint.Parse(entry[index++].Trim()) : defaultFrequency.ScalingValue; Offset = entry.Length > index?double.Parse(entry[index++].Trim()) : defaultFrequency.Offset; DfDtScalingValue = entry.Length > index?uint.Parse(entry[index++].Trim()) : defaultFrequency.DfDtScalingValue; DfDtOffset = entry.Length > index?double.Parse(entry[index++].Trim()) : defaultFrequency.DfDtOffset; m_dummy = entry.Length > index?int.Parse(entry[index++].Trim()) : defaultFrequency.m_dummy; Label = entry.Length > index ? entry[index].Trim() : defaultFrequency.Label; }
/// <summary> /// Creates a new <see cref="FrequencyDefinition"/> from the specified parameters. /// </summary> /// <param name="parent">The <see cref="ConfigurationCell"/> parent of this <see cref="FrequencyDefinition"/>.</param> /// <param name="entryValue">The entry value from the INI based configuration file.</param> public FrequencyDefinition(ConfigurationCell parent, string entryValue) : base(parent) { string[] entry = entryValue.Split(','); FrequencyDefinition defaultFrequency; int index = 0; if (parent != null) defaultFrequency = parent.Parent.DefaultFrequency; else defaultFrequency = new FrequencyDefinition(null as IConfigurationCell); // If initial entry is an F - we just ignore this if (string.Compare(entry[index].Trim(), "F", StringComparison.OrdinalIgnoreCase) == 0) index++; if (entry.Length > index) ScalingValue = uint.Parse(entry[index++].Trim()); else ScalingValue = defaultFrequency.ScalingValue; if (entry.Length > index) Offset = double.Parse(entry[index++].Trim()); else Offset = defaultFrequency.Offset; if (entry.Length > index) DfDtScalingValue = uint.Parse(entry[index++].Trim()); else DfDtScalingValue = defaultFrequency.DfDtScalingValue; if (entry.Length > index) DfDtOffset = double.Parse(entry[index++].Trim()); else DfDtOffset = defaultFrequency.DfDtOffset; if (entry.Length > index) m_dummy = int.Parse(entry[index++].Trim()); else m_dummy = defaultFrequency.m_dummy; if (entry.Length > index) Label = entry[index++].Trim(); else Label = defaultFrequency.Label; }
// Static Methods // Creates frequency information for an INI based BPA PDCstream configuration file internal static string ConfigFileFormat(IFrequencyDefinition definition) { FrequencyDefinition frequency = definition as FrequencyDefinition; // type, scale, offset, dF/dt scale, dF/dt offset, dummy, label // F, 1000, 60, 1000, 0, 0, Frequency if (frequency != null) { return("F," + frequency.ScalingValue + "," + frequency.Offset + "," + frequency.DfDtScalingValue + "," + frequency.DfDtOffset + "," + frequency.m_dummy + "," + frequency.Label); } else if (definition != null) { return("F," + definition.ScalingValue + "," + definition.Offset + "," + definition.DfDtScalingValue + "," + definition.DfDtOffset + ",0," + definition.Label); } return(""); }
/// <summary> /// Creates a new <see cref="FrequencyValue"/> from specified parameters. /// </summary> /// <param name="parent">The <see cref="DataCell"/> parent of this <see cref="FrequencyValue"/>.</param> /// <param name="frequencyDefinition">The <see cref="FrequencyDefinition"/> associated with this <see cref="FrequencyValue"/>.</param> /// <param name="frequency">The floating point value that represents this <see cref="FrequencyValue"/>.</param> /// <param name="dfdt">The floating point value that represents the change in this <see cref="FrequencyValue"/> over time.</param> public FrequencyValue(DataCell parent, FrequencyDefinition frequencyDefinition, double frequency, double dfdt) : base(parent, frequencyDefinition, frequency, dfdt) { }
/// <summary> /// Creates a new <see cref="ConfigurationCell"/> from specified parameters. /// </summary> /// <param name="parent">The parent <see cref="ConfigurationFrame"/> reference to use.</param> /// <param name="deviceLabel">INI section device label to use.</param> public ConfigurationCell(ConfigurationFrame parent, string deviceLabel = null) : base(parent, 0, Common.MaximumPhasorValues, Common.MaximumAnalogValues, Common.MaximumDigitalValues) { // Assign station name that came in from header frame StationName = parent.StationName; if (!string.IsNullOrEmpty(deviceLabel)) { SectionEntry = deviceLabel; } // Add a single frequency definition FrequencyDefinition = new FrequencyDefinition(this) { Label = "Line frequency" }; OnlineDataFormatFlags flags = parent.OnlineDataFormatFlags; PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 1", PhasorType.Voltage, null)); if ((flags & OnlineDataFormatFlags.Phasor2Enabled) == OnlineDataFormatFlags.Phasor2Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 2", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Phasor3Enabled) == OnlineDataFormatFlags.Phasor3Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 3", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Phasor4Enabled) == OnlineDataFormatFlags.Phasor4Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 4", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Phasor5Enabled) == OnlineDataFormatFlags.Phasor5Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 5", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Phasor6Enabled) == OnlineDataFormatFlags.Phasor6Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 6", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Phasor7Enabled) == OnlineDataFormatFlags.Phasor7Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 7", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Phasor8Enabled) == OnlineDataFormatFlags.Phasor8Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 8", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Phasor9Enabled) == OnlineDataFormatFlags.Phasor9Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 9", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Phasor10Enabled) == OnlineDataFormatFlags.Phasor10Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 10", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Digital1Enabled) == OnlineDataFormatFlags.Digital1Enabled) { DigitalDefinitions.Add(new DigitalDefinition(this, "Digital 1")); } if ((flags & OnlineDataFormatFlags.Digital2Enabled) == OnlineDataFormatFlags.Digital2Enabled) { DigitalDefinitions.Add(new DigitalDefinition(this, "Digital 2")); } }
// Static Methods /// <summary> /// Gets a generated INI configuration file image. /// </summary> public static string GetIniFileImage(IConfigurationFrame configFrame) { StringBuilder fileImage = new StringBuilder(); fileImage.AppendLine("; BPA PDCstream Style IniFile for Macrodyne Configuration " + configFrame.IDCode); fileImage.AppendLine("; Auto-generated on " + DateTime.Now); fileImage.AppendLine("; Assembly: " + AssemblyInfo.ExecutingAssembly.Name); fileImage.AppendLine("; Compiled: " + File.GetLastWriteTime(AssemblyInfo.ExecutingAssembly.Location)); fileImage.AppendLine(";"); fileImage.AppendLine(";"); fileImage.AppendLine("; Format:"); fileImage.AppendLine("; Each Column in data file is given a bracketed identifier, numbered in the order it"); fileImage.AppendLine("; appears in the data file, and identified by data type ( PMU, PDC, or other)"); fileImage.AppendLine("; PMU designates column data format from a single PMU"); fileImage.AppendLine("; PDC designates column data format from another PDC which is somewhat different from a single PMU"); fileImage.AppendLine("; Default gives default values for a processing algorithm in case quantities are omitted"); fileImage.AppendLine("; Name= gives the overall station name for print labels"); fileImage.AppendLine("; NumberPhasors= : for PMU data, gives the number of phasors contained in column"); fileImage.AppendLine("; for PDC data, gives the number of PMUs data included in the column"); fileImage.AppendLine("; Note - for PDC data, there will be 2 phasors & 1 freq per PMU"); fileImage.AppendLine("; Quantities within the column are listed by PhasorI=, Frequency=, etc"); fileImage.AppendLine("; Each quantity has 7 comma separated fields followed by an optional comment"); fileImage.AppendLine(";"); fileImage.AppendLine("; Phasor entry format: Type, Ratio, Cal Factor, Offset, Shunt, VoltageRef/Class, Label ;Comments"); fileImage.AppendLine("; Type: Type of measurement, V=voltage, I=current, N=don\'t care, single ASCII character"); fileImage.AppendLine("; Ratio: PT/CT ratio N:1 where N is a floating point number"); fileImage.AppendLine("; Cal Factor: Conversion factor between integer in file and secondary volts, floating point"); fileImage.AppendLine("; Offset: Phase Offset to correct for phase angle measurement errors or differences, floating point"); fileImage.AppendLine("; Shunt: Current- shunt resistence in ohms, or the equivalent ratio for aux CTs, floating point"); fileImage.AppendLine("; Voltage- empty, not used"); fileImage.AppendLine("; VoltageRef: Current- phasor number (1-10) of voltage phasor to use for power calculation, integer"); fileImage.AppendLine("; Voltage- voltage class, standard l-l voltages, 500, 230, 115, etc, integer"); fileImage.AppendLine("; Label: Phasor quantity label for print label, text"); fileImage.AppendLine("; Comments: All text after the semicolon on a line are optional comments not for processing"); fileImage.AppendLine(";"); fileImage.AppendLine("; Voltage Magnitude = MAG(Real,Imaginary) * CalFactor * PTR (line-neutral)"); fileImage.AppendLine("; Current Magnitude = MAG(Real,Imaginary) * CalFactor * CTR / Shunt (phase current)"); fileImage.AppendLine("; Phase Angle = ATAN(Imaginary/Real) + Phase Offset (usually degrees)"); fileImage.AppendLine("; Note: Usually phase Offset is 0, but is sometimes required for comparing measurements"); fileImage.AppendLine("; from different systems or through transformer banks"); fileImage.AppendLine(";"); fileImage.AppendLine("; Frequency entry format: scale, offset, dF/dt scale, dF/dt offset, dummy, label ;Comments"); fileImage.AppendLine("; Frequency = Number / scale + offset"); fileImage.AppendLine("; dF/dt = Number / (dF/dt scale) + (dF/dt offset)"); fileImage.AppendLine(";"); fileImage.AppendLine(";"); fileImage.AppendLine("[DEFAULT]"); fileImage.AppendLine("PhasorV=" + DefaultVoltagePhasorEntry); //PhasorDefinition.ConfigFileFormat(DefaultPhasorV)); fileImage.AppendLine("PhasorI=" + DefaultCurrentPhasorEntry); //PhasorDefinition.ConfigFileFormat(DefaultPhasorI)); fileImage.AppendLine("Frequency=" + DefaultFrequencyEntry); //FrequencyDefinition.ConfigFileFormat(DefaultFrequency)); fileImage.AppendLine(); fileImage.AppendLine("[CONFIG]"); fileImage.AppendLine("SampleRate=" + configFrame.FrameRate); fileImage.AppendLine("NumberOfPMUs=" + configFrame.Cells.Count); fileImage.AppendLine(); for (int x = 0; x < configFrame.Cells.Count; x++) { fileImage.AppendLine("[" + configFrame.Cells[x].IDLabel + "]"); fileImage.AppendLine("Name=" + configFrame.Cells[x].StationName); fileImage.AppendLine("PMU=" + x); fileImage.AppendLine("NumberPhasors=" + configFrame.Cells[x].PhasorDefinitions.Count); for (int y = 0; y < configFrame.Cells[x].PhasorDefinitions.Count; y++) { fileImage.AppendLine("Phasor" + (y + 1) + "=" + PhasorDefinition.ConfigFileFormat(configFrame.Cells[x].PhasorDefinitions[y])); } fileImage.AppendLine("Frequency=" + FrequencyDefinition.ConfigFileFormat(configFrame.Cells[x].FrequencyDefinition)); fileImage.AppendLine(); } return(fileImage.ToString()); }
/// <summary> /// Reload Macrodyne INI based configuration file. /// </summary> public void Refresh() { if ((object)m_iniFile == null) { return; } // The only time we need an access lock is when we reload the config file... lock (m_iniFile) { if (File.Exists(m_iniFile.FileName)) { ConfigurationCell pmuCell; int phasorCount, pmuCount, x, y; m_defaultPhasorV = new PhasorDefinition(null, 0, m_iniFile["DEFAULT", "PhasorV", DefaultVoltagePhasorEntry]); m_defaultPhasorI = new PhasorDefinition(null, 0, m_iniFile["DEFAULT", "PhasorI", DefaultCurrentPhasorEntry]); m_defaultFrequency = new FrequencyDefinition(null, m_iniFile["DEFAULT", "Frequency", DefaultFrequencyEntry]); FrameRate = ushort.Parse(m_iniFile["CONFIG", "SampleRate", "30"]); // We read all cells in the config file into their own configuration cell collection - cells parsed // from the configuration frame will be mapped to their associated config file cell by ID label // when the configuration cell is parsed from the configuration frame if (m_configurationFileCells == null) { m_configurationFileCells = new ConfigurationCellCollection(int.MaxValue); } m_configurationFileCells.Clear(); // Load phasor data for each section in config file... foreach (string section in m_iniFile.GetSectionNames()) { if (section.Length > 0) { // Make sure this is not a special section if (string.Compare(section, "DEFAULT", true) != 0 && string.Compare(section, "CONFIG", true) != 0) { // Create new PMU entry structure from config file settings... phasorCount = int.Parse(m_iniFile[section, "NumberPhasors", "0"]); // Check for PDC code int pdcID = int.Parse(m_iniFile[section, "PDC", "-1"]); if (pdcID == -1) { // No PDC entry exists, assume this is a PMU pmuCell = new ConfigurationCell(this); pmuCell.IDCode = ushort.Parse(m_iniFile[section, "PMU", Cells.Count.ToString()]); pmuCell.SectionEntry = section; // This will automatically assign ID label as first 4 digits of section pmuCell.StationName = m_iniFile[section, "Name", section]; pmuCell.PhasorDefinitions.Clear(); for (x = 0; x < phasorCount; x++) { pmuCell.PhasorDefinitions.Add(new PhasorDefinition(pmuCell, x + 1, m_iniFile[section, "Phasor" + (x + 1), DefaultVoltagePhasorEntry])); } pmuCell.FrequencyDefinition = new FrequencyDefinition(pmuCell, m_iniFile[section, "Frequency", DefaultFrequencyEntry]); m_configurationFileCells.Add(pmuCell); } else { // This is a PDC, need to define one virtual entry for each PMU pmuCount = int.Parse(m_iniFile[section, "NumberPMUs", "0"]); for (x = 0; x < pmuCount; x++) { // Create a new PMU cell for each PDC entry that exists pmuCell = new ConfigurationCell(this); // For BPA INI files, PMUs tradionally have an ID number indexed starting at zero or one - so we multiply // ID by 1000 and add index to attempt to create a fairly unique ID to help optimize downstream parsing pmuCell.IDCode = unchecked ((ushort)(pdcID * 1000 + x)); pmuCell.SectionEntry = string.Format("{0}pmu{1}", section, x); // This will automatically assign ID label as first 4 digits of section pmuCell.StationName = string.Format("{0} - Device {1}", m_iniFile[section, "Name", section], (x + 1)); pmuCell.PhasorDefinitions.Clear(); for (y = 0; y < 2; y++) { pmuCell.PhasorDefinitions.Add(new PhasorDefinition(pmuCell, y + 1, m_iniFile[section, "Phasor" + ((x * 2) + (y + 1)), DefaultVoltagePhasorEntry])); } pmuCell.FrequencyDefinition = new FrequencyDefinition(pmuCell, m_iniFile[section, "Frequency", DefaultFrequencyEntry]); m_configurationFileCells.Add(pmuCell); } } } } } // Associate single Macrodyne cell with its associated cell hopefully defined in INI file if (m_configurationFileCells.Count > 0 && (object)Cells != null && Cells.Count > 0) { ConfigurationCell configurationFileCell = null; // Assign INI file cell associating by section entry ConfigurationCell cell = Cells[0]; // Attempt to associate this configuration cell with information read from external INI based configuration file m_configurationFileCells.TryGetBySectionEntry(cell.SectionEntry, ref configurationFileCell); cell.ConfigurationFileCell = configurationFileCell; m_onlineDataFormatFlags = Common.GetFormatFlagsFromPhasorCount(cell.PhasorDefinitions.Count); m_stationName = cell.StationName; } } else { throw new InvalidOperationException("Macrodyne config file \"" + m_iniFile.FileName + "\" does not exist."); } } // In case other classes want to know, we send out a notification that the config file has been reloaded (make sure // you do this after the write lock has been released to avoid possible dead-lock situations) if (ConfigurationFileReloaded != null) { ConfigurationFileReloaded(this, EventArgs.Empty); } }
/// <summary> /// Creates a new <see cref="FrequencyDefinition"/> from the specified parameters. /// </summary> /// <param name="parent">The <see cref="ConfigurationCell"/> parent of this <see cref="FrequencyDefinition"/>.</param> /// <param name="entryValue">The entry value from the INI based configuration file.</param> public FrequencyDefinition(ConfigurationCell parent, string entryValue) : base(parent) { string[] entry = entryValue.Split(','); FrequencyDefinition defaultFrequency; int index = 0; if (parent != null) { defaultFrequency = parent.Parent.DefaultFrequency; } else { defaultFrequency = new FrequencyDefinition(null as IConfigurationCell); } // If initial entry is an F - we just ignore this if (string.Compare(entry[index].Trim(), "F", StringComparison.OrdinalIgnoreCase) == 0) { index++; } if (entry.Length > index) { ScalingValue = uint.Parse(entry[index++].Trim()); } else { ScalingValue = defaultFrequency.ScalingValue; } if (entry.Length > index) { Offset = double.Parse(entry[index++].Trim()); } else { Offset = defaultFrequency.Offset; } if (entry.Length > index) { DfDtScalingValue = uint.Parse(entry[index++].Trim()); } else { DfDtScalingValue = defaultFrequency.DfDtScalingValue; } if (entry.Length > index) { DfDtOffset = double.Parse(entry[index++].Trim()); } else { DfDtOffset = defaultFrequency.DfDtOffset; } if (entry.Length > index) { m_dummy = int.Parse(entry[index++].Trim()); } else { m_dummy = defaultFrequency.m_dummy; } if (entry.Length > index) { Label = entry[index++].Trim(); } else { Label = defaultFrequency.Label; } }