277 lines · 11.6 KB · C#
RawDownload
//******************************************************************************************************//  TrackingFrame.cs - Gbtc////  Copyright © 2010, 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 Eclipse Public License -v 1.0 (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/eclipse-1.0.php////  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://  ----------------------------------------------------------------------------------------------------//  09/02/2010 - J. Ritchie Carroll//       Generated original version of source code.////****************************************************************************************************** using GSF.Threading;using System.Collections.Concurrent;using System.Collections.Generic; namespace GSF.TimeSeries{    /// <summary>    /// <see cref="IFrame"/> container used to track <see cref="IMeasurement"/> values for downsampling.    /// </summary>    internal class TrackingFrame    {        #region [ Members ]         // Fields        private IFrame m_sourceFrame;        private long m_timestamp;        private DownsamplingMethod m_downsamplingMethod;        private ConcurrentDictionary<MeasurementKey, List<IMeasurement>> m_measurements;        private ReaderWriterSpinLock m_frameLock;        private long m_derivedMeasurements;         #endregion         #region [ Constructors ]         /// <summary>        /// Constructs a new <see cref="TrackingFrame"/> given the specified parameters.        /// </summary>        /// <param name="sourceFrame">Source <see cref="IFrame"/> to track.</param>        /// <param name="downsamplingMethod"><see cref="DownsamplingMethod"/> to apply.</param>        public TrackingFrame(IFrame sourceFrame, DownsamplingMethod downsamplingMethod)        {            m_sourceFrame = sourceFrame;            m_timestamp = sourceFrame.Timestamp;            m_downsamplingMethod = downsamplingMethod;            m_frameLock = new ReaderWriterSpinLock();             if (downsamplingMethod != DownsamplingMethod.LastReceived)                m_measurements = new ConcurrentDictionary<MeasurementKey, List<IMeasurement>>();        }         #endregion         #region [ Properties ]         /// <summary>        /// Gets instance of <see cref="IFrame"/> being tracked.        /// </summary>        public IFrame SourceFrame        {            get            {                return m_sourceFrame;            }        }         /// <summary>        /// Gets timestamp of <see cref="IFrame"/> being tracked.        /// </summary>        public long Timestamp        {            get            {                return m_timestamp;            }        }         /// <summary>        /// Total number of measurements downsampled by <see cref="TrackingFrame"/>.        /// </summary>        public long DownsampledMeasurements        {            get            {                // Only measurements that came in after initial sorts were downsampled...                return m_derivedMeasurements - m_sourceFrame.SortedMeasurements;            }        }         /// <summary>        /// Gets the <see cref="TrackingFrame"/> locking primitive.        /// </summary>        public ReaderWriterSpinLock Lock        {            get            {                return m_frameLock;            }        }         #endregion         #region [ Methods ]         /// <summary>        /// Derives measurement value, downsampling if needed.        /// </summary>        /// <param name="measurement">New <see cref="IMeasurement"/> value.</param>        /// <returns>New derived <see cref="IMeasurement"/> value, or null if value should not be assigned to <see cref="IFrame"/>.</returns>        public IMeasurement DeriveMeasurementValue(IMeasurement measurement)        {            IMeasurement derivedMeasurement;            List<IMeasurement> values;             switch (m_downsamplingMethod)            {                case DownsamplingMethod.LastReceived:                    // Keep track of total number of derived measurements                    m_derivedMeasurements++;                     // This is the simplest case, just apply latest value                    return measurement;                case DownsamplingMethod.Closest:                    // Get tracked measurement values                    if (m_measurements.TryGetValue(measurement.Key, out values))                    {                        if ((object)values != null && values.Count > 0)                        {                            // Get first tracked value (should only be one for "Closest")                            derivedMeasurement = values[0];                             if ((object)derivedMeasurement != null)                            {                                // Determine if new measurement's timestamp is closer to frame                                if (measurement.Timestamp < derivedMeasurement.Timestamp && measurement.Timestamp >= m_timestamp)                                {                                    // This measurement came in out-of-order and is closer to frame timestamp, so                                     // we sort this measurement instead of the original                                    values[0] = measurement;                                     // Keep track of total number of derived measurements                                    m_derivedMeasurements++;                                     return measurement;                                }                                 // Prior measurement is closer to frame than new one                                return null;                            }                        }                    }                     // No prior measurement exists, track this initial one                    values = new List<IMeasurement> { measurement };                    m_measurements[measurement.Key] = values;                     // Keep track of total number of derived measurements                    m_derivedMeasurements++;                     return measurement;                case DownsamplingMethod.Filtered:                    // Get tracked measurement values                    if (m_measurements.TryGetValue(measurement.Key, out values))                    {                        if ((object)values != null && values.Count > 0)                        {                            // Get first tracked value - we clone the measurement since we are updating its value                            derivedMeasurement = Measurement.Clone(values[0]);                             if ((object)derivedMeasurement != null)                            {                                // Get function defined for measurement value filtering                                MeasurementValueFilterFunction measurementValueFilter = derivedMeasurement.MeasurementValueFilter;                                 // Default to average value filter if none is specified                                if (measurementValueFilter == null)                                    measurementValueFilter = Measurement.AverageValueFilter;                                 // Add new measurement to tracking collection                                if ((object)measurement != null)                                    values.Add(measurement);                                 // Perform filter calculation as specified by device measurement                                if (values.Count > 1)                                {                                    derivedMeasurement.Value = measurementValueFilter(values);                                     // Keep track of total number of derived measurements                                    m_derivedMeasurements++;                                     return derivedMeasurement;                                }                                 // No change from existing measurement                                return null;                            }                        }                    }                     // No prior measurement exists, track this initial one                    values = new List<IMeasurement> { measurement };                    m_measurements[measurement.Key] = values;                     // Keep track of total number of derived measurements                    m_derivedMeasurements++;                     return measurement;                case DownsamplingMethod.BestQuality:                    // Get tracked measurement values                    if (m_measurements.TryGetValue(measurement.Key, out values))                    {                        if ((object)values != null && values.Count > 0)                        {                            // Get first tracked value (should only be one for "BestQuality")                            derivedMeasurement = values[0];                             if ((object)derivedMeasurement != null)                            {                                // Determine if new measurement's quality is better than existing one or if new measurement's timestamp is closer to frame                                if                                (                                    (                                        (!derivedMeasurement.ValueQualityIsGood() || !derivedMeasurement.TimestampQualityIsGood())                                            &&                                        (measurement.ValueQualityIsGood() || measurement.TimestampQualityIsGood())                                    )                                        ||                                    (                                        measurement.Timestamp < derivedMeasurement.Timestamp && measurement.Timestamp >= m_timestamp                                    )                                )                                {                                    // This measurement has a better quality or came in out-of-order and is closer to frame timestamp, so                                     // we sort this measurement instead of the original                                    values[0] = measurement;                                     // Keep track of total number of derived measurements                                    m_derivedMeasurements++;                                     return measurement;                                }                                 // Prior measurement is closer to frame than new one                                return null;                            }                        }                    }                     // No prior measurement exists, track this initial one                    values = new List<IMeasurement> { measurement };                    m_measurements[measurement.Key] = values;                     // Keep track of total number of derived measurements                    m_derivedMeasurements++;                     return measurement;            }             return null;        }         #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