Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #33, getCoefficientOfVariation #35

Merged
merged 2 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).


## [0.4.7] - 2024-08-12
- Fix #33, add **float getCoefficientOfVariation()**
- update readme.md
- update keywords.txt

## [0.4.6] - 2024-06-15
- Fix #30, add **float getSum()** (thanks to heidnerd)
- Fix #31, add **float getStandardDeviationLast(uint16_t count)** (thanks to alvaro-oliver)
Expand Down
32 changes: 18 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ update the internal **\_sum**.
- https://github.com/RobTillaart/RunningMedian
- https://github.com/RobTillaart/statHelpers - combinations & permutations
- https://github.com/RobTillaart/Statistic
- https://github.com/RobTillaart/Student


## Interface
Expand Down Expand Up @@ -83,8 +84,14 @@ Updates the variables used by **getFastAverage()** to improve its accuracy again
- **float getStandardDeviation()** returns the standard deviation of the current content.
Needs more than one element to be calculable.
- **float getStandardError()** returns the standard error of the current content.
- **float getMin()** returns minimum since last clear, does not need to be in the buffer any more.
- **float getMax()** returns maximum since last clear, does not need to be in the buffer any more.
- **float getCoefficientOfVariation()** returns coefficient of variation.
This is defined as standardDeviation / Average.
It indicates if the distribution is relative small ( < 1) or relative wide ( > 1).
Note it has no meaning when the average is zero (or close to zero).
- **float getMin()** returns minimum since last call to clear().
The returned value does not need to be in the buffer any more.
- **float getMax()** returns maximum since last call to clear().
The returned value does not need to be in the buffer any more.
- **float getMinInBuffer()** returns minimum in the internal buffer.
- **float getMaxInBuffer()** returns maximum in the internal buffer.
- **float getSum()** returns sum of values in the internal buffer.
Expand All @@ -94,7 +101,7 @@ Needs more than one element to be calculable.

- **bool bufferIsFull()** returns true if buffer is full.
- **float getElement(uint16_t index)** get element directly from internal buffer at index. (debug)
- **uint16_t getSize()** returns the size of the internal array.
- **uint16_t getSize()** returns the size of the internal array as set in constructor.
- **uint16_t getCount()** returns the number of slots used of the internal array.


Expand All @@ -114,6 +121,7 @@ Returns NAN if there are no elements and it will reduce count if there are less
count elements in the buffer.

- **float getAverageLast(uint16_t count)** get the average of the last count elements.
- **float getStandardDeviationLast(uint16_t count)** get the stddev 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.

Expand Down Expand Up @@ -174,22 +182,14 @@ See examples
#### Should

