//****************************************************************************************************** // Measurement.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. // 04/14/2011 - J. Ritchie Carroll // Added received and published timestamps for measurements. // //****************************************************************************************************** using GSF.Collections; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; namespace GSF.TimeSeries { /// /// Implementation of a basic measurement. /// [Serializable()] public class Measurement : IMeasurement { #region [ Members ] // Fields private Guid m_id; private MeasurementKey m_key; private MeasurementStateFlags m_stateFlags; private string m_tagName; private double m_value; private double m_adder; private double m_multiplier; private Ticks m_timestamp; private Ticks m_receivedTimestamp; private Ticks m_publishedTimestamp; private MeasurementValueFilterFunction m_measurementValueFilter; #endregion #region [ Constructors ] /// /// Constructs a new using default settings. /// public Measurement() { #if UseHighResolutionTime m_receivedTimestamp = PrecisionTimer.UtcNow.Ticks; #else m_receivedTimestamp = DateTime.UtcNow.Ticks; #endif m_multiplier = 1.0D; } #endregion #region [ Properties ] /// /// Gets or sets the based signal ID of this , if available. /// public virtual Guid ID { get { return m_id; } set { m_id = value; } } /// /// Gets or sets the primary of this . /// public virtual MeasurementKey Key { get { return m_key; } set { m_key = value; } } /// /// Gets or sets associated with this . /// public virtual MeasurementStateFlags StateFlags { get { return m_stateFlags; } set { m_stateFlags = value; } } /// /// Gets or sets the text based tag name of this . /// public virtual string TagName { get { return m_tagName; } set { m_tagName = value; } } /// /// Gets or sets the raw measurement value that is not offset by and . /// /// Raw value of this (i.e., value that is not offset by and ). public virtual double Value { get { return m_value; } set { m_value = value; } } /// /// Gets the adjusted numeric value of this measurement, taking into account the specified and offsets. /// /// /// Note that returned value will be offset by and . /// /// offset by and (i.e., * + ). public virtual double AdjustedValue { get { return m_value * m_multiplier + m_adder; } } /// /// Gets or sets an offset to add to the measurement value. This defaults to 0.0. /// [DefaultValue(0.0)] public virtual double Adder { get { return m_adder; } set { m_adder = value; } } /// /// Defines a mulplicative offset to apply to the measurement value. This defaults to 1.0. /// [DefaultValue(1.0)] public virtual double Multiplier { get { return m_multiplier; } set { m_multiplier = value; } } /// /// Gets or sets exact timestamp, in ticks, of the data represented by this . /// /// /// The value of this property represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001. /// public virtual Ticks Timestamp { get { return m_timestamp; } set { m_timestamp = value; } } /// /// Gets or sets exact timestamp, in ticks, of when this was received (i.e., created). /// /// /// In the default implementation, this timestamp will simply be the ticks of of when this class was created. /// The value of this property represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001. /// public Ticks ReceivedTimestamp { get { return m_receivedTimestamp; } set { m_receivedTimestamp = value; } } /// /// Gets or sets exact timestamp, in ticks, of when this was published (post-processing). /// /// /// The value of this property represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001. /// public Ticks PublishedTimestamp { get { return m_publishedTimestamp; } set { m_publishedTimestamp = value; } } /// /// Gets or sets function used to apply a downsampling filter over a sequence of values. /// public virtual MeasurementValueFilterFunction MeasurementValueFilter { get { return m_measurementValueFilter; } set { m_measurementValueFilter = value; } } // Big-Endian binary value interpretation BigBinaryValue ITimeSeriesValue.Value { get { return m_value; } set { switch (value.TypeCode) { case TypeCode.Byte: m_value = (Byte)value; break; case TypeCode.SByte: m_value = (SByte)value; break; case TypeCode.Int16: m_value = (Int16)value; break; case TypeCode.UInt16: m_value = (UInt16)value; break; case TypeCode.Int32: m_value = (Int32)value; break; case TypeCode.UInt32: m_value = (UInt32)value; break; case TypeCode.Int64: m_value = (Int64)value; break; case TypeCode.UInt64: m_value = (UInt64)value; break; case TypeCode.Single: m_value = (Single)value; break; case TypeCode.Double: m_value = (Double)value; break; //case TypeCode.Boolean: // break; //case TypeCode.Char: // break; //case TypeCode.DateTime: // break; //case TypeCode.Decimal: // break; //case TypeCode.String: // m_value = double.Parse(value); // break; default: m_value = value; break; } } } #endregion #region [ Methods ] /// /// Returns a that represents the current . /// /// A that represents the current . public override string ToString() { return Measurement.ToString(this); } /// /// Determines whether the specified is equal to the current . /// /// The to compare with the current . /// /// true if the specified is equal to the current ; /// otherwise, false. /// public bool Equals(ITimeSeriesValue other) { return (CompareTo(other) == 0); } /// /// Determines whether the specified is equal to the current . /// /// The to compare with the current . /// /// true if the specified is equal to the current ; /// otherwise, false. /// public override bool Equals(object obj) { ITimeSeriesValue other = obj as ITimeSeriesValue; if ((object)other != null) return Equals(other); return false; } /// /// Compares the with an . /// /// The to compare with the current . /// A 32-bit signed integer that indicates the relative order of the objects being compared. /// Measurement implementations should compare by hash code. public int CompareTo(ITimeSeriesValue other) { if ((object)other != null) return GetHashCode().CompareTo(other.GetHashCode()); return 1; } /// /// Compares the with the specified . /// /// The to compare with the current . /// A 32-bit signed integer that indicates the relative order of the objects being compared. /// is not an . /// Measurement implementations should compare by hash code. public int CompareTo(object obj) { ITimeSeriesValue other = obj as ITimeSeriesValue; if ((object)other != null) return CompareTo(other); throw new ArgumentException("Measurement can only be compared with other measurements or time-series values"); } /// /// Serves as a hash function for the current . /// /// A hash code for the current . /// Hash code based on value of measurement. public override int GetHashCode() { return m_id.GetHashCode(); } #endregion #region [ Operators ] /// /// Compares two values for equality. /// /// A left hand operand. /// A right hand operand. /// A boolean representing the result. public static bool operator ==(Measurement measurement1, Measurement measurement2) { return measurement1.Equals(measurement2); } /// /// Compares two values for inequality. /// /// A left hand operand. /// A right hand operand. /// A boolean representing the result. public static bool operator !=(Measurement measurement1, Measurement measurement2) { return !measurement1.Equals(measurement2); } /// /// Returns true if left value is greater than right value. /// /// A left hand operand. /// A right hand operand. /// A boolean representing the result. public static bool operator >(Measurement measurement1, Measurement measurement2) { return measurement1.CompareTo(measurement2) > 0; } /// /// Returns true if left value is greater than or equal to right value. /// /// A left hand operand. /// A right hand operand. /// A boolean representing the result. public static bool operator >=(Measurement measurement1, Measurement measurement2) { return measurement1.CompareTo(measurement2) >= 0; } /// /// Returns true if left value is less than right value. /// /// A left hand operand. /// A right hand operand. /// A boolean representing the result. public static bool operator <(Measurement measurement1, Measurement measurement2) { return measurement1.CompareTo(measurement2) < 0; } /// /// Returns true if left value is less than or equal to right value. /// /// A left hand operand. /// A right hand operand. /// A boolean representing the result. public static bool operator <=(Measurement measurement1, Measurement measurement2) { return measurement1.CompareTo(measurement2) <= 0; } #endregion #region [ Static ] /// /// Represents an undefined measurement. /// public static readonly Measurement Undefined = new Measurement() { Key = MeasurementKey.Undefined }; /// /// Creates a copy of the specified measurement. /// /// Specified measurement to clone. /// A copy of the object. public static Measurement Clone(IMeasurement measurementToClone) { return new Measurement() { ID = measurementToClone.ID, Key = measurementToClone.Key, Value = measurementToClone.Value, Adder = measurementToClone.Adder, Multiplier = measurementToClone.Multiplier, Timestamp = measurementToClone.Timestamp, TagName = measurementToClone.TagName, StateFlags = measurementToClone.StateFlags }; } /// /// Creates a copy of the specified measurement using a new timestamp. /// /// Specified measurement to clone. /// New timestamp, in ticks, for cloned measurement. /// A copy of the object. public static Measurement Clone(IMeasurement measurementToClone, Ticks timestamp) { return new Measurement() { ID = measurementToClone.ID, Key = measurementToClone.Key, Value = measurementToClone.Value, Adder = measurementToClone.Adder, Multiplier = measurementToClone.Multiplier, Timestamp = timestamp, TagName = measurementToClone.TagName, StateFlags = measurementToClone.StateFlags }; } /// /// Creates a copy of the specified measurement using a new value and timestamp. /// /// Specified measurement to clone. /// New value for cloned measurement. /// New timestamp, in ticks, for cloned measurement. /// A copy of the object. public static Measurement Clone(IMeasurement measurementToClone, double value, Ticks timestamp) { return new Measurement() { ID = measurementToClone.ID, Key = measurementToClone.Key, Value = value, Adder = measurementToClone.Adder, Multiplier = measurementToClone.Multiplier, Timestamp = timestamp, TagName = measurementToClone.TagName, StateFlags = measurementToClone.StateFlags }; } public static string ToString(IMeasurement measurement) { return ToString (measurement, true); } /// /// Returns a that represents the specified . /// /// to convert to a representation. /// Set to true to include measurement's tag name, if defined; otherwise set to false. /// A that represents the specified . public static string ToString(IMeasurement measurement, bool includeTagName) { if (measurement == null) { return "Undefined"; } else { string tagName = measurement.TagName; string keyText = measurement.Key.ToString(); if (includeTagName && !tagName.IsNullOrWhiteSpace()) return string.Format("{0} [{1}]", tagName, keyText); else return keyText; } } /// /// Calculates an average of the specified sequence of values. /// /// Sequence of values over which to run calculation. /// Average of the specified sequence of values. public static double AverageValueFilter(IEnumerable source) { return source.Select(m => m.Value).Average(); } /// /// Returns the majority value of the specified sequence of values. /// /// Sequence of values over which to run calculation. /// Majority value of the specified sequence of values. public static double MajorityValueFilter(IEnumerable source) { return source.Select(m => m.Value).Majority(); } #endregion } }