226 lines · 7.6 KB · C#
RawDownload
//******************************************************************************************************//  RealTimeSlope.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://  ----------------------------------------------------------------------------------------------------//  01/24/2006 - J. Ritchie Carroll//       Generated original version of source code.//  09/17/2008 - J. Ritchie Carroll//       Converted to C#.//  09/14/2009 - Stephen C. Wills//       Added new header and license agreement.//  12/14/2012 - Starlynn Danyelle Gilliam//       Modified Header.////****************************************************************************************************** using System;using System.Collections.Generic;using System.Threading;using GSF.Units; namespace GSF.NumericalAnalysis{    /// <summary>Calculates slope for a real-time continuous data stream.</summary>    public class RealTimeSlope    {        #region [ Members ]         // Events         /// <summary>        /// Raised when new status messages come from the <see cref="RealTimeSlope"/>.        /// </summary>        /// <remarks>        /// <see cref="EventArgs{T}.Argument"/> is status message from the <see cref="RealTimeSlope"/>.        /// </remarks>        public event EventHandler<EventArgs<string>> Status;         /// <summary>        /// Raised when new real-time <see cref="Slope"/> has been calculated and is available.        /// </summary>        public event EventHandler Recalculated;         // Fields        private int m_regressionInterval;        private int m_pointCount;        private List<double> m_xValues;        private List<double> m_yValues;        private double m_slope;        private double m_lastSlope;        private DateTime m_slopeRun;        private bool m_calculating;         #endregion         #region [ Constructors ]         /// <summary>        /// Creates a default instance of the real-time slope calculation class. Must call Initialize before using.        /// </summary>        public RealTimeSlope()        {        }         /// <summary>Creates a new instance of the real-time slope calculation class.</summary>        /// <param name="regressionInterval">Time span over which to calculate slope.</param>        /// <param name="estimatedRefreshInterval">Estimated data points per second.</param>        public RealTimeSlope(int regressionInterval, double estimatedRefreshInterval)            : this()        {            Initialize(regressionInterval, estimatedRefreshInterval);        }         #endregion         #region [ Properties ]         /// <summary>Gets current calculated slope for data set.</summary>        public double Slope        {            get            {                return m_slope;            }        }         /// <summary>Gets run-time, in seconds, for which slope has maintained a continuous positive or negative        /// trend.</summary>        public Time RunTime        {            get            {                return (m_regressionInterval + Ticks.ToSeconds(DateTime.UtcNow.Ticks - m_slopeRun.Ticks));            }        }         #endregion         #region [ Methods ]         /// <summary>Adds a new x, y data pair to continuous data set.</summary>        /// <param name="x">New x-axis value.</param>        /// <param name="y">New y-axis value.</param>        public void Calculate(double x, double y)        {            lock (m_xValues)            {                // Adds latest values to regression data set.                m_xValues.Add(x);                m_yValues.Add(y);                 // Keeps a constant number of points by removing them from the left.                while (m_xValues.Count > m_pointCount)                {                    m_xValues.RemoveAt(0);                }                 while (m_yValues.Count > m_pointCount)                {                    m_yValues.RemoveAt(0);                }            }             if (m_xValues.Count >= m_pointCount && !m_calculating)            {                // Performs curve fit calculation on separate thread, since it could be time consuming.#if ThreadTracking                ManagedThread thread = ManagedThreadPool.QueueUserWorkItem(PerformCalculation);                thread.Name = "GSF.Math.RealTimeSlope.PerformCalculation()";#else                ThreadPool.QueueUserWorkItem(PerformCalculation);#endif            }        }         /// <summary>        /// Initializes real-time slope calculation.        /// </summary>        /// <param name="regressionInterval">Time span over which to calculate slope.</param>        /// <param name="estimatedRefreshInterval">Estimated data points per second.</param>        public void Initialize(int regressionInterval, double estimatedRefreshInterval)        {            m_slopeRun = DateTime.UtcNow;            m_regressionInterval = regressionInterval;            m_pointCount = m_regressionInterval * (int)(1 / estimatedRefreshInterval);             if ((object)m_xValues == null)            {                m_xValues = new List<double>();            }            else            {                lock (m_xValues)                {                    m_xValues.Clear();                }            }            if ((object)m_yValues == null)            {                m_yValues = new List<double>();            }            else            {                lock (m_yValues)                {                    m_yValues.Clear();                }            }        }         private void PerformCalculation(object state)        {            try            {                m_calculating = true;                 double[] xValues;                double[] yValues;                 // Calculations are made against a copy of the current data set to keep lock time on                // data values down to a minimum. This allows data to be added with minimal delay.                lock (m_xValues)                {                    xValues = m_xValues.ToArray();                    yValues = m_yValues.ToArray();                }                 // Takes new values and calculates slope (curve fit for 1st order polynomial).                m_slope = CurveFit.Compute(1, xValues, yValues)[1];            }            catch (Exception ex)            {                if ((object)Status != null)                    Status(this, new EventArgs<string>("CurveFit failed: " + ex.Message));            }            finally            {                m_calculating = false;            }             if (Math.Sign(m_slope) != Math.Sign(m_lastSlope))                m_slopeRun = DateTime.UtcNow;             m_lastSlope = m_slope;             // Notifies consumer of new calculated slope.            if ((object)Recalculated != null)                Recalculated(this, EventArgs.Empty);        }         #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