240 lines
6.2 KiB
C#
240 lines
6.2 KiB
C#
using System;
|
|
using TBF.BenchControl.GenericDevices;
|
|
|
|
namespace TBF.BenchControl.Sequences
|
|
{
|
|
public class Statistics
|
|
{
|
|
public readonly int DefaultSkippedSamplesCount; /// 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 skippedSamplesCount;
|
|
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 defaultSkippedSamplesCount, int filterSize, bool medianFilter, IPlotter plotter)
|
|
{
|
|
this.DefaultSkippedSamplesCount = defaultSkippedSamplesCount;
|
|
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 defaultSkippedSamplesCount, int filterSize, bool medianFilter)
|
|
: this(defaultSkippedSamplesCount, 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)
|
|
{
|
|
Start(batchNr, testName, repetition, DefaultSkippedSamplesCount);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resets statistics and start collecting, 4th arument specifies skipped samples count
|
|
/// </summary>
|
|
public void Start(int batchNr, string testName, int repetition, int skippedSamplesCount)
|
|
{
|
|
this.skippedSamplesCount = skippedSamplesCount;
|
|
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, (float)min, (float)max);
|
|
}
|
|
}
|
|
|
|
|
|
/// <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 (filteredValue < min) min = filteredValue;
|
|
if (filteredValue > max) max = filteredValue;
|
|
|
|
plotter.UpdateGraph(graphId, (float)(count + skippedSamplesCount + FilterSize / 2), (float)filteredValue);
|
|
|
|
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)
|
|
{
|
|
if (FilterSize == 0)
|
|
{
|
|
/// No filter => Pass the input value to the output
|
|
filteredValue = value;
|
|
return true;
|
|
}
|
|
|
|
|
|
/// Shift values in FIFO buffer, calculate the sum
|
|
double sum1 = 0;
|
|
for (int i = FilterSize - 1; i > 0; i--)
|
|
{
|
|
fifo[i] = fifo[i - 1];
|
|
sum1 += fifo[i];
|
|
}
|
|
/// Insert the current value into FIFO, add it to the sum
|
|
fifo[0] = value;
|
|
sum1 += value;
|
|
|
|
|
|
fifoCount++;
|
|
|
|
|
|
if (fifoCount < FilterSize)
|
|
{
|
|
/// FIFO not filled yet => Pass the input value to the output
|
|
filteredValue = value;
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
/// FIFO already filled => Apply filter
|
|
if (MedianFilter)
|
|
{
|
|
for (int i = 0; i < FilterSize; i++) sorted[i] = fifo[i];
|
|
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 = sum1 / 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) { }
|
|
}
|
|
}
|