示例#1
0
        /// <summary>
        /// Initializes <see cref="PhasorInputOscillationDetector" />.
        /// </summary>
        public override void Initialize()
        {
            InputCount  = 4;
            OutputCount = Outputs.Length;

            base.Initialize();

            MeasurementKey getMeasurementKey(SignalType signalType) => InputMeasurementKeys.Where((_, index) => InputMeasurementKeyTypes[index] == signalType).FirstOrDefault();

            // Validate input contains voltage and current phase angle / magnitude measurement keys
            m_voltageMagnitude = getMeasurementKey(SignalType.VPHM) ?? throw new InvalidOperationException("One voltage magnitude input measurement is required. Cannot initialize adapter.");
            m_voltageAngle     = getMeasurementKey(SignalType.VPHA) ?? throw new InvalidOperationException("One voltage angle input measurement is required. Cannot initialize adapter.");
            m_currentMagnitude = getMeasurementKey(SignalType.IPHM) ?? throw new InvalidOperationException("One current magnitude input measurement is required. Cannot initialize adapter.");
            m_currentAngle     = getMeasurementKey(SignalType.IPHA) ?? throw new InvalidOperationException("One current angle input measurement is required. Cannot initialize adapter.");

            // Make sure input measurement keys are in desired order
            InputMeasurementKeys = new[] { m_voltageMagnitude, m_voltageAngle, m_currentMagnitude, m_currentAngle };

            // Provide algorithm with parameters as configured by adapter
            PseudoConfiguration configuration = new PseudoConfiguration
            {
                FramesPerSecond = FramesPerSecond,
                IsLineToNeutral = AdjustmentStrategy == VoltageAdjustmentStrategy.LineToNeutral
            };

            m_detector.DetectorAPI = new PseudoDetectorAPI
            {
                Configuration = configuration
            };

            m_detector.OutputMeasurements = OutputMeasurements;
            m_detector.FramesPerSecond    = FramesPerSecond;
            m_detector.InputTypes         = InputMeasurementKeyTypes;
            m_detector.Initialize(Name);
        }
示例#2
0
        private double CalculateSignalToNoise(List <double> values, Guid key)
        {
            int        sampleCount   = values.Count;
            int        keyIndex      = InputMeasurementKeys.IndexOf(item => item.SignalID == key);
            SignalType keySignalType = InputMeasurementKeyTypes[keyIndex];

            // If its a Phase
            if ((keySignalType == SignalType.IPHA || keySignalType == SignalType.VPHA) && sampleCount == m_refWindow.Count && Reference != null)
            {
                values = Angle.Unwrap(values.Select((item, index) => item - (Angle)m_refWindow[index]).ToArray()).Select(item => (double)item).ToList();
            }

            values      = values.Where(item => !double.IsNaN(item)).ToList();
            sampleCount = values.Count;

            if (sampleCount < 1)
            {
                return(double.NaN);
            }

            double sampleAverage = values.Average();
            double totalVariance = values.Select(item => item - sampleAverage).Select(deviation => deviation * deviation).Sum();
            double result        = 10 * Math.Log10(Math.Abs(sampleAverage / Math.Sqrt(totalVariance / sampleCount)));

            return(double.IsInfinity(result) ? double.NaN : result);
        }
示例#3
0
        /// <summary>
        /// Initializes the <see cref="ImpedanceCalculator"/> monitor.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();

            // Load needed phase angle and magnitude measurement keys from defined InputMeasurementKeys
            m_voltageAngles     = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.VPHA).ToArray();
            m_voltageMagnitudes = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.VPHM).ToArray();
            m_currentAngles     = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHA).ToArray();
            m_currentMagnitudes = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHM).ToArray();

            if (m_voltageAngles.Length != m_voltageMagnitudes.Length)
            {
                throw new InvalidOperationException("A different number of voltage magnitude and angle input measurement keys were supplied - the angles and magnitudes must be supplied in pairs, i.e., one voltage magnitude input measurement must be supplied for each voltage angle input measurement in a consecutive sequence (e.g., VA1;VM1; VA2;VM2)");
            }

            if (m_currentAngles.Length != m_currentMagnitudes.Length)
            {
                throw new InvalidOperationException("A different number of current magnitude and angle input measurement keys were supplied - the angles and magnitudes must be supplied in pairs, i.e., one current magnitude input measurement must be supplied for each current angle input measurement in a consecutive sequence (e.g., IA1;IM1; IA2;IM2)");
            }

            if (m_voltageAngles.Length != 2)
            {
                throw new InvalidOperationException("Exactly two voltage angle input measurements are required for the impedance calculator, note that \"Vs\" angle/magnitude pair should be specified first followed by \"Vr\" angle/magnitude pair second.");
            }

            if (m_voltageMagnitudes.Length != 2)
            {
                throw new InvalidOperationException("Exactly two voltage magnitude input measurements are required for the impedance calculator, note that \"Vs\" angle/magnitude pair should be specified first followed by \"Vr\" angle/magnitude pair second.");
            }

            if (m_currentAngles.Length != 2)
            {
                throw new InvalidOperationException("Exactly two current angle input measurements are required for the impedance calculator, note that \"Is\" angle/magnitude pair should be specified first followed by \"Ir\" angle/magnitude pair second.");
            }

            if (m_currentMagnitudes.Length != 2)
            {
                throw new InvalidOperationException("Exactly two current magnitude input measurements are required for the impedance calculator, note that \"Is\" angle/magnitude pair should be specified first followed by \"Ir\" angle/magnitude pair second.");
            }

            // Make sure only these phasor measurements are used as input
            InputMeasurementKeys = m_voltageAngles.Concat(m_voltageMagnitudes).Concat(m_currentAngles).Concat(m_currentMagnitudes).ToArray();

            // Validate output measurements
            if (OutputMeasurements.Length < Enum.GetValues(typeof(Output)).Length)
            {
                throw new InvalidOperationException("Not enough output measurements were specified for the impedance calculator, expecting measurements for the \"Resistance\", \"Reactance\", \"Conductance\", \"Susceptance\", \"LineImpedance\", \"LineImpedanceAngle\", \"LineAdmittance\" and \"LineAdmittanceAngle\" - in this order.");
            }

            Dictionary <string, string> settings = Settings;
            string setting;

            ApplyLineToLineAdjustment = !settings.TryGetValue("ApplyLineToLineAdjustment", out setting) || setting.ParseBoolean();
        }
