Exemple #1
0
        /// <summary>
        /// Given three of the four current channels, calculates the
        /// missing channel based on the relationship IR = IA + IB + IC.
        /// </summary>
        /// <param name="meterInfo">Data context for accessing configuration tables in the database.</param>
        public DataSeries CalculateMissingCurrentChannel(MeterInfoDataContext meterInfo)
        {
            Meter      meter;
            DataSeries missingSeries;

            // If the data group does not have exactly 3 channels,
            // then there is no missing channel or there is not
            // enough data to calculate the missing channel
            if (DefinedCurrents != 3)
            {
                return(null);
            }

            // Get the meter associated with the channels in this data group
            meter = (IA ?? IB).SeriesInfo.Channel.Meter;

            if (m_iaIndex == -1)
            {
                // Calculate IA = IR - IB - IC
                missingSeries            = IR.Add(IB.Negate()).Add(IC.Negate());
                missingSeries.SeriesInfo = GetSeriesInfo(meterInfo, meter, m_dataGroup, "Current", "AN");
                m_iaIndex = m_dataGroup.DataSeries.Count;
                m_dataGroup.Add(missingSeries);
            }
            else if (m_ibIndex == -1)
            {
                // Calculate IB = IR - IA - IC
                missingSeries            = IR.Add(IA.Negate()).Add(IC.Negate());
                missingSeries.SeriesInfo = GetSeriesInfo(meterInfo, meter, m_dataGroup, "Current", "BN");
                m_ibIndex = m_dataGroup.DataSeries.Count;
                m_dataGroup.Add(missingSeries);
            }
            else if (m_icIndex == -1)
            {
                // Calculate IC = IR - IA - IB
                missingSeries            = IR.Add(IA.Negate()).Add(IB.Negate());
                missingSeries.SeriesInfo = GetSeriesInfo(meterInfo, meter, m_dataGroup, "Current", "CN");
                m_icIndex = m_dataGroup.DataSeries.Count;
                m_dataGroup.Add(missingSeries);
            }
            else
            {
                // Calculate IR = IA + IB + IC
                missingSeries            = IA.Add(IB).Add(IC);
                missingSeries.SeriesInfo = GetSeriesInfo(meterInfo, meter, m_dataGroup, "Current", "RES");
                m_irIndex = m_dataGroup.DataSeries.Count;
                m_dataGroup.Add(missingSeries);
            }

            return(missingSeries);
        }
Exemple #2
0
        public DataGroup ToSubGroup(int startIndex, int endIndex)
        {
            DataGroup subGroup = new DataGroup();

            foreach (DataSeries dataSeries in m_dataSeries)
            {
                subGroup.Add(dataSeries.ToSubSeries(startIndex, endIndex));
            }

            return(subGroup);
        }
Exemple #3
0
        public DataGroup ToSubGroup(DateTime startTime, DateTime endTime)
        {
            DataGroup subGroup = new DataGroup();

            foreach (DataSeries dataSeries in m_dataSeries)
            {
                subGroup.Add(dataSeries.ToSubSeries(startTime, endTime));
            }

            return(subGroup);
        }
Exemple #4
0
        public static DataGroup Combine(params DataGroup[] dataGroups)
        {
            DataGroup combination = new DataGroup();

            foreach (DataGroup dataGroup in dataGroups)
            {
                foreach (DataSeries dataSeries in dataGroup.DataSeries)
                {
                    combination.Add(dataSeries);
                }
            }

            return(combination);
        }
