Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
OutlierRemoval.cs
1using System;
2using System.Collections.Generic;
3using System.Threading.Tasks;
4using System.Xml;
7using Waher.Events;
8
10{
15 {
16 private readonly object synchObj = new object();
17 private IFilter filter;
18 private DateTime[] timespans;
19 private double?[] values;
20 private double? min;
21 private double? max;
22 private double sum;
23 private int count;
24 private int pos;
25 private int avgPos;
26 private int windowSize;
27 private int threshold;
28 private bool smooth;
29 private bool logNotice;
30
37 : base(Parent, Model)
38 {
39 }
40
44 public int WindowSize => this.windowSize;
45
49 public int Threshold => this.threshold;
50
54 public bool Smooth => this.smooth;
55
59 public override string LocalName => nameof(OutlierRemoval);
60
68 {
69 return new OutlierRemoval(Parent, Model);
70 }
71
76 public override Task FromXml(XmlElement Definition)
77 {
78 this.windowSize = XML.Attribute(Definition, "windowSize", 0);
79 this.threshold = XML.Attribute(Definition, "threshold", 0);
80 this.smooth = XML.Attribute(Definition, "smooth", false);
81 this.logNotice = XML.Attribute(Definition, "logNotice", true);
82 this.max = Definition.HasAttribute("max") ? XML.Attribute(Definition, "max", 0.0) : (double?)null;
83 this.min = Definition.HasAttribute("min") ? XML.Attribute(Definition, "min", 0.0) : (double?)null;
84
85 if (this.windowSize < 1)
86 throw new Exception("Windows size must be positive.");
87
88 if (this.threshold < 1)
89 throw new Exception("Threshold must be positive.");
90
91 this.timespans = new DateTime[this.windowSize];
92 this.values = new double?[this.windowSize];
93 this.sum = 0;
94 this.count = 0;
95 this.pos = 0;
96 this.avgPos = this.count / 2;
97
98 return base.FromXml(Definition);
99 }
100
104 public override async Task Start()
105 {
106 await base.Start();
107 this.Bucket.Add(this);
108 }
109
114 public void Append(IFilter Filter)
115 {
116 if (this.filter is null)
117 this.filter = Filter;
118 else
119 this.filter.Append(Filter);
120 }
121
128 public bool Filter(ref DateTime Timestamp, ref double Value)
129 {
130 if (this.min.HasValue && Value < this.min.Value)
131 {
132 if (this.logNotice)
133 {
134 Log.Notice("Outlier removed. Smaller than minimum value.", this.For, string.Empty, "Outlier",
135 new KeyValuePair<string, object>("Value", Value));
136 }
137
138 this.Model.CountEvent(this.For + " Outlier");
139
140 return true;
141 }
142
143 if (this.max.HasValue && Value > this.max.Value)
144 {
145 if (this.logNotice)
146 {
147 Log.Notice("Outlier removed. Larger than maximum value.", this.For, string.Empty, "Outlier",
148 new KeyValuePair<string, object>("Value", Value));
149 }
150
151 this.Model.CountEvent(this.For + " Outlier");
152
153 return true;
154 }
155
156 double? Old;
157 double Average;
158 int NrAbove = 0;
159 int NrBelow = 0;
160 int i;
161
162 lock (this.synchObj)
163 {
164 Old = this.values[this.pos];
165
166 this.timespans[this.pos] = Timestamp;
167 this.values[this.pos] = Value;
168
169 if (++this.pos == this.windowSize)
170 this.pos = 0;
171
172 if (Old.HasValue)
173 {
174 this.sum -= Old.Value;
175 this.count--;
176 }
177
178 this.sum += Value;
179 this.count++;
180
181 Average = this.sum / this.count;
182
183 for (i = 0; i < this.windowSize; i++)
184 {
185 Old = this.values[i];
186 if (Old.HasValue)
187 {
188 if (Old.Value > Average)
189 NrAbove++;
190 else if (Old.Value < Average)
191 NrBelow++;
192 }
193 }
194
195 Timestamp = this.timespans[this.avgPos];
196 Old = this.values[this.avgPos];
197
198 if (NrAbove <= this.threshold && NrBelow > this.threshold)
199 {
200 if (Old.HasValue && Old.Value > Average)
201 {
202 this.sum -= Old.Value;
203 this.count--;
204 this.values[this.avgPos] = Old = null;
205 }
206 }
207 else if (NrBelow <= this.threshold && NrAbove > this.threshold)
208 {
209 if (Old.HasValue && Old.Value < Average)
210 {
211 this.sum -= Old.Value;
212 this.count--;
213 this.values[this.avgPos] = Old = null;
214 }
215 }
216
217 if (++this.avgPos == this.windowSize)
218 this.avgPos = 0;
219 }
220
221 if (!Old.HasValue)
222 {
223 if (this.logNotice)
224 {
225 Log.Notice("Outlier removed. Threshold reached.", this.For, string.Empty, "Outlier",
226 new KeyValuePair<string, object>("Value", Value));
227 }
228
229 this.Model.CountEvent(this.For + " Outlier");
230
231 return true;
232 }
233
234 if (this.smooth)
235 Value = Average;
236 else
237 Value = Old.Value;
238
239 return false;
240 }
241 }
242}
Root node of a simulation model
Definition: Model.cs:49
void CountEvent(string CounterName)
Counts an event.
Definition: Model.cs:983
Removes outliers by comparing incoming samples with the average of the last samples.
override Task FromXml(XmlElement Definition)
Sets properties and attributes of class in accordance with XML definition.
override async Task Start()
Starts the node.
bool Smooth
If the average value should be used to also smooth the output.
void Append(IFilter Filter)
Appends a filter to the current filter.
bool Filter(ref DateTime Timestamp, ref double Value)
Filters a value
int Threshold
Threshold for outlier detection.
OutlierRemoval(ISimulationNode Parent, Model Model)
Removes outliers by comparing incoming samples with the average of the last samples.
override string LocalName
Local name of XML element defining contents of class.
override ISimulationNode Create(ISimulationNode Parent, Model Model)
Creates a new instance of the node.
int WindowSize
Number of samples to include in the average calculation.
Abstract base class for series references nodes.
ISimulationNode Parent
Parent node in the simulation model.
Statistical bucket
Definition: Bucket.cs:17
void Add(IFilter Filter)
Adds a filter to the bucket.
Definition: Bucket.cs:477
Helps with common XML-related tasks.
Definition: XML.cs:19
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
Definition: XML.cs:914
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static void Notice(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a notice event.
Definition: Log.cs:450
Basic interface for simulator nodes. Implementing this interface allows classes with default contruct...
Interface for sample filters
Definition: IFilter.cs:9
void Append(IFilter Filter)
Appends a filter to the current filter.