示例#4
0
        private IMeasurement GetBestMeasurement(IFrame frame)
        {
            IMeasurement measurement;

            if (m_publishBadValues)
            {
                return(InputMeasurementKeys
                       .Select(key => frame.Measurements.TryGetValue(key, out measurement) ? measurement : null)
                       .Where(m => (object)m != null)
                       .OrderBy(m => (m_handleNaNAsBad && double.IsNaN(m.Value)) ? 1 : 0)
                       .ThenBy(m => (m_handleZeroAsBad && m.Value == 0.0D) ? 1 : 0)
                       .ThenBy(m => CountFlags(m.StateFlags & m_badFlags))
                       .FirstOrDefault());
            }

            return(InputMeasurementKeys
                   .Select(key => frame.Measurements.TryGetValue(key, out measurement) ? measurement : null)
                   .Where(m => (object)m != null)
                   .Where(m => !m_handleNaNAsBad || !double.IsNaN(m.Value))
                   .Where(m => !m_handleZeroAsBad || m.Value != 0.0D)
                   .Where(m => (m.StateFlags & m_badFlags) == MeasurementStateFlags.Normal)
                   .FirstOrDefault());
        }
示例#5
0
        /// <summary>
        /// Initializes <see cref="FileExporter"/>.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();

            Dictionary <string, string> settings = Settings;
            const string errorMessage            = "{0} is missing from Settings - Example: exportInterval=5; useReferenceAngle=True; referenceAngleMeasurement=DEVARCHIVE:6; companyTagPrefix=TVA; useNumericQuality=True; inputMeasurementKeys={{FILTER ActiveMeasurements WHERE Device='SHELBY' AND SignalType='FREQ'}}";
            string       setting;
            double       seconds;

            // Load required parameters
            if (!settings.TryGetValue("exportInterval", out setting) || !double.TryParse(setting, out seconds))
            {
                throw new ArgumentException(string.Format(errorMessage, "exportInterval"));
            }

            m_exportInterval      = (int)(seconds * 1000.0D);
            m_lastPublicationTime = 0;

            if (m_exportInterval <= 0)
            {
                throw new ArgumentException("exportInterval should not be 0 - Example: exportInterval=5.5");
            }

            if (InputMeasurementKeys == null || InputMeasurementKeys.Length == 0)
            {
                throw new InvalidOperationException("There are no input measurements defined. You must define \"inputMeasurementKeys\" to define which measurements to export.");
            }

            if (!settings.TryGetValue("useReferenceAngle", out setting))
            {
                throw new ArgumentException(string.Format(errorMessage, "useReferenceAngle"));
            }

            m_useReferenceAngle = setting.ParseBoolean();

            if (m_useReferenceAngle)
            {
                // Reference angle measurement has to be defined if using reference angle
                if (!settings.TryGetValue("referenceAngleMeasurement", out setting))
                {
                    throw new ArgumentException(string.Format(errorMessage, "referenceAngleMeasurement"));
                }

                m_referenceAngleKey = MeasurementKey.Parse(setting);

                // Make sure reference angle is part of input measurement keys collection
                if (!InputMeasurementKeys.Contains(m_referenceAngleKey))
                {
                    InputMeasurementKeys = InputMeasurementKeys.Concat(new[] { m_referenceAngleKey }).ToArray();
                }

                // Make sure sure reference angle key is actually an angle measurement
                SignalType signalType = InputMeasurementKeyTypes[InputMeasurementKeys.IndexOf(key => key == m_referenceAngleKey)];

                if (signalType != SignalType.IPHA && signalType != SignalType.VPHA)
                {
                    throw new InvalidOperationException(string.Format("Specified reference angle measurement key is a {0} signal, not a phase angle.", signalType.GetFormattedName()));
                }
            }

            // Load optional parameters
            if (settings.TryGetValue("companyTagPrefix", out setting))
            {
                m_companyTagPrefix = setting.ToUpper().Trim();
            }
            else
            {
                m_companyTagPrefix = null;
            }

            if (settings.TryGetValue("useNumericQuality", out setting))
            {
                m_useNumericQuality = setting.ParseBoolean();
            }
            else
            {
                m_useNumericQuality = false;
            }

            // Suffix company tag prefix with an underscore if defined
            if (!string.IsNullOrWhiteSpace(m_companyTagPrefix))
            {
                m_companyTagPrefix = m_companyTagPrefix.EnsureEnd('_');
            }

            // Define a default export location - user can override and add multiple locations in config later...
            m_dataExporter = new MultipleDestinationExporter(ConfigurationSection, m_exportInterval);
            m_dataExporter.StatusMessage    += m_dataExporter_StatusMessage;
            m_dataExporter.ProcessException += m_dataExporter_ProcessException;
            m_dataExporter.Initialize(new[] { new ExportDestination(FilePath.GetAbsolutePath(ConfigurationSection + ".txt"), false) });

            // Create new measurement tag name dictionary
            m_measurementTags = new ConcurrentDictionary <MeasurementKey, string>();
            string pointID = "undefined";

            // Lookup point tag name for input measurement in the ActiveMeasurements table
            foreach (MeasurementKey key in InputMeasurementKeys)
            {
                try
                {
                    // Get measurement key as a string
                    pointID = key.ToString();

                    // Lookup measurement key in active measurements table
                    DataRow row = DataSource.Tables["ActiveMeasurements"].Select(string.Format("ID='{0}'", pointID))[0];

                    // Remove invalid symbols that may be in tag name
                    string pointTag = row["PointTag"].ToNonNullString(pointID).Replace('-', '_').Replace(':', '_').ToUpper();

                    // Prefix point tag with company prefix if defined
                    if (!string.IsNullOrWhiteSpace(m_companyTagPrefix) && !pointTag.StartsWith(m_companyTagPrefix))
                    {
                        pointTag = m_companyTagPrefix + pointTag;
                    }

                    m_measurementTags.TryAdd(key, pointTag);
                }
                catch (ThreadAbortException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    OnProcessException(new InvalidOperationException(string.Format("Failed to lookup point tag for measurement [{0}] due to exception: {1}", pointID, ex.Message)));
                }
            }

            // We enable tracking of latest measurements so we can use these values if points are missing - since we are using
            // latest measurement tracking, we sort all incoming points even though most of them will be thrown out...
            TrackLatestMeasurements = true;
        }
