//******************************************************************************************************
// 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
}
}