Arduino ci (#3)

* add Arduino-ci
* add unit test
This commit is contained in:
Rob Tillaart 2021-01-08 15:14:13 +01:00 committed by GitHub
parent 593d1780c2
commit 5cbc9c0651
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 192 additions and 57 deletions

7
.arduino-ci.yml Normal file
View file

@ -0,0 +1,7 @@
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
- leonardo
- due
- zero

View file

@ -0,0 +1,13 @@
---
name: Arduino CI
on: [push, pull_request]
jobs:
arduino_ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: Arduino-CI/action@master
# Arduino-CI/action@v0.1.1

View file

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2010-2020 Rob Tillaart Copyright (c) 2010-2021 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

@ -1,44 +1,55 @@
[![Arduino CI](https://github.com/RobTillaart/Statistic/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/Statistic/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/RobTillaart/Statistic.svg?maxAge=3600)](https://github.com/RobTillaart/Statistic/releases)
# Statistic # Statistic
Statistic library for Arduino includes sum, average, variance and std deviation Statistic library for Arduino includes sum, average, variance and std deviation
# Description
## Description
The statistic library is made to get basic statistical information from a The statistic library is made to get basic statistical information from a
one dimensional set of data, e.g. a stream of values of a sensor. one dimensional set of data, e.g. a stream of values of a sensor.
The stability of the formulas is improved by the help of Gil Ross (Thanks!) The stability of the formulas is improved by the help of Gil Ross (Thanks!)
The functions implemented are: ## Interface
* **clear(useStdDev)** - **Statistic(bool useStdDev = true)** Constructor, default use the standard deviation
* **add(value)** functions. Setting this flag to **false** reduces math so slight increase of performance.
* **count()** returns zero if count == zero (of course) - **void clear(bool useStdDev = true)** resets all variables.
* **sum()** returns zero if count == zero - **void add(float value)**
* **minimum()** returns zero if count == zero - **uint32_t count()** returns zero if count == zero (of course)
* **maximum()** returns zero if count == zero - **float sum()** returns zero if count == zero
* **average()** returns NAN if count == zero - **float minimum()** returns zero if count == zero
- **float maximum()** returns zero if count == zero
- **float average()** returns NAN if count == zero
These three functions only work id useStdDev == true: These three functions only work if **useStdDev == true**
* **variance()** returns NAN if count == zero - **variance()** returns NAN if count == zero
* **pop_stdev()** population stdev, returns NAN if count == zero - **pop_stdev()** population stdev, returns NAN if count == zero
* **unbiased_stdev()** returnsNAN if count == zero - **unbiased_stdev()** returnsNAN if count == zero
# Operational ## Operational
See examples See examples
# FAQ ## FAQ
#### Q: Are individual samples still available?
### Q: Are individual samples still available?
The values added to the library are not stored in the lib as it would use lots The values added to the library are not stored in the lib as it would use lots
of memory quite fast. Instead a few calculated values are kept to be able to of memory quite fast. Instead a few calculated values are kept to be able to
calculate the most important statistics. calculate the most important statistics.
### Q: How many samples can the lib hold? (internal variables and overflow) #### Q: How many samples can the lib hold? (internal variables and overflow)
The counter of samples is an **uint32_t**, implying a maximum of about **4 billion** samples. The counter of samples is an **uint32_t**, implying a maximum of about **4 billion** samples.
In practice 'strange' things might happen before this number is reached. In practice 'strange' things might happen before this number is reached.
There are two internal variables, **_sum** which is the sum of the values and **_ssq** There are two internal variables, **_sum** which is the sum of the values and **_ssq**
@ -52,10 +63,11 @@ This workaround has no influence on the standard deviation.
!! Do not forget to add the expected average to the calculated average. !! Do not forget to add the expected average to the calculated average.
*(Q: should this subtraction trick be build into the lib?)* - Q: should this subtraction trick be build into the lib?
### Q: How about the precision of the library? #### Q: How about the precision of the library?
The precision of the internal variables is restricted due to the fact The precision of the internal variables is restricted due to the fact
that they are 32 bit float (IEEE754). If the internal variable **_sum** has that they are 32 bit float (IEEE754). If the internal variable **_sum** has
a large value, adding relative small values to the dataset wouldn't a large value, adding relative small values to the dataset wouldn't
@ -69,11 +81,13 @@ but it works only if the samples are available and the they may be added
in the sorted increasing order. in the sorted increasing order.
### Q: When will internal var's overflow? esp. squared sum #### Q: When will internal var's overflow? esp. squared sum
IEEE754 floats have a max value of about **+-3.4028235E+38** IEEE754 floats have a max value of about **+-3.4028235E+38**
### Q: Why are there two functions for stdev? #### Q: Why are there two functions for stdev?
There are two stdev functions the population stdev and the unbiased stdev. There are two stdev functions the population stdev and the unbiased stdev.
See Wikipedia for an elaborate description of the difference between these two. See Wikipedia for an elaborate description of the difference between these two.

View file

@ -2,7 +2,7 @@
// FILE: Statistic.cpp // FILE: Statistic.cpp
// AUTHOR: Rob dot Tillaart at gmail dot com // AUTHOR: Rob dot Tillaart at gmail dot com
// modified at 0.3 by Gil Ross at physics dot org // modified at 0.3 by Gil Ross at physics dot org
// VERSION: 0.4.1 // VERSION: 0.4.2
// PURPOSE: Recursive statistical library for Arduino // PURPOSE: Recursive statistical library for Arduino
// //
// NOTE: 2011-01-07 Gill Ross // NOTE: 2011-01-07 Gill Ross
@ -28,40 +28,43 @@
// unbiassed SE. // unbiassed SE.
// ------------- // -------------
// //
// HISTORY: // HISTORY:
// 0.1 2010-10-29 initial version // 0.1 2010-10-29 initial version
// 0.2 2010-10-29 stripped to minimal functionality // 0.2 2010-10-29 stripped to minimal functionality
// 0.2.01 2010-10-30 // 0.2.01 2010-10-30
// added minimim, maximum, unbiased stdev, // added minimim, maximum, unbiased stdev,
// changed counter to long -> int overflows @32K samples // changed counter to long -> int overflows @32K samples
// 0.3 2011-01-07 // 0.3 2011-01-07
// branched from 0.2.01 version of Rob Tillaart's code // branched from 0.2.01 version of Rob Tillaart's code
// 0.3.1 2012-11-10 minor edits // 0.3.1 2012-11-10 minor edits
// 0.3.2 2012-11-10 minor edits // 0.3.2 2012-11-10 minor edits
// changed count -> unsigned long allows for 2^32 samples // changed count -> unsigned long allows for 2^32 samples
// added variance() // added variance()
// 0.3.3 2015-03-07 // 0.3.3 2015-03-07
// float -> double to support ARM (compiles) // float -> double to support ARM (compiles)
// moved count() sum() min() max() to .h; for optimizing compiler // moved count() sum() min() max() to .h; for optimizing compiler
// 0.3.4 2017-07-31 // 0.3.4 2017-07-31
// Refactored const in many places // Refactored const in many places
// [reverted] double to float on request as float is 99.99% of the cases // [reverted] double to float on request as float is 99.99% of the cases
// good enough and float(32 bit) is supported in HW for some processors. // good enough and float(32 bit) is supported in HW for some processors.
// 0.3.5 2017-09-27 // 0.3.5 2017-09-27
// Added #include <Arduino.h> to fix uint32_t bug // Added #include <Arduino.h> to fix uint32_t bug
// 0.4.0 2020-05-13 // 0.4.0 2020-05-13
// refactor // refactor
// Added flag to switch on the use of stdDev runtime. [idea marc.recksiedl] // Added flag to switch on the use of stdDev runtime. [idea marc.recksiedl]
// 0.4.1 2020-06-19 fix library.json // 0.4.1 2020-06-19 fix library.json
// // 0.4.2 2021-01-08 add Arduino-CI + unit tests
#include "Statistic.h" #include "Statistic.h"
Statistic::Statistic(bool useStdDev) Statistic::Statistic(bool useStdDev)
{ {
clear(useStdDev); clear(useStdDev);
} }
void Statistic::clear(bool useStdDev) // useStdDev default true. void Statistic::clear(bool useStdDev) // useStdDev default true.
{ {
_cnt = 0; _cnt = 0;
@ -74,6 +77,7 @@ void Statistic::clear(bool useStdDev) // useStdDev default true.
// which is SUM(from i = 1 to N) of f(i)-_ave_N)**2 // which is SUM(from i = 1 to N) of f(i)-_ave_N)**2
} }
// adds a new value to the data-set // adds a new value to the data-set
void Statistic::add(const float value) void Statistic::add(const float value)
{ {
@ -96,12 +100,13 @@ void Statistic::add(const float value)
// ~10% faster but limits the amount of samples to 65K as _cnt*_cnt overflows // ~10% faster but limits the amount of samples to 65K as _cnt*_cnt overflows
// float _store = _sum - _cnt * value; // float _store = _sum - _cnt * value;
// _ssqdif = _ssqdif + _store * _store / (_cnt*_cnt - _cnt); // _ssqdif = _ssqdif + _store * _store / (_cnt*_cnt - _cnt);
// //
// solution: TODO verify // solution: TODO verify
// _ssqdif = _ssqdif + (_store * _store / _cnt) / (_cnt - 1); // _ssqdif = _ssqdif + (_store * _store / _cnt) / (_cnt - 1);
} }
} }
// returns the average of the data-set added sofar // returns the average of the data-set added sofar
float Statistic::average() const float Statistic::average() const
{ {
@ -109,6 +114,7 @@ float Statistic::average() const
return _sum / _cnt; return _sum / _cnt;
} }
// Population standard deviation = s = sqrt [ S ( Xi - µ )2 / N ] // Population standard deviation = s = sqrt [ S ( Xi - µ )2 / N ]
// http://www.suite101.com/content/how-is-standard-deviation-used-a99084 // http://www.suite101.com/content/how-is-standard-deviation-used-a99084
float Statistic::variance() const float Statistic::variance() const
@ -118,6 +124,7 @@ float Statistic::variance() const
return _ssqdif / _cnt; return _ssqdif / _cnt;
} }
float Statistic::pop_stdev() const float Statistic::pop_stdev() const
{ {
if (!_useStdDev) return NAN; if (!_useStdDev) return NAN;
@ -125,6 +132,7 @@ float Statistic::pop_stdev() const
return sqrt( _ssqdif / _cnt); return sqrt( _ssqdif / _cnt);
} }
float Statistic::unbiased_stdev() const float Statistic::unbiased_stdev() const
{ {
if (!_useStdDev) return NAN; if (!_useStdDev) return NAN;

View file

@ -3,15 +3,17 @@
// FILE: Statistic.h // FILE: Statistic.h
// AUTHOR: Rob dot Tillaart at gmail dot com // AUTHOR: Rob dot Tillaart at gmail dot com
// modified at 0.3 by Gil Ross at physics dot org // modified at 0.3 by Gil Ross at physics dot org
// VERSION: 0.4.1 // VERSION: 0.4.2
// PURPOSE: Recursive Statistical library for Arduino // PURPOSE: Recursive Statistical library for Arduino
// HISTORY: See Statistic.cpp // HISTORY: See Statistic.cpp
// //
#include <Arduino.h> #include <Arduino.h>
#include <math.h> #include <math.h>
#define STATISTIC_LIB_VERSION "0.4.1"
#define STATISTIC_LIB_VERSION (F("0.4.2"))
class Statistic class Statistic
{ {

View file

@ -18,7 +18,7 @@
"type": "git", "type": "git",
"url": "https://github.com/RobTillaart/Statistic.git" "url": "https://github.com/RobTillaart/Statistic.git"
}, },
"version":"0.4.1", "version":"0.4.2",
"frameworks": "arduino", "frameworks": "arduino",
"platforms": "*" "platforms": "*"
} }