示例#6
0
        /// <summary>
        /// Initializes the <see cref="PowerCalculator"/>.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();

            Dictionary <string, string> settings = Settings;
            string setting;

            // Load parameters
            if (settings.TryGetValue("trackRecentValues", out setting))
            {
                m_trackRecentValues = setting.ParseBoolean();
            }
            else
            {
                m_trackRecentValues = true;
            }

            if (settings.TryGetValue("sampleSize", out setting))            // Data sample size to monitor, in seconds
            {
                m_sampleSize = int.Parse(setting);
            }
            else
            {
                m_sampleSize = 5;
            }

            // Load needed phase angle and magnitude measurement keys from defined InputMeasurementKeys
            m_voltageAngle     = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.VPHA).FirstOrDefault();
            m_voltageMagnitude = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.VPHM).FirstOrDefault();
            m_currentAngle     = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHA).FirstOrDefault();
            m_currentMagnitude = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHM).FirstOrDefault();

            if ((object)m_voltageAngle == null || m_voltageAngle.ID == 0)
            {
                throw new InvalidOperationException("No voltage angle input was defined - one voltage angle input measurement is required for the power calculator.");
            }

            if ((object)m_voltageMagnitude == null || m_voltageMagnitude.ID == 0)
            {
                throw new InvalidOperationException("No voltage magnitude input was defined - one voltage magnitude input measurement is required for the power calculator.");
            }

            if ((object)m_currentAngle == null || m_currentAngle.ID == 0)
            {
                throw new InvalidOperationException("No current angle input was defined - one current angle input measurement is required for the power calculator.");
            }

            if ((object)m_currentMagnitude == null || m_currentMagnitude.ID == 0)
            {
                throw new InvalidOperationException("No current magnitude input measurement was defined - one current magnitude input measurement is required for the power calculator.");
            }

            // Make sure only these four phasor measurements are used as input (any others will be ignored)
            InputMeasurementKeys = new[] { m_voltageAngle, m_voltageMagnitude, m_currentAngle, m_currentMagnitude };

            // Validate output measurements
            if (OutputMeasurements.Length < Enum.GetValues(typeof(Output)).Length)
            {
                throw new InvalidOperationException("Not enough output measurements were specified for the power calculator, expecting measurements for the \"Calculated Power\" and the \"Calculated Reactive Power\" - in this order.");
            }

            if (m_trackRecentValues)
            {
                m_powerSample         = new List <double>();
                m_reactivePowerSample = new List <double>();
            }

            // Assign a default adapter name to be used if power calculator is loaded as part of automated collection
            if (string.IsNullOrWhiteSpace(Name))
            {
                Name = string.Format("PC!{0}", OutputMeasurements[(int)Output.Power].Key);
            }
        }
示例#7
0
        /// <summary>
        /// Initializes <see cref="FileExporter"/>.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();

            Dictionary <string, string> settings = Settings;
            const string errorMessage            = "{0} is missing from Settings - Example: exportInterval=5; modelIdentifier=Goslin; referenceAngleMeasurement=DEVARCHIVE:6; inputMeasurementKeys={{FILTER ActiveMeasurements WHERE Device='SHELBY' AND SignalType='FREQ'}}";
            string       setting;
            double       seconds;

            // Load required parameters
            if (!settings.TryGetValue("exportInterval", out setting) || !double.TryParse(setting, out seconds))
            {
                throw new ArgumentException(string.Format(errorMessage, "exportInterval"));
            }

            if (!settings.TryGetValue("fileExportPath", out m_fileExportPath))
            {
                m_fileExportPath = FilePath.GetAbsolutePath("");
            }

            m_exportInterval = (int)(seconds * 1000.0D);

            if (m_exportInterval <= 0)
            {
                throw new ArgumentException("exportInterval should not be 0 - Example: exportInterval=5.5");
            }

            if ((object)InputMeasurementKeys == null || InputMeasurementKeys.Length == 0)
            {
                throw new InvalidOperationException("There are no input measurements defined. You must define \"inputMeasurementKeys\" to define which measurements to export.");
            }

            // Reference angle measurement has to be defined if using reference angle
            if (!settings.TryGetValue("referenceAngleMeasurement", out setting))
            {
                throw new ArgumentException(string.Format(errorMessage, "referenceAngleMeasurement"));
            }

            m_referenceAngleKey = MeasurementKey.Parse(setting);

            // Make sure reference angle is first angle of input measurement keys collection
            InputMeasurementKeys = (new[] { m_referenceAngleKey }).Concat(InputMeasurementKeys).ToArray();

            // Make sure sure reference angle key is actually an angle measurement
            SignalType signalType = InputMeasurementKeyTypes[InputMeasurementKeys.IndexOf(key => key == m_referenceAngleKey)];

            if (signalType != SignalType.IPHA && signalType != SignalType.VPHA)
            {
                throw new InvalidOperationException(string.Format("Specified reference angle measurement key is a {0} signal, not a phase angle.", signalType.GetFormattedName()));
            }

            Comments = settings.TryGetValue("comments", out setting) ? setting : "Comment section---";

            if (!settings.TryGetValue("modelIdentifier", out setting))
            {
                throw new ArgumentException(string.Format(errorMessage, "modelIdentifier"));
            }

            ModelIdentifier = setting;

            // We enable tracking of latest measurements so we can use these values if points are missing - since we are using
            // latest measurement tracking, we sort all incoming points even though most of them will be thrown out...
            TrackLatestMeasurements = true;

            //// Create a new dictionary of base voltages
            //m_baseVoltages = new Dictionary<MeasurementKey, double>();

            StringBuilder header = new StringBuilder();

            //MeasurementKey voltageMagnitudeKey;
            //double baseKV;

            // Write header row
            header.Append("TimeStamp");

            DataTable measurements   = DataSource.Tables["ActiveMeasurements"];
            int       tieLines       = 0;
            bool      referenceAdded = false;

            for (int i = 0; i < InputMeasurementKeys.Length; i++)
            {
                // Lookup measurement key in active measurements table
                DataRow row        = measurements.Select(string.Format("ID='{0}'", InputMeasurementKeys[i]))[0];
                string  deviceName = row["Device"].ToNonNullString("UNDEFINED").ToUpper().Trim();

                if (!referenceAdded && InputMeasurementKeys[i] == m_referenceAngleKey)
                {
                    header.AppendFormat(",Ref. Angle of {0}", deviceName);
                    referenceAdded = true;
                }
                else
                {
                    switch (InputMeasurementKeyTypes[i])
                    {
                    case SignalType.VPHM:
                        header.AppendFormat(",{0} |V|", deviceName);
                        tieLines++;

                        //voltageMagnitudeKey = InputMeasurementKeys[i];

                        //if (settings.TryGetValue(voltageMagnitudeKey + "BaseKV", out setting) && double.TryParse(setting, out baseKV))
                        //{
                        //    m_baseVoltages.Add(voltageMagnitudeKey, baseKV * SI.Kilo);
                        //}
                        //else
                        //{
                        //    int baseKVCode;

                        //    // Second check if base KV can be inferred from device name suffixed KV index
                        //    if (int.TryParse(deviceName[deviceName.Length - 1].ToString(), out baseKVCode) && baseKVCode > 1 && baseKVCode < BaseKVs.Length)
                        //    {
                        //        m_baseVoltages.Add(voltageMagnitudeKey, BaseKVs[baseKVCode]);
                        //    }
                        //    else
                        //    {
                        //        OnStatusMessage("WARNING: Did not find a valid base KV setting for voltage magnitude {0}, assumed 500KV", voltageMagnitudeKey.ToString());
                        //        m_baseVoltages.Add(voltageMagnitudeKey, 500.0D * SI.Kilo);
                        //    }
                        //}
                        break;

                    case SignalType.VPHA:
                        header.AppendFormat(",{0} Voltage Angle", deviceName);
                        break;

                    case SignalType.IPHM:
                        header.AppendFormat(",{0} |I|", deviceName);
                        break;

                    case SignalType.IPHA:
                        header.AppendFormat(",{0} Current Angle", deviceName);
                        break;

                    default:
                        header.AppendFormat(",{0} ??", deviceName);
                        break;
                    }
                }
            }

            string row5 = header.ToString();

            header = new StringBuilder();

            // Add row 1
            header.AppendFormat("Comments: {0}\r\n", Comments);

            // Add row 2
            header.AppendFormat("Model Identifier: {0}\r\n", ModelIdentifier);

            // Add row 3
            header.Append("Datapoints,Tielines,TimeStep");

            if (InputMeasurementKeys.Length - 3 > 0)
            {
                header.Append(new string(',', InputMeasurementKeys.Length - 3));
            }

            header.AppendLine();

            // Add row 4
            header.AppendFormat("{0},{1},{2}", RowCountMarker, tieLines, 1.0D / FramesPerSecond);
            header.AppendLine();

            // Add row 5
            header.AppendLine(row5);

            // Cache header for each file export
            m_header = header.ToString();
        }
