Skip to content

Commit 7ab7146

Browse files
authored
Fix #30 #31, add getSum() and getStandardDeviationLast(count) (#32)
- Fix #30, add **float getSum()** (thanks to heidnerd) - Fix #31, add **float getStandardDeviationLast(uint16_t count)** (thanks to alvaro-oliver) - added code to detect inner array == NULL in more functions (return NAN). - changed return type **bool clear()** - changed return type **bool addValue(..)** - changed return type **bool fillValue(..)** - changed return type **bool setPartial(..)** - moved performance.txt to performance sketch - update unit test - update keywords.txt - update readme.md - minor edits.
1 parent c03f48a commit 7ab7146

12 files changed

Lines changed: 246 additions & 51 deletions

CHANGELOG.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,24 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

88

9+
## [0.4.6] - 2024-06-15
10+
- Fix #30, add **float getSum()** (thanks to heidnerd)
11+
- Fix #31, add **float getStandardDeviationLast(uint16_t count)** (thanks to alvaro-oliver)
12+
- added code to detect inner array == NULL in more functions (return NAN).
13+
- changed return type **bool clear()**
14+
- changed return type **bool addValue(..)**
15+
- changed return type **bool fillValue(..)**
16+
- changed return type **bool setPartial(..)**
17+
- moved performance.txt to performance sketch
18+
- update unit test
19+
- update keywords.txt
20+
- update readme.md
21+
- minor edits.
22+
923
## [0.4.5] - 2024-01-05
1024
- fix URL in examples
1125
- minor edits
1226

13-
1427
## [0.4.4] - 2023-10-18
1528
- update readme.md badges
1629
- update examples
@@ -29,7 +42,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2942
- minor edits
3043

3144
## [0.4.1] - 2021-11-22
32-
- updated buil-CI, readme, badges
45+
- updated build-CI, readme, badges
3346
- add getAverageLast() functions.
3447

3548
## [0.4.0] - 2021-05-18
@@ -57,7 +70,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
5770
## [0.2.15] - 2020-01-17
5871
- fix overflow in getValue - see issue #139
5972

60-
6173
## [0.2.14] - 2020-01-15
6274
- added getValue(n) to retrieve elements in order of addition - see issue #132
6375

@@ -107,7 +119,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
107119
## [0.2.01] - 2012-11-21
108120
- refactored
109121

110-
## [0.2.00] - 2012-??-??
122+
## [0.2.00] - 2012-??-??
111123
- Yuval Naveh added trimValue (found on web)
112124
- http://stromputer.googlecode.com/svn-history/r74/trunk/Arduino/Libraries/RunningAverage/RunningAverage.cpp
113125

README.md

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,19 @@ No default size (yet).
5858

5959
### Basic
6060

61-
- **void clear()** empties the internal buffer.
62-
- **void add(float value)** wrapper for **addValue()**
63-
- **void addValue(float value)** adds a new value to the object, if the internal buffer is full,
61+
The following functions return **false** if the internal buffer is not allocated.
62+
63+
- **bool clear()** empties the internal buffer.
64+
- **bool add(float value)** wrapper for **addValue()**.
65+
- **bool addValue(float value)** adds a new value to the object, if the internal buffer is full,
6466
the oldest element is removed.
65-
- **void fillValue(float value, uint16_t number)** adds number elements of value.
67+
- **bool fillValue(float value, uint16_t number)** adds number elements of value.
6668
Good for initializing the system to a certain starting average.
69+
70+
71+
The following functions returns NAN if there are no values present (count == 0) or
72+
of internal array is not allocated.
73+
6774
- **float getValue(uint16_t position)** returns the value at **position** from the additions.
6875
Position 0 is the first one to disappear.
6976
- **float getAverage()** iterates over all elements to get the average, slower but accurate.
@@ -80,6 +87,7 @@ Needs more than one element to be calculable.
8087
- **float getMax()** returns maximum since last clear, does not need to be in the buffer any more.
8188
- **float getMinInBuffer()** returns minimum in the internal buffer.
8289
- **float getMaxInBuffer()** returns maximum in the internal buffer.
90+
- **float getSum()** returns sum of values in the internal buffer.
8391

8492

8593
### Admin functions
@@ -92,9 +100,10 @@ Needs more than one element to be calculable.
92100

93101
## Partial functions
94102

