forked from PeterWaher/IoTGateway
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSpikeRemoval.cs
More file actions
116 lines (100 loc) · 2.88 KB
/
SpikeRemoval.cs
File metadata and controls
116 lines (100 loc) · 2.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
using System;
using System.Collections.Generic;
using System.Text;
namespace Waher.Networking.XMPP.Synchronization
{
/// <summary>
/// Class tha removes erroneous samples from a sequence of samples.
/// </summary>
public class SpikeRemoval
{
private readonly long?[] window;
private readonly int windowSize;
private readonly int spikePos;
private readonly int spikeWidth;
private long sum;
private int nrInWindow;
/// <summary>
/// Class tha removes erroneous samples from a sequence of samples.
/// </summary>
/// <param name="WindowSize">Size of window to use to identify spikes.</param>
/// <param name="SpikePosition">Position in window where spike removal is made.</param>
/// <param name="SpikeWidth">Number of samples that can constitute a spike.</param>
public SpikeRemoval(int WindowSize, int SpikePosition, int SpikeWidth)
{
this.windowSize = WindowSize;
this.spikePos = SpikePosition;
this.spikeWidth = SpikeWidth;
this.window = new long?[WindowSize];
this.nrInWindow = 0;
this.sum = 0;
}
/// <summary>
/// Adds a sample to the spike removal window.
/// </summary>
/// <param name="Sample">Sample</param>
/// <param name="Removed">If a suspected spike value was removed at the spike position.</param>
/// <param name="Sum">Sum of all samples that have passed the spike removal test.</param>
/// <param name="NrSamples">Number of samples in sum.</param>
/// <returns>If a sum of ok samples has been calculated.</returns>
public bool Add(long Sample, out bool Removed, out long Sum, out int NrSamples)
{
if (this.window[0].HasValue)
{
this.sum -= this.window[0].Value;
this.nrInWindow--;
}
Array.Copy(this.window, 1, this.window, 0, this.windowSize - 1);
this.window[this.windowSize - 1] = Sample;
this.sum += Sample;
this.nrInWindow++;
double Avg = ((double)this.sum) / this.nrInWindow;
long? v;
Removed = false;
if (this.nrInWindow >= this.spikePos)
{
int NrLt = 0;
int NrGt = 0;
foreach (int? Value in this.window)
{
if (Value.HasValue)
{
if (Value.Value < Avg)
NrLt++;
else if (Value.Value > Avg)
NrGt++;
}
}
if (NrLt <= this.spikeWidth || NrGt <= this.spikeWidth)
{
v = this.window[this.windowSize - this.spikePos - 1];
if (v.HasValue)
{
if ((NrLt <= this.spikeWidth && v.Value < Avg) ||
(NrGt <= this.spikeWidth && v.Value > Avg))
{
Removed = true;
this.sum -= v.Value;
this.nrInWindow--;
this.window[this.windowSize - this.spikePos - 1] = null;
Avg = ((double)this.sum) / this.nrInWindow;
}
}
}
}
int i;
for (Sum = NrSamples = i = 0; i < this.spikePos; i++)
{
if ((v = this.window[i]).HasValue)
{
NrSamples++;
Sum += v.Value;
}
}
if (NrSamples > 0)
return true;
else
return false;
}
}
}