示例#8
0
        /// <summary>
        /// Initializes the <see cref="PowerCalculator"/>.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();

            Dictionary <string, string> settings = Settings;

            // Load parameters
            if (settings.TryGetValue(nameof(TrackRecentValues), out string setting))
            {
                TrackRecentValues = setting.ParseBoolean();
            }

            // Data sample size to monitor, in seconds
            if (settings.TryGetValue(nameof(SampleSize), out setting) && int.TryParse(setting, out int sampleSize))
            {
                SampleSize = sampleSize;
            }

            if (settings.TryGetValue(nameof(IncludePositiveSequence), out setting))
            {
                IncludePositiveSequence = setting.ParseBoolean();
            }

            if (settings.TryGetValue(nameof(IncludeNegativeSequence), out setting))
            {
                IncludeNegativeSequence = setting.ParseBoolean();
            }

            if (settings.TryGetValue(nameof(IncludeZeroSequence), out setting))
            {
                IncludeZeroSequence = setting.ParseBoolean();
            }

            // Load needed phase angle measurement keys from defined InputMeasurementKeys
            m_angles = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.VPHA).ToArray();

            if (m_angles.Length == 0)
            {
                // No voltage angles existed, check for current angles
                m_angles = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHA).ToArray();
            }
            else
            {
                // Make sure only one kind of angles are defined - not a mixture of voltage and currents
                if (InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHA).Any())
                {
                    throw new InvalidOperationException("Angle input measurements for a single sequence calculator instance should only be for voltages or currents - not both.");
                }
            }

            // Load needed phase magnitude measurement keys from defined InputMeasurementKeys
            m_magnitudes = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.VPHM).ToArray();

            if (m_magnitudes.Length == 0)
            {
                // No voltage magnitudes existed, check for current magnitudes
                m_magnitudes     = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHM).ToArray();
                m_magnitudeUnits = "amps";
            }
            else
            {
                // Make only one kind of magnitudes are defined - not a mixture of voltage and currents
                if (InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHM).Any())
                {
                    throw new InvalidOperationException("Magnitude input measurements for a single sequence calculator instance should only be for voltages or currents - not both.");
                }

                m_magnitudeUnits = "volts";
            }

            if (m_angles.Length < 3)
            {
                throw new InvalidOperationException("Three angle input measurements, i.e., A, B and C - in that order, are required for the sequence calculator.");
            }

            if (m_magnitudes.Length < 3)
            {
                throw new InvalidOperationException("Three magnitude input measurements, i.e., A, B and C - in that order, are required for the sequence calculator.");
            }

            if (m_angles.Length != m_magnitudes.Length)
            {
                throw new InvalidOperationException("A different number of magnitude and angle input measurement keys were supplied - the angles and magnitudes must be supplied in pairs in A, B, C sequence, i.e., one magnitude input measurement must be supplied for each angle input measurement in a consecutive sequence (e.g., A1;M1;  A2;M2; ... An;Mn)");
            }

            // Make sure only these phasor measurements are used as input
            InputMeasurementKeys = m_angles.Concat(m_magnitudes).ToArray();

            // Validate output measurements
            if (IncludePositiveSequence && IncludeNegativeSequence && IncludeZeroSequence)
            {
                if (OutputMeasurements.Length < 6)
                {
                    throw new InvalidOperationException("Not enough output measurements were specified for the sequence calculator, expecting measurements for the \"Positive Sequence Magnitude\", \"Positive Sequence Angle\", \"Negative Sequence Magnitude\", \"Negative Sequence Angle\", \"Zero Sequence Magnitude\" and \"Zero Sequence Angle\" - in this order.");
                }
            }
            else if (IncludePositiveSequence && IncludeNegativeSequence)
            {
                if (OutputMeasurements.Length < 4)
                {
                    throw new InvalidOperationException("Not enough output measurements were specified for the sequence calculator, expecting measurements for the \"Positive Sequence Magnitude\", \"Positive Sequence Angle\", \"Negative Sequence Magnitude\" and \"Negative Sequence Angle\" - in this order.");
                }
            }
            else if (IncludePositiveSequence && IncludeZeroSequence)
            {
                if (OutputMeasurements.Length < 4)
                {
                    throw new InvalidOperationException("Not enough output measurements were specified for the sequence calculator, expecting measurements for the \"Positive Sequence Magnitude\", \"Positive Sequence Angle\", \"Zero Sequence Magnitude\" and \"Zero Sequence Angle\" - in this order.");
                }
            }
            else if (IncludeNegativeSequence && IncludeZeroSequence)
            {
                if (OutputMeasurements.Length < 4)
                {
                    throw new InvalidOperationException("Not enough output measurements were specified for the sequence calculator, expecting measurements for the \"Negative Sequence Magnitude\", \"Negative Sequence Angle\", \"Zero Sequence Magnitude\" and \"Zero Sequence Angle\" - in this order.");
                }
            }
            else if (IncludePositiveSequence)
            {
                if (OutputMeasurements.Length < 2)
                {
                    throw new InvalidOperationException("Not enough output measurements were specified for the sequence calculator, expecting measurements for the \"Positive Sequence Magnitude\" and \"Positive Sequence Angle\" - in this order.");
                }
            }
            else if (IncludeNegativeSequence)
            {
                if (OutputMeasurements.Length < 2)
                {
                    throw new InvalidOperationException("Not enough output measurements were specified for the sequence calculator, expecting measurements for the \"Negative Sequence Magnitude\" and \"Negative Sequence Angle\" - in this order.");
                }
            }
            else if (IncludeZeroSequence)
            {
                if (OutputMeasurements.Length < 2)
                {
                    throw new InvalidOperationException("Not enough output measurements were specified for the sequence calculator, expecting measurements for the \"Zero Sequence Magnitude\" and \"Zero Sequence Angle\" - in this order.");
                }
            }
            else
            {
                throw new InvalidOperationException("At least one of positive, negative or sequence calculations must be included to calculate.");
            }

            if (TrackRecentValues)
            {
                m_positiveSequenceMagnitudeSample = new List <double>();
                m_positiveSequenceAngleSample     = new List <double>();
                m_negativeSequenceMagnitudeSample = new List <double>();
                m_negativeSequenceAngleSample     = new List <double>();
                m_zeroSequenceMagnitudeSample     = new List <double>();
                m_zeroSequenceAngleSample         = new List <double>();
            }

            // Assign a default adapter name to be used if sequence calculator is loaded as part of automated collection
            if (string.IsNullOrWhiteSpace(Name))
            {
                Name = $"SC!{OutputMeasurements[(int)Output.PositiveSequenceMagnitude].Key}";
            }
        }
