278 lines · 11.5 KB · C#
RawDownload
//******************************************************************************************************//  AverageFrequency.cs - Gbtc////  Copyright © 2012, Grid Protection Alliance.  All Rights Reserved.////  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See//  the NOTICE file distributed with this work for additional information regarding copyright ownership.//  The GPA licenses this file to you under the MIT License (MIT), the "License"; you may//  not use this file except in compliance with the License. You may obtain a copy of the License at:////      http://www.opensource.org/licenses/MIT////  Unless agreed to in writing, the subject software distributed under the License is distributed on an//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the//  License for the specific language governing permissions and limitations.////  Code Modification History://  ----------------------------------------------------------------------------------------------------//  11/22/2006 - J. Ritchie Carroll//       Initial version of source generated//  12/24/2009 - Jian R. Zuo//       Converted code to C#//  04/12/2010 - J. Ritchie Carroll//       Performed full code review, optimization and further abstracted code for average calculation.//  12/13/2012 - Starlynn Danyelle Gilliam//       Modified Header.////****************************************************************************************************** using System;using System.Collections.Concurrent;using System.Collections.Generic;using System.ComponentModel;using System.Text;using GSF;using GSF.TimeSeries;using GSF.TimeSeries.Adapters;using GSF.Units.EE;using PhasorProtocolAdapters; namespace PowerCalculations{    /// <summary>    /// Calculates a real-time average frequency reporting the average, maximum and minimum values.    /// </summary>    [Description("Average Frequency: Calculates a real-time average frequency reporting the average, maximum, and minimum values")]    public class AverageFrequency : CalculatedMeasurementBase    {        #region [ Members ]         // Constants        private const double DefaultLowFrequencyThreshold = 57.0D;        private const double DefaultHighFrequencyThreshold = 62.0D;        private const bool DefaultReportUnreasonableResultsAsNaN = false;         // Fields        private double m_averageFrequency;        private double m_maximumFrequency;        private double m_minimumFrequency;        private readonly ConcurrentDictionary<Guid, Tuple<int, long>> m_lastValues = new ConcurrentDictionary<Guid, Tuple<int, long>>();         // Important: Make sure output definition defines points in the following order        private enum Output        {            Average,            Maximum,            Minimum        }         #endregion         #region [ Properties ]         /// <summary>        /// Gets or sets low frequency reasonability threshold, inclusive.        /// </summary>        [ConnectionStringParameter]        [Description("Defines low frequency reasonability threshold. Value is inclusive, i.e., frequency will be unreasonable at and beyond specified threshold.")]        [DefaultValue(DefaultLowFrequencyThreshold)]        public double LowFrequencyThreshold        {            get;            set;        }         /// <summary>        /// Gets or sets high frequency reasonability threshold, inclusive.        /// </summary>        [ConnectionStringParameter]        [Description("Defines high frequency reasonability threshold. Value is inclusive, i.e., frequency will be unreasonable at and beyond specified threshold.")]        [DefaultValue(DefaultHighFrequencyThreshold)]        public double HighFrequencyThreshold        {            get;            set;        }         /// <summary>        /// Gets or sets flag that determines if unreasonable results should be reported as NaN.        /// </summary>        [ConnectionStringParameter]        [Description("Defines flag that determines if unreasonable results should be reported as NaN.")]        [DefaultValue(DefaultReportUnreasonableResultsAsNaN)]        public bool ReportUnreasonableResultsAsNaN        {            get;            set;        }         /// <summary>        /// Returns the detailed status of the <see cref="AverageFrequency"/> calculator.        /// </summary>        public override string Status        {            get            {                StringBuilder status = new StringBuilder();                 status.AppendFormat("   Low frequency threshold: {0:N3} Hz", LowFrequencyThreshold);                status.AppendLine();                status.AppendFormat("  High frequency threshold: {0:N3} Hz", HighFrequencyThreshold);                status.AppendLine();                status.AppendFormat("Report unreasonable as NaN: {0}", ReportUnreasonableResultsAsNaN);                status.AppendLine();                status.AppendFormat("    Last average frequency: {0:N3} Hz", m_averageFrequency);                status.AppendLine();                status.AppendFormat("    Last maximum frequency: {0:N3} Hz", m_maximumFrequency);                status.AppendLine();                status.AppendFormat("    Last minimum frequency: {0:N3} Hz", m_minimumFrequency);                status.AppendLine();                status.Append(base.Status);                 return status.ToString();            }        }        #endregion         #region [ Methods ]         /// <summary>        /// Initializes the <see cref="AverageFrequency"/> calculator.        /// </summary>        public override void Initialize()        {            base.Initialize();             Dictionary<string, string> settings = Settings;            string setting;            double threshold;             // Get settings            if (settings.TryGetValue("LowFrequencyThreshold", out setting) && double.TryParse(setting, out threshold))                LowFrequencyThreshold = threshold;            else                LowFrequencyThreshold = DefaultLowFrequencyThreshold;             if (settings.TryGetValue("HighFrequencyThreshold", out setting) && double.TryParse(setting, out threshold))                HighFrequencyThreshold = threshold;            else                HighFrequencyThreshold = DefaultHighFrequencyThreshold;             if (settings.TryGetValue("ReportUnreasonableResultsAsNaN", out setting))                ReportUnreasonableResultsAsNaN = setting.ParseBoolean();            else                ReportUnreasonableResultsAsNaN = DefaultReportUnreasonableResultsAsNaN;             // Validate input measurements            List<MeasurementKey> validInputMeasurementKeys = new List<MeasurementKey>();             for (int i = 0; i < InputMeasurementKeys.Length; i++)            {                if (InputMeasurementKeyTypes[i] == SignalType.FREQ)                    validInputMeasurementKeys.Add(InputMeasurementKeys[i]);            }             if (validInputMeasurementKeys.Count == 0)                throw new InvalidOperationException("No valid frequency measurements were specified as inputs to the average frequency calculator.");             // Make sure only frequencies are used as input            InputMeasurementKeys = validInputMeasurementKeys.ToArray();             // Validate output measurements            if (OutputMeasurements.Length < Enum.GetValues(typeof(Output)).Length)                throw new InvalidOperationException("Not enough output measurements were specified for the average frequency calculator, expecting measurements for \"Average\", \"Maximum\", and \"Minimum\" frequencies - in this order.");        }         /// <summary>        /// Calculates the average frequency for all frequencies that have reported in the specified lag time.        /// </summary>        /// <param name="frame">Single frame of measurement data within a one second sample.</param>        /// <param name="index">Index of frame within the one second sample.</param>        protected override void PublishFrame(IFrame frame, int index)        {            if (frame.Measurements.Count > 0)            {                double total = 0.0D;                double maximumFrequency = LowFrequencyThreshold;                double minimumFrequency = HighFrequencyThreshold;                int count = 0;                 foreach (IMeasurement measurement in frame.Measurements.Values)                {                    double frequency = measurement.AdjustedValue;                     // Do some simple flat line avoidance, validating at three decimal places...                    int truncatedFrequency = (int)(frequency * 1000.0D);                     Tuple<int, long> lastValues = m_lastValues.GetOrAdd(measurement.ID, id => new Tuple<int, long>(truncatedFrequency, 0L));                    long flatLineCount = lastValues.Item2;                     if (lastValues.Item1 == truncatedFrequency)                    {                        flatLineCount++;                         // If value remains the same more than 4 times, assume flat-line value                        if (flatLineCount > 4L)                            frequency = double.NaN;                    }                    else                    {                        flatLineCount = 0L;                    }                     m_lastValues[measurement.ID] = new Tuple<int, long>(truncatedFrequency, flatLineCount);                     // Validate frequency                    if (!double.IsNaN(frequency) && frequency > LowFrequencyThreshold && frequency < HighFrequencyThreshold)                    {                        total += frequency;                         if (frequency > maximumFrequency)                            maximumFrequency = frequency;                         if (frequency < minimumFrequency)                            minimumFrequency = frequency;                         count++;                    }                }                 if (count > 0)                {                    m_averageFrequency = total / count;                    m_maximumFrequency = maximumFrequency;                    m_minimumFrequency = minimumFrequency;                }                 if (ReportUnreasonableResultsAsNaN)                {                    if (m_averageFrequency <= LowFrequencyThreshold || m_averageFrequency >= HighFrequencyThreshold)                        m_averageFrequency = double.NaN;                     if (m_maximumFrequency <= LowFrequencyThreshold || m_maximumFrequency >= HighFrequencyThreshold)                        m_maximumFrequency = double.NaN;                     if (m_minimumFrequency <= LowFrequencyThreshold || m_minimumFrequency >= HighFrequencyThreshold)                        m_minimumFrequency = double.NaN;                }                 // Provide calculated measurements for external consumption                IMeasurement[] outputMeasurements = OutputMeasurements;                 OnNewMeasurements(new IMeasurement[]{                    Measurement.Clone(outputMeasurements[(int)Output.Average], m_averageFrequency, frame.Timestamp),                    Measurement.Clone(outputMeasurements[(int)Output.Maximum], m_maximumFrequency, frame.Timestamp),                    Measurement.Clone(outputMeasurements[(int)Output.Minimum], m_minimumFrequency, frame.Timestamp)});            }            else            {                m_averageFrequency = 0.0D;                m_maximumFrequency = 0.0D;                m_minimumFrequency = 0.0D;            }        }         #endregion    }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t