- check for optimizations.
- divide by count happens often
- fillValue can be optimized (See #13)
- ```temp = sqrt(temp/(_count - 1));``` is this correct STDDEV?
- divide by count or count - 1?
- https://www.zaner.com/3.0/education/technicalstudies/MSD.asp

- divide by count (-1) happens often.
- fillValue can be optimized (See #13).

#### Could

- create a double based derived class?
- Template class?
- add error handling (important?).
- investigate **modus()** most frequently occurring value.
- difficult with floats ?
- what to do when on two or more values are on par? (no modus?)
- **int getUniqueValuesInBuffer()** O(n^2)


#### Wont

Expand All @@ -198,6 +198,10 @@ See examples
- clear(bool zero = true) to suppress setting all to 0. ?
- makes **addValue()** slightly more complex
- could introduce conflicts due to randomness data?
- investigate **modus()** most frequently occurring value.
- difficult with floats ?
- what to do when on two or more values are on par? (no modus?)
- **int getUniqueValuesInBuffer()** O(n^2).


## Support
Expand Down
31 changes: 23 additions & 8 deletions RunningAverage.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//
// FILE: RunningAverage.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.4.6
// VERSION: 0.4.7
// DATE: 2011-01-30
// PURPOSE: Arduino library to calculate the running average by means of a circular buffer
// URL: https://github.com/RobTillaart/RunningAverage
Expand Down Expand Up @@ -140,7 +140,7 @@ float RunningAverage::getMaxInBuffer() const


// returns the value of an element if exist, NAN otherwise
float RunningAverage::getElement(uint16_t index) const
float RunningAverage::getElement(const uint16_t index) const
{
if ((_count == 0) || (_array == NULL))
{
Expand All @@ -166,7 +166,9 @@ float RunningAverage::getStandardDeviation() const
{
temp += pow((_array[i] - average), 2);
}
// TODO: when to divide by count || count-1?
// when to divide by count || count-1?
// - divide by count: whole set
// - divide by count - 1: sample of larger set (which run avg is)
temp = sqrt(temp/(_count - 1));
return temp;
// see issue #13
Expand All @@ -191,6 +193,19 @@ float RunningAverage::getStandardError() const
}


// Return coefficient of variation.
// If buffer is empty or has only one element or zero average, return NAN.
float RunningAverage::getCoefficientOfVariation() const
{
float temp = getStandardDeviation();
if (temp == NAN) return NAN;
if (_sum == 0) return NAN;

float cv = temp * _count / _sum;
return cv;
}


// 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%
Expand Down Expand Up @@ -256,7 +271,7 @@ bool RunningAverage::setPartial(const uint16_t partial)
}


float RunningAverage::getAverageLast(uint16_t count)
float RunningAverage::getAverageLast(const uint16_t count)
{
uint16_t cnt = count;
if (cnt > _count) cnt = _count;
Expand All @@ -274,7 +289,7 @@ float RunningAverage::getAverageLast(uint16_t count)
}


float RunningAverage::getStandardDeviationLast(uint16_t count)
float RunningAverage::getStandardDeviationLast(const uint16_t count)
{
uint16_t cnt = count;
if (cnt > _count) cnt = _count;
Expand All @@ -296,7 +311,7 @@ float RunningAverage::getStandardDeviationLast(uint16_t count)
}


float RunningAverage::getMinInBufferLast(uint16_t count)
float RunningAverage::getMinInBufferLast(const uint16_t count)
{
uint16_t cnt = count;
if (cnt > _count) cnt = _count;
Expand All @@ -316,7 +331,7 @@ float RunningAverage::getMinInBufferLast(uint16_t count)
}


float RunningAverage::getMaxInBufferLast(uint16_t count)
float RunningAverage::getMaxInBufferLast(const uint16_t count)
{
uint16_t cnt = count;
if (cnt > _count) cnt = _count;
Expand All @@ -336,7 +351,7 @@ float RunningAverage::getMaxInBufferLast(uint16_t count)
}


float RunningAverage::getAverageSubset(uint16_t start, uint16_t count)
float RunningAverage::getAverageSubset(const uint16_t start, const uint16_t count)
{
if ((_count == 0) || (_array == NULL))
{
Expand Down
17 changes: 9 additions & 8 deletions RunningAverage.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// FILE: RunningAverage.h
// AUTHOR: Rob Tillaart
// VERSION: 0.4.6
// VERSION: 0.4.7
// DATE: 2011-01-30
// PURPOSE: Arduino library to calculate the running average by means of a circular buffer
// URL: https://github.com/RobTillaart/RunningAverage
Expand All @@ -14,7 +14,7 @@
#include "Arduino.h"


#define RUNNINGAVERAGE_LIB_VERSION (F("0.4.6"))
#define RUNNINGAVERAGE_LIB_VERSION (F("0.4.7"))


class RunningAverage
Expand All @@ -36,6 +36,7 @@ class RunningAverage
// return statistical characteristics of the running average
float getStandardDeviation() const;
float getStandardError() const;
float getCoefficientOfVariation() const;

// returns min/max added to the data-set since last clear
float getMin() const { return _min; };
Expand All @@ -49,7 +50,7 @@ class RunningAverage
// return true if buffer is full
bool bufferIsFull() const { return _count == _size; };

float getElement(uint16_t index) const;
float getElement(const uint16_t index) const;

uint16_t getSize() const { return _size; }
uint16_t getCount() const { return _count; }
Expand All @@ -61,13 +62,13 @@ class RunningAverage


// get some stats from the last count additions.
float getAverageLast(uint16_t count);
float getStandardDeviationLast(uint16_t count);
float getMinInBufferLast(uint16_t count);
float getMaxInBufferLast(uint16_t count);
float getAverageLast(const uint16_t count);
float getStandardDeviationLast(const uint16_t count);
float getMinInBufferLast(const uint16_t count);
float getMaxInBufferLast(const uint16_t count);

// Experimental 0.4.3
float getAverageSubset(uint16_t start, uint16_t count);
float getAverageSubset(const uint16_t start, const uint16_t count);


protected:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//
// FILE: ra_getCoefficientOfVariation.ino
// AUTHOR: Rob Tillaart
// PURPOSE: show working of runningAverage
// URL: https://github.com/RobTillaart/RunningAverage


#include "RunningAverage.h"


RunningAverage myRA(10);
int samples = 0;


RunningAverage A(60);
RunningAverage B(60);
RunningAverage C(60);


void setup(void)
{
Serial.begin(115200);
Serial.println();
Serial.println(__FILE__);
Serial.print("RUNNINGAVERAGE_LIB_VERSION: ");
Serial.println(RUNNINGAVERAGE_LIB_VERSION);

myRA.clear(); // explicitly start clean

for (int i = 0; i < 10; i++)
{
myRA.add(i * 0.01 + 1 );
Serial.print(myRA.getCount());
Serial.print("\t");
Serial.print(myRA.getAverage(), 3);
Serial.print("\t");
Serial.print(myRA.getStandardDeviation(), 3);
Serial.print("\t");
Serial.print(myRA.getStandardDeviation() / myRA.getAverage(), 3);
Serial.print("\t");
Serial.println(myRA.getCoefficientOfVariation(), 3);
}
Serial.println();


Serial.println();
Serial.println("Show effect of changing average and standard deviation.");
Serial.println("- A is reference");
Serial.println("- B has same stdev, distribution is 'smaller' (sharper)");
Serial.println("- C has same average, distribution is 'wider'");
Serial.println();

A.clear();
B.clear();
C.clear();

for (int i = 0; i <= 50; i++)
{
A.add((i - 25) * 1.0 + 100); // reference
B.add((i - 25) * 1.0 + 200); // change average
C.add((i - 25) * 3.0 + 100); // change stddev
}
Serial.println("\tA\tB\tC");
Serial.print("AVG\t");
Serial.print(A.getAverage(), 3);
Serial.print("\t");
Serial.print(B.getAverage(), 3);
Serial.print("\t");
Serial.println(C.getAverage(), 3);

Serial.print("STDEV\t");
Serial.print(A.getStandardDeviation(), 3);
Serial.print("\t");
Serial.print(B.getStandardDeviation(), 3);
Serial.print("\t");
Serial.println(C.getStandardDeviation(), 3);

Serial.print("COFVAR\t");
Serial.print(A.getCoefficientOfVariation(), 3);
Serial.print("\t");
Serial.print(B.getCoefficientOfVariation(), 3);
Serial.print("\t");
Serial.println(C.getCoefficientOfVariation(), 3);


delay(10000);
}


void loop(void)
{
}


// -- END OF FILE --
3 changes: 2 additions & 1 deletion keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ getAverage KEYWORD2
getFastAverage KEYWORD2
getStandardDeviation KEYWORD2
getStandardError KEYWORD2
getCoefficientOfVariation KEYWORD2

getMin KEYWORD2
getMax KEYWORD2
getMinInBuffer KEYWORD2
getMaxInBuffer KEYWORD2
getSum KEYWORD2

bufferIsFull() KEYWORD2
bufferIsFull KEYWORD2
getElement KEYWORD2
getSize KEYWORD2
getCount KEYWORD2
Expand Down
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/RunningAverage.git"
},
"version": "0.4.6",
"version": "0.4.7",
"license": "MIT",
"frameworks": "*",
"platforms": "*",
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=RunningAverage
version=0.4.6
version=0.4.7
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=The library stores the last N individual values in a circular buffer to calculate the running average.
Expand Down
28 changes: 0 additions & 28 deletions performance.txt

This file was deleted.

Loading