示例#9
0
        /// <summary>
        /// Initializes <see cref="UnBalancedCalculation"/>.
        /// </summary>
        public override void Initialize()
        {
            new ConnectionStringParser <CalculatedMesaurementAttribute>().ParseConnectionString(ConnectionString, this);

            base.Initialize();

            m_threePhaseComponent = new List <ThreePhaseSet>();
            m_statisticsMapping   = new Dictionary <Guid, StatisticsCollection>();
            m_saveStats           = SaveAggregates;

            CategorizedSettingsElementCollection reportSettings = ConfigurationFile.Current.Settings["reportSettings"];

            reportSettings.Add("IUnbalanceThreshold", "4.0", "Current Unbalance Alert threshold.");
            reportSettings.Add("VUnbalanceThreshold", "4.0", "Voltage Unbalance Alert threshold.");
            double i_threshold = reportSettings["IUnbalanceThreshold"].ValueAs(1.0D);
            double v_threshold = reportSettings["VUnbalanceThreshold"].ValueAs(1.0D);

            List <Guid> processed = new List <Guid>();

            using (AdoDataConnection connection = new AdoDataConnection("systemSettings"))
            {
                TableOperations <MeasurementRecord> measurementTable      = new TableOperations <MeasurementRecord>(connection);
                TableOperations <ActiveMeasurement> activeMeasurmentTable = new TableOperations <ActiveMeasurement>(connection);

                TableOperations <Device>           deviceTable = new TableOperations <Device>(connection);
                TableOperations <SignalTypeRecord> signalTable = new TableOperations <SignalTypeRecord>(connection);

                Device device      = deviceTable.QueryRecordWhere("Acronym = {0}", ResultDeviceName);
                int    historianID = Convert.ToInt32(connection.ExecuteScalar("SELECT ID FROM Historian WHERE Acronym = {0}", new object[] { HistorianInstance }));

                // Take Care of the Device
                if (InputMeasurementKeys.Length < 1)
                {
                    return;
                }

                m_nodeID = deviceTable.QueryRecordWhere("Id={0}", measurementTable.QueryRecordWhere("SignalID = {0}", InputMeasurementKeys[0].SignalID).DeviceID).NodeID;

                if (device == null)
                {
                    device = CreateDefaultDevice(deviceTable);
                    OnStatusMessage(MessageLevel.Warning, $"Default Device for Output Measurments not found. Created Device {device.Acronym}");
                }


                if (MappingFilePath != "")
                {
                    // Read Mapping File
                    using (StreamReader reader = new StreamReader(FilePath.GetAbsolutePath(MappingFilePath)))
                    {
                        string line;
                        int    index = -1;


                        while ((line = reader.ReadLine()) != null)
                        {
                            index++;
                            List <string> pointTags = line.Split(',').Select(item => item.Trim()).ToList();

                            List <MeasurementKey> availableInputs = new List <MeasurementKey>(3);

                            if (pointTags.Count != 3)
                            {
                                OnStatusMessage(MessageLevel.Warning, $"Skipping Line {index} in mapping file.");
                                continue;
                            }

                            OnStatusMessage(MessageLevel.Info, $"PointTag of Measurment 1 is: {pointTags[0]}");
                            OnStatusMessage(MessageLevel.Info, $"PointTag of Measurment 1 is: {pointTags[0]}");
                            OnStatusMessage(MessageLevel.Info, $"PointTag of Measurment 1 is: {pointTags[0]}");

                            // check if measurments are in inputmeasurments
                            availableInputs.Add(InputMeasurementKeys.FirstOrDefault(item => item.SignalID == GetSignalID(pointTags[0], activeMeasurmentTable)));
                            availableInputs.Add(InputMeasurementKeys.FirstOrDefault(item => item.SignalID == GetSignalID(pointTags[1], activeMeasurmentTable)));
                            availableInputs.Add(InputMeasurementKeys.FirstOrDefault(item => item.SignalID == GetSignalID(pointTags[2], activeMeasurmentTable)));

                            if (availableInputs[0] == null || availableInputs[1] == null || availableInputs[2] == null)
                            {
                                OnStatusMessage(MessageLevel.Warning, $"Skipping Line {index} in mapping file. PointTag not found");
                                continue;
                            }

                            SignalType type = GetSignalType(availableInputs[0], new TableOperations <ActiveMeasurement>(connection));

                            MeasurementKey neg = availableInputs.FirstOrDefault(item =>
                                                                                SearchNegative(item, new TableOperations <ActiveMeasurement>(connection)) &&
                                                                                GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type);
                            MeasurementKey pos = availableInputs.FirstOrDefault(item =>
                                                                                SearchPositive(item, new TableOperations <ActiveMeasurement>(connection)) &&
                                                                                GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type);
                            MeasurementKey zero = availableInputs.FirstOrDefault(item =>
                                                                                 SearchZero(item, new TableOperations <ActiveMeasurement>(connection)) &&
                                                                                 GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type
                                                                                 );

                            if (neg != null && zero != null && pos != null)
                            {
                                MeasurementKey unBalance;
                                string         outputReference = measurementTable.QueryRecordWhere("SignalID = {0}", pos.SignalID).SignalReference + "-" + (type == SignalType.IPHM? "I" : "V") + "UBAL";

                                if (measurementTable.QueryRecordCountWhere("SignalReference = {0}", outputReference) > 0)
                                {
                                    // Measurement Exists
                                    unBalance = MeasurementKey.LookUpBySignalID(measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID);
                                }
                                else
                                {
                                    // Add Measurment to Database and make a statement
                                    MeasurementRecord inMeasurement = measurementTable.QueryRecordWhere("SignalID = {0}", pos.SignalID);

                                    MeasurementRecord outMeasurement = new MeasurementRecord
                                    {
                                        HistorianID     = historianID,
                                        DeviceID        = device.ID,
                                        PointTag        = inMeasurement.PointTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL",
                                        AlternateTag    = inMeasurement.AlternateTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL",
                                        SignalTypeID    = signalTable.QueryRecordWhere("Acronym = {0}", "CALC").ID,
                                        SignalReference = outputReference,
                                        Description     = GetDescription(pos, new TableOperations <ActiveMeasurement>(connection)) + " UnBalanced",
                                        Enabled         = true,
                                        CreatedOn       = DateTime.UtcNow,
                                        UpdatedOn       = DateTime.UtcNow,
                                        CreatedBy       = UserInfo.CurrentUserID,
                                        UpdatedBy       = UserInfo.CurrentUserID,
                                        SignalID        = Guid.NewGuid(),
                                        Adder           = 0.0D,
                                        Multiplier      = 1.0D
                                    };

                                    measurementTable.AddNewRecord(outMeasurement);
                                    unBalance = MeasurementKey.LookUpBySignalID(measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID);

                                    OnStatusMessage(MessageLevel.Warning, $"Output measurment {outputReference} not found. Creating measurement");
                                }

                                double threshold = InputMeasurementKeyTypes[InputMeasurementKeys.IndexOf(item => item == availableInputs[0])] == SignalType.IPHM ? i_threshold : v_threshold;

                                m_threePhaseComponent.Add(new ThreePhaseSet(pos, zero, neg, unBalance, threshold));

                                if (m_saveStats)
                                {
                                    m_statisticsMapping.Add(pos.SignalID, CreateStatistics(measurementTable, pos, device, historianID, type));
                                }
                            }
                            else
                            {
                                OnStatusMessage(MessageLevel.Warning, $"Skipping Line {index} in mapping file. Did not find pos. neg. and zero seq.");
                            }
                        }
                    }
                }
                else
                {
                    foreach (MeasurementKey key in InputMeasurementKeys)
                    {
                        if (processed.Contains(key.SignalID))
                        {
                            continue;
                        }

                        // ensure only magnitudes are being used
                        if (!(GetSignalType(key, new TableOperations <ActiveMeasurement>(connection)) == SignalType.IPHM ||
                              GetSignalType(key, new TableOperations <ActiveMeasurement>(connection)) == SignalType.VPHM))
                        {
                            continue;
                        }



                        bool isNeg  = SearchNegative(key, new TableOperations <ActiveMeasurement>(connection));
                        bool isPos  = SearchPositive(key, new TableOperations <ActiveMeasurement>(connection));
                        bool isZero = SearchZero(key, new TableOperations <ActiveMeasurement>(connection));

                        if (!(isNeg || isPos || isZero))
                        {
                            continue;
                        }

                        string description = GetDescription(key, new TableOperations <ActiveMeasurement>(connection));

                        // Check to make sure can actually deal with this
                        if (description == string.Empty)
                        {
                            OnStatusMessage(MessageLevel.Warning, "Failed to apply automatic Line bundling to " + key.SignalID);
                            continue;
                        }

                        //Make sure only correct Type (V vs I) makes it here....
                        SignalType type = GetSignalType(key, new TableOperations <ActiveMeasurement>(connection));

                        MeasurementKey neg = InputMeasurementKeys.FirstOrDefault(item =>
                                                                                 GetDescription(item, new TableOperations <ActiveMeasurement>(connection)) == description &&
                                                                                 SearchNegative(item, new TableOperations <ActiveMeasurement>(connection)) &&
                                                                                 GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type);
                        MeasurementKey pos = InputMeasurementKeys.FirstOrDefault(item =>
                                                                                 GetDescription(item, new TableOperations <ActiveMeasurement>(connection)) == description &&
                                                                                 SearchPositive(item, new TableOperations <ActiveMeasurement>(connection)) &&
                                                                                 GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type);
                        MeasurementKey zero = InputMeasurementKeys.FirstOrDefault(item =>
                                                                                  GetDescription(item, new TableOperations <ActiveMeasurement>(connection)) == description &&
                                                                                  SearchZero(item, new TableOperations <ActiveMeasurement>(connection)) &&
                                                                                  GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type
                                                                                  );

                        if (neg != null && zero != null && pos != null)
                        {
                            MeasurementKey unBalance;
                            string         outputReference = measurementTable.QueryRecordWhere("SignalID = {0}", pos.SignalID).SignalReference + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL";

                            if (measurementTable.QueryRecordCountWhere("SignalReference = {0}", outputReference) > 0)
                            {
                                // Measurement Exists
                                unBalance = MeasurementKey.LookUpBySignalID(measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID);
                            }
                            else
                            {
                                // Add Measurment to Database and make a statement
                                MeasurementRecord inMeasurement = measurementTable.QueryRecordWhere("SignalID = {0}", pos.SignalID);

                                MeasurementRecord outMeasurement = new MeasurementRecord
                                {
                                    HistorianID     = historianID,
                                    DeviceID        = device.ID,
                                    PointTag        = inMeasurement.PointTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL",
                                    AlternateTag    = inMeasurement.AlternateTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL",
                                    SignalTypeID    = signalTable.QueryRecordWhere("Acronym = {0}", "CALC").ID,
                                    SignalReference = outputReference,
                                    Description     = GetDescription(pos, new TableOperations <ActiveMeasurement>(connection)) + " UnBalanced",
                                    Enabled         = true,
                                    CreatedOn       = DateTime.UtcNow,
                                    UpdatedOn       = DateTime.UtcNow,
                                    CreatedBy       = UserInfo.CurrentUserID,
                                    UpdatedBy       = UserInfo.CurrentUserID,
                                    SignalID        = Guid.NewGuid(),
                                    Adder           = 0.0D,
                                    Multiplier      = 1.0D
                                };

                                measurementTable.AddNewRecord(outMeasurement);
                                unBalance = MeasurementKey.LookUpBySignalID(measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID);

                                OnStatusMessage(MessageLevel.Warning, $"Output measurment {outputReference} not found. Creating measurement");
                            }

                            double threshold = InputMeasurementKeyTypes[InputMeasurementKeys.IndexOf(item => item == key)] == SignalType.IPHM ? i_threshold : v_threshold;

                            m_threePhaseComponent.Add(new ThreePhaseSet(pos, zero, neg, unBalance, threshold));

                            processed.Add(pos.SignalID);
                            processed.Add(neg.SignalID);
                            processed.Add(zero.SignalID);

                            if (m_saveStats)
                            {
                                m_statisticsMapping.Add(pos.SignalID, CreateStatistics(measurementTable, pos, device, historianID, type));
                            }
                        }

                        else
                        {
                            if (pos != null)
                            {
                                processed.Add(pos.SignalID);
                            }

                            if (neg != null)
                            {
                                processed.Add(neg.SignalID);
                            }

                            if (zero != null)
                            {
                                processed.Add(zero.SignalID);
                            }
                        }
                    }
                }

                if (m_threePhaseComponent.Count == 0)
                {
                    OnStatusMessage(MessageLevel.Error, "No case with all 3 sequences was found");
                }
            }
        }
