550 lines · 18.9 KB · C#
RawDownload
//******************************************************************************************************//  RangeTest.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/25/2009 - Stephen C. Wills//       Generated original version of source code.//  12/13/2012 - Starlynn Danyelle Gilliam//       Modified Header.////****************************************************************************************************** using System;using System.Collections.Generic;using System.ComponentModel;using System.Timers;using DataQualityMonitoring.Services;using GSF;using GSF.TimeSeries;using GSF.TimeSeries.Adapters; namespace DataQualityMonitoring{    /// <summary>    /// Tests measurements to determine whether their values satisfy a range condition.    /// </summary>    [Description("Range Test: Notifies when the values of received measurements are outside of a given range")]    public class RangeTest : ActionAdapterBase    {        #region [ Members ]         // Constants         /// <summary>        /// Default low range for frequency measurements.        /// </summary>        public const double DEFAULT_FREQ_LOW_RANGE = 59.95;         /// <summary>        /// Default high range for frequency measurements.        /// </summary>        public const double DEFAULT_FREQ_HIGH_RANGE = 60.05;         /// <summary>        /// Default low range for voltage phasor magnitudes.        /// </summary>        public const double DEFAULT_VPHM_LOW_RANGE = 475000.0;         /// <summary>        /// Default high range for voltage phasor magnitudes.        /// </summary>        public const double DEFAULT_VPHM_HIGH_RANGE = 525000.0;         /// <summary>        /// Default low range for current phasor magnitudes.        /// </summary>        public const double DEFAULT_IPHM_LOW_RANGE = 0.0;         /// <summary>        /// Default high range for current phasor magnitudes.        /// </summary>        public const double DEFAULT_IPHM_HIGH_RANGE = 3000.0;         /// <summary>        /// Default low range for voltage phasor angles.        /// </summary>        public const double DEFAULT_VPHA_LOW_RANGE = -180.0;         /// <summary>        /// Default high range for voltage phasor angles.        /// </summary>        public const double DEFAULT_VPHA_HIGH_RANGE = 180.0;         /// <summary>        /// Default low range for current phasor angles.        /// </summary>        public const double DEFAULT_IPHA_LOW_RANGE = -180.0;         /// <summary>        /// Default high range for current phasor angles.        /// </summary>        public const double DEFAULT_IPHA_HIGH_RANGE = 180.0;         // Fields        private readonly Dictionary<MeasurementKey, LinkedList<IMeasurement>> m_outOfRangeMeasurements;        private string m_signalType;        private double m_lowRange;        private double m_highRange;        private Ticks m_timeToPurge;        private Ticks m_warnInterval;        private readonly Timer m_warningTimer;        private readonly Timer m_purgeTimer;         #endregion         #region [ Constructors ]         /// <summary>        /// Creates a new instance of the <see cref="RangeTest"/> class.        /// </summary>        public RangeTest()        {            m_outOfRangeMeasurements = new Dictionary<MeasurementKey, LinkedList<IMeasurement>>();            m_timeToPurge = Ticks.FromSeconds(1.0);            m_warnInterval = Ticks.FromSeconds(4.0);            m_warningTimer = new Timer();            m_purgeTimer = new Timer();        }         #endregion         #region [ Properties ]         /// <summary>        /// Gets or sets the signal type of the measurements sent to this range test.        /// </summary>        [ConnectionStringParameter,        Description("Define the signal type of the measurements sent to this range test. Valid values are FREQ, VPHM, IPHM, VPHA, IPHA. IMPORTANT: If this is not defined, LowRange and HighRange are required parameters."),        DefaultValue(null)]        public string SignalType        {            get            {                return m_signalType;            }            set            {                m_signalType = value;            }        }         /// <summary>        /// Gets or sets the low range of the measurements sent to this range test.        /// </summary>        [ConnectionStringParameter,        Description("Define the low range of the measurements sent to this range test."),        DefaultValue("")]        public double LowRange        {            get            {                return m_lowRange;            }            set            {                m_lowRange = value;            }        }         /// <summary>        /// Gets or sets the high range of the measurements sent to this range test.        /// </summary>        [ConnectionStringParameter,        Description("Define the high range of the measurements sent to this range test."),        DefaultValue("")]        public double HighRange        {            get            {                return m_highRange;            }            set            {                m_highRange = value;            }        }         /// <summary>        /// Gets or sets the age, in seconds, at which out-of-range measurements are purged.        /// </summary>        [ConnectionStringParameter,        Description("Define the age, in seconds, at which out-of-range measurements are purged from the adapter."),        DefaultValue(1.0)]        public double TimeToPurge        {            get            {                return m_timeToPurge.ToSeconds();            }            set            {                m_timeToPurge = Ticks.FromSeconds(value);            }        }         /// <summary>        /// Gets or sets how often the <see cref="RangeTest"/> sends out-of-range notifications to the console.        /// </summary>        [ConnectionStringParameter,        Description("Define the amount of time, in seconds, between console updates."),        DefaultValue(4.0)]        public double WarnInterval        {            get            {                return m_warnInterval.ToSeconds();            }            set            {                m_warnInterval = Ticks.FromSeconds(value);            }        }         /// <summary>        /// Gets the flag indicating if this adapter supports temporal processing.        /// </summary>        public override bool SupportsTemporalProcessing        {            get            {                return false;            }        }         #endregion         #region [ Methods ]         /// <summary>        /// Initializes this <see cref="RangeTest"/>.        /// </summary>        public override void Initialize()        {            base.Initialize();             string errorMessage = "{0} is missing from Settings - Example: lowRange=59.95; highRange=60.05";            bool rangeSet = false;             Dictionary<string, string> settings = Settings;            string setting;             if (settings.TryGetValue("signalType", out m_signalType))                rangeSet = TrySetRange(m_signalType);             if (!rangeSet)            {                // Load required parameters                if (!settings.TryGetValue("lowRange", out setting))                    throw new ArgumentException(string.Format(errorMessage, "lowRange"));                 m_lowRange = double.Parse(setting);                 if (!settings.TryGetValue("highRange", out setting))                    throw new ArgumentException(string.Format(errorMessage, "highRange"));                 m_highRange = double.Parse(setting);                 rangeSet = true;            }             // Load optional parameters            if (settings.TryGetValue("timeToPurge", out setting))                m_timeToPurge = Ticks.FromSeconds(double.Parse(setting));             if (settings.TryGetValue("warnInterval", out setting))                m_warnInterval = Ticks.FromSeconds(double.Parse(setting));             m_warningTimer.Interval = m_warnInterval.ToMilliseconds();            m_warningTimer.Elapsed += m_warningTimer_Elapsed;             m_purgeTimer.Interval = m_timeToPurge.ToMilliseconds();            m_purgeTimer.Elapsed += m_purgeTimer_Elapsed;        }         /// <summary>        /// Starts the <see cref="RangeTest"/>.        /// </summary>        public override void Start()        {            base.Start();             AttachToService();            m_warningTimer.Start();        }         /// <summary>        /// Stops the <see cref="RangeTest"/>.        /// </summary>        public override void Stop()        {            base.Stop();             DetachFromService();            m_warningTimer.Stop();        }         /// <summary>        /// Publish <see cref="IFrame"/> of time-aligned collection of <see cref="IMeasurement"/> values that arrived within the        /// concentrator's defined <see cref="ConcentratorBase.LagTime"/>.        /// </summary>        /// <param name="frame"><see cref="IFrame"/> of measurements with the same timestamp that arrived within <see cref="ConcentratorBase.LagTime"/> that are ready for processing.</param>        /// <param name="index">Index of <see cref="IFrame"/> within a second ranging from zero to <c><see cref="ConcentratorBase.FramesPerSecond"/> - 1</c>.</param>        /// <remarks>        /// If user implemented publication function consistently exceeds available publishing time (i.e., <c>1 / <see cref="ConcentratorBase.FramesPerSecond"/></c> seconds),        /// concentration will fall behind. A small amount of this time is required by the <see cref="ConcentratorBase"/> for processing overhead, so actual total time        /// available for user function process will always be slightly less than <c>1 / <see cref="ConcentratorBase.FramesPerSecond"/></c> seconds.        /// </remarks>        protected override void PublishFrame(IFrame frame, int index)        {            IMeasurement measurement = null;             foreach (MeasurementKey key in frame.Measurements.Keys)            {                measurement = frame.Measurements[key];                 if (measurement.AdjustedValue < m_lowRange || measurement.AdjustedValue > m_highRange)                {                    AddOutOfRangeMeasurement(key, measurement);                }            }        }         /// <summary>        /// Get a dictionary of <see cref="MeasurementKey"/>,<see cref="System.Int32"/> pairs representing        /// the number of times each key received has been out-of-range within the last <see cref="TimeToPurge"/> seconds.        /// </summary>        /// <returns>A dictionary of count values for each out-of-range measurement.</returns>        public Dictionary<MeasurementKey, int> GetOutOfRangeCounts()        {            Dictionary<MeasurementKey, int> outOfRangeCounts = new Dictionary<MeasurementKey, int>();             lock (m_outOfRangeMeasurements)            {                PurgeOldMeasurements();                 int count = 0;                foreach (MeasurementKey key in m_outOfRangeMeasurements.Keys)                {                    count = m_outOfRangeMeasurements[key].Count;                     if (count > 0)                        outOfRangeCounts.Add(key, count);                }            }             return outOfRangeCounts;        }         /// <summary>        /// Get the full collection of out-of-range <see cref="IMeasurement"/>s.        /// </summary>        /// <returns>The full collection of out-of-range <see cref="IMeasurement"/>s.</returns>        public ICollection<IMeasurement> GetOutOfRangeMeasurements()        {            ICollection<IMeasurement> allOutOfRangeMeasurements = new LinkedList<IMeasurement>();             lock (m_outOfRangeMeasurements)            {                PurgeOldMeasurements();                 foreach (LinkedList<IMeasurement> measurementList in m_outOfRangeMeasurements.Values)                {                    foreach (IMeasurement measurement in measurementList)                    {                        allOutOfRangeMeasurements.Add(measurement);                    }                }            }             return allOutOfRangeMeasurements;        }         /// <summary>        /// Get a collection of out-of-range <see cref="IMeasurement"/>s with the given key.        /// </summary>        /// <param name="key">The <see cref="MeasurementKey"/> corresponding to the desired measurements.</param>        /// <returns>A collection of out-of-range <see cref="IMeasurement"/>s.</returns>        public ICollection<IMeasurement> GetOutOfRangeMeasurements(MeasurementKey key)        {            lock (m_outOfRangeMeasurements)            {                PurgeOldMeasurements(key);                return new LinkedList<IMeasurement>(m_outOfRangeMeasurements[key]);            }        }         // Purge all old out-of-range measurements.        private void PurgeOldMeasurements()        {            lock (m_outOfRangeMeasurements)            {                foreach (MeasurementKey key in m_outOfRangeMeasurements.Keys)                {                    PurgeOldMeasurements(key);                }            }        }         // Purge old, out-of-range measurements with the given key.        private void PurgeOldMeasurements(MeasurementKey key)        {            lock (m_outOfRangeMeasurements)            {                LinkedList<IMeasurement> measurements = m_outOfRangeMeasurements[key];                bool donePurging = false;                 // Purge old measurements to prevent redundant warnings.                while (measurements.Count > 0 && !donePurging)                {                    IMeasurement measurement = measurements.First.Value;                    Ticks diff = base.RealTime - measurement.Timestamp;                     if (diff >= base.LagTicks + m_timeToPurge)                        measurements.RemoveFirst();                    else                        donePurging = true;                }            }        }         // Try to set the testing range based on the given signal type.        private bool TrySetRange(string signalType)        {            switch (signalType.ToUpper())            {                case "FREQ":                    m_lowRange = DEFAULT_FREQ_LOW_RANGE;                    m_highRange = DEFAULT_FREQ_HIGH_RANGE;                    break;                 case "VPHM":                    m_lowRange = DEFAULT_VPHM_LOW_RANGE;                    m_highRange = DEFAULT_VPHM_HIGH_RANGE;                    break;                 case "IPHM":                    m_lowRange = DEFAULT_IPHM_LOW_RANGE;                    m_highRange = DEFAULT_IPHM_HIGH_RANGE;                    break;                 case "VPHA":                    m_lowRange = DEFAULT_VPHA_LOW_RANGE;                    m_highRange = DEFAULT_VPHA_HIGH_RANGE;                    break;                 case "IPHA":                    m_lowRange = DEFAULT_IPHA_LOW_RANGE;                    m_highRange = DEFAULT_IPHA_HIGH_RANGE;                    break;                 default:                    return false;            }             return true;        }         // Add a measurement to the list of out of range measurements corresponding to the given key.        private void AddOutOfRangeMeasurement(MeasurementKey key, IMeasurement measurement)        {            lock (m_outOfRangeMeasurements)            {                LinkedList<IMeasurement> outOfRangeList;                 if (!m_outOfRangeMeasurements.TryGetValue(key, out outOfRangeList))                {                    outOfRangeList = new LinkedList<IMeasurement>();                    m_outOfRangeMeasurements.Add(key, outOfRangeList);                }                 outOfRangeList.AddLast(measurement);            }        }         private void AttachToService()        {            lock (s_service)            {                s_service.AttachRangeTest(this);                 if (s_exceptionProcessor == null)                    s_exceptionProcessor = this;            }        }         private void DetachFromService()        {            lock (s_service)            {                s_service.DetachRangeTest(this);                 if (this == s_exceptionProcessor)                {                    ICollection<RangeTest> tests = s_service.Tests;                     if (tests.Count > 0)                        s_exceptionProcessor = tests.GetEnumerator().Current;

Lines 1–500 of 550.

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