using System; 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 double[] fifo; double[] sorted; double first; double last; double min; double max; double sum; UInt32 totalCount; /// Number of samples passed to Update() UInt32 count; /// Number of processed and filtered samples UInt32 fifoCount; /// Number of samples inserted into FIFO 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 UInt32 Count { get { return count; } } public double Sum { get { return sum; } } public Statistics(int skippedSamplesCount, int filterSize, bool medianFilter) { this.SkippedSamplesCount = skippedSamplesCount; this.FilterSize = filterSize; this.MedianFilter = medianFilter; Clear(); if (FilterSize > 0) { fifo = new double[FilterSize]; sorted = new double[FilterSize]; } } public Statistics() : this(0, 0, false) { } /// /// Resets statistics /// public void Clear() { sum = 0; min = double.MaxValue; max = double.MinValue; first = 0; last = 0; totalCount = 0; count = 0; fifoCount = 0; } /// /// 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 (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; 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); filteredValue = sorted[FilterSize / 2]; } else { filteredValue = sum / FilterSize; } return true; } } } }