using System; using TBF.BenchControl.GenericDevices; namespace TBF.BenchControl.Sequences { public class Statistics { public readonly int SkippedSamplesCount; /// 0 = do not skip any samples public readonly int FilterSize; /// 0 = no filter public readonly bool MedianFilter; /// true - median filter instead of average public readonly IPlotter plotter; bool recordingInProgress; double[] fifo; double[] sorted; double first; double last; double min; double max; double sum; int totalCount; /// Number of samples passed to Update() int count; /// Number of processed and filtered samples int fifoCount; /// Number of samples inserted into FIFO int graphId; public bool RecordingIProgress { get { return recordingInProgress; } } public double First { get { return first; } } public double Last { get { return last; } } public double Min { get { return (count > 0) ? min : 0; } } /// 0 when there were no samples public double Max { get { return (count > 0) ? max : 0; } } /// 0 when there were no samples public double Average { get { return (count > 0) ? (sum / (double)count) : 0; } } public int Count { get { return count; } } public double Sum { get { return sum; } } public Statistics(int skippedSamplesCount, int filterSize, bool medianFilter, IPlotter plotter) { this.SkippedSamplesCount = skippedSamplesCount; this.FilterSize = filterSize; this.MedianFilter = medianFilter; this.plotter = plotter; if (filterSize > 0) { fifo = new double[FilterSize]; sorted = new double[FilterSize]; } recordingInProgress = false; } public Statistics(int skippedSamplesCount, int filterSize, bool medianFilter) : this(skippedSamplesCount, filterSize, medianFilter, new DummyPlotter()) { } public Statistics(IPlotter plotter) : this(0, 0, false, plotter) { } public Statistics() : this(0, 0, false, new DummyPlotter()) { } /// /// Resets statistics and start collecting /// public void Start(int batchNr, string testName, int repetition) { sum = 0; min = double.MaxValue; max = double.MinValue; first = 0; last = 0; totalCount = 0; count = 0; fifoCount = 0; recordingInProgress = true; graphId = plotter.StartGraph(batchNr, testName, repetition); } /// /// Resets statistics /// public void Stop() { if (recordingInProgress) { recordingInProgress = false; plotter.StopGraph(graphId, (float)min, (float)max); } } /// /// Updates statistics /// /// New boxed value public void Update(TBF.Boxes.DoubleBox box) { Update(box.Val); } /// /// Updates statistics /// /// New boxed value public void Update(TBF.Boxes.FloatBox box) { Update(box.Val); } /// /// All samples are passed to this function /// /// New value public void Update(double value) { if (recordingInProgress) { if (totalCount >= SkippedSamplesCount) { Process(value); } totalCount++; } } /// /// Only samples after first 'SkippedSamplesCount' samples are passed to this function. /// Any filtering is done inside this function. /// /// New value void Process(double value) { double filteredValue; if (ApplyFilter(value, out filteredValue)) { sum += filteredValue; if (count == 0) first = filteredValue; last = filteredValue; if (value < min) min = filteredValue; if (value > max) max = filteredValue; plotter.UpdateGraph(graphId, (float)(count + SkippedSamplesCount + FilterSize / 2), (float)value); count++; } } /// /// Inserts values to FIFO and calculates filetered value when FIFO is full. /// Returns true when FIFO is full and calculated values are valid. /// /// Input value /// Output filtered value /// true when 'fileterdValue' is valid bool ApplyFilter(double value, out double filteredValue) { filteredValue = value; if (FilterSize == 0) return true; /// no filter -> input value is passed to output /// Shift values in FIFO buffer, put the new value into fifo[0] double sum = 0; for (int i = FilterSize - 1; i > 0; i--) { sorted[i] = fifo[i] = fifo[i - 1]; sum += fifo[i]; } sorted[0] = fifo[0] = value; sum += value; fifoCount++; if (fifoCount < FilterSize) { return false; } else { if (MedianFilter) { Array.Sort(sorted); #if false filteredValue = sorted[FilterSize / 2]; #else double sum2 = 0; for (int j = 1; j < FilterSize - 1; j++) sum2 += sorted[j]; filteredValue = sum2 / (FilterSize - 2); #endif } else { filteredValue = sum / FilterSize; } return true; } } } class DummyPlotter : IPlotter { public DummyPlotter() { } public int StartGraph(int batchNr, string testName, int repetition) { return 1; } public void UpdateGraph(int graphId, float x, float y) { } public void StopGraph(int graphId, float ymin, float ymax) { } } }