View file

@ -1,5 +1,5 @@
name=Statistic name=Statistic
version=0.4.1 version=0.4.2
author=Rob Tillaart <rob.tillaart@gmail.com> author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com> maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library with basic statistical functions for Arduino. sentence=Library with basic statistical functions for Arduino.

91
test/unit_test_001.cpp Normal file
View file

@ -0,0 +1,91 @@
//
// FILE: unit_test_001.cpp
// AUTHOR: Rob Tillaart
// DATE: 2021-01-08
// PURPOSE: unit tests for the Statistic library
// https://github.com/RobTillaart/Statistic
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
//
// supported assertions
// ----------------------------
// assertEqual(expected, actual); // a == b
// assertNotEqual(unwanted, actual); // a != b
// assertComparativeEquivalent(expected, actual); // abs(a - b) == 0 or (!(a > b) && !(a < b))
// assertComparativeNotEquivalent(unwanted, actual); // abs(a - b) > 0 or ((a > b) || (a < b))
// assertLess(upperBound, actual); // a < b
// assertMore(lowerBound, actual); // a > b
// assertLessOrEqual(upperBound, actual); // a <= b
// assertMoreOrEqual(lowerBound, actual); // a >= b
// assertTrue(actual);
// assertFalse(actual);
// assertNull(actual);
// // special cases for floats
// assertEqualFloat(expected, actual, epsilon); // fabs(a - b) <= epsilon
// assertNotEqualFloat(unwanted, actual, epsilon); // fabs(a - b) >= epsilon
// assertInfinity(actual); // isinf(a)
// assertNotInfinity(actual); // !isinf(a)
// assertNAN(arg); // isnan(a)
// assertNotNAN(arg); // !isnan(a)
#include <ArduinoUnitTests.h>
#include "Arduino.h"
#include "Statistic.h"
unittest_setup()
{
}
unittest_teardown()
{
}
unittest(test_constructor)
{
fprintf(stderr, "VERSION: %s\n", STATISTIC_LIB_VERSION);
Statistic myStats;
assertEqual(0, myStats.count());
}
unittest(test_basic)
{
fprintf(stderr, "VERSION: %s\n", STATISTIC_LIB_VERSION);
Statistic myStats;
for (int i = 1; i < 100; i++) myStats.add(i);
assertEqual(99, myStats.count());
assertEqualFloat(4950, myStats.sum(), 0.0001);
assertEqualFloat(1, myStats.minimum(), 0.0001);
assertEqualFloat(50, myStats.average(), 0.0001);
assertEqualFloat(99, myStats.maximum(), 0.0001);
assertEqualFloat(816.667, myStats.variance(), 0.001); // note 1 digit less
assertEqualFloat(28.5774, myStats.pop_stdev(), 0.0001);
assertEqualFloat(28.7228, myStats.unbiased_stdev(), 0.0001);
myStats.clear();
assertEqualFloat(0, myStats.sum(), 0.0001);
assertEqualFloat(0, myStats.minimum(), 0.0001);
assertEqualFloat(0, myStats.average(), 0.0001);
assertEqualFloat(0, myStats.maximum(), 0.0001);
assertEqualFloat(0, myStats.variance(), 0.0001);
assertEqualFloat(0, myStats.pop_stdev(), 0.0001);
assertEqualFloat(0, myStats.unbiased_stdev(), 0.0001);
assertEqual(0, myStats.count());
}
unittest_main()
// --------