95-
- **void setPartial(uint16_t partial = 0)** use only a part of the internal array.
103+
- **bool setPartial(uint16_t partial = 0)** use only a part of the internal array.
96104
Allows to change the weight and history factor.
97105
0 ==> use all == default.
106+
Returns false if internal buffer is not allocated.
98107
- **uint16_t getPartial()** returns the set value for partial.
99108

100109

@@ -122,15 +131,41 @@ parameter, the functions will return the statistics of the whole buffer.
122131

123132
- **float getAverageSubset(uint16_t start, uint16_t count)**
124133
Get the average of subset - count elements from start.
134+
Returns NAN if no elements or internal array not allocated.
135+
136+
137+
## Performance
138+
139+
Indicative performance on an UNO, see examples.
140+
141+
| Function | 0.4.5 us | 0.4.6 us | Notes |
142+
|:----------------------:|:----------:|:----------:|:-------:|
143+
| clear | 60 | 60 |
144+
| addValue | 24 | 24 |
145+
| fillValue | 1512 | 1520 |
146+
| getValue | 4 | 8 |
147+
| getAverage | 520 | 552 |
148+
| getFastAverage | 36 | 40 |
149+
| getStandardDeviation | 1856 | 1856 |
150+
| getStandardError | 1920 | 1920 |
151+
| getMin | 8 | 4 |
152+
| getMax | 4 | 4 |
153+
| getMinInBuffer | 216 | 212 |
154+
| getMaxInBuffer | 208 | 208 |
155+
| getSum | - | 8 |
156+
| bufferIsFull | 8 | 8 |
157+
| getElement | 4 | 4 |
158+
| getSize | 8 | 8 |
159+
| getCount | 8 | 8 |
160+
| last functions | - | - | not tested
125161

126162

127163
## Operation
128164

129165
See examples
130166

131167

132-
## Future
133-
168+
## Future
134169

135170
#### Must
136171

@@ -139,16 +174,22 @@ See examples
139174
#### Should
140175

