From b5d01a353f387bc6c96f5280d373a92f6fa0be87 Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Wed, 26 May 2021 16:30:43 +0200 Subject: [PATCH] Develop (#10) * 0.4.0 increase size to 16 bit * add examples --- README.md | 4 +- RunningAverage.cpp | 39 +++++---- RunningAverage.h | 59 +++++++------ examples/ra_300/ra_300.ino | 41 +++++++++ examples/ra_getValue/ra_getValue.ino | 8 +- examples/ra_hour/ra_hour.ino | 2 +- examples/ra_partial/ra_partial.ino | 96 ++++++++++++++++++++++ examples/ra_test/ra_test.ino | 9 +- examples/ra_two_sensors/ra_two_sensors.ino | 2 + keywords.txt | 4 + library.json | 3 +- library.properties | 2 +- test/unit_test_001.cpp | 42 ++++++++++ 13 files changed, 258 insertions(+), 53 deletions(-) create mode 100644 examples/ra_300/ra_300.ino create mode 100644 examples/ra_partial/ra_partial.ino diff --git a/README.md b/README.md index 9f6c58f..9f8b49d 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ update the internal **\_sum**. ### Constructor -- **RunningAverage(const uint8_t size)** allocates dynamic memory, one float (4 bytes) per element. +- **RunningAverage(size)** allocates dynamic memory, one float (4 bytes) per element. No default size (yet). - **~RunningAverage()** deconstructor to free the memory allocated. @@ -55,7 +55,7 @@ No default size (yet). ### Admin functions - **bufferIsFull()** returns true if buffer is full. -- **getElement(uint8_t idx)** get element directly from internal buffer. (debug) +- **getElement(idx)** get element directly from internal buffer. (debug) - **getSize()** idem. - **getCount()** idem. diff --git a/RunningAverage.cpp b/RunningAverage.cpp index 47062cb..0164099 100644 --- a/RunningAverage.cpp +++ b/RunningAverage.cpp @@ -1,7 +1,7 @@ // // FILE: RunningAverage.cpp // AUTHOR: Rob Tillaart -// VERSION: 0.3.2 +// VERSION: 0.4.0 // DATE: 2015-July-10 // PURPOSE: Arduino library to calculate the running average by means of a circular buffer // URL: https://github.com/RobTillaart/RunningAverage @@ -35,14 +35,15 @@ // 0.3.0 2020-04-16 main refactor // 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) #include "RunningAverage.h" -RunningAverage::RunningAverage(const uint8_t size) +RunningAverage::RunningAverage(const uint16_t size) { _size = size; + _partial = _size; _array = (float*) malloc(_size * sizeof(float)); if (_array == NULL) _size = 0; clear(); @@ -63,7 +64,7 @@ void RunningAverage::clear() _sum = 0.0; _min = NAN; _max = NAN; - for (uint8_t i = _size; i > 0; ) + for (uint16_t i = _size; i > 0; ) { _array[--i] = 0.0; // keeps addValue simpler } @@ -80,7 +81,7 @@ void RunningAverage::addValue(const float value) _sum += _array[_index]; _index++; - if (_index == _size) _index = 0; // faster than % + if (_index == _partial) _index = 0; // faster than % // handle min max if (_count == 0) _min = _max = value; @@ -88,7 +89,7 @@ void RunningAverage::addValue(const float value) else if (value > _max) _max = value; // update count as last otherwise if ( _count == 0) above will fail - if (_count < _size) _count++; + if (_count < _partial) _count++; } @@ -98,7 +99,7 @@ float RunningAverage::getAverage() if (_count == 0) return NAN; _sum = 0; - for (uint8_t i = 0; i < _count; i++) + for (uint16_t i = 0; i < _count; i++) { _sum += _array[i]; } @@ -121,7 +122,7 @@ float RunningAverage::getMinInBuffer() const if (_count == 0) return NAN; float min = _array[0]; - for (uint8_t i = 1; i < _count; i++) + for (uint16_t i = 1; i < _count; i++) { if (_array[i] < min) min = _array[i]; } @@ -135,7 +136,7 @@ float RunningAverage::getMaxInBuffer() const if (_count == 0) return NAN; float max = _array[0]; - for (uint8_t i = 1; i < _count; i++) + for (uint16_t i = 1; i < _count; i++) { if (_array[i] > max) max = _array[i]; } @@ -144,7 +145,7 @@ float RunningAverage::getMaxInBuffer() const // returns the value of an element if exist, NAN otherwise -float RunningAverage::getElement(uint8_t index) const +float RunningAverage::getElement(uint16_t index) const { if (index >=_count ) return NAN; @@ -159,7 +160,7 @@ float RunningAverage::getStandardDeviation() const float temp = 0; float average = getFastAverage(); - for (uint8_t i = 0; i < _count; i++) + for (uint16_t i = 0; i < _count; i++) { temp += pow((_array[i] - average), 2); } @@ -188,19 +189,19 @@ float RunningAverage::getStandardError() const //++ // fill the average with the same value number times. (weight) // This is maximized to size times. no need to fill the internal buffer over 100% -void RunningAverage::fillValue(const float value, const uint8_t number) +void RunningAverage::fillValue(const float value, const uint16_t number) { clear(); - uint8_t s = number; + uint16_t s = number; if (s > _size) s = _size; - for (uint8_t i = s; i > 0; i--) + for (uint16_t i = s; i > 0; i--) { addValue(value); } } -float RunningAverage::getValue(const uint8_t index) +float RunningAverage::getValue(const uint16_t index) { if (_count == 0) return NAN; if (index >= _count) return NAN; // cannot ask more than is added @@ -210,4 +211,12 @@ float RunningAverage::getValue(const uint8_t index) return _array[pos]; } + +void RunningAverage::setPartial(const uint16_t part) +{ + _partial = part; + if ((_partial == 0) || (_partial > _size)) _partial = _size; + clear(); +} + // -- END OF FILE -- diff --git a/RunningAverage.h b/RunningAverage.h index ea49a80..cfafaa5 100644 --- a/RunningAverage.h +++ b/RunningAverage.h @@ -2,7 +2,7 @@ // // FILE: RunningAverage.h // AUTHOR: Rob.Tillaart@gmail.com -// VERSION: 0.3.2 +// VERSION: 0.4.0 // 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,53 +13,58 @@ #include "Arduino.h" -#define RUNNINGAVERAGE_LIB_VERSION (F("0.3.2")) +#define RUNNINGAVERAGE_LIB_VERSION (F("0.4.0")) class RunningAverage { public: - explicit RunningAverage(const uint8_t size); + explicit RunningAverage(const uint16_t size); ~RunningAverage(); - void clear(); - void add(const float value) { addValue(value); }; - void addValue(const float); - void fillValue(const float, const uint8_t); - float getValue(const uint8_t); + void clear(); + void add(const float value) { addValue(value); }; + void addValue(const float); + void fillValue(const float, const uint16_t); + float getValue(const uint16_t); - float getAverage(); // iterates over all elements. - float getFastAverage() const; // reuses previous calculated values. + float getAverage(); // iterates over all elements. + float getFastAverage() const; // reuses previous calculated values. // return statistical characteristics of the running average - float getStandardDeviation() const; - float getStandardError() const; + float getStandardDeviation() const; + float getStandardError() const; // returns min/max added to the data-set since last clear - float getMin() const { return _min; }; - float getMax() const { return _max; }; + float getMin() const { return _min; }; + float getMax() const { return _max; }; // returns min/max from the values in the internal buffer - float getMinInBuffer() const; - float getMaxInBuffer() const; + float getMinInBuffer() const; + float getMaxInBuffer() const; // return true if buffer is full - bool bufferIsFull() const { return _count == _size; }; + bool bufferIsFull() const { return _count == _size; }; - float getElement(uint8_t idx) const; + float getElement(uint16_t idx) const; - uint8_t getSize() const { return _size; } - uint8_t getCount() const { return _count; } + uint16_t getSize() const { return _size; } + uint16_t getCount() const { return _count; } + // use not all elements just a part from 0..partial-1 + // (re)setting partial will clear the internal buffer. + void setPartial(const uint16_t part = 0); // 0 ==> use all + uint16_t getPartial() { return _partial; }; protected: - uint8_t _size; - uint8_t _count; - uint8_t _index; - float _sum; - float* _array; - float _min; - float _max; + uint16_t _size; + uint16_t _count; + uint16_t _index; + uint16_t _partial; + float _sum; + float* _array; + float _min; + float _max; }; // -- END OF FILE -- diff --git a/examples/ra_300/ra_300.ino b/examples/ra_300/ra_300.ino new file mode 100644 index 0000000..4e35a24 --- /dev/null +++ b/examples/ra_300/ra_300.ino @@ -0,0 +1,41 @@ +// +// 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); + Serial.print(i); + Serial.print("\t"); + Serial.print(myRA.getCount()); + Serial.print("\t"); + Serial.print(myRA.getAverage()); + Serial.println(); + } +} + + +void loop(void) +{ +} + +// -- END OF FILE -- diff --git a/examples/ra_getValue/ra_getValue.ino b/examples/ra_getValue/ra_getValue.ino index e3658d4..648fe3d 100644 --- a/examples/ra_getValue/ra_getValue.ino +++ b/examples/ra_getValue/ra_getValue.ino @@ -26,13 +26,13 @@ void loop(void) Serial.println(); myRA.clear(); - for (int i = 0; i < 7; i++) + for (uint16_t i = 0; i < 7; i++) { myRA.addValue(i); } Serial.print("\t getValue 0..getCount(): "); - for (int i = 0; i < myRA.getCount(); i++) + for (uint16_t i = 0; i < myRA.getCount(); i++) { Serial.print("\t"); Serial.print(myRA.getValue(i), 0); @@ -41,13 +41,13 @@ void loop(void) // note first values (0..2) will be overwritten by 10..12 myRA.clear(); - for (int i = 0; i < 13; i++) + for (uint16_t i = 0; i < 13; i++) { myRA.addValue(i); } Serial.print("\t getValue 0..getCount(): "); - for (int i = 0; i < myRA.getCount(); i++) + for (uint16_t i = 0; i < myRA.getCount(); i++) { Serial.print("\t"); Serial.print(myRA.getValue(i), 0); diff --git a/examples/ra_hour/ra_hour.ino b/examples/ra_hour/ra_hour.ino index 09d9214..0f8dc41 100644 --- a/examples/ra_hour/ra_hour.ino +++ b/examples/ra_hour/ra_hour.ino @@ -1,5 +1,5 @@ // -// FILE: runningAverageHour.pde +// FILE: runningAverageHour.ino // AUTHOR: Rob Tillaart // DATE: 2012-12-30 // diff --git a/examples/ra_partial/ra_partial.ino b/examples/ra_partial/ra_partial.ino new file mode 100644 index 0000000..866b9ec --- /dev/null +++ b/examples/ra_partial/ra_partial.ino @@ -0,0 +1,96 @@ +// +// FILE: ra_partial.ino +// AUTHOR: Rob Tillaart +// VERSION: 0.1.0 +// DATE: 2021-05-26 +// +// PUPROSE: demonstrate partial use of internal buffer +// + + +#include "RunningAverage.h" + +RunningAverage myRA(25); +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 < 30; i++) + { + myRA.addValue(i); + Serial.print(i); + Serial.print("\t"); + Serial.print(myRA.getCount()); + Serial.print("\t"); + Serial.print(myRA.getAverage()); + Serial.println(); + } + Serial.println(); + + myRA.setPartial(20); + for (uint16_t i = 0; i < 30; i++) + { + myRA.addValue(i); + Serial.print(i); + Serial.print("\t"); + Serial.print(myRA.getCount()); + Serial.print("\t"); + Serial.print(myRA.getAverage()); + Serial.println(); + } + Serial.println(); + + myRA.setPartial(50); + for (uint16_t i = 0; i < 30; i++) + { + myRA.addValue(i); + Serial.print(i); + Serial.print("\t"); + Serial.print(myRA.getCount()); + Serial.print("\t"); + Serial.print(myRA.getAverage()); + Serial.println(); + } + Serial.println(); + + myRA.setPartial(10); + for (uint16_t i = 0; i < 30; i++) + { + myRA.addValue(i); + Serial.print(i); + Serial.print("\t"); + Serial.print(myRA.getCount()); + Serial.print("\t"); + Serial.print(myRA.getAverage()); + Serial.println(); + } + Serial.println(); + + myRA.setPartial(); + for (uint16_t i = 0; i < 30; i++) + { + myRA.addValue(i); + Serial.print(i); + Serial.print("\t"); + Serial.print(myRA.getCount()); + Serial.print("\t"); + Serial.print(myRA.getAverage()); + Serial.println(); + } + Serial.println(); + +} + +void loop(void) +{ +} + + +// -- END OF FILE -- diff --git a/examples/ra_test/ra_test.ino b/examples/ra_test/ra_test.ino index 146112e..3b6e085 100644 --- a/examples/ra_test/ra_test.ino +++ b/examples/ra_test/ra_test.ino @@ -1,5 +1,5 @@ // -// FILE: runningAverageTest.pde +// FILE: runningAverageTest.ino // AUTHOR: Rob Tillaart // VERSION: 0.1.01 // DATE: 2012-12-30 @@ -7,11 +7,13 @@ // PUPROSE: show working of runningAverage // + #include "RunningAverage.h" RunningAverage myRA(10); int samples = 0; + void setup(void) { Serial.begin(115200); @@ -21,6 +23,7 @@ void setup(void) myRA.clear(); // explicitly start clean } + void loop(void) { long rn = random(0, 1000); @@ -37,4 +40,6 @@ void loop(void) Serial.println(); } delay(10); -} \ No newline at end of file +} + +// -- END OF FILE -- \ No newline at end of file diff --git a/examples/ra_two_sensors/ra_two_sensors.ino b/examples/ra_two_sensors/ra_two_sensors.ino index 85e60c2..730844d 100644 --- a/examples/ra_two_sensors/ra_two_sensors.ino +++ b/examples/ra_two_sensors/ra_two_sensors.ino @@ -30,6 +30,7 @@ void setup(void) RAH.clear(); } + void loop(void) { // random function simulates 2 sensors @@ -60,4 +61,5 @@ void loop(void) delay(500); } + // -- END OF FILE -- diff --git a/keywords.txt b/keywords.txt index 14d0da0..4d7f90d 100644 --- a/keywords.txt +++ b/keywords.txt @@ -1,8 +1,10 @@ # Syntax Coloring Map For RunningAverage + # Datatypes (KEYWORD1) RunningAverage KEYWORD1 + # Methods and Functions (KEYWORD2) clear KEYWORD2 add KEYWORD2 @@ -22,7 +24,9 @@ getMinInBuffer KEYWORD2 getMaxInBuffer KEYWORD2 getValue KEYWORD2 + # Instances (KEYWORD2) + # Constants (LITERAL1) RUNNINGAVERAGE_LIB_VERSION LITERAL1 \ No newline at end of file diff --git a/library.json b/library.json index 1178e33..b6f809a 100644 --- a/library.json +++ b/library.json @@ -15,7 +15,8 @@ "type": "git", "url": "https://github.com/RobTillaart/RunningAverage.git" }, - "version": "0.3.2", + "version": "0.4.0", + "license": "MIT", "frameworks": "arduino", "platforms": "*" } diff --git a/library.properties b/library.properties index 28e561f..4ed06a1 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RunningAverage -version=0.3.2 +version=0.4.0 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 636d0fe..bebb810 100644 --- a/test/unit_test_001.cpp +++ b/test/unit_test_001.cpp @@ -44,6 +44,7 @@ unittest_teardown() { } + unittest(test_zero_elements) { fprintf(stderr, "VERSION: %s\n", RUNNINGAVERAGE_LIB_VERSION); @@ -61,6 +62,7 @@ unittest(test_zero_elements) assertNAN(x); } + unittest(test_min_max) { RunningAverage myRA(10); @@ -82,6 +84,7 @@ unittest(test_min_max) assertEqual(5, ma); } + unittest(test_buffer_full) { RunningAverage myRA(10); @@ -99,6 +102,45 @@ unittest(test_buffer_full) } +unittest(test_large) +{ + RunningAverage myRA(300); + myRA.clear(); + assertFalse(myRA.bufferIsFull()); + + for (int i = 0; i < 299; i++) + { + myRA.addValue(i); + assertFalse(myRA.bufferIsFull()); + } + + myRA.addValue(42); + assertTrue(myRA.bufferIsFull()); +} + + +unittest(test_partial) +{ + RunningAverage myRA(100); + myRA.clear(); + assertFalse(myRA.bufferIsFull()); + + myRA.setPartial(10); + for (int i = 0; i < 100; i++) + { + myRA.addValue(i); + } + assertEqualFloat(94.5, myRA.getAverage(), 0.001); + + myRA.setPartial(20); + for (int i = 0; i < 100; i++) + { + myRA.addValue(i); + } + assertEqualFloat(89.5, myRA.getAverage(), 0.001); +} + + unittest_main() // --------