tbf/TBF/BenchControl/Sequences/Statistics.cs

214 lines
5.0 KiB
C#

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())
{
}
/// <summary>
/// Resets statistics and start collecting
/// </summary>
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);
}
/// <summary>
/// Resets statistics
/// </summary>
public void Stop()
{
if (recordingInProgress)
{
recordingInProgress = false;
plotter.StopGraph(graphId);
}
}
/// <summary>
/// Updates statistics
/// </summary>
/// <param name="value">New boxed value</param>
public void Update(TBF.Boxes.DoubleBox box)
{
Update(box.Val);
}
/// <summary>
/// Updates statistics
/// </summary>
/// <param name="value">New boxed value</param>
public void Update(TBF.Boxes.FloatBox box)
{
Update(box.Val);
}
/// <summary>
/// All samples are passed to this function
/// </summary>
/// <param name="value">New value</param>
public void Update(double value)
{
if (recordingInProgress)
{
if (totalCount >= SkippedSamplesCount)
{
Process(value);
}
totalCount++;
}
}
/// <summary>
/// Only samples after first 'SkippedSamplesCount' samples are passed to this function.
/// Any filtering is done inside this function.
/// </summary>
/// <param name="value">New value</param>
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++;
}
}
/// <summary>
/// Inserts values to FIFO and calculates filetered value when FIFO is full.
/// Returns true when FIFO is full and calculated values are valid.
/// </summary>
/// <param name="value">Input value</param>
/// <param name="filteredValue">Output filtered value</param>
/// <returns>true when 'fileterdValue' is valid</returns>
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;
}
}
}
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) { }
}
}