/// <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);
        }