Clone() public static method

Creates a copy of the specified measurement.
public static Clone ( IMeasurement measurementToClone ) : Measurement
measurementToClone IMeasurement Specified measurement to clone.
return Measurement
Esempio n. 1
0
        private void PollingOperation()
        {
            if ((object)m_modbusConnection == null)
            {
                return;
            }

            try
            {
                Ticks timestamp = DateTime.UtcNow.Ticks;
                Dictionary <MeasurementKey, Measurement> measurements = OutputMeasurements.Select(measurement => Measurement.Clone(measurement, timestamp)).ToDictionary(measurement => measurement.Key, measurement => measurement);
                Group[] groups = m_sequences.SelectMany(sequence => sequence.Groups).ToArray();
                int     measurementsReceived = 0;

                int overallTasksCompleted = 0;
                int overallTasksCount     = m_sequences.Count + 1;
                OnProgressUpdated(this, new ProgressUpdate(ProgressState.Processing, true, "Starting polling operation...", overallTasksCompleted, overallTasksCount));
                OnStatusMessage(MessageLevel.Info, $"Executing poll operation {m_pollOperations + 1}.");

                // Handle read/write operations for sequence groups
                try
                {
                    foreach (Sequence sequence in m_sequences)
                    {
                        foreach (Group group in sequence.Groups)
                        {
                            OnProgressUpdated(this, new ProgressUpdate(ProgressState.Processing, false, $"Executing poll for {sequence.Type.ToString().ToLowerInvariant()} sequence group \"{group.Type}@{group.StartAddress}\"...", 0, group.PointCount));

                            switch (group.Type)
                            {
                            case RecordType.DI:
                                group.DataValues = ReadDiscreteInputs(group.StartAddress, group.PointCount);
                                break;

                            case RecordType.CO:
                                if (sequence.Type == SequenceType.Read)
                                {
                                    group.DataValues = ReadCoils(group.StartAddress, group.PointCount);
                                }
                                else
                                {
                                    WriteCoils(group.StartAddress, group.DataValues);
                                }
                                break;

                            case RecordType.IR:
                                group.DataValues = ReadInputRegisters(group.StartAddress, group.PointCount);
                                break;

                            case RecordType.HR:
                                if (sequence.Type == SequenceType.Read)
                                {
                                    group.DataValues = ReadHoldingRegisters(group.StartAddress, group.PointCount);
                                }
                                else
                                {
                                    WriteHoldingRegisters(group.StartAddress, group.DataValues);
                                }
                                break;
                            }

                            OnProgressUpdated(this, new ProgressUpdate(ProgressState.Processing, false, $"Completed poll for {sequence.Type.ToString().ToLowerInvariant()} sequence group \"{group.Type}@{group.StartAddress}\".", group.PointCount, group.PointCount));
                            Thread.Sleep(m_interSequenceGroupPollDelay);
                        }

                        OnProgressUpdated(this, new ProgressUpdate(ProgressState.Processing, true, null, ++overallTasksCompleted, overallTasksCount));
                    }
                }
                catch
                {
                    m_deviceErrors++;
                    throw;
                }

                OnProgressUpdated(this, new ProgressUpdate(ProgressState.Processing, false, "Processing derived values...", 0, m_derivedValues.Count));

                // Calculate derived values
                foreach (KeyValuePair <MeasurementKey, DerivedValue> item in m_derivedValues)
                {
                    DerivedValue derivedValue = item.Value;
                    ushort[]     dataValues   = derivedValue.GetDataValues(groups);
                    Measurement  measurement;

                    if (measurements.TryGetValue(item.Key, out measurement))
                    {
                        // TODO: Properly interpret measurement types after GSF data type transport update
                        switch (derivedValue.Type)
                        {
                        case DerivedType.String:
                            if (derivedValue.AddressRecords.Count > 0)
                            {
                                m_derivedStrings[item.Key] = DeriveString(dataValues);
                                measurementsReceived++;
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"No address records defined for derived String value \"{item.Key}\".");
                            }
                            break;

                        case DerivedType.Single:
                            if (derivedValue.AddressRecords.Count > 1)
                            {
                                measurement.Value = DeriveSingle(dataValues[0], dataValues[1]);
                                measurementsReceived++;
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"{derivedValue.AddressRecords.Count} address records defined for derived Single value \"{item.Key}\", expected 2.");
                            }
                            break;

                        case DerivedType.Double:
                            if (derivedValue.AddressRecords.Count > 3)
                            {
                                measurement.Value = DeriveDouble(dataValues[0], dataValues[1], dataValues[2], dataValues[3]);
                                measurementsReceived++;
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"{derivedValue.AddressRecords.Count} address records defined for derived Double value \"{item.Key}\", expected 4.");
                            }
                            break;

                        case DerivedType.UInt16:
                            if (derivedValue.AddressRecords.Count > 0)
                            {
                                measurement.Value = dataValues[0];
                                measurementsReceived++;
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"No address records defined for UInt16 value \"{item.Key}\".");
                            }
                            break;

                        case DerivedType.Int32:
                            if (derivedValue.AddressRecords.Count > 1)
                            {
                                measurement.Value = DeriveInt32(dataValues[0], dataValues[1]);
                                measurementsReceived++;
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"{derivedValue.AddressRecords.Count} address records defined for derived Int32 value \"{item.Key}\", expected 2.");
                            }
                            break;

                        case DerivedType.UInt32:
                            if (derivedValue.AddressRecords.Count > 1)
                            {
                                measurement.Value = DeriveUInt32(dataValues[0], dataValues[1]);
                                measurementsReceived++;
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"{derivedValue.AddressRecords.Count} address records defined for derived UInt32 value \"{item.Key}\", expected 2.");
                            }
                            break;

                        case DerivedType.Int64:
                            if (derivedValue.AddressRecords.Count > 3)
                            {
                                measurement.Value = DeriveInt64(dataValues[0], dataValues[1], dataValues[2], dataValues[3]);
                                measurementsReceived++;
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"{derivedValue.AddressRecords.Count} address records defined for derived Int64 value \"{item.Key}\", expected 4.");
                            }
                            break;

                        case DerivedType.UInt64:
                            if (derivedValue.AddressRecords.Count > 3)
                            {
                                measurement.Value = DeriveUInt64(dataValues[0], dataValues[1], dataValues[2], dataValues[3]);
                                measurementsReceived++;
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"{derivedValue.AddressRecords.Count} address records defined for derived UInt64 value \"{item.Key}\", expected 4.");
                            }
                            break;
                        }
                    }

                    if (measurementsReceived % 20 == 0)
                    {
                        OnProgressUpdated(this, new ProgressUpdate(ProgressState.Processing, false, null, measurementsReceived, m_derivedValues.Count));
                    }
                }

                OnProgressUpdated(this, new ProgressUpdate(ProgressState.Processing, false, "Completed derived value processing.", m_derivedValues.Count, m_derivedValues.Count));
                OnProgressUpdated(this, new ProgressUpdate(ProgressState.Succeeded, true, "Polling operation complete.", overallTasksCount, overallTasksCount));

                OnNewMeasurements(measurements.Values.ToArray());

                m_measurementsReceived += measurementsReceived;
                m_pollOperations++;
            }
            catch (Exception ex)
            {
                OnProgressUpdated(this, new ProgressUpdate(ProgressState.Failed, true, $"Failed during poll operation: {ex.Message}", 0, 1));

                // Restart connection cycle when an exception occurs
                Start();
                throw;
            }
            finally
            {
                m_measurementsExpected += OutputMeasurements.Length;
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Publish frame of time-aligned collection of measurement values that arrived within the defined lag time.
        /// </summary>
        /// <param name="frame">Frame of measurements with the same timestamp that arrived within lag time that are ready for processing.</param>
        /// <param name="index">Index of frame within a second ranging from zero to frames per second - 1.</param>
        protected override void PublishFrame(IFrame frame, int index)
        {
            IMeasurement[]      available          = frame.Measurements.Values.ToArray();
            List <Guid>         availableGuids     = available.Select(item => item.Key.SignalID).ToList();
            List <IMeasurement> outputmeasurements = new List <IMeasurement>();

            m_numberOfFrames++;

            foreach (ThreePhaseSet set in m_threePhaseComponent)
            {
                bool hasP = availableGuids.Contains(set.Positive.SignalID);
                bool hasN = availableGuids.Contains(set.Negative.SignalID);
                //bool hasZ = availableGuids.Contains(set.Zero.SignalID);

                if (hasP && hasN)
                {
                    double v1P = available.FirstOrDefault(item => (item.Key?.SignalID ?? Guid.Empty) == set.Positive.SignalID)?.Value ?? 0.0D;
                    double v2N = available.FirstOrDefault(item => (item.Key?.SignalID ?? Guid.Empty) == set.Negative.SignalID)?.Value ?? 0.0D;

                    if (v1P != 0.0D)
                    {
                        double      unbalanced        = v2N / v1P;
                        Measurement outputMeasurement = new Measurement {
                            Metadata = set.OutMapping.Metadata
                        };

                        if (m_saveStats)
                        {
                            m_statisticsMapping[set.Positive.SignalID].Count++;

                            if (unbalanced > m_statisticsMapping[set.Positive.SignalID].Maximum)
                            {
                                m_statisticsMapping[set.Positive.SignalID].Maximum = unbalanced;
                            }

                            if (unbalanced < m_statisticsMapping[set.Positive.SignalID].Minimum)
                            {
                                m_statisticsMapping[set.Positive.SignalID].Minimum = unbalanced;
                            }

                            if (unbalanced > set.Threshold)
                            {
                                m_statisticsMapping[set.Positive.SignalID].AlertCount++;
                            }

                            m_statisticsMapping[set.Positive.SignalID].Summation        += unbalanced;
                            m_statisticsMapping[set.Positive.SignalID].SquaredSummation += unbalanced * unbalanced;
                        }

                        outputmeasurements.Add(Measurement.Clone(outputMeasurement, unbalanced * 100.0D, frame.Timestamp));
                    }
                }

                if (!m_saveStats)
                {
                    m_numberOfFrames = 0;
                }
            }

            // Reporting if necessary
            if ((m_numberOfFrames >= ReportingInterval && m_saveStats) && (m_threePhaseComponent.Count > 0))
            {
                foreach (ThreePhaseSet set in m_threePhaseComponent)
                {
                    Guid key = set.Positive.SignalID;

                    Measurement statisticMeasurement = new Measurement {
                        Metadata = m_statisticsMapping[key].Sum.Metadata
                    };
                    outputmeasurements.Add(Measurement.Clone(statisticMeasurement, m_statisticsMapping[key].Summation, frame.Timestamp));

                    statisticMeasurement = new Measurement {
                        Metadata = m_statisticsMapping[key].SqrD.Metadata
                    };
                    outputmeasurements.Add(Measurement.Clone(statisticMeasurement, m_statisticsMapping[key].SquaredSummation, frame.Timestamp));

                    statisticMeasurement = new Measurement {
                        Metadata = m_statisticsMapping[key].Min.Metadata
                    };
                    outputmeasurements.Add(Measurement.Clone(statisticMeasurement, m_statisticsMapping[key].Minimum, frame.Timestamp));

                    statisticMeasurement = new Measurement {
                        Metadata = m_statisticsMapping[key].Max.Metadata
                    };
                    outputmeasurements.Add(Measurement.Clone(statisticMeasurement, m_statisticsMapping[key].Maximum, frame.Timestamp));

                    statisticMeasurement = new Measurement {
                        Metadata = m_statisticsMapping[key].Total.Metadata
                    };
                    outputmeasurements.Add(Measurement.Clone(statisticMeasurement, m_statisticsMapping[key].Count, frame.Timestamp));

                    statisticMeasurement = new Measurement {
                        Metadata = m_statisticsMapping[key].Alert.Metadata
                    };
                    outputmeasurements.Add(Measurement.Clone(statisticMeasurement, m_statisticsMapping[key].AlertCount, frame.Timestamp));

                    m_statisticsMapping[key].Reset();
                    m_numberOfFrames = 0;
                }
            }

            OnNewMeasurements(outputmeasurements);
        }
Esempio n. 3
0
        /// <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);
        }