141176
- check for optimizations.
142-
- divide by count happens often ...
143-
- clear(bool zero = true) to suppress setting all to 0. ?
144-
177+
- divide by count happens often
178+
- fillValue can be optimized (See #13)
179+
- ```temp = sqrt(temp/(_count - 1));``` is this correct STDDEV?
180+
- divide by count or count - 1?
181+
- https://www.zaner.com/3.0/education/technicalstudies/MSD.asp
182+
145183
#### Could
146184

147-
- create a double based derived class? Template class?
185+
- create a double based derived class?
186+
- Template class?
148187
- add error handling (important?).
149188
- investigate **modus()** most frequently occurring value.
150189
- difficult with floats ?
151-
- what to do when on two or more values are on par?
190+
- what to do when on two or more values are on par? (no modus?)
191+
- **int getUniqueValuesInBuffer()** O(n^2)
192+
152193

153194
#### Wont
154195

RunningAverage.cpp

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// FILE: RunningAverage.cpp
33
// AUTHOR: Rob Tillaart
4-
// VERSION: 0.4.5
4+
// VERSION: 0.4.6
55
// DATE: 2011-01-30
66
// PURPOSE: Arduino library to calculate the running average by means of a circular buffer
77
// URL: https://github.com/RobTillaart/RunningAverage
@@ -30,26 +30,31 @@ RunningAverage::~RunningAverage()
3030

3131

3232
// resets all counters
33-
void RunningAverage::clear()
33+
bool RunningAverage::clear()
3434
{
3535
_count = 0;
3636
_index = 0;
3737
_sum = 0.0;
3838
_min = NAN;
3939
_max = NAN;
40+
if (_array == NULL)
41+
{
42+
return false;
43+
}
4044
for (uint16_t i = _size; i > 0; )
4145
{
4246
_array[--i] = 0.0; // keeps addValue simpler
4347
}
48+
return true;
4449
}
4550

4651

4752
// adds a new value to the data-set
48-
void RunningAverage::addValue(const float value)
53+
bool RunningAverage::addValue(const float value)
4954
{
5055
if (_array == NULL)
5156
{
52-
return;
57+
return false;
5358
}
5459

5560
_sum -= _array[_index];
@@ -66,13 +71,15 @@ void RunningAverage::addValue(const float value)
6671

6772
// update count as last otherwise if ( _count == 0) above will fail
6873
if (_count < _partial) _count++;
74+
return true;
6975
}
7076

7177

72-
// returns the average of the data-set added so far, NAN if no elements.
78+
// returns the average of the data-set added so far,
79+
// returns NAN if no elements or missing array
7380
float RunningAverage::getAverage()
7481
{
75-
if (_count == 0)
82+
if ((_count == 0) || (_array == NULL))
7683
{
7784
return NAN;
7885
}
@@ -94,15 +101,14 @@ float RunningAverage::getFastAverage() const
94101
{
95102
return NAN;
96103
}
97-
98104
return _sum / _count; // multiplication is faster ==> extra admin
99105
}
100106

101107

102108
// returns the minimum value in the buffer
103109
float RunningAverage::getMinInBuffer() const
104110
{
105-
if (_count == 0)
111+
if ((_count == 0) || (_array == NULL))
106112
{
107113
return NAN;
108114
}
@@ -119,7 +125,7 @@ float RunningAverage::getMinInBuffer() const
119125
// returns the maximum value in the buffer
120126
float RunningAverage::getMaxInBuffer() const
121127
{
122-
if (_count == 0)
128+
if ((_count == 0) || (_array == NULL))
123129
{
124130
return NAN;
125131
}
@@ -136,11 +142,10 @@ float RunningAverage::getMaxInBuffer() const
136142
// returns the value of an element if exist, NAN otherwise
137143
float RunningAverage::getElement(uint16_t index) const
138144
{
139-
if (_count == 0)
145+
if ((_count == 0) || (_array == NULL))
140146
{
141147
return NAN;
142148
}
143-
144149
return _array[index];
145150
}
146151

@@ -161,6 +166,7 @@ float RunningAverage::getStandardDeviation() const
161166
{
162167
temp += pow((_array[i] - average), 2);
163168
}
169+
// TODO: when to divide by count || count-1?
164170
temp = sqrt(temp/(_count - 1));
165171
return temp;
166172
// see issue #13
@@ -188,16 +194,20 @@ float RunningAverage::getStandardError() const
188194
// fill the average with the same value number times. (weight)
189195
// This is maximized to size times.
190196
// no need to fill the internal buffer over 100%
191-
void RunningAverage::fillValue(const float value, const uint16_t number)
197+
bool RunningAverage::fillValue(const float value, const uint16_t number)
192198
{
193-
clear();
199+
if (!clear())
200+
{
201+
return false;
202+
}
194203
uint16_t s = number;
195204
if (s > _partial) s = _partial;
196205

197206
for (uint16_t i = s; i > 0; i--)
198207
{
199208
addValue(value);
200209
}
210+
return true;
201211
}
202212

203213

@@ -223,7 +233,7 @@ void RunningAverage::fillValue(const float value, const uint16_t number)
223233

224234
float RunningAverage::getValue(const uint16_t position)
225235
{
226-
if (_count == 0)
236+
if ((_count == 0) || (_array == NULL))
227237
{
228238
return NAN;
229239
}
@@ -238,11 +248,11 @@ float RunningAverage::getValue(const uint16_t position)
238248
}
239249

240250

241-
void RunningAverage::setPartial(const uint16_t partial)
251+
bool RunningAverage::setPartial(const uint16_t partial)
242252
{
243253
_partial = partial;
244254
if ((_partial == 0) || (_partial > _size)) _partial = _size;
245-
clear();
255+
return clear();
246256
}
247257

248258

@@ -264,6 +274,28 @@ float RunningAverage::getAverageLast(uint16_t count)
264274
}
265275

266276

277+
float RunningAverage::getStandardDeviationLast(uint16_t count)
278+
{
279+
uint16_t cnt = count;
280+
if (cnt > _count) cnt = _count;
281+
if (cnt <= 1) return NAN;
282+
283+
float temp = 0;
284+
float average = getAverageLast(count);
285+
286+
uint16_t idx = _index;
287+
288+
for (uint16_t i = 0; i < cnt; i++)
289+
{
290+
if (idx == 0) idx = _size;
291+
idx--;
292+
temp += pow((_array[idx] - average), 2);
293+
}
294+
temp = sqrt(temp/(cnt - 1));
295+
return temp;
296+
}
297+
298+
267299
float RunningAverage::getMinInBufferLast(uint16_t count)
268300
{
269301
uint16_t cnt = count;
@@ -306,7 +338,7 @@ float RunningAverage::getMaxInBufferLast(uint16_t count)
306338

307339
float RunningAverage::getAverageSubset(uint16_t start, uint16_t count)
308340
{
309-
if (_count == 0)
341+
if ((_count == 0) || (_array == NULL))
310342
{
311343
return NAN;
312344
}

0 commit comments

Comments
 (0)