示例#10
0
        /// <summary>
        /// Initializes the <see cref="PowerStability"/> monitor.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();

            Dictionary <string, string> settings = Settings;
            string setting;

            // Load parameters
            if (settings.TryGetValue("sampleSize", out setting))            // Data sample size to monitor, in seconds
            {
                m_minimumSamples = int.Parse(setting) * FramesPerSecond;
            }
            else
            {
                m_minimumSamples = 15 * FramesPerSecond;
            }

            if (settings.TryGetValue("energizedThreshold", out setting))    // Energized bus threshold, in volts, recommended value
            {
                m_energizedThreshold = double.Parse(setting);               // is 20% of nominal line-to-neutral voltage
            }
            else
            {
                m_energizedThreshold = 58000.0D;
            }

            // Load needed phase angle and magnitude measurement keys from defined InputMeasurementKeys
            m_voltageAngles     = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.VPHA).ToArray();
            m_voltageMagnitudes = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.VPHM).ToArray();
            m_currentAngles     = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHA).ToArray();
            m_currentMagnitudes = InputMeasurementKeys.Where((key, index) => InputMeasurementKeyTypes[index] == SignalType.IPHM).ToArray();

            if (m_voltageAngles.Length < 1)
            {
                throw new InvalidOperationException("No voltage angle input measurement keys were not found - at least one voltage angle input measurement is required for the power stability monitor.");
            }

            if (m_voltageMagnitudes.Length < 1)
            {
                throw new InvalidOperationException("No voltage magnitude input measurement keys were not found - at least one voltage magnitude input measurement is required for the power stability monitor.");
            }

            if (m_currentAngles.Length < 1)
            {
                throw new InvalidOperationException("No current angle input measurement keys were not found - at least one current angle input measurement is required for the power stability monitor.");
            }

            if (m_currentMagnitudes.Length < 1)
            {
                throw new InvalidOperationException("No current magnitude input measurement keys were not found - at least one current magnitude input measurement is required for the power stability monitor.");
            }

            if (m_voltageAngles.Length != m_voltageMagnitudes.Length)
            {
                throw new InvalidOperationException("A different number of voltage magnitude and angle input measurement keys were supplied - the angles and magnitudes must be supplied in pairs, i.e., one voltage magnitude input measurement must be supplied for each voltage angle input measurement in a consecutive sequence (e.g., VA1;VM1;  VA2;VM2; ... VAn;VMn)");
            }

            if (m_currentAngles.Length != m_currentMagnitudes.Length)
            {
                throw new InvalidOperationException("A different number of current magnitude and angle input measurement keys were supplied - the angles and magnitudes must be supplied in pairs, i.e., one current magnitude input measurement must be supplied for each current angle input measurement in a consecutive sequence (e.g., IA1;IM1;  IA2;IM2; ... IAn;IMn)");
            }

            // Make sure only these phasor measurements are used as input
            InputMeasurementKeys = m_voltageAngles.Concat(m_voltageMagnitudes).Concat(m_currentAngles).Concat(m_currentMagnitudes).ToArray();

            // Validate output measurements
            if (OutputMeasurements.Length < Enum.GetValues(typeof(Output)).Length)
            {
                throw new InvalidOperationException("Not enough output measurements were specified for the power stability monitor, expecting measurements for the \"Calculated Power\", and the \"Standard Deviation of Power\" - in this order.");
            }

            m_powerDataSample = new List <double>();
        }