Exemple #5
0
        public static CycleDataGroup ToCycleDataGroup(DataSeries dataSeries, double frequency)
        {
            DataGroup dataGroup = new DataGroup();

            DataSeries rmsSeries   = new DataSeries();
            DataSeries phaseSeries = new DataSeries();
            DataSeries peakSeries  = new DataSeries();
            DataSeries errorSeries = new DataSeries();

            int samplesPerCycle;

            double[] yValues;
            double[] tValues;
            double   sum;

            DateTime cycleTime;
            SineWave sineFit;

            if ((object)dataSeries == null)
            {
                return(null);
            }

            // Set series info to the source series info
            rmsSeries.SeriesInfo   = dataSeries.SeriesInfo;
            phaseSeries.SeriesInfo = dataSeries.SeriesInfo;
            peakSeries.SeriesInfo  = dataSeries.SeriesInfo;
            errorSeries.SeriesInfo = dataSeries.SeriesInfo;

            // Get samples per cycle of the data series based on the given frequency
            samplesPerCycle = CalculateSamplesPerCycle(dataSeries, frequency);

            // Initialize arrays of y-values and t-values for calculating cycle data
            yValues = new double[samplesPerCycle];
            tValues = new double[samplesPerCycle];

            // Obtain a list of time gaps in the data series
            List <int> gapIndexes = Enumerable.Range(0, dataSeries.DataPoints.Count - 1)
                                    .Where(index =>
            {
                DataPoint p1     = dataSeries[index];
                DataPoint p2     = dataSeries[index + 1];
                double cycleDiff = (p2.Time - p1.Time).TotalSeconds * frequency;

                // Detect gaps larger than a quarter cycle.
                // Tolerance of 0.000062 calculated
                // assuming 3.999 samples per cycle
                return(cycleDiff > 0.250062);
            })
                                    .ToList();

            for (int i = 0; i <= dataSeries.DataPoints.Count - samplesPerCycle; i++)
            {
                // If the cycle following i contains a data gap, do not calculate cycle data
                if (gapIndexes.Any(index => i <= index && (i + samplesPerCycle - 1) > index))
                {
                    continue;
                }

                // Use the time of the first data point in the cycle as the time of the cycle
                cycleTime = dataSeries.DataPoints[i].Time;
                sum       = 0.0D;

                // Copy values from the original data series into the y-value and t-value arrays
                for (int j = 0; j < samplesPerCycle; j++)
                {
                    yValues[j] = dataSeries.DataPoints[i + j].Value;
                    tValues[j] = (dataSeries.DataPoints[i + j].Time - cycleTime).TotalSeconds;
                    sum       += yValues[j] * yValues[j];
                }

                // Use a curve fitting algorithm to estimate the sine wave over this cycle
                sineFit = WaveFit.SineFit(yValues, tValues, frequency);

                // Add data points to each of the cycle data series
                rmsSeries.DataPoints.Add(new DataPoint()
                {
                    Time  = cycleTime,
                    Value = Math.Sqrt(sum / samplesPerCycle)
                });

                phaseSeries.DataPoints.Add(new DataPoint()
                {
                    Time  = cycleTime,
                    Value = sineFit.Phase
                });

                peakSeries.DataPoints.Add(new DataPoint()
                {
                    Time  = cycleTime,
                    Value = sineFit.Amplitude
                });

                errorSeries.DataPoints.Add(new DataPoint()
                {
                    Time = cycleTime,

                    Value = tValues
                            .Select(sineFit.CalculateY)
                            .Zip(yValues, (estimate, value) => Math.Abs(estimate - value))
                            .Sum()
                });
            }

            // Add a series to the data group for each series of cycle data
            dataGroup.Add(rmsSeries);
            dataGroup.Add(phaseSeries);
            dataGroup.Add(peakSeries);
            dataGroup.Add(errorSeries);

            return(new CycleDataGroup(dataGroup));
        }
Exemple #6
0
        public static CycleDataGroup ToCycleDataGroup(DataSeries dataSeries, double frequency)
        {
            DataGroup dataGroup = new DataGroup();

            DataSeries rmsSeries   = new DataSeries();
            DataSeries phaseSeries = new DataSeries();
            DataSeries peakSeries  = new DataSeries();
            DataSeries errorSeries = new DataSeries();

            int samplesPerCycle;

            double[] yValues;
            double[] tValues;
            double   sum;

            DateTime cycleTime;
            SineWave sineFit;

            if ((object)dataSeries == null)
            {
                return(new CycleDataGroup(dataGroup));
            }

            // Set series info to the source series info
            rmsSeries.SeriesInfo   = dataSeries.SeriesInfo;
            phaseSeries.SeriesInfo = dataSeries.SeriesInfo;
            peakSeries.SeriesInfo  = dataSeries.SeriesInfo;
            errorSeries.SeriesInfo = dataSeries.SeriesInfo;

            // Get samples per cycle of the data series based on the given frequency
            samplesPerCycle = CalculateSamplesPerCycle(dataSeries, frequency);

            // Initialize arrays of y-values and t-values for calculating cycle data
            yValues = new double[samplesPerCycle];
            tValues = new double[samplesPerCycle];

            for (int i = 0; i <= dataSeries.DataPoints.Count - samplesPerCycle; i++)
            {
                // Use the time of the first data point in the cycle as the time of the cycle
                cycleTime = dataSeries.DataPoints[i].Time;
                sum       = 0.0D;

                // Copy values from the original data series into the y-value and t-value arrays
                for (int j = 0; j < samplesPerCycle; j++)
                {
                    yValues[j] = dataSeries.DataPoints[i + j].Value;
                    tValues[j] = (dataSeries.DataPoints[i + j].Time - cycleTime).TotalSeconds;
                    sum       += yValues[j] * yValues[j];
                }

                // Use a curve fitting algorithm to estimate the sine wave over this cycle
                sineFit = WaveFit.SineFit(yValues, tValues, frequency);

                // Add data points to each of the cycle data series
                rmsSeries.DataPoints.Add(new DataPoint()
                {
                    Time  = cycleTime,
                    Value = Math.Sqrt(sum / samplesPerCycle)
                });

                phaseSeries.DataPoints.Add(new DataPoint()
                {
                    Time  = cycleTime,
                    Value = sineFit.Phase
                });

                peakSeries.DataPoints.Add(new DataPoint()
                {
                    Time  = cycleTime,
                    Value = sineFit.Amplitude
                });

                errorSeries.DataPoints.Add(new DataPoint()
                {
                    Time = cycleTime,

                    Value = tValues
                            .Select(sineFit.CalculateY)
                            .Zip(yValues, (estimate, value) => Math.Abs(estimate - value))
                            .Sum()
                });
            }

            // Add a series to the data group for each series of cycle data
            dataGroup.Add(rmsSeries);
            dataGroup.Add(phaseSeries);
            dataGroup.Add(peakSeries);
            dataGroup.Add(errorSeries);

            return(new CycleDataGroup(dataGroup));
        }