Esempio n. 4
0
        /// <summary>
        /// Publish frame of time-aligned collection of measurement values that arrived within the defined lag time.
        /// </summary>
        /// <param name="frame">Frame of measurements with the same timestamp that arrived within lag time that are ready for processing.</param>
        /// <param name="index">Index of frame within a second ranging from zero to frames per second - 1.</param>
        protected override void PublishFrame(IFrame frame, int index)
        {
            m_numberOfFrames++;

            MeasurementKey[] availableKeys = frame.Measurements.Values.MeasurementKeys();

            foreach (Guid key in m_dataWindow.Keys)
            {
                int keyIndex = availableKeys.IndexOf(item => item.SignalID == key);
                m_dataWindow[key].Add(keyIndex > -1 ? frame.Measurements[availableKeys[keyIndex]].Value : double.NaN);
            }

            if (Reference != null)
            {
                int keyIndex = availableKeys.IndexOf(item => item.SignalID == Reference.SignalID);
                m_refWindow.Add(keyIndex > -1 ? frame.Measurements[availableKeys[keyIndex]].Value : double.NaN);
            }

            int currentWindowLength = m_dataWindow.Keys.Select(key => m_dataWindow[key].Count).Max();

            if (currentWindowLength >= WindowLength)
            {
                List <IMeasurement> outputmeasurements = new List <IMeasurement>();

                List <Guid> Keys = m_dataWindow.Keys.ToList();

                foreach (Guid key in Keys)
                {
                    double      snr = CalculateSignalToNoise(m_dataWindow[key], key);
                    Measurement outputMeasurement = new Measurement {
                        Metadata = m_outputMapping[key].Metadata
                    };

                    if (!double.IsNaN(snr) && m_saveStats)
                    {
                        m_statisticsMapping[key].Count++;

                        if (snr > m_statisticsMapping[key].Maximum)
                        {
                            m_statisticsMapping[key].Maximum = snr;
                        }

                        if (snr < m_statisticsMapping[key].Minimum)
                        {
                            m_statisticsMapping[key].Minimum = snr;
                        }

                        if (snr > m_threshold)
                        {
                            m_statisticsMapping[key].AlertCount++;
                        }

                        m_statisticsMapping[key].Summation        += snr;
                        m_statisticsMapping[key].SquaredSummation += snr * snr;
                    }

                    outputmeasurements.Add(Measurement.Clone(outputMeasurement, snr, frame.Timestamp));

                    m_dataWindow[key].RemoveAt(0);

                    if (!m_saveStats)
                    {
                        m_numberOfFrames = 0;
                    }
                }

                m_refWindow.RemoveAt(0);;

                // Reporting if necessary
                if (m_numberOfFrames >= ReportingInterval && m_saveStats)
                {
                    m_numberOfFrames = 0;

                    foreach (Guid key in Keys)
                    {
                        Measurement stateMeasurement = new Measurement {
                            Metadata = m_statisticsMapping[key].Sum.Metadata
                        };
                        outputmeasurements.Add(Measurement.Clone(stateMeasurement, m_statisticsMapping[key].Summation, frame.Timestamp));

                        stateMeasurement = new Measurement {
                            Metadata = m_statisticsMapping[key].SqrD.Metadata
                        };
                        outputmeasurements.Add(Measurement.Clone(stateMeasurement, m_statisticsMapping[key].SquaredSummation, frame.Timestamp));

                        stateMeasurement = new Measurement {
                            Metadata = m_statisticsMapping[key].Min.Metadata
                        };
                        outputmeasurements.Add(Measurement.Clone(stateMeasurement, m_statisticsMapping[key].Minimum, frame.Timestamp));

                        stateMeasurement = new Measurement {
                            Metadata = m_statisticsMapping[key].Max.Metadata
                        };
                        outputmeasurements.Add(Measurement.Clone(stateMeasurement, m_statisticsMapping[key].Maximum, frame.Timestamp));

                        stateMeasurement = new Measurement {
                            Metadata = m_statisticsMapping[key].Total.Metadata
                        };
                        outputmeasurements.Add(Measurement.Clone(stateMeasurement, m_statisticsMapping[key].Count, frame.Timestamp));

                        stateMeasurement = new Measurement {
                            Metadata = m_statisticsMapping[key].Alert.Metadata
                        };
                        outputmeasurements.Add(Measurement.Clone(stateMeasurement, m_statisticsMapping[key].AlertCount, frame.Timestamp));

                        m_statisticsMapping[key].Reset();
                    }
                }

                OnNewMeasurements(outputmeasurements);
            }
        }