From 58cddba198b7979c4d4b6e4cc16b3f1df10b7e6f Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Wed, 24 Nov 2021 09:58:51 +0100 Subject: [PATCH] add getAverageLast(n) (#16) * add getAverageLast(n), getMinInBufferLast(n), getMaxInBufferLast(n) * update keywords.txt * update unit test * update readme.md --- .arduino-ci.yml | 10 +-- README.md | 22 ++++++ RunningAverage.cpp | 100 +++++++++++++++++++++++---- RunningAverage.h | 13 +++- examples/ra_300_last/ra_300_last.ino | 59 ++++++++++++++++ keywords.txt | 4 ++ library.json | 2 +- library.properties | 2 +- test/unit_test_001.cpp | 35 +++++++++- 9 files changed, 225 insertions(+), 22 deletions(-) create mode 100644 examples/ra_300_last/ra_300_last.ino diff --git a/.arduino-ci.yml b/.arduino-ci.yml index 3e49662..cecf585 100644 --- a/.arduino-ci.yml +++ b/.arduino-ci.yml @@ -2,10 +2,10 @@ compile: # Choosing to run compilation tests on 2 different Arduino platforms platforms: - uno - - due - - zero - - leonardo + # - due + # - zero + # - leonardo - m4 - esp32 - - esp8266 - - mega2560 + # - esp8266 + # - mega2560 diff --git a/README.md b/README.md index ea4eeba..5049365 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,28 @@ Allows to change the weight and history factor. - **uint16_t getPartial()** returns the set value for partial. +## Last + +These functions get the basic statistics of the last N added elements. +Returns NAN if there are no elements and it will reduce count if there are less than +count elements in the buffer. + +- **float getAverageLast(uint16_t count)** get the average of the last count elements. +- **float getMinInBufferLast(uint16_t count)** get the minimum of the last count elements. +- **float getMaxInBufferLast(uint16_t count)** get the maximum of the last count elements. + +These functions are useful in cases where you might want to calculate and display the +statistics of a subset of the added elements. Reason might be to compare this with the +numbers of the whole buffer to notice changes earlier. +Otherwise one should create multiple RunningAverage objects each with its own length, +effectively having multiple copies of the data added. + +Note: if called with a value larger or equal to **getCount()** (incl **getSize()**) as +parameter, the functions will return the statistics of the whole buffer. + + + + ## Operation See examples diff --git a/RunningAverage.cpp b/RunningAverage.cpp index f500c49..0c1f020 100644 --- a/RunningAverage.cpp +++ b/RunningAverage.cpp @@ -1,7 +1,7 @@ // // FILE: RunningAverage.cpp // AUTHOR: Rob Tillaart -// VERSION: 0.4.0 +// VERSION: 0.4.1 // DATE: 2015-July-10 // PURPOSE: Arduino library to calculate the running average by means of a circular buffer // URL: https://github.com/RobTillaart/RunningAverage @@ -36,7 +36,9 @@ // 0.3.1 2020-06-19 fix library.json; minor refactor // 0.3.2 2021-01-15 add add() + license + refactor // 0.4.0 2021-05-18 increase size above 256 elements (16 bit version) -// +// 0.4.1 2021-11-22 updated buil-CI, readme, badges +// add getAverageLast() functions. +// #include "RunningAverage.h" @@ -135,12 +137,12 @@ float RunningAverage::getMinInBuffer() const return NAN; } - float min = _array[0]; + float _min = _array[0]; for (uint16_t i = 1; i < _count; i++) { - if (_array[i] < min) min = _array[i]; + if (_array[i] < _min) _min = _array[i]; } - return min; + return _min; } @@ -152,12 +154,12 @@ float RunningAverage::getMaxInBuffer() const return NAN; } - float max = _array[0]; + float _max = _array[0]; for (uint16_t i = 1; i < _count; i++) { - if (_array[i] > max) max = _array[i]; + if (_array[i] > _max) _max = _array[i]; } - return max; + return _max; } @@ -177,7 +179,10 @@ float RunningAverage::getElement(uint16_t index) const // If buffer is empty or has only one element, return NAN. float RunningAverage::getStandardDeviation() const { - if (_count <= 1) return NAN; + if (_count <= 1) + { + return NAN; + } float temp = 0; float average = getFastAverage(); @@ -195,7 +200,10 @@ float RunningAverage::getStandardDeviation() const // If buffer is empty or has only one element, return NAN. float RunningAverage::getStandardError() const //++ { - if (_count <= 1) return NAN; + if (_count <= 1) + { + return NAN; + } float temp = getStandardDeviation(); if (temp == NAN) return NAN; @@ -226,8 +234,14 @@ void RunningAverage::fillValue(const float value, const uint16_t number) float RunningAverage::getValue(const uint16_t position) { - if (_count == 0) return NAN; - if (position >= _count) return NAN; // cannot ask more than is added + if (_count == 0) + { + return NAN; + } + if (position >= _count) + { + return NAN; // cannot ask more than is added + } uint16_t _pos = position + _index; if (_pos >= _count) _pos -= _count; @@ -243,5 +257,67 @@ void RunningAverage::setPartial(const uint16_t partial) } +//////////////////////////////////////////////////////////////// +// +// 0.4.1 added. +// +float RunningAverage::getAverageLast(uint16_t count) +{ + uint16_t cnt = count; + if (cnt > _count) cnt = _count; + if (cnt == 0) return NAN; + + uint16_t idx = _index; + float _sum = 0; + for (uint16_t i = 0; i < cnt; i++) + { + if (idx == 0) idx = _size; + idx--; + _sum +=_array[idx]; + } + return _sum / cnt; +} + + +float RunningAverage::getMinInBufferLast(uint16_t count) +{ + uint16_t cnt = count; + if (cnt > _count) cnt = _count; + if (cnt == 0) return NAN; + + uint16_t idx = _index; + if (idx == 0) idx = _size; + idx--; + float _min = _array[idx]; + for (uint16_t i = 0; i < cnt; i++) + { + if (_array[idx] < _min) _min = _array[idx]; + if (idx == 0) idx = _size; + idx--; + } + return _min; +} + + +float RunningAverage::getMaxInBufferLast(uint16_t count) +{ + uint16_t cnt = count; + if (cnt > _count) cnt = _count; + if (cnt == 0) return NAN; + + uint16_t idx = _index; + if (idx == 0) idx = _size; + idx--; + float _max = _array[idx]; + for (uint16_t i = 0; i < cnt; i++) + { + if (_array[idx] > _max) _max = _array[idx]; + if (idx == 0) idx = _size; + idx--; + } + return _max; +} + + // -- END OF FILE -- diff --git a/RunningAverage.h b/RunningAverage.h index b8b2a00..72abc78 100644 --- a/RunningAverage.h +++ b/RunningAverage.h @@ -2,7 +2,7 @@ // // FILE: RunningAverage.h // AUTHOR: Rob.Tillaart@gmail.com -// VERSION: 0.4.0 +// VERSION: 0.4.1 // DATE: 2016-dec-01 // PURPOSE: Arduino library to calculate the running average by means of a circular buffer // URL: https://github.com/RobTillaart/RunningAverage @@ -13,7 +13,7 @@ #include "Arduino.h" -#define RUNNINGAVERAGE_LIB_VERSION (F("0.4.0")) +#define RUNNINGAVERAGE_LIB_VERSION (F("0.4.1")) class RunningAverage @@ -56,6 +56,15 @@ class RunningAverage void setPartial(const uint16_t partial = 0); // 0 ==> use all uint16_t getPartial() { return _partial; }; + + // get some stats from the last count additions. + float getAverageLast(uint16_t count); + float getMinInBufferLast(uint16_t count); + float getMaxInBufferLast(uint16_t count); + + + + protected: uint16_t _size; uint16_t _count; diff --git a/examples/ra_300_last/ra_300_last.ino b/examples/ra_300_last/ra_300_last.ino new file mode 100644 index 0000000..3c97ca9 --- /dev/null +++ b/examples/ra_300_last/ra_300_last.ino @@ -0,0 +1,59 @@ +// +// FILE: ra_300.ino +// AUTHOR: Rob Tillaart +// VERSION: 0.1.0 +// DATE: 2021-05-26 +// +// PUPROSE: demonstrate large (16 bit) buffer +// + + +#include "RunningAverage.h" + +RunningAverage myRA(300); +int samples = 0; + + +void setup(void) +{ + Serial.begin(115200); + Serial.println("Demo RunningAverage lib"); + Serial.print("Version: "); + Serial.println(RUNNINGAVERAGE_LIB_VERSION); + + myRA.clear(); + for (uint16_t i = 0; i < 1000; i++) + { + myRA.addValue(i); // random(1000)); (i); + // Serial.print(i); + // Serial.print("\t"); + // Serial.print(myRA.getCount()); + // Serial.print("\t"); + // Serial.print(myRA.getAverage()); + // Serial.println(); + } + + Serial.println(); + for (uint16_t i = 1; i < 1000; i++) + { + Serial.print(i); + Serial.print("\t"); + Serial.print(myRA.getMinInBufferLast(i)); + Serial.print("\t"); + Serial.print(myRA.getAverageLast(i)); + Serial.print("\t"); + Serial.print(myRA.getMaxInBufferLast(i)); + Serial.println(); + } + + + +} + + +void loop(void) +{ +} + + +// -- END OF FILE -- diff --git a/keywords.txt b/keywords.txt index 6025f2d..3a5330f 100644 --- a/keywords.txt +++ b/keywords.txt @@ -30,6 +30,10 @@ getCount KEYWORD2 setPartial KEYWORD2 getPartial KEYWORD2 +getAverageLast KEYWORD2 +getMinInBufferLast KEYWORD2 +getMaxInBufferLast KEYWORD2 + # Instances (KEYWORD2) diff --git a/library.json b/library.json index c2a55a3..65416ae 100644 --- a/library.json +++ b/library.json @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/RunningAverage.git" }, - "version": "0.4.0", + "version": "0.4.1", "license": "MIT", "frameworks": "arduino", "platforms": "*", diff --git a/library.properties b/library.properties index 4ed06a1..f2c7412 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RunningAverage -version=0.4.0 +version=0.4.1 author=Rob Tillaart maintainer=Rob Tillaart sentence=The library stores the last N individual values in a circular buffer to calculate the running average. diff --git a/test/unit_test_001.cpp b/test/unit_test_001.cpp index bebb810..7457ece 100644 --- a/test/unit_test_001.cpp +++ b/test/unit_test_001.cpp @@ -47,7 +47,7 @@ unittest_teardown() unittest(test_zero_elements) { - fprintf(stderr, "VERSION: %s\n", RUNNINGAVERAGE_LIB_VERSION); + fprintf(stderr, "VERSION: %s\n", (char *) RUNNINGAVERAGE_LIB_VERSION); RunningAverage myRA(10); myRA.clear(); @@ -141,6 +141,39 @@ unittest(test_partial) } + +unittest(test_last) +{ + RunningAverage myRA(300); + myRA.clear(); + assertFalse(myRA.bufferIsFull()); + + for (int i = 0; i < 1000; i++) + { + myRA.addValue(i); + } + assertNAN(myRA.getMinInBufferLast(0)); + assertNAN(myRA.getAverageLast(0)); + assertNAN(myRA.getMaxInBufferLast(0)); + + assertEqualFloat(999.0, myRA.getMinInBufferLast(1), 0.001); + assertEqualFloat(999.0, myRA.getAverageLast(1), 0.001); + assertEqualFloat(999.0, myRA.getMaxInBufferLast(1), 0.001); + + assertEqualFloat(990.0, myRA.getMinInBufferLast(10), 0.001); + assertEqualFloat(994.5, myRA.getAverageLast(10), 0.001); + assertEqualFloat(999.0, myRA.getMaxInBufferLast(10), 0.001); + + assertEqualFloat(900.0, myRA.getMinInBufferLast(100), 0.001); + assertEqualFloat(949.5, myRA.getAverageLast(100), 0.001); + assertEqualFloat(999.0, myRA.getMaxInBufferLast(100), 0.001); + + assertEqualFloat(700.0, myRA.getMinInBufferLast(1000), 0.001); + assertEqualFloat(849.5, myRA.getAverageLast(1000), 0.001); + assertEqualFloat(999.0, myRA.getMaxInBufferLast(1000), 0.001); +} + + unittest_main() // --------