Exemple #7
0
        // Static Methods
        public static DataSeries AddMissingCurrentSeries(MeterInfoDataContext meterInfo, Meter meter, DataGroup dataGroup)
        {
            DataSeries missingSeries = null;

            // Get all necessary voltage and current channels in the proper order
            List <DataSeries> viSeriesList = Enumerable.Range(VAIndex, IRIndex + 1)
                                             .GroupJoin(dataGroup.DataSeries.Where(IsInstantaneous), i => i, GetIndex, (i, series) => series.FirstOrDefault())
                                             .ToList();

            // Validate that no more than one current channel is missing
            if (viSeriesList.Count(series => (object)series == null) > 1)
            {
                return(null);
            }

            // Attempt to fill in missing current channels
            // based on the relation IR = IA + IB + IC
            if ((object)viSeriesList[IAIndex] == null)
            {
                missingSeries = viSeriesList[IRIndex];
                missingSeries = missingSeries.Add(viSeriesList[IBIndex].Negate());
                missingSeries = missingSeries.Add(viSeriesList[ICIndex].Negate());

                missingSeries.SeriesInfo = GetSeriesInfo(meterInfo, meter, dataGroup, IAIndex);
                missingSeries.SeriesInfo.Channel.Line = viSeriesList[IBIndex].SeriesInfo.Channel.Line;

                viSeriesList[IAIndex] = missingSeries;
            }
            else if ((object)viSeriesList[IBIndex] == null)
            {
                missingSeries = viSeriesList[IRIndex];
                missingSeries = missingSeries.Add(viSeriesList[IAIndex].Negate());
                missingSeries = missingSeries.Add(viSeriesList[ICIndex].Negate());

                missingSeries.SeriesInfo = GetSeriesInfo(meterInfo, meter, dataGroup, IBIndex);
                missingSeries.SeriesInfo.Channel.Line = viSeriesList[IAIndex].SeriesInfo.Channel.Line;

                viSeriesList[IBIndex] = missingSeries;
            }
            else if ((object)viSeriesList[ICIndex] == null)
            {
                missingSeries = viSeriesList[IRIndex];
                missingSeries = missingSeries.Add(viSeriesList[IAIndex].Negate());
                missingSeries = missingSeries.Add(viSeriesList[IBIndex].Negate());

                missingSeries.SeriesInfo = GetSeriesInfo(meterInfo, meter, dataGroup, ICIndex);
                missingSeries.SeriesInfo.Channel.Line = viSeriesList[IAIndex].SeriesInfo.Channel.Line;

                viSeriesList[ICIndex] = missingSeries;
            }
            else if ((object)viSeriesList[IRIndex] == null)
            {
                missingSeries = viSeriesList[IAIndex];
                missingSeries = missingSeries.Add(viSeriesList[IBIndex]);
                missingSeries = missingSeries.Add(viSeriesList[ICIndex]);

                missingSeries.SeriesInfo = GetSeriesInfo(meterInfo, meter, dataGroup, IRIndex);
                missingSeries.SeriesInfo.Channel.Line = viSeriesList[IAIndex].SeriesInfo.Channel.Line;

                viSeriesList[IRIndex] = missingSeries;
            }

            if ((object)missingSeries != null)
            {
                dataGroup.Add(missingSeries);
            }

            return(missingSeries);
        }