/// <summary> /// Initializes <see cref="PhasorInputOscillationDetector" />. /// </summary> public override void Initialize() { InputCount = 4; OutputCount = Outputs.Length; base.Initialize(); MeasurementKey getMeasurementKey(SignalType signalType) => InputMeasurementKeys.Where((_, index) => InputMeasurementKeyTypes[index] == signalType).FirstOrDefault(); // Validate input contains voltage and current phase angle / magnitude measurement keys m_voltageMagnitude = getMeasurementKey(SignalType.VPHM) ?? throw new InvalidOperationException("One voltage magnitude input measurement is required. Cannot initialize adapter."); m_voltageAngle = getMeasurementKey(SignalType.VPHA) ?? throw new InvalidOperationException("One voltage angle input measurement is required. Cannot initialize adapter."); m_currentMagnitude = getMeasurementKey(SignalType.IPHM) ?? throw new InvalidOperationException("One current magnitude input measurement is required. Cannot initialize adapter."); m_currentAngle = getMeasurementKey(SignalType.IPHA) ?? throw new InvalidOperationException("One current angle input measurement is required. Cannot initialize adapter."); // Make sure input measurement keys are in desired order InputMeasurementKeys = new[] { m_voltageMagnitude, m_voltageAngle, m_currentMagnitude, m_currentAngle }; // Provide algorithm with parameters as configured by adapter PseudoConfiguration configuration = new PseudoConfiguration { FramesPerSecond = FramesPerSecond, IsLineToNeutral = AdjustmentStrategy == VoltageAdjustmentStrategy.LineToNeutral }; m_detector.DetectorAPI = new PseudoDetectorAPI { Configuration = configuration }; m_detector.OutputMeasurements = OutputMeasurements; m_detector.FramesPerSecond = FramesPerSecond; m_detector.InputTypes = InputMeasurementKeyTypes; m_detector.Initialize(Name); }
private double CalculateSignalToNoise(List <double> values, Guid key) { int sampleCount = values.Count; int keyIndex = InputMeasurementKeys.IndexOf(item => item.SignalID == key); SignalType keySignalType = InputMeasurementKeyTypes[keyIndex]; // If its a Phase if ((keySignalType == SignalType.IPHA || keySignalType == SignalType.VPHA) && sampleCount == m_refWindow.Count && Reference != null) { values = Angle.Unwrap(values.Select((item, index) => item - (Angle)m_refWindow[index]).ToArray()).Select(item => (double)item).ToList(); } values = values.Where(item => !double.IsNaN(item)).ToList(); sampleCount = values.Count; if (sampleCount < 1) { return(double.NaN); } double sampleAverage = values.Average(); double totalVariance = values.Select(item => item - sampleAverage).Select(deviation => deviation * deviation).Sum(); double result = 10 * Math.Log10(Math.Abs(sampleAverage / Math.Sqrt(totalVariance / sampleCount))); return(double.IsInfinity(result) ? double.NaN : result); }
/// <summary> /// Initializes the <see cref="ImpedanceCalculator"/> monitor. /// </summary> public override void Initialize() { base.Initialize(); // Load needed phase angle and magnitude measurement keys from defined InputMeasurementKeys m_voltageAngles = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.VPHA).ToArray(); m_voltageMagnitudes = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.VPHM).ToArray(); m_currentAngles = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHA).ToArray(); m_currentMagnitudes = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHM).ToArray(); if (m_voltageAngles.Length != m_voltageMagnitudes.Length) { throw new InvalidOperationException("A different number of voltage magnitude and angle input measurement keys were supplied - the angles and magnitudes must be supplied in pairs, i.e., one voltage magnitude input measurement must be supplied for each voltage angle input measurement in a consecutive sequence (e.g., VA1;VM1; VA2;VM2)"); } if (m_currentAngles.Length != m_currentMagnitudes.Length) { throw new InvalidOperationException("A different number of current magnitude and angle input measurement keys were supplied - the angles and magnitudes must be supplied in pairs, i.e., one current magnitude input measurement must be supplied for each current angle input measurement in a consecutive sequence (e.g., IA1;IM1; IA2;IM2)"); } if (m_voltageAngles.Length != 2) { throw new InvalidOperationException("Exactly two voltage angle input measurements are required for the impedance calculator, note that \"Vs\" angle/magnitude pair should be specified first followed by \"Vr\" angle/magnitude pair second."); } if (m_voltageMagnitudes.Length != 2) { throw new InvalidOperationException("Exactly two voltage magnitude input measurements are required for the impedance calculator, note that \"Vs\" angle/magnitude pair should be specified first followed by \"Vr\" angle/magnitude pair second."); } if (m_currentAngles.Length != 2) { throw new InvalidOperationException("Exactly two current angle input measurements are required for the impedance calculator, note that \"Is\" angle/magnitude pair should be specified first followed by \"Ir\" angle/magnitude pair second."); } if (m_currentMagnitudes.Length != 2) { throw new InvalidOperationException("Exactly two current magnitude input measurements are required for the impedance calculator, note that \"Is\" angle/magnitude pair should be specified first followed by \"Ir\" angle/magnitude pair second."); } // Make sure only these phasor measurements are used as input InputMeasurementKeys = m_voltageAngles.Concat(m_voltageMagnitudes).Concat(m_currentAngles).Concat(m_currentMagnitudes).ToArray(); // Validate output measurements if (OutputMeasurements.Length < Enum.GetValues(typeof(Output)).Length) { throw new InvalidOperationException("Not enough output measurements were specified for the impedance calculator, expecting measurements for the \"Resistance\", \"Reactance\", \"Conductance\", \"Susceptance\", \"LineImpedance\", \"LineImpedanceAngle\", \"LineAdmittance\" and \"LineAdmittanceAngle\" - in this order."); } Dictionary <string, string> settings = Settings; string setting; ApplyLineToLineAdjustment = !settings.TryGetValue("ApplyLineToLineAdjustment", out setting) || setting.ParseBoolean(); }
private IMeasurement GetBestMeasurement(IFrame frame) { IMeasurement measurement; if (m_publishBadValues) { return(InputMeasurementKeys .Select(key => frame.Measurements.TryGetValue(key, out measurement) ? measurement : null) .Where(m => (object)m != null) .OrderBy(m => (m_handleNaNAsBad && double.IsNaN(m.Value)) ? 1 : 0) .ThenBy(m => (m_handleZeroAsBad && m.Value == 0.0D) ? 1 : 0) .ThenBy(m => CountFlags(m.StateFlags & m_badFlags)) .FirstOrDefault()); } return(InputMeasurementKeys .Select(key => frame.Measurements.TryGetValue(key, out measurement) ? measurement : null) .Where(m => (object)m != null) .Where(m => !m_handleNaNAsBad || !double.IsNaN(m.Value)) .Where(m => !m_handleZeroAsBad || m.Value != 0.0D) .Where(m => (m.StateFlags & m_badFlags) == MeasurementStateFlags.Normal) .FirstOrDefault()); }
/// <summary> /// Initializes <see cref="FileExporter"/>. /// </summary> public override void Initialize() { base.Initialize(); Dictionary <string, string> settings = Settings; const string errorMessage = "{0} is missing from Settings - Example: exportInterval=5; useReferenceAngle=True; referenceAngleMeasurement=DEVARCHIVE:6; companyTagPrefix=TVA; useNumericQuality=True; inputMeasurementKeys={{FILTER ActiveMeasurements WHERE Device='SHELBY' AND SignalType='FREQ'}}"; string setting; double seconds; // Load required parameters if (!settings.TryGetValue("exportInterval", out setting) || !double.TryParse(setting, out seconds)) { throw new ArgumentException(string.Format(errorMessage, "exportInterval")); } m_exportInterval = (int)(seconds * 1000.0D); m_lastPublicationTime = 0; if (m_exportInterval <= 0) { throw new ArgumentException("exportInterval should not be 0 - Example: exportInterval=5.5"); } if (InputMeasurementKeys == null || InputMeasurementKeys.Length == 0) { throw new InvalidOperationException("There are no input measurements defined. You must define \"inputMeasurementKeys\" to define which measurements to export."); } if (!settings.TryGetValue("useReferenceAngle", out setting)) { throw new ArgumentException(string.Format(errorMessage, "useReferenceAngle")); } m_useReferenceAngle = setting.ParseBoolean(); if (m_useReferenceAngle) { // Reference angle measurement has to be defined if using reference angle if (!settings.TryGetValue("referenceAngleMeasurement", out setting)) { throw new ArgumentException(string.Format(errorMessage, "referenceAngleMeasurement")); } m_referenceAngleKey = MeasurementKey.Parse(setting); // Make sure reference angle is part of input measurement keys collection if (!InputMeasurementKeys.Contains(m_referenceAngleKey)) { InputMeasurementKeys = InputMeasurementKeys.Concat(new[] { m_referenceAngleKey }).ToArray(); } // Make sure sure reference angle key is actually an angle measurement SignalType signalType = InputMeasurementKeyTypes[InputMeasurementKeys.IndexOf(key => key == m_referenceAngleKey)]; if (signalType != SignalType.IPHA && signalType != SignalType.VPHA) { throw new InvalidOperationException(string.Format("Specified reference angle measurement key is a {0} signal, not a phase angle.", signalType.GetFormattedName())); } } // Load optional parameters if (settings.TryGetValue("companyTagPrefix", out setting)) { m_companyTagPrefix = setting.ToUpper().Trim(); } else { m_companyTagPrefix = null; } if (settings.TryGetValue("useNumericQuality", out setting)) { m_useNumericQuality = setting.ParseBoolean(); } else { m_useNumericQuality = false; } // Suffix company tag prefix with an underscore if defined if (!string.IsNullOrWhiteSpace(m_companyTagPrefix)) { m_companyTagPrefix = m_companyTagPrefix.EnsureEnd('_'); } // Define a default export location - user can override and add multiple locations in config later... m_dataExporter = new MultipleDestinationExporter(ConfigurationSection, m_exportInterval); m_dataExporter.StatusMessage += m_dataExporter_StatusMessage; m_dataExporter.ProcessException += m_dataExporter_ProcessException; m_dataExporter.Initialize(new[] { new ExportDestination(FilePath.GetAbsolutePath(ConfigurationSection + ".txt"), false) }); // Create new measurement tag name dictionary m_measurementTags = new ConcurrentDictionary <MeasurementKey, string>(); string pointID = "undefined"; // Lookup point tag name for input measurement in the ActiveMeasurements table foreach (MeasurementKey key in InputMeasurementKeys) { try { // Get measurement key as a string pointID = key.ToString(); // Lookup measurement key in active measurements table DataRow row = DataSource.Tables["ActiveMeasurements"].Select(string.Format("ID='{0}'", pointID))[0]; // Remove invalid symbols that may be in tag name string pointTag = row["PointTag"].ToNonNullString(pointID).Replace('-', '_').Replace(':', '_').ToUpper(); // Prefix point tag with company prefix if defined if (!string.IsNullOrWhiteSpace(m_companyTagPrefix) && !pointTag.StartsWith(m_companyTagPrefix)) { pointTag = m_companyTagPrefix + pointTag; } m_measurementTags.TryAdd(key, pointTag); } catch (ThreadAbortException) { throw; } catch (Exception ex) { OnProcessException(new InvalidOperationException(string.Format("Failed to lookup point tag for measurement [{0}] due to exception: {1}", pointID, ex.Message))); } } // We enable tracking of latest measurements so we can use these values if points are missing - since we are using // latest measurement tracking, we sort all incoming points even though most of them will be thrown out... TrackLatestMeasurements = true; }
/// <summary> /// Initializes the <see cref="PowerCalculator"/>. /// </summary> public override void Initialize() { base.Initialize(); Dictionary <string, string> settings = Settings; string setting; // Load parameters if (settings.TryGetValue("trackRecentValues", out setting)) { m_trackRecentValues = setting.ParseBoolean(); } else { m_trackRecentValues = true; } if (settings.TryGetValue("sampleSize", out setting)) // Data sample size to monitor, in seconds { m_sampleSize = int.Parse(setting); } else { m_sampleSize = 5; } // Load needed phase angle and magnitude measurement keys from defined InputMeasurementKeys m_voltageAngle = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.VPHA).FirstOrDefault(); m_voltageMagnitude = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.VPHM).FirstOrDefault(); m_currentAngle = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHA).FirstOrDefault(); m_currentMagnitude = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHM).FirstOrDefault(); if ((object)m_voltageAngle == null || m_voltageAngle.ID == 0) { throw new InvalidOperationException("No voltage angle input was defined - one voltage angle input measurement is required for the power calculator."); } if ((object)m_voltageMagnitude == null || m_voltageMagnitude.ID == 0) { throw new InvalidOperationException("No voltage magnitude input was defined - one voltage magnitude input measurement is required for the power calculator."); } if ((object)m_currentAngle == null || m_currentAngle.ID == 0) { throw new InvalidOperationException("No current angle input was defined - one current angle input measurement is required for the power calculator."); } if ((object)m_currentMagnitude == null || m_currentMagnitude.ID == 0) { throw new InvalidOperationException("No current magnitude input measurement was defined - one current magnitude input measurement is required for the power calculator."); } // Make sure only these four phasor measurements are used as input (any others will be ignored) InputMeasurementKeys = new[] { m_voltageAngle, m_voltageMagnitude, m_currentAngle, m_currentMagnitude }; // Validate output measurements if (OutputMeasurements.Length < Enum.GetValues(typeof(Output)).Length) { throw new InvalidOperationException("Not enough output measurements were specified for the power calculator, expecting measurements for the \"Calculated Power\" and the \"Calculated Reactive Power\" - in this order."); } if (m_trackRecentValues) { m_powerSample = new List <double>(); m_reactivePowerSample = new List <double>(); } // Assign a default adapter name to be used if power calculator is loaded as part of automated collection if (string.IsNullOrWhiteSpace(Name)) { Name = string.Format("PC!{0}", OutputMeasurements[(int)Output.Power].Key); } }
/// <summary> /// Initializes <see cref="FileExporter"/>. /// </summary> public override void Initialize() { base.Initialize(); Dictionary <string, string> settings = Settings; const string errorMessage = "{0} is missing from Settings - Example: exportInterval=5; modelIdentifier=Goslin; referenceAngleMeasurement=DEVARCHIVE:6; inputMeasurementKeys={{FILTER ActiveMeasurements WHERE Device='SHELBY' AND SignalType='FREQ'}}"; string setting; double seconds; // Load required parameters if (!settings.TryGetValue("exportInterval", out setting) || !double.TryParse(setting, out seconds)) { throw new ArgumentException(string.Format(errorMessage, "exportInterval")); } if (!settings.TryGetValue("fileExportPath", out m_fileExportPath)) { m_fileExportPath = FilePath.GetAbsolutePath(""); } m_exportInterval = (int)(seconds * 1000.0D); if (m_exportInterval <= 0) { throw new ArgumentException("exportInterval should not be 0 - Example: exportInterval=5.5"); } if ((object)InputMeasurementKeys == null || InputMeasurementKeys.Length == 0) { throw new InvalidOperationException("There are no input measurements defined. You must define \"inputMeasurementKeys\" to define which measurements to export."); } // Reference angle measurement has to be defined if using reference angle if (!settings.TryGetValue("referenceAngleMeasurement", out setting)) { throw new ArgumentException(string.Format(errorMessage, "referenceAngleMeasurement")); } m_referenceAngleKey = MeasurementKey.Parse(setting); // Make sure reference angle is first angle of input measurement keys collection InputMeasurementKeys = (new[] { m_referenceAngleKey }).Concat(InputMeasurementKeys).ToArray(); // Make sure sure reference angle key is actually an angle measurement SignalType signalType = InputMeasurementKeyTypes[InputMeasurementKeys.IndexOf(key => key == m_referenceAngleKey)]; if (signalType != SignalType.IPHA && signalType != SignalType.VPHA) { throw new InvalidOperationException(string.Format("Specified reference angle measurement key is a {0} signal, not a phase angle.", signalType.GetFormattedName())); } Comments = settings.TryGetValue("comments", out setting) ? setting : "Comment section---"; if (!settings.TryGetValue("modelIdentifier", out setting)) { throw new ArgumentException(string.Format(errorMessage, "modelIdentifier")); } ModelIdentifier = setting; // We enable tracking of latest measurements so we can use these values if points are missing - since we are using // latest measurement tracking, we sort all incoming points even though most of them will be thrown out... TrackLatestMeasurements = true; //// Create a new dictionary of base voltages //m_baseVoltages = new Dictionary<MeasurementKey, double>(); StringBuilder header = new StringBuilder(); //MeasurementKey voltageMagnitudeKey; //double baseKV; // Write header row header.Append("TimeStamp"); DataTable measurements = DataSource.Tables["ActiveMeasurements"]; int tieLines = 0; bool referenceAdded = false; for (int i = 0; i < InputMeasurementKeys.Length; i++) { // Lookup measurement key in active measurements table DataRow row = measurements.Select(string.Format("ID='{0}'", InputMeasurementKeys[i]))[0]; string deviceName = row["Device"].ToNonNullString("UNDEFINED").ToUpper().Trim(); if (!referenceAdded && InputMeasurementKeys[i] == m_referenceAngleKey) { header.AppendFormat(",Ref. Angle of {0}", deviceName); referenceAdded = true; } else { switch (InputMeasurementKeyTypes[i]) { case SignalType.VPHM: header.AppendFormat(",{0} |V|", deviceName); tieLines++; //voltageMagnitudeKey = InputMeasurementKeys[i]; //if (settings.TryGetValue(voltageMagnitudeKey + "BaseKV", out setting) && double.TryParse(setting, out baseKV)) //{ // m_baseVoltages.Add(voltageMagnitudeKey, baseKV * SI.Kilo); //} //else //{ // int baseKVCode; // // Second check if base KV can be inferred from device name suffixed KV index // if (int.TryParse(deviceName[deviceName.Length - 1].ToString(), out baseKVCode) && baseKVCode > 1 && baseKVCode < BaseKVs.Length) // { // m_baseVoltages.Add(voltageMagnitudeKey, BaseKVs[baseKVCode]); // } // else // { // OnStatusMessage("WARNING: Did not find a valid base KV setting for voltage magnitude {0}, assumed 500KV", voltageMagnitudeKey.ToString()); // m_baseVoltages.Add(voltageMagnitudeKey, 500.0D * SI.Kilo); // } //} break; case SignalType.VPHA: header.AppendFormat(",{0} Voltage Angle", deviceName); break; case SignalType.IPHM: header.AppendFormat(",{0} |I|", deviceName); break; case SignalType.IPHA: header.AppendFormat(",{0} Current Angle", deviceName); break; default: header.AppendFormat(",{0} ??", deviceName); break; } } } string row5 = header.ToString(); header = new StringBuilder(); // Add row 1 header.AppendFormat("Comments: {0}\r\n", Comments); // Add row 2 header.AppendFormat("Model Identifier: {0}\r\n", ModelIdentifier); // Add row 3 header.Append("Datapoints,Tielines,TimeStep"); if (InputMeasurementKeys.Length - 3 > 0) { header.Append(new string(',', InputMeasurementKeys.Length - 3)); } header.AppendLine(); // Add row 4 header.AppendFormat("{0},{1},{2}", RowCountMarker, tieLines, 1.0D / FramesPerSecond); header.AppendLine(); // Add row 5 header.AppendLine(row5); // Cache header for each file export m_header = header.ToString(); }
/// <summary> /// Initializes the <see cref="PowerCalculator"/>. /// </summary> public override void Initialize() { base.Initialize(); Dictionary <string, string> settings = Settings; // Load parameters if (settings.TryGetValue(nameof(TrackRecentValues), out string setting)) { TrackRecentValues = setting.ParseBoolean(); } // Data sample size to monitor, in seconds if (settings.TryGetValue(nameof(SampleSize), out setting) && int.TryParse(setting, out int sampleSize)) { SampleSize = sampleSize; } if (settings.TryGetValue(nameof(IncludePositiveSequence), out setting)) { IncludePositiveSequence = setting.ParseBoolean(); } if (settings.TryGetValue(nameof(IncludeNegativeSequence), out setting)) { IncludeNegativeSequence = setting.ParseBoolean(); } if (settings.TryGetValue(nameof(IncludeZeroSequence), out setting)) { IncludeZeroSequence = setting.ParseBoolean(); } // Load needed phase angle measurement keys from defined InputMeasurementKeys m_angles = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.VPHA).ToArray(); if (m_angles.Length == 0) { // No voltage angles existed, check for current angles m_angles = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHA).ToArray(); } else { // Make sure only one kind of angles are defined - not a mixture of voltage and currents if (InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHA).Any()) { throw new InvalidOperationException("Angle input measurements for a single sequence calculator instance should only be for voltages or currents - not both."); } } // Load needed phase magnitude measurement keys from defined InputMeasurementKeys m_magnitudes = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.VPHM).ToArray(); if (m_magnitudes.Length == 0) { // No voltage magnitudes existed, check for current magnitudes m_magnitudes = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHM).ToArray(); m_magnitudeUnits = "amps"; } else { // Make only one kind of magnitudes are defined - not a mixture of voltage and currents if (InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHM).Any()) { throw new InvalidOperationException("Magnitude input measurements for a single sequence calculator instance should only be for voltages or currents - not both."); } m_magnitudeUnits = "volts"; } if (m_angles.Length < 3) { throw new InvalidOperationException("Three angle input measurements, i.e., A, B and C - in that order, are required for the sequence calculator."); } if (m_magnitudes.Length < 3) { throw new InvalidOperationException("Three magnitude input measurements, i.e., A, B and C - in that order, are required for the sequence calculator."); } if (m_angles.Length != m_magnitudes.Length) { throw new InvalidOperationException("A different number of magnitude and angle input measurement keys were supplied - the angles and magnitudes must be supplied in pairs in A, B, C sequence, i.e., one magnitude input measurement must be supplied for each angle input measurement in a consecutive sequence (e.g., A1;M1; A2;M2; ... An;Mn)"); } // Make sure only these phasor measurements are used as input InputMeasurementKeys = m_angles.Concat(m_magnitudes).ToArray(); // Validate output measurements if (IncludePositiveSequence && IncludeNegativeSequence && IncludeZeroSequence) { if (OutputMeasurements.Length < 6) { throw new InvalidOperationException("Not enough output measurements were specified for the sequence calculator, expecting measurements for the \"Positive Sequence Magnitude\", \"Positive Sequence Angle\", \"Negative Sequence Magnitude\", \"Negative Sequence Angle\", \"Zero Sequence Magnitude\" and \"Zero Sequence Angle\" - in this order."); } } else if (IncludePositiveSequence && IncludeNegativeSequence) { if (OutputMeasurements.Length < 4) { throw new InvalidOperationException("Not enough output measurements were specified for the sequence calculator, expecting measurements for the \"Positive Sequence Magnitude\", \"Positive Sequence Angle\", \"Negative Sequence Magnitude\" and \"Negative Sequence Angle\" - in this order."); } } else if (IncludePositiveSequence && IncludeZeroSequence) { if (OutputMeasurements.Length < 4) { throw new InvalidOperationException("Not enough output measurements were specified for the sequence calculator, expecting measurements for the \"Positive Sequence Magnitude\", \"Positive Sequence Angle\", \"Zero Sequence Magnitude\" and \"Zero Sequence Angle\" - in this order."); } } else if (IncludeNegativeSequence && IncludeZeroSequence) { if (OutputMeasurements.Length < 4) { throw new InvalidOperationException("Not enough output measurements were specified for the sequence calculator, expecting measurements for the \"Negative Sequence Magnitude\", \"Negative Sequence Angle\", \"Zero Sequence Magnitude\" and \"Zero Sequence Angle\" - in this order."); } } else if (IncludePositiveSequence) { if (OutputMeasurements.Length < 2) { throw new InvalidOperationException("Not enough output measurements were specified for the sequence calculator, expecting measurements for the \"Positive Sequence Magnitude\" and \"Positive Sequence Angle\" - in this order."); } } else if (IncludeNegativeSequence) { if (OutputMeasurements.Length < 2) { throw new InvalidOperationException("Not enough output measurements were specified for the sequence calculator, expecting measurements for the \"Negative Sequence Magnitude\" and \"Negative Sequence Angle\" - in this order."); } } else if (IncludeZeroSequence) { if (OutputMeasurements.Length < 2) { throw new InvalidOperationException("Not enough output measurements were specified for the sequence calculator, expecting measurements for the \"Zero Sequence Magnitude\" and \"Zero Sequence Angle\" - in this order."); } } else { throw new InvalidOperationException("At least one of positive, negative or sequence calculations must be included to calculate."); } if (TrackRecentValues) { m_positiveSequenceMagnitudeSample = new List <double>(); m_positiveSequenceAngleSample = new List <double>(); m_negativeSequenceMagnitudeSample = new List <double>(); m_negativeSequenceAngleSample = new List <double>(); m_zeroSequenceMagnitudeSample = new List <double>(); m_zeroSequenceAngleSample = new List <double>(); } // Assign a default adapter name to be used if sequence calculator is loaded as part of automated collection if (string.IsNullOrWhiteSpace(Name)) { Name = $"SC!{OutputMeasurements[(int)Output.PositiveSequenceMagnitude].Key}"; } }
/// <summary> /// Initializes <see cref="UnBalancedCalculation"/>. /// </summary> public override void Initialize() { new ConnectionStringParser <CalculatedMesaurementAttribute>().ParseConnectionString(ConnectionString, this); base.Initialize(); m_threePhaseComponent = new List <ThreePhaseSet>(); m_statisticsMapping = new Dictionary <Guid, StatisticsCollection>(); m_saveStats = SaveAggregates; CategorizedSettingsElementCollection reportSettings = ConfigurationFile.Current.Settings["reportSettings"]; reportSettings.Add("IUnbalanceThreshold", "4.0", "Current Unbalance Alert threshold."); reportSettings.Add("VUnbalanceThreshold", "4.0", "Voltage Unbalance Alert threshold."); double i_threshold = reportSettings["IUnbalanceThreshold"].ValueAs(1.0D); double v_threshold = reportSettings["VUnbalanceThreshold"].ValueAs(1.0D); List <Guid> processed = new List <Guid>(); using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) { TableOperations <MeasurementRecord> measurementTable = new TableOperations <MeasurementRecord>(connection); TableOperations <ActiveMeasurement> activeMeasurmentTable = new TableOperations <ActiveMeasurement>(connection); TableOperations <Device> deviceTable = new TableOperations <Device>(connection); TableOperations <SignalTypeRecord> signalTable = new TableOperations <SignalTypeRecord>(connection); Device device = deviceTable.QueryRecordWhere("Acronym = {0}", ResultDeviceName); int historianID = Convert.ToInt32(connection.ExecuteScalar("SELECT ID FROM Historian WHERE Acronym = {0}", new object[] { HistorianInstance })); // Take Care of the Device if (InputMeasurementKeys.Length < 1) { return; } m_nodeID = deviceTable.QueryRecordWhere("Id={0}", measurementTable.QueryRecordWhere("SignalID = {0}", InputMeasurementKeys[0].SignalID).DeviceID).NodeID; if (device == null) { device = CreateDefaultDevice(deviceTable); OnStatusMessage(MessageLevel.Warning, $"Default Device for Output Measurments not found. Created Device {device.Acronym}"); } if (MappingFilePath != "") { // Read Mapping File using (StreamReader reader = new StreamReader(FilePath.GetAbsolutePath(MappingFilePath))) { string line; int index = -1; while ((line = reader.ReadLine()) != null) { index++; List <string> pointTags = line.Split(',').Select(item => item.Trim()).ToList(); List <MeasurementKey> availableInputs = new List <MeasurementKey>(3); if (pointTags.Count != 3) { OnStatusMessage(MessageLevel.Warning, $"Skipping Line {index} in mapping file."); continue; } OnStatusMessage(MessageLevel.Info, $"PointTag of Measurment 1 is: {pointTags[0]}"); OnStatusMessage(MessageLevel.Info, $"PointTag of Measurment 1 is: {pointTags[0]}"); OnStatusMessage(MessageLevel.Info, $"PointTag of Measurment 1 is: {pointTags[0]}"); // check if measurments are in inputmeasurments availableInputs.Add(InputMeasurementKeys.FirstOrDefault(item => item.SignalID == GetSignalID(pointTags[0], activeMeasurmentTable))); availableInputs.Add(InputMeasurementKeys.FirstOrDefault(item => item.SignalID == GetSignalID(pointTags[1], activeMeasurmentTable))); availableInputs.Add(InputMeasurementKeys.FirstOrDefault(item => item.SignalID == GetSignalID(pointTags[2], activeMeasurmentTable))); if (availableInputs[0] == null || availableInputs[1] == null || availableInputs[2] == null) { OnStatusMessage(MessageLevel.Warning, $"Skipping Line {index} in mapping file. PointTag not found"); continue; } SignalType type = GetSignalType(availableInputs[0], new TableOperations <ActiveMeasurement>(connection)); MeasurementKey neg = availableInputs.FirstOrDefault(item => SearchNegative(item, new TableOperations <ActiveMeasurement>(connection)) && GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type); MeasurementKey pos = availableInputs.FirstOrDefault(item => SearchPositive(item, new TableOperations <ActiveMeasurement>(connection)) && GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type); MeasurementKey zero = availableInputs.FirstOrDefault(item => SearchZero(item, new TableOperations <ActiveMeasurement>(connection)) && GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type ); if (neg != null && zero != null && pos != null) { MeasurementKey unBalance; string outputReference = measurementTable.QueryRecordWhere("SignalID = {0}", pos.SignalID).SignalReference + "-" + (type == SignalType.IPHM? "I" : "V") + "UBAL"; if (measurementTable.QueryRecordCountWhere("SignalReference = {0}", outputReference) > 0) { // Measurement Exists unBalance = MeasurementKey.LookUpBySignalID(measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID); } else { // Add Measurment to Database and make a statement MeasurementRecord inMeasurement = measurementTable.QueryRecordWhere("SignalID = {0}", pos.SignalID); MeasurementRecord outMeasurement = new MeasurementRecord { HistorianID = historianID, DeviceID = device.ID, PointTag = inMeasurement.PointTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL", AlternateTag = inMeasurement.AlternateTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL", SignalTypeID = signalTable.QueryRecordWhere("Acronym = {0}", "CALC").ID, SignalReference = outputReference, Description = GetDescription(pos, new TableOperations <ActiveMeasurement>(connection)) + " UnBalanced", Enabled = true, CreatedOn = DateTime.UtcNow, UpdatedOn = DateTime.UtcNow, CreatedBy = UserInfo.CurrentUserID, UpdatedBy = UserInfo.CurrentUserID, SignalID = Guid.NewGuid(), Adder = 0.0D, Multiplier = 1.0D }; measurementTable.AddNewRecord(outMeasurement); unBalance = MeasurementKey.LookUpBySignalID(measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID); OnStatusMessage(MessageLevel.Warning, $"Output measurment {outputReference} not found. Creating measurement"); } double threshold = InputMeasurementKeyTypes[InputMeasurementKeys.IndexOf(item => item == availableInputs[0])] == SignalType.IPHM ? i_threshold : v_threshold; m_threePhaseComponent.Add(new ThreePhaseSet(pos, zero, neg, unBalance, threshold)); if (m_saveStats) { m_statisticsMapping.Add(pos.SignalID, CreateStatistics(measurementTable, pos, device, historianID, type)); } } else { OnStatusMessage(MessageLevel.Warning, $"Skipping Line {index} in mapping file. Did not find pos. neg. and zero seq."); } } } } else { foreach (MeasurementKey key in InputMeasurementKeys) { if (processed.Contains(key.SignalID)) { continue; } // ensure only magnitudes are being used if (!(GetSignalType(key, new TableOperations <ActiveMeasurement>(connection)) == SignalType.IPHM || GetSignalType(key, new TableOperations <ActiveMeasurement>(connection)) == SignalType.VPHM)) { continue; } bool isNeg = SearchNegative(key, new TableOperations <ActiveMeasurement>(connection)); bool isPos = SearchPositive(key, new TableOperations <ActiveMeasurement>(connection)); bool isZero = SearchZero(key, new TableOperations <ActiveMeasurement>(connection)); if (!(isNeg || isPos || isZero)) { continue; } string description = GetDescription(key, new TableOperations <ActiveMeasurement>(connection)); // Check to make sure can actually deal with this if (description == string.Empty) { OnStatusMessage(MessageLevel.Warning, "Failed to apply automatic Line bundling to " + key.SignalID); continue; } //Make sure only correct Type (V vs I) makes it here.... SignalType type = GetSignalType(key, new TableOperations <ActiveMeasurement>(connection)); MeasurementKey neg = InputMeasurementKeys.FirstOrDefault(item => GetDescription(item, new TableOperations <ActiveMeasurement>(connection)) == description && SearchNegative(item, new TableOperations <ActiveMeasurement>(connection)) && GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type); MeasurementKey pos = InputMeasurementKeys.FirstOrDefault(item => GetDescription(item, new TableOperations <ActiveMeasurement>(connection)) == description && SearchPositive(item, new TableOperations <ActiveMeasurement>(connection)) && GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type); MeasurementKey zero = InputMeasurementKeys.FirstOrDefault(item => GetDescription(item, new TableOperations <ActiveMeasurement>(connection)) == description && SearchZero(item, new TableOperations <ActiveMeasurement>(connection)) && GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type ); if (neg != null && zero != null && pos != null) { MeasurementKey unBalance; string outputReference = measurementTable.QueryRecordWhere("SignalID = {0}", pos.SignalID).SignalReference + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL"; if (measurementTable.QueryRecordCountWhere("SignalReference = {0}", outputReference) > 0) { // Measurement Exists unBalance = MeasurementKey.LookUpBySignalID(measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID); } else { // Add Measurment to Database and make a statement MeasurementRecord inMeasurement = measurementTable.QueryRecordWhere("SignalID = {0}", pos.SignalID); MeasurementRecord outMeasurement = new MeasurementRecord { HistorianID = historianID, DeviceID = device.ID, PointTag = inMeasurement.PointTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL", AlternateTag = inMeasurement.AlternateTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL", SignalTypeID = signalTable.QueryRecordWhere("Acronym = {0}", "CALC").ID, SignalReference = outputReference, Description = GetDescription(pos, new TableOperations <ActiveMeasurement>(connection)) + " UnBalanced", Enabled = true, CreatedOn = DateTime.UtcNow, UpdatedOn = DateTime.UtcNow, CreatedBy = UserInfo.CurrentUserID, UpdatedBy = UserInfo.CurrentUserID, SignalID = Guid.NewGuid(), Adder = 0.0D, Multiplier = 1.0D }; measurementTable.AddNewRecord(outMeasurement); unBalance = MeasurementKey.LookUpBySignalID(measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID); OnStatusMessage(MessageLevel.Warning, $"Output measurment {outputReference} not found. Creating measurement"); } double threshold = InputMeasurementKeyTypes[InputMeasurementKeys.IndexOf(item => item == key)] == SignalType.IPHM ? i_threshold : v_threshold; m_threePhaseComponent.Add(new ThreePhaseSet(pos, zero, neg, unBalance, threshold)); processed.Add(pos.SignalID); processed.Add(neg.SignalID); processed.Add(zero.SignalID); if (m_saveStats) { m_statisticsMapping.Add(pos.SignalID, CreateStatistics(measurementTable, pos, device, historianID, type)); } } else { if (pos != null) { processed.Add(pos.SignalID); } if (neg != null) { processed.Add(neg.SignalID); } if (zero != null) { processed.Add(zero.SignalID); } } } } if (m_threePhaseComponent.Count == 0) { OnStatusMessage(MessageLevel.Error, "No case with all 3 sequences was found"); } } }
/// <summary> /// Initializes the <see cref="PowerStability"/> monitor. /// </summary> public override void Initialize() { base.Initialize(); Dictionary <string, string> settings = Settings; string setting; // Load parameters if (settings.TryGetValue("sampleSize", out setting)) // Data sample size to monitor, in seconds { m_minimumSamples = int.Parse(setting) * FramesPerSecond; } else { m_minimumSamples = 15 * FramesPerSecond; } if (settings.TryGetValue("energizedThreshold", out setting)) // Energized bus threshold, in volts, recommended value { m_energizedThreshold = double.Parse(setting); // is 20% of nominal line-to-neutral voltage } else { m_energizedThreshold = 58000.0D; } // Load needed phase angle and magnitude measurement keys from defined InputMeasurementKeys m_voltageAngles = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.VPHA).ToArray(); m_voltageMagnitudes = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.VPHM).ToArray(); m_currentAngles = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHA).ToArray(); m_currentMagnitudes = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHM).ToArray(); if (m_voltageAngles.Length < 1) { throw new InvalidOperationException("No voltage angle input measurement keys were not found - at least one voltage angle input measurement is required for the power stability monitor."); } if (m_voltageMagnitudes.Length < 1) { throw new InvalidOperationException("No voltage magnitude input measurement keys were not found - at least one voltage magnitude input measurement is required for the power stability monitor."); } if (m_currentAngles.Length < 1) { throw new InvalidOperationException("No current angle input measurement keys were not found - at least one current angle input measurement is required for the power stability monitor."); } if (m_currentMagnitudes.Length < 1) { throw new InvalidOperationException("No current magnitude input measurement keys were not found - at least one current magnitude input measurement is required for the power stability monitor."); } if (m_voltageAngles.Length != m_voltageMagnitudes.Length) { throw new InvalidOperationException("A different number of voltage magnitude and angle input measurement keys were supplied - the angles and magnitudes must be supplied in pairs, i.e., one voltage magnitude input measurement must be supplied for each voltage angle input measurement in a consecutive sequence (e.g., VA1;VM1; VA2;VM2; ... VAn;VMn)"); } if (m_currentAngles.Length != m_currentMagnitudes.Length) { throw new InvalidOperationException("A different number of current magnitude and angle input measurement keys were supplied - the angles and magnitudes must be supplied in pairs, i.e., one current magnitude input measurement must be supplied for each current angle input measurement in a consecutive sequence (e.g., IA1;IM1; IA2;IM2; ... IAn;IMn)"); } // Make sure only these phasor measurements are used as input InputMeasurementKeys = m_voltageAngles.Concat(m_voltageMagnitudes).Concat(m_currentAngles).Concat(m_currentMagnitudes).ToArray(); // Validate output measurements if (OutputMeasurements.Length < Enum.GetValues(typeof(Output)).Length) { throw new InvalidOperationException("Not enough output measurements were specified for the power stability monitor, expecting measurements for the \"Calculated Power\", and the \"Standard Deviation of Power\" - in this order."); } m_powerDataSample = new List <double>(); }
/// <summary> /// Initializes <see cref="SNRComputation"/>. /// </summary> public override void Initialize() { new ConnectionStringParser <CalculatedMesaurementAttribute>().ParseConnectionString(ConnectionString, this); base.Initialize(); // Figure Output Measurement Keys m_dataWindow = new Dictionary <Guid, List <double> >(); m_refWindow = new List <double>(); m_outputMapping = new Dictionary <Guid, MeasurementKey>(); m_statisticsMapping = new Dictionary <Guid, StatisticsCollection>(); m_saveStats = SaveAggregates; if (ReportingInterval % (double)WindowLength != 0.0D) { ReportingInterval = WindowLength * (ReportingInterval / WindowLength); OnStatusMessage(MessageLevel.Warning, $"Adjusting Reporting Interval to every {ReportingInterval} frames."); } CategorizedSettingsElementCollection reportSettings = ConfigurationFile.Current.Settings["reportSettings"]; reportSettings.Add("DefaultSNRThreshold", "4.0", "Default SNR Alert threshold."); m_threshold = reportSettings["DefaultSNRThreshold"].ValueAs(m_threshold); using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) { TableOperations <MeasurementRecord> measurementTable = new TableOperations <MeasurementRecord>(connection); TableOperations <Device> deviceTable = new TableOperations <Device>(connection); TableOperations <SignalTypeRecord> signalTable = new TableOperations <SignalTypeRecord>(connection); Device device = deviceTable.QueryRecordWhere("Acronym = {0}", ResultDeviceName); int historianID = Convert.ToInt32(connection.ExecuteScalar("SELECT ID FROM Historian WHERE Acronym = {0}", new object[] { HistorianInstance })); if (!InputMeasurementKeys.Any()) { return; } m_nodeID = deviceTable.QueryRecordWhere("Id={0}", measurementTable.QueryRecordWhere("SignalID = {0}", InputMeasurementKeys[0].SignalID).DeviceID).NodeID; if (device == null) { device = CreateDefaultDevice(deviceTable); OnStatusMessage(MessageLevel.Warning, $"Default Device for Output Measurments not found. Created Device {device.Acronym}"); } foreach (MeasurementKey key in InputMeasurementKeys) { m_dataWindow.Add(key.SignalID, new List <double>()); string outputReference = measurementTable.QueryRecordWhere("SignalID = {0}", key.SignalID).SignalReference + "-SNR"; if (measurementTable.QueryRecordCountWhere("SignalReference = {0}", outputReference) > 0) { // Measurement Exists m_outputMapping.Add(key.SignalID, MeasurementKey.LookUpBySignalID(measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID)); } else { // Add Measurment to Database and make a statement MeasurementRecord inMeasurement = measurementTable.QueryRecordWhere("SignalID = {0}", key.SignalID); MeasurementRecord outMeasurement = new MeasurementRecord { HistorianID = historianID, DeviceID = device.ID, PointTag = inMeasurement.PointTag + "-SNR", AlternateTag = inMeasurement.AlternateTag + "-SNR", SignalTypeID = signalTable.QueryRecordWhere("Acronym = {0}", "CALC").ID, SignalReference = outputReference, Description = inMeasurement.Description + " SNR", Enabled = true, CreatedOn = DateTime.UtcNow, UpdatedOn = DateTime.UtcNow, CreatedBy = UserInfo.CurrentUserID, UpdatedBy = UserInfo.CurrentUserID, SignalID = Guid.NewGuid(), Adder = 0.0D, Multiplier = 1.0D }; measurementTable.AddNewRecord(outMeasurement); m_outputMapping.Add(key.SignalID, MeasurementKey.LookUpBySignalID( measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID)); OnStatusMessage(MessageLevel.Warning, $"Output measurment {outputReference} not found. Creating measurement"); } if (m_saveStats) { m_statisticsMapping.Add(key.SignalID, CreateStatistics(measurementTable, key, device, historianID)); } } if (Reference == null) { OnStatusMessage(MessageLevel.Warning, "No Reference Angle Specified"); int refIndex = InputMeasurementKeyTypes.IndexOf(item => item == SignalType.IPHA || item == SignalType.VPHA); if (refIndex > -1) { Reference = InputMeasurementKeys[refIndex]; } } if (Reference != null) { if (!InputMeasurementKeys.Contains(Reference)) { InputMeasurementKeys.AddRange(new[] { Reference }); } } } }