/// <summary> /// Creates a <see cref="MeasurementMetadata"/> /// </summary> /// <param name="key">Gets or sets the primary key of this <see cref="IMeasurement"/>.</param> /// <param name="tagName">Gets or sets the text based tag name of this <see cref="IMeasurement"/>.</param> /// <param name="adder">Defines an offset to add to the <see cref="IMeasurement"/> value.</param> /// <param name="multiplier">Defines a multiplicative offset to apply to the <see cref="IMeasurement"/> value.</param> /// <param name="measurementValueFilter">Gets or sets function used to apply a down-sampling filter over a sequence of <see cref="IMeasurement"/> values.</param> public MeasurementMetadata(MeasurementKey key, string tagName, double adder, double multiplier, MeasurementValueFilterFunction measurementValueFilter) { Key = key; TagName = tagName; Adder = adder; Multiplier = multiplier; MeasurementValueFilter = measurementValueFilter; }
/// <summary> /// Creates a <see cref="MeasurementMetadata"/> /// </summary> /// <param name="key">Gets or sets the primary key of this <see cref="IMeasurement"/>.</param> /// <param name="tagName">Gets or sets the text based tag name of this <see cref="IMeasurement"/>.</param> /// <param name="adder">Defines an offset to add to the <see cref="IMeasurement"/> value.</param> /// <param name="multiplier">Defines a multiplicative offset to apply to the <see cref="IMeasurement"/> value.</param> /// <param name="measurementValueFilter">Gets or sets function used to apply a down-sampling filter over a sequence of <see cref="IMeasurement"/> values.</param> public MeasurementMetadata(MeasurementKey key, string tagName, double adder, double multiplier, MeasurementValueFilterFunction measurementValueFilter) { Key = key; TagName = tagName; Adder = adder; Multiplier = multiplier; MeasurementValueFilter = measurementValueFilter; }
/// <summary> /// Updates the values of the <see cref="Metadata"/>. /// </summary> /// <param name="tagName">Gets or sets the text based tag name.</param> /// <param name="adder">Defines an offset to add to the <see cref="IMeasurement"/> value.</param> /// <param name="multiplier">Defines a multiplicative offset to apply to the <see cref="IMeasurement"/> value.</param> /// <param name="valueFilter">Defines the <see cref="MeasurementValueFilterFunction"/> to use when downsampling this type of <see cref="IMeasurement"/> value.</param> public void SetMeasurementMetadata(string tagName, double adder, double multiplier, MeasurementValueFilterFunction valueFilter) { if (this == Undefined) { throw new NotSupportedException("Cannot set data source information for an undefined measurement."); } if (m_metadata.TagName != tagName || m_metadata.Adder != adder || m_metadata.Multiplier != multiplier || m_metadata.MeasurementValueFilter != valueFilter) { m_metadata = new MeasurementMetadata(this, tagName, adder, multiplier, valueFilter); } }
/// <summary> /// Creates a new instance of <see cref="MeasurementMetadata"/> using the provided <paramref name="measurementValueFilter"/>. All other fields remain the same. /// </summary> /// <param name="measurementValueFilter">the measurementValueFilter to set.</param> /// <returns>New instance of <see cref="MeasurementMetadata"/> using the provided <paramref name="measurementValueFilter"/>.</returns> public MeasurementMetadata ChangeMeasurementValueFilter(MeasurementValueFilterFunction measurementValueFilter) => ReferenceEquals(MeasurementValueFilter, measurementValueFilter) ? this : new MeasurementMetadata(Key, TagName, Adder, Multiplier, measurementValueFilter);
/// <summary> /// Updates the values of the <see cref="Metadata"/>. /// </summary> /// <param name="tagName">Gets or sets the text based tag name.</param> /// <param name="adder">Defines an offset to add to the <see cref="IMeasurement"/> value.</param> /// <param name="multiplier">Defines a multiplicative offset to apply to the <see cref="IMeasurement"/> value.</param> /// <param name="valueFilter">Defines the <see cref="MeasurementValueFilterFunction"/> to use when downsampling this type of <see cref="IMeasurement"/> value.</param> public void SetMeasurementMetadata(string tagName, double adder, double multiplier, MeasurementValueFilterFunction valueFilter) { if (this == Undefined) throw new NotSupportedException("Cannot set data source information for an undefined measurement."); if (m_metadata.TagName != tagName || m_metadata.Adder != adder || m_metadata.Multiplier != multiplier || m_metadata.MeasurementValueFilter != valueFilter) m_metadata = new MeasurementMetadata(this, tagName, adder, multiplier, valueFilter); }
/// <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); }
/// <summary> /// Creates a new instance of <see cref="MeasurementMetadata"/> using the provided <paramref name="measurementValueFilter"/>. All other fields remain the same. /// </summary> /// <param name="measurementValueFilter">the measurementValueFilter to set.</param> /// <returns>New instance of <see cref="MeasurementMetadata"/> using the provided <paramref name="measurementValueFilter"/>.</returns> public MeasurementMetadata ChangeMeasurementValueFilter(MeasurementValueFilterFunction measurementValueFilter) => ReferenceEquals(MeasurementValueFilter, measurementValueFilter) ? this : new MeasurementMetadata(Key, TagName, Adder, Multiplier, measurementValueFilter);