示例#11
0
        /// <summary>
        /// Initializes <see cref="SNRComputation"/>.
        /// </summary>
        public override void Initialize()
        {
            new ConnectionStringParser <CalculatedMesaurementAttribute>().ParseConnectionString(ConnectionString, this);

            base.Initialize();

            // Figure Output Measurement Keys
            m_dataWindow        = new Dictionary <Guid, List <double> >();
            m_refWindow         = new List <double>();
            m_outputMapping     = new Dictionary <Guid, MeasurementKey>();
            m_statisticsMapping = new Dictionary <Guid, StatisticsCollection>();
            m_saveStats         = SaveAggregates;

            if (ReportingInterval % (double)WindowLength != 0.0D)
            {
                ReportingInterval = WindowLength * (ReportingInterval / WindowLength);
                OnStatusMessage(MessageLevel.Warning, $"Adjusting Reporting Interval to every {ReportingInterval} frames.");
            }

            CategorizedSettingsElementCollection reportSettings = ConfigurationFile.Current.Settings["reportSettings"];

            reportSettings.Add("DefaultSNRThreshold", "4.0", "Default SNR Alert threshold.");
            m_threshold = reportSettings["DefaultSNRThreshold"].ValueAs(m_threshold);

            using (AdoDataConnection connection = new AdoDataConnection("systemSettings"))
            {
                TableOperations <MeasurementRecord> measurementTable = new TableOperations <MeasurementRecord>(connection);
                TableOperations <Device>            deviceTable      = new TableOperations <Device>(connection);
                TableOperations <SignalTypeRecord>  signalTable      = new TableOperations <SignalTypeRecord>(connection);

                Device device      = deviceTable.QueryRecordWhere("Acronym = {0}", ResultDeviceName);
                int    historianID = Convert.ToInt32(connection.ExecuteScalar("SELECT ID FROM Historian WHERE Acronym = {0}", new object[] { HistorianInstance }));

                if (!InputMeasurementKeys.Any())
                {
                    return;
                }

                m_nodeID = deviceTable.QueryRecordWhere("Id={0}", measurementTable.QueryRecordWhere("SignalID = {0}", InputMeasurementKeys[0].SignalID).DeviceID).NodeID;

                if (device == null)
                {
                    device = CreateDefaultDevice(deviceTable);
                    OnStatusMessage(MessageLevel.Warning, $"Default Device for Output Measurments not found. Created Device {device.Acronym}");
                }

                foreach (MeasurementKey key in InputMeasurementKeys)
                {
                    m_dataWindow.Add(key.SignalID, new List <double>());

                    string outputReference = measurementTable.QueryRecordWhere("SignalID = {0}", key.SignalID).SignalReference + "-SNR";

                    if (measurementTable.QueryRecordCountWhere("SignalReference = {0}", outputReference) > 0)
                    {
                        // Measurement Exists
                        m_outputMapping.Add(key.SignalID, MeasurementKey.LookUpBySignalID(measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID));
                    }
                    else
                    {
                        // Add Measurment to Database and make a statement
                        MeasurementRecord inMeasurement = measurementTable.QueryRecordWhere("SignalID = {0}", key.SignalID);

                        MeasurementRecord outMeasurement = new MeasurementRecord
                        {
                            HistorianID     = historianID,
                            DeviceID        = device.ID,
                            PointTag        = inMeasurement.PointTag + "-SNR",
                            AlternateTag    = inMeasurement.AlternateTag + "-SNR",
                            SignalTypeID    = signalTable.QueryRecordWhere("Acronym = {0}", "CALC").ID,
                            SignalReference = outputReference,
                            Description     = inMeasurement.Description + " SNR",
                            Enabled         = true,
                            CreatedOn       = DateTime.UtcNow,
                            UpdatedOn       = DateTime.UtcNow,
                            CreatedBy       = UserInfo.CurrentUserID,
                            UpdatedBy       = UserInfo.CurrentUserID,
                            SignalID        = Guid.NewGuid(),
                            Adder           = 0.0D,
                            Multiplier      = 1.0D
                        };

                        measurementTable.AddNewRecord(outMeasurement);

                        m_outputMapping.Add(key.SignalID, MeasurementKey.LookUpBySignalID(
                                                measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID));

                        OnStatusMessage(MessageLevel.Warning, $"Output measurment {outputReference} not found. Creating measurement");
                    }

                    if (m_saveStats)
                    {
                        m_statisticsMapping.Add(key.SignalID, CreateStatistics(measurementTable, key, device, historianID));
                    }
                }

                if (Reference == null)
                {
                    OnStatusMessage(MessageLevel.Warning, "No Reference Angle Specified");

                    int refIndex = InputMeasurementKeyTypes.IndexOf(item => item == SignalType.IPHA || item == SignalType.VPHA);

                    if (refIndex > -1)
                    {
                        Reference = InputMeasurementKeys[refIndex];
                    }
                }

                if (Reference != null)
                {
                    if (!InputMeasurementKeys.Contains(Reference))
                    {
                        InputMeasurementKeys.AddRange(new[] { Reference });
                    }
                }
            }
        }