/// <summary> /// Calculates MW, MVAR and MVA then publishes those measurements /// </summary> /// <param name="frame">Input values for calculation</param> /// <param name="index">Index of frame within second.</param> protected override void PublishFrame(IFrame frame, int index) { ConcurrentDictionary <MeasurementKey, IMeasurement> measurements = frame.Measurements; Ticks totalCalculationTime = DateTime.UtcNow.Ticks; Ticks lastCalculationTime = DateTime.UtcNow.Ticks; List <IMeasurement> outputMeasurements = new List <IMeasurement>(); int calculations = 0; foreach (PowerCalculation powerCalculation in m_configuredCalculations) { double activePower = double.NaN, reactivePower = double.NaN, apparentPower = double.NaN; IMeasurement measurement; try { double voltageMagnitude = 0.0D, voltageAngle = 0.0D, currentMagnitude = 0.0D, currentAngle = 0.0D; bool allValuesReceivedWithGoodQuality = false; lastCalculationTime = DateTime.UtcNow.Ticks; if (measurements.TryGetValue(powerCalculation.VoltageMagnitudeMeasurementKey, out measurement) && measurement.ValueQualityIsGood()) { voltageMagnitude = measurement.AdjustedValue; if (!m_adjustmentStrategies.TryGetValue(powerCalculation.VoltageMagnitudeMeasurementKey, out VoltageAdjustmentStrategy adjustmentStrategy)) { adjustmentStrategy = AdjustmentStrategy; } switch (adjustmentStrategy) { case VoltageAdjustmentStrategy.LineToNeutral: voltageMagnitude *= 3.0D; break; case VoltageAdjustmentStrategy.LineToLine: voltageMagnitude *= SqrtOf3; break; case VoltageAdjustmentStrategy.LineToLineSinglePhase: voltageMagnitude /= SqrtOf3; break; } if (measurements.TryGetValue(powerCalculation.VoltageAngleMeasurementKey, out measurement) && measurement.ValueQualityIsGood()) { voltageAngle = measurement.AdjustedValue; if (measurements.TryGetValue(powerCalculation.CurrentMagnitudeMeasurementKey, out measurement) && measurement.ValueQualityIsGood()) { currentMagnitude = measurement.AdjustedValue; if (measurements.TryGetValue(powerCalculation.CurrentAngleMeasurementKey, out measurement) && measurement.ValueQualityIsGood()) { currentAngle = measurement.AdjustedValue; allValuesReceivedWithGoodQuality = true; } } } } if (allValuesReceivedWithGoodQuality) { // Calculate power (P), reactive power (Q) and apparent power (|S|) Phasor voltage = new Phasor(PhasorType.Voltage, Angle.FromDegrees(voltageAngle), voltageMagnitude); Phasor current = new Phasor(PhasorType.Current, Angle.FromDegrees(currentAngle), currentMagnitude); activePower = Phasor.CalculateActivePower(voltage, current) / SI.Mega; reactivePower = Phasor.CalculateReactivePower(voltage, current) / SI.Mega; apparentPower = Phasor.CalculateApparentPower(voltage, current) / SI.Mega; } } catch (Exception ex) { OnProcessException(MessageLevel.Warning, ex); } finally { if (!(powerCalculation.ActivePowerOutputMeasurement is null)) { Measurement activePowerMeasurement = Measurement.Clone(powerCalculation.ActivePowerOutputMeasurement, activePower, frame.Timestamp); if (AlwaysProduceResult || !double.IsNaN(activePowerMeasurement.Value)) { outputMeasurements.Add(activePowerMeasurement); calculations++; m_lastActivePowerCalculations.Enqueue(activePowerMeasurement); while (m_lastActivePowerCalculations.Count > ValuesToTrack) { m_lastActivePowerCalculations.TryDequeue(out measurement); } } } if (!(powerCalculation.ReactivePowerOutputMeasurement is null)) { Measurement reactivePowerMeasurement = Measurement.Clone(powerCalculation.ReactivePowerOutputMeasurement, reactivePower, frame.Timestamp); if (AlwaysProduceResult || !double.IsNaN(reactivePowerMeasurement.Value)) { outputMeasurements.Add(reactivePowerMeasurement); calculations++; m_lastReactivePowerCalculations.Enqueue(reactivePowerMeasurement); while (m_lastReactivePowerCalculations.Count > ValuesToTrack) { m_lastReactivePowerCalculations.TryDequeue(out measurement); } } } if (!(powerCalculation.ApparentPowerOutputMeasurement is null)) { Measurement apparentPowerMeasurement = Measurement.Clone(powerCalculation.ApparentPowerOutputMeasurement, apparentPower, frame.Timestamp); if (AlwaysProduceResult || !double.IsNaN(apparentPowerMeasurement.Value)) { outputMeasurements.Add(apparentPowerMeasurement); calculations++; m_lastApparentPowerCalculations.Enqueue(apparentPowerMeasurement); while (m_lastApparentPowerCalculations.Count > ValuesToTrack) { m_lastApparentPowerCalculations.TryDequeue(out measurement); } } } m_averageCalculationTime.AddValue((DateTime.UtcNow.Ticks - lastCalculationTime).ToMilliseconds()); } } m_lastTotalCalculationTime = (DateTime.UtcNow.Ticks - totalCalculationTime).ToMilliseconds(); m_averageTotalCalculationTime.AddValue(m_lastTotalCalculationTime); m_lastTotalCalculations = calculations; m_averageCalculationsPerFrame.AddValue(calculations); OnNewMeasurements(outputMeasurements); }