/// <summary> /// Creates a new instance of the <see cref="Cycle"/> class. /// </summary> /// <param name="startSample">The index of the start of the cycle.</param> /// <param name="frequency">The frequency of the measured system, in Hz.</param> /// <param name="waveFormData">The time-domain data to be used to calculate frequency-domain values.</param> public Cycle(int startSample, double frequency, MeasurementData waveFormData) { long timeStart; double[] timeInSeconds; double[] measurements; SineWave sineFit; if (startSample < 0) { throw new ArgumentOutOfRangeException("startSample"); } if (startSample + waveFormData.SampleRate > waveFormData.Times.Length) { throw new ArgumentOutOfRangeException("startSample"); } if (startSample + waveFormData.SampleRate > waveFormData.Measurements.Length) { throw new ArgumentOutOfRangeException("startSample"); } timeStart = waveFormData.Times[startSample]; timeInSeconds = new double[waveFormData.SampleRate]; measurements = new double[waveFormData.SampleRate]; for (int i = 0; i < waveFormData.SampleRate; i++) { timeInSeconds[i] = Ticks.ToSeconds(waveFormData.Times[i + startSample] - timeStart); measurements[i] = waveFormData.Measurements[i + startSample]; } sineFit = WaveFit.SineFit(measurements, timeInSeconds, frequency); RMS = Math.Sqrt(measurements.Select(vi => vi * vi).Average()); Phase = sineFit.Phase - PiOverTwo; Peak = sineFit.Amplitude; Frequency = frequency; Error = timeInSeconds .Select(time => sineFit.CalculateY(time)) .Zip(measurements, (calc, measurement) => Math.Abs(calc - measurement)) .Sum(); }
private static IEnumerable <DataPoint> CalculateCycleData(IEnumerable <DataPoint> waveformData) { // Organize the data into individual series List <List <DataPoint> > seriesList = waveformData .GroupBy(dataPoint => dataPoint.SeriesID) .Where(grouping => IsVIWaveform(grouping.Key)) .Select(grouping => grouping.OrderBy(dataPoint => dataPoint.Time)) .Select(grouping => grouping.ToList()) .ToList(); double frequency = GetFrequency(); foreach (List <DataPoint> dataSeries in seriesList) { // Get samples per cycle of the data series based on the given frequency int samplesPerCycle = CalculateSamplesPerCycle(dataSeries, frequency); // Initialize arrays of y-values and t-values for calculating cycle data double[] yValues = new double[samplesPerCycle]; double[] tValues = new double[samplesPerCycle]; // Obtain a list of time gaps in the data series List <int> gapIndexes = Enumerable.Range(0, dataSeries.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.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 DateTime cycleTime = dataSeries[i].Time; double 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[i + j].Value; tValues[j] = (dataSeries[i + j].Time - cycleTime).TotalSeconds; sum += yValues[j] * yValues[j]; } // Use a curve fitting algorithm to estimate the sine wave over this cycle SineWave sineFit = WaveFit.SineFit(yValues, tValues, frequency); // Add data points to each of the cycle data series yield return(new DataPoint() { SeriesID = dataSeries[0].SeriesID, Characteristic = "RMS", Time = cycleTime, Value = Math.Sqrt(sum / samplesPerCycle) }); yield return(new DataPoint() { SeriesID = dataSeries[0].SeriesID, Characteristic = "AngleFund", Time = cycleTime, Value = sineFit.Phase }); yield return(new DataPoint() { SeriesID = dataSeries[0].SeriesID, Characteristic = "WaveAmplitude", Time = cycleTime, Value = sineFit.Amplitude }); yield return(new DataPoint() { SeriesID = dataSeries[0].SeriesID, Characteristic = "WaveError", Time = cycleTime, Value = tValues .Select(sineFit.CalculateY) .Zip(yValues, (estimate, value) => Math.Abs(estimate - value)) .Sum() }); } } }
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)); }
public static DataGroup 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]; for (int i = 0; i <= dataSeries.DataPoints.Count - samplesPerCycle; i += samplesPerCycle) { // 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(dataGroup); }