update libraries R-Z

This commit is contained in:
rob tillaart 2020-11-27 11:33:55 +01:00
parent 9abe1508b1
commit 72861821fc
105 changed files with 3357 additions and 1016 deletions

21
libraries/Radar/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2013-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,17 +1,14 @@
//
// FILE: radarDemo.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE:
// DATE:
// URL:
//
// Released to the public domain
//
// VERSION: 0.1.1
// PURPOSE: demo of the radar library
// DATE: 29-03-2015
// URL: https://github.com/RobTillaart/RADAR
#include "radar.h"
uint32_t del = 250;
uint32_t del = 150;
RADAR radar(10, 11);
@ -22,36 +19,71 @@ void setup()
Serial.println(RADAR_LIB_VERSION);
Serial.println();
test1();
test2();
test3();
test4();
test5();
test6();
test7();
gohome();
Serial.println();
Serial.print(millis());
Serial.println("\tdone...");
}
void loop()
{
}
void test1()
{
Serial.print(millis());
Serial.println("\t1. home position");
radar.setHomePosition(0, 0);
radar.gotoHomePosition();
wait();
}
void test2()
{
Serial.print(millis());
Serial.println("\t2. gotoPan 20");
radar.gotoPan(20);
wait();
Serial.println();
}
void test3()
{
Serial.print(millis());
Serial.println("\t3. gotoTilt 60");
radar.gotoTilt(60);
wait();
Serial.println();
}
void test4()
{
Serial.print(millis());
Serial.println("\t4. gotoPanTilt 60 20");
radar.gotoPanTilt(60, 20);
wait();
Serial.println();
}
void test5()
{
Serial.print(millis());
Serial.println("\t5. home position");
radar.gotoHomePosition();
wait();
Serial.println();
}
void test6()
{
Serial.print(millis());
Serial.println("\t6. setPosition");
for (int i = 0; i < 10; i++)
@ -59,14 +91,17 @@ void setup()
radar.setPosition(i, random(90), random(90));
}
Serial.println();
}
void test7()
{
Serial.print(millis());
Serial.println("\t7. gotoPosition");
for (int i = 0; i < 10; i++)
{
radar.gotoPosition(i);
int p, t;
radar.getPosition(i, &p, &t);
int16_t p, t;
radar.getPosition(i, p, t);
Serial.print(millis());
Serial.print("\t");
Serial.print(i);
@ -78,32 +113,34 @@ void setup()
wait();
Serial.println();
}
}
void gohome()
{
Serial.print(millis());
Serial.println("\t8. home position");
Serial.println("\tgo home position");
radar.gotoHomePosition();
wait();
Serial.println();
Serial.println();
Serial.print(millis());
Serial.println("\tdone...");
}
void loop()
{
}
void wait()
{
Serial.println("\nTIME\t\tPAN\tTILT");
do
{
int p = radar.getPan();
int t = radar.getTilt();
Serial.print(millis());
Serial.print("\t*\t");
Serial.print(p);
Serial.print(radar.getPan());
Serial.print("\t");
Serial.println(t);
Serial.println(radar.getTilt());
delay(del);
} while (radar.isMoving());
Serial.print(millis());
Serial.print("\t*\t");
Serial.print(radar.getPan());
Serial.print("\t");
Serial.println(radar.getTilt());
}
// -- END OF FILE --

View File

@ -1,7 +1,7 @@
{
"name": "Radar",
"keywords": "Pan,tilt,radar",
"description": "Experimental library for a pan tilt radar.",
"name": "RADAR",
"keywords": "Pan,tilt,radar,ping",
"description": "Arduino library for a pan tilt radar. Experimental",
"authors":
[
{
@ -13,12 +13,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/RADAR"
},
"version":"0.1.1",
"version":"0.1.3",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/Radar"
}
"platforms": "*"
}

View File

@ -1,9 +1,11 @@
name=Radar
version=0.1.1
name=RADAR
version=0.1.3
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Experimental library for a pan tilt radar.
paragraph=
category=Device
url=https://github.com/RobTillaart/Arduino/tree/master/libraries/
architectures=*
sentence=Arduino library for a pan tilt radar.
paragraph=Experimental
category=Uncategorized
url=https://github.com/RobTillaart/RADAR
architectures=*
includes=radar.h
depends=

View File

@ -1,14 +1,14 @@
//
// FILE: radar.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.01
// PURPOSE: demo pan tilt radar framework
// URL:
//
// Released to the public domain
// VERSION: 0.1.3
// PURPOSE: Arduino library for a pan tilt radar.
// URL: https://github.com/RobTillaart/RADAR
//
// 0.1.00 - 2013-09-30 (?) outline
// 0.1.01 - 2015-03-06 updated some code, still not functional
// 0.1.2 - 2017-07-16 refactor & review
// 0.1.3 2020-07-06 refactor, clean up and some documentation
#include "radar.h"
@ -16,111 +16,124 @@
//
// CONSTRUCTOR
//
RADAR::RADAR(uint8_t pinPan, uint8_t pinTilt)
RADAR::RADAR(const uint8_t pinPan, const uint8_t pinTilt)
{
_pinPan = pinPan;
_pinTilt = pinTilt;
_homePan = 0;
_homeTilt = 0;
_pan = _prevPan = 0;
_tilt = _prevTilt = 0;
_lastPanTime = _lastTiltTime = millis();
_pinPan = pinPan;
_pinTilt = pinTilt;
_homePan = 0;
_homeTilt = 0;
_pan = _prevPan = 0;
_tilt = _prevTilt = 0;
_panPerSecond = 15;
_tiltPerSecond = 15;
_lastPanTime = _lastTiltTime = millis();
for (uint8_t i = 0; i < RADAR_POSITIONS; i++)
{
_panArray[i] = 0;
_tiltArray[i] = 0;
}
}
// PUBLIC
void RADAR::gotoPan(int pan)
void RADAR::gotoPan(const int16_t pan)
{
if (pan == _pan) return;
_prevPan = getPan();
_pan = pan;
analogWrite(_pinPan, _pan);
_lastPanTime = millis();
if (pan == _pan) return;
_prevPan = getPan();
_pan = pan;
analogWrite(_pinPan, _pan);
_lastPanTime = millis();
}
int RADAR::getPan()
int16_t RADAR::getPan()
{
// ESTIMATE current position on time it takes to go from previous to new
if (_pan == _prevPan) return _pan;
// if (enough time passed to move to new position) return new position
unsigned long duration = millis() - _lastPanTime;
if ( abs(_pan - _prevPan) <= (duration * PAN_PER_SEC)/1000UL) return _pan;
// else estimate by linear interpolation
if (_pan > _prevPan) return _prevPan + (duration * PAN_PER_SEC)/1000UL;
return _prevPan - (duration * PAN_PER_SEC)/1000UL;
// ESTIMATE current position on time it takes to go from previous to new
if (_pan == _prevPan) return _pan;
// if (enough time passed to move to new position) return new position
uint32_t duration = millis() - _lastPanTime;
uint32_t movement = round(duration * _panPerSecond * 0.001);
if ( abs(_pan - _prevPan) <= movement) return _pan;
// else estimate PAN by linear interpolation
if (_pan > _prevPan) return _prevPan + movement;
return _prevPan - movement;
}
void RADAR::gotoTilt(int tilt)
void RADAR::gotoTilt(const int16_t tilt)
{
if (tilt == _tilt) return;
_prevTilt = getTilt();
_tilt = tilt;
analogWrite(_pinTilt, _tilt);
_lastTiltTime = millis();
if (tilt == _tilt) return;
_prevTilt = getTilt();
_tilt = tilt;
analogWrite(_pinTilt, _tilt); // 0..180
_lastTiltTime = millis();
}
int RADAR::getTilt()
int16_t RADAR::getTilt()
{
// comments see getPan()
if (_tilt == _prevTilt) return _tilt;
unsigned long duration = millis() - _lastTiltTime;
if (abs(_tilt - _prevTilt) <= (duration * TILT_PER_SEC)/1000UL) return _tilt;
if (_tilt > _prevTilt) return _prevTilt + (duration * TILT_PER_SEC)/1000UL;
return _prevTilt - (duration * TILT_PER_SEC)/1000UL;
// ESTIMATE current position on time it takes to go from previous to new
if (_tilt == _prevTilt) return _tilt;
// if (enough time passed to move to new position) return new position
uint32_t duration = millis() - _lastTiltTime;
uint32_t movement = round(duration * _tiltPerSecond * 0.001);
if (abs(_tilt - _prevTilt) <= movement) return _tilt;
// estimate TILT by linear interpolation
if (_tilt > _prevTilt) return _prevTilt + movement;
return _prevTilt - movement;
}
void RADAR::gotoPanTilt(int pan, int tilt)
void RADAR::gotoPanTilt(const int16_t pan, const int16_t tilt)
{
gotoPan(pan);
gotoTilt(tilt);
gotoPan(pan);
gotoTilt(tilt);
}
void RADAR::setPosition(uint8_t n, int pan, int tilt)
bool RADAR::setPosition(const uint8_t n, const int16_t pan, const int16_t tilt)
{
_parray[n] = pan;
_tarry[n] = tilt;
if (n >= RADAR_POSITIONS) return false;
_panArray[n] = pan;
_tiltArray[n] = tilt;
return true;
}
bool RADAR::getPosition(uint8_t n, int *pan, int *tilt)
bool RADAR::getPosition(const uint8_t n, int16_t & pan, int16_t & tilt)
{
if (n > 10) return false;
*pan = _parray[n];
*tilt = _tarry[n];
return true;
if (n >= RADAR_POSITIONS) return false;
pan = _panArray[n];
tilt = _tiltArray[n];
return true;
}
bool RADAR::gotoPosition(uint8_t n)
bool RADAR::gotoPosition(const uint8_t n)
{
if (n > 10) return false;
gotoPan(_parray[n]);
gotoTilt(_tarry[n]);
return true;
if (n >= RADAR_POSITIONS) return false;
gotoPan(_panArray[n]);
gotoTilt(_tiltArray[n]);
return true;
}
void RADAR::setHomePosition(int pan, int tilt)
void RADAR::setHomePosition(const int16_t pan, const int16_t tilt)
{
_homePan = pan;
_homeTilt = tilt;
_homePan = pan;
_homeTilt = tilt;
}
void RADAR::gotoHomePosition()
{
gotoPan(_homePan);
gotoTilt(_homeTilt);
gotoPan(_homePan);
gotoTilt(_homeTilt);
}
bool RADAR::isMoving()
{
return ((getPan() != _pan) || (getTilt() != _tilt));
}
unsigned long RADAR::ping()
uint32_t RADAR::ping()
{
// TODO ping code here - playground or teckel's improved ping)))
return 0;
}
unsigned long RADAR::ping(int pan, int tilt)
uint32_t RADAR::ping(const int16_t pan, const int16_t tilt)
{
gotoPan(pan);
gotoTilt(tilt);

View File

@ -1,68 +1,72 @@
#pragma once
//
// FILE: radar.h
// AUTHOR: Rob Tillaart
// VERSION: see RADAR_LIB_VERSION
// PURPOSE: pan tilt radar framework
// URL:
//
// Released to the public domain
//
// PURPOSE: Arduino library for a pan tilt radar.
// URL: https://github.com/RobTillaart/RADAR
#ifndef Radar_h
#define Radar_h
#include "Arduino.h"
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#define RADAR_LIB_VERSION "0.1.3"
#ifndef RADAR_POSITIONS
#define RADAR_POSITIONS 10
#endif
#define RADAR_LIB_VERSION "0.1.01"
#define PAN_PER_SEC 25 // TODO determine emperically
#define TILT_PER_SEC 25 // TODO determine emperically
class RADAR
{
public:
RADAR(uint8_t, uint8_t);
public:
RADAR(const uint8_t, const uint8_t);
void gotoPan(int pan);
int getPan();
void gotoTilt(int tilt);
int getTilt();
void gotoPanTilt(int pan, int tilt);
// no valid range checking or negative value check.
void setPanPerSecond(float pps) { _panPerSecond = pps; };
float getPanPerSecond() { return _panPerSecond; };
void setTiltPerSecond(float tps) { _tiltPerSecond = tps; };
float getTiltPerSecond() { return _tiltPerSecond; };
// memory positions
void setPosition(uint8_t idx, int pan, int tilt);
bool getPosition(uint8_t idx, int *pan, int *tilt);
bool gotoPosition(uint8_t idx);
void setHomePosition(int pan, int tilt);
void gotoHomePosition();
// basic moves
void gotoPan(const int16_t pan);
int16_t getPan();
void gotoTilt(const int16_t tilt);
int16_t getTilt();
void gotoPanTilt(const int16_t pan, const int16_t tilt);
//
bool isMoving();
// memory positions - store / recall?
uint8_t getMaxPositions() { return RADAR_POSITIONS; };
bool setPosition(const uint8_t idx, const int16_t pan, const int16_t tilt);
bool getPosition(const uint8_t idx, int16_t & pan, int16_t & tilt);
bool gotoPosition(const uint8_t idx);
void setHomePosition(const int16_t pan, const int16_t tilt);
void gotoHomePosition();
unsigned long ping();
unsigned long ping(int pan, int tilt);
// feedback on positions.
bool isMoving() { return isPanMoving() || isTiltMoving(); };
bool isPanMoving() { return getPan() != _pan; };
bool isTiltMoving() { return getTilt() != _tilt; };
uint32_t ping();
uint32_t ping(const int16_t pan, const int16_t tilt);
private:
int _pinPan;
int _pinTilt;
private:
int16_t _pinPan;
int16_t _pinTilt;
int _prevPan;
int _pan;
int _homePan;
unsigned long _lastPanTime;
int16_t _prevPan;
int16_t _pan;
int16_t _homePan;
uint32_t _lastPanTime;
int _prevTilt;
int _tilt;
int _homeTilt;
unsigned long _lastTiltTime;
int16_t _prevTilt;
int16_t _tilt;
int16_t _homeTilt;
uint32_t _lastTiltTime;
int _parray[10];
int _tarry[10];
int16_t _panArray[RADAR_POSITIONS];
int16_t _tiltArray[RADAR_POSITIONS];
float _panPerSecond = 15;
float _tiltPerSecond = 15;
};
#endif
// -- END OF FILE --

View File

@ -1,12 +1,43 @@
WARNING: not working version !!!
# Radar
Arduino library for a pan tilt radar based upon 2 servo's.
## Warning
**WARNING: not extensively tested**
There are stil a lot of things to be tested.
The example code is now working to show the concept.
## Description
radar is a concept library not elaborated yet that implements a Ping))) based Radar
with the use of a pan/tilt servo's. Was written after a question on the forum but
never finished it. Still, it has some interesting concepts wrt determine the position of
pan/tilt while in progress.
with the use of two pan/tilt servo's. It was written after a question on the forum but
never finished or tested it. Still, it has some interesting concepts wrt determine
the position of pan/tilt while in progress.
The idea is that one knows how fast the pan and tilt servos are working in degrees per second.
From that number and the start moment one can determine approximately its position.
Given its position while moving is interesting for radar purposes as one can determine e.g.
in which direction a ping is given and which distance belongs to which pair of angles.
## Interface
TODO - see radar.h file
- **RADAR(pan, tilt)** define pan / tilt pins of the radar. These should be PWM pins.
RADAR_POSITIONS
## Operation
See examples
In short a lot todo

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2012-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,19 @@
# RunningAverage
Arduino library to calculate the running average by means of a circular buffer.
## Description
The RunningAverage object gives a running average of the last N numbers, giving them
all equal weight. This is doen by adding new data to an internal circular buffer,
removing the oldest and replace it by the newest. The size of the internal buffer
By keeping track of the **_sum** the runningAverage can be calculated fast (only 1 division).
This is done with **getFastAverage()**.
However the constant adding/subtracting when adding new elements introduces an accumulating error.
In tests adding up to 1500000 numbers this error was always small. But that is no proof.
In version 0.2.16 there is a fix added that uses the calculation of the sum in **getAverage()** to
update the internal **_sum**.
## Operation
See examples

View File

@ -1,9 +1,10 @@
//
// FILE: RunningAverage.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.2.16
// VERSION: 0.3.1
// DATE: 2015-July-10
// PURPOSE: RunningAverage library for Arduino
// PURPOSE: Arduino library to calculate the running average by means of a circular buffer
// URL: https://github.com/RobTillaart/RunningAverage
//
// The library stores N individual values in a circular buffer,
// to calculate the running average.
@ -31,16 +32,11 @@
// 0.2.14 - 2020-01-15 added getValue(n) to retrieve elements in order of addition - see issue #132
// 0.2.15 - 2020-01-17 fix overflow in getValue - see issue #139
// 0.2.16 2020-04-16 improve _sum - see issue #149 (bourkemcrobbo)
//
// Released to the public domain
//
// 0.3.0 2020-04-16 main refactor
// 0.3.1 2020-06-19 fix library.json; minor refactor
#include "RunningAverage.h"
#include <stdlib.h>
#include <math.h>
RunningAverage::RunningAverage(const uint8_t size)
{
_size = size;
@ -62,9 +58,9 @@ void RunningAverage::clear()
_sum = 0.0;
_min = NAN;
_max = NAN;
for (uint8_t i = 0; i < _size; i++)
for (uint8_t i = _size; i > 0; )
{
_ar[i] = 0.0; // keeps addValue simpler
_ar[--i] = 0.0; // keeps addValue simpler
}
}
@ -99,14 +95,15 @@ float RunningAverage::getAverage()
{
_sum += _ar[i];
}
return _sum / _cnt;
return _sum / _cnt; // multiplication is faster ==> extra admin
}
// the larger the size of the internal buffer the greater the gain wrt getAverage()
float RunningAverage::getFastAverage() const
{
if (_cnt == 0) return NAN;
return _sum / _cnt;
return _sum / _cnt; // multiplication is faster ==> extra admin
}
// returns the minimum value in the buffer
@ -147,7 +144,7 @@ float RunningAverage::getElement(uint8_t idx) const
// Return standard deviation of running average. If buffer is empty, return NAN.
float RunningAverage::getStandardDeviation() const
{
if (_cnt == 0) return NAN;
if (_cnt <= 1) return NAN;
float temp = 0;
float average = getFastAverage();
@ -166,26 +163,29 @@ float RunningAverage::getStandardError() const //++
float temp = getStandardDeviation();
if (temp == NAN) return NAN;
if (_cnt <= 1) return NAN;
float n;
if (_cnt >= 30) n = _cnt;
else n = _cnt - 1; // TODO fails if _cnt == 0
temp = temp/sqrt(n); // TODO fails if _cnt == 1
else n = _cnt - 1;
temp = temp/sqrt(n);
return temp;
}
// fill the average with a value
// the param number determines how often value is added (weight)
// number should preferably be between 1 and size
// 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)
{
clear();
for (uint8_t i = 0; i < number; i++)
uint8_t s = number;
if (s > _size) s = _size;
for (uint8_t i = s; i > 0; i--)
{
addValue(value);
}
// NOTE: the clear iterates over the buffer,
// so merging the clear loop could gain some performance.
}
float RunningAverage::getValue(const uint8_t idx)
@ -196,4 +196,5 @@ float RunningAverage::getValue(const uint8_t idx)
if (pos >= _cnt) pos -= _cnt;
return _ar[pos];
}
// END OF FILE
// -- END OF FILE --

View File

@ -1,23 +1,16 @@
#pragma once
//
// FILE: RunningAverage.h
// AUTHOR: Rob.Tillaart@gmail.com
// VERSION: 0.2.16
// VERSION: 0.3.1
// DATE: 2016-dec-01
// PURPOSE: RunningAverage library for Arduino
// URL: https://github.com/RobTillaart/Arduino/tree/master/libraries/RunningAverage
// PURPOSE: Arduino library to calculate the running average by means of a circular buffer
// URL: https://github.com/RobTillaart/RunningAverage
//
// HISTORY: See RunningAverage.cpp
//
// Released to the public domain
//
// backwards compatibility
// clr() clear()
// add(x) addValue(x)
// avg() getAverage()
#ifndef RunningAverage_h
#define RunningAverage_h
#define RUNNINGAVERAGE_LIB_VERSION "0.2.16"
#define RUNNINGAVERAGE_LIB_VERSION "0.3.1"
#include "Arduino.h"
@ -25,7 +18,7 @@ class RunningAverage
{
public:
RunningAverage(void);
explicit RunningAverage(const uint8_t);
explicit RunningAverage(const uint8_t size);
~RunningAverage();
void clear();
@ -34,7 +27,7 @@ public:
float getValue(const uint8_t);
float getAverage(); // iterates over all elements.
float getFastAverage() const; // reuses previous values.
float getFastAverage() const; // reuses previous calculated values.
// return statistical characteristics of the running average
float getStandardDeviation() const;
@ -57,7 +50,6 @@ public:
uint8_t getCount() const { return _cnt; }
protected:
uint8_t _size;
uint8_t _cnt;
@ -68,5 +60,4 @@ protected:
float _max;
};
#endif
// END OF FILE
// -- END OF FILE --

View File

@ -1,9 +1,9 @@
//
// FILE: fillValue.pde
// FILE: fillValue.ino
// AUTHOR: Rob Tillaart
// DATE: 2012-12-30
//
// PUPROSE: show working of fillValue
// PUPROSE: demo + timing of fillValue
//
#include "RunningAverage.h"
@ -11,20 +11,29 @@
RunningAverage myRA(10);
int samples = 0;
uint32_t start, stop;
void setup(void)
{
Serial.begin(115200);
Serial.print("Demo RunningAverage lib - fillValue ");
Serial.print("Version: ");
Serial.println(RUNNINGAVERAGE_LIB_VERSION);
myRA.fillValue(100,5);
delay(10);
for (int i = 0; i < 15; i++)
{
measure_duration(i);
}
Serial.println();
}
void loop(void)
{
long rn = random(0, 100);
myRA.addValue(rn/100.0);
myRA.addValue(rn / 100.0);
samples++;
Serial.print("Running Average: ");
Serial.println(myRA.getAverage(), 4);
@ -35,4 +44,18 @@ void loop(void)
myRA.fillValue(100, 10);
}
delay(100);
}
}
void measure_duration(int n)
{
start = micros();
myRA.fillValue(100, n);
stop = micros();
Serial.print("fillValue(100, ");
Serial.print(n);
Serial.print("): ");
Serial.println(stop - start);
delay(10);
}
// -- END OF FILE --

View File

@ -1,7 +1,7 @@
//
// FILE: ra_FastAverageTest.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// VERSION: 0.2.0
// DATE: 2015-sep-04
//
// PUPROSE: demo to see if different average algorithm give different result
@ -9,11 +9,15 @@
#include "RunningAverage.h"
RunningAverage myRA(10);
uint32_t samples = 0;
RunningAverage myRA(16);
float avg = 0;
float favg = 0;
float diff = 0;
float maxDiff = 0;
uint32_t start, stop;
void setup(void)
{
Serial.begin(115200);
@ -23,37 +27,67 @@ void setup(void)
Serial.println(RUNNINGAVERAGE_LIB_VERSION);
myRA.clear(); // explicitly start clean
Serial.println("\nCNT\tAVG\tFASTAVG");
measure_duration();
}
void loop(void)
void loop()
{
long rn = random(0, 1000);
myRA.addValue(rn * 0.001);
samples++;
//
float avg = myRA.getAverage();
float favg = myRA.getFastAverage();
float diff = abs(avg - favg);
boolean pr = (samples % 10000 == 0);
if (maxDiff < diff)
{
maxDiff = diff;
pr = true;
}
if (pr)
{
Serial.print(samples);
Serial.print("\t");
Serial.print(avg, 7);
Serial.print("\t");
Serial.print(favg, 7);
Serial.print("\t");
Serial.print(diff, 7);
Serial.print("\t");
Serial.print(maxDiff, 7);
Serial.println();
}
test(1000000);
}
void measure_duration()
{
myRA.fillValue(100, 16);
start = micros();
favg = myRA.getFastAverage();
stop = micros();
Serial.print("getFastAverage: ");
Serial.println(stop - start);
delay(10);
myRA.fillValue(100, 16);
start = micros();
favg = myRA.getAverage();
stop = micros();
Serial.print(" getAverage: ");
Serial.println(stop - start);
delay(10);
Serial.println();
}
void test(long n)
{
Serial.println("\nCNT\tAVG\t\tFASTAVG\t\tDIFF\t\tMAXDIFF");
for (long i = 0; i < n; i++)
{
long rn = random(0, 1000);
myRA.addValue(rn * 0.001);
if ( i % 1000 == 0)
{
// the order of the next two lines is important as getAverage() resets the _sum
// used by the getFastAverage();
favg = myRA.getFastAverage();
avg = myRA.getAverage();
diff = abs(avg - favg);
if (diff > maxDiff) maxDiff = diff;
Serial.print(i);
Serial.print("\t");
Serial.print(avg, 7);
Serial.print("\t");
Serial.print(favg, 7);
Serial.print("\t");
Serial.print(diff, 7);
Serial.print("\t");
Serial.print(maxDiff, 7);
Serial.println();
}
}
delay(100);
}
// -- END OF FILE --

View File

@ -66,4 +66,4 @@ void loop(void)
delay(1000);
}
// END OF FILE
// -- END OF FILE --

View File

@ -0,0 +1,221 @@
//
// FILE: ra_performance.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// DATE: 2020-04-16
//
// PUPROSE: timing of runningAverage
//
#include "RunningAverage.h"
RunningAverage myRA(50);
int samples = 0;
uint32_t start, stop;
volatile float x;
void setup(void)
{
Serial.begin(115200);
Serial.print("\nPerformance RunningAverage lib: ");
Serial.println(RUNNINGAVERAGE_LIB_VERSION);
Serial.println();
myRA.clear(); // explicitly start clean
for (int i = 0; i < 10; i++)
{
myRA.addValue(random(1000) * 0.001);
}
test_clear();
test_addvalue();
test_fillValue();
test_getValue();
test_getAverage();
test_getFastAverage();
test_getStandardDeviation();
test_getStandardError();
test_getMin();
test_getMax();
test_getMinInBuffer();
test_getMaxInBuffer();
test_bufferIsFull();
test_getElement();
test_getSize();
test_getCount();
Serial.println("\ndone...\n");
}
void test_clear(void)
{
start = micros();
myRA.clear();
stop = micros();
Serial.print("\tclear \t\t: ");
Serial.println(stop - start);
delay(10);
}
void test_addvalue()
{
start = micros();
myRA.addValue(3.1415);
stop = micros();
Serial.print("\taddValue \t: ");
Serial.println(stop - start);
delay(10);
}
void test_fillValue()
{
start = micros();
myRA.fillValue(1.235, 50);
stop = micros();
Serial.print("\tfillValue \t: ");
Serial.println(stop - start);
delay(10);
}
void test_getValue()
{
start = micros();
x = myRA.getValue(4);
stop = micros();
Serial.print("\tgetValue \t: ");
Serial.println(stop - start);
delay(10);
}
void test_getAverage()
{
start = micros();
x = myRA.getAverage();
stop = micros();
Serial.print("\tgetAverage \t: ");
Serial.println(stop - start);
delay(10);
}
void test_getFastAverage()
{
start = micros();
x = myRA.getFastAverage();
stop = micros();
Serial.print("\tgetFastAverage \t: ");
Serial.println(stop - start);
delay(10);
}
void test_getStandardDeviation()
{
start = micros();
x = myRA.getStandardDeviation();
stop = micros();
Serial.print("\tgetStandardDeviation \t: ");
Serial.println(stop - start);
delay(10);
}
void test_getStandardError()
{
start = micros();
x = myRA.getStandardError();
stop = micros();
Serial.print("\tgetStandardError \t: ");
Serial.println(stop - start);
delay(10);
}
void test_getMin()
{
start = micros();
x = myRA.getMin();
stop = micros();
Serial.print("\tgetMin \t\t: ");
Serial.println(stop - start);
delay(10);
}
void test_getMax()
{
start = micros();
x = myRA.getMax();
stop = micros();
Serial.print("\tgetMax \t\t: ");
Serial.println(stop - start);
delay(10);
}
void test_getMinInBuffer()
{
start = micros();
x = myRA.getMinInBuffer();
stop = micros();
Serial.print("\tgetMinInBuffer \t: ");
Serial.println(stop - start);
delay(10);
}
void test_getMaxInBuffer()
{
start = micros();
x = myRA.getMaxInBuffer();
stop = micros();
Serial.print("\tgetMaxInBuffer \t: ");
Serial.println(stop - start);
delay(10);
}
void test_bufferIsFull()
{
start = micros();
x = myRA.bufferIsFull();
stop = micros();
Serial.print("\tbufferIsFull \t: ");
Serial.println(stop - start);
delay(10);
}
void test_getElement()
{
start = micros();
x = myRA.getElement(4);
stop = micros();
Serial.print("\tgetElement \t: ");
Serial.println(stop - start);
delay(10);
}
void test_getSize()
{
start = micros();
x = myRA.getSize();
stop = micros();
Serial.print("\tgetSize \t: ");
Serial.println(stop - start);
delay(10);
}
void test_getCount()
{
start = micros();
x = myRA.getCount();
stop = micros();
Serial.print("\tgetCount \t: ");
Serial.println(stop - start);
delay(10);
}
void loop()
{
}
// -- END OF FILE --

View File

@ -13,12 +13,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/RunningAverage.git"
},
"version": "0.2.16",
"version": "0.3.1",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/RunningAverage"
}
"platforms": "*"
}

View File

@ -1,11 +1,11 @@
name=RunningAverage
version=0.2.16
version=0.3.1
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.
paragraph=Supports min max average
category=Data Processing
url=https://github.com/RobTillaart/Arduino
url=https://github.com/RobTillaart/RunningAverage
architectures=*
includes=RunningAverage.h
includes=RunningAverager.h
depends=

View File

@ -0,0 +1,28 @@
--------------------------------------
Arduino UNO
IDE 1.8.12
Performance RunningAverage lib: 0.3.0
clear : 80
addValue : 24
fillValue : 1548
getValue : 4
getAverage : 512
getFastAverage : 36
getStandardDeviation : 1832
getStandardError : 1896
getMin : 4
getMax : 4
getMinInBuffer : 212
getMaxInBuffer : 204
bufferIsFull : 8
getElement : 4
getSize : 8
getCount : 8
done...
--------------------------------------

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2011-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,24 @@
# RunningMedian
Arduino library to determine the running median by means of a circular buffer.
## Description
Running Median looks like a running average with a small but important twist.
Running average averages the last N samples while the running median takes
the last N samples, sort them and take the middle one, or the average of the middle two.
Important differences between running average and running median:
- Running median will return real data (e.g. a real sample from a sensor)
if one uses an odd size of the buffer (preferred).
Running average may return a value that is never sampled.
- Running median will give zero weight to outliers, and 100% to the middle sample,
whereas running average gives the same weight to all samples.
- Running median will give often constant values for some time.
- As one knows the values in the buffer one can predict to some extend how much
the next samples will change the running median.
- Running median is a bit harder as one needs to keep the values in order
to remove the oldest and keep them sorted to be able to select the median.
## Operation
See examples

View File

@ -1,7 +1,7 @@
//
// FILE: RunningMedian.cpp
// AUTHOR: Rob.Tillaart at gmail.com
// VERSION: 0.1.15
// VERSION: 0.2.1
// PURPOSE: RunningMedian library for Arduino
//
// HISTORY:
@ -21,9 +21,8 @@
// 0.1.13 - 2015-10-30 fix getElement(n) - kudos to Gdunge
// 0.1.14 - 2017-07-26 revert double to float - issue #33
// 0.1.15 - 2018-08-24 make runningMedian Configurable #110
//
// Released to the public domain
//
// 0.2.0 2020-04-16 refactor.
// 0.2.1 2020-06-19 fix library.json
#include "RunningMedian.h"
@ -53,7 +52,10 @@ void RunningMedian::clear()
_cnt = 0;
_idx = 0;
_sorted = false;
for (uint8_t i = 0; i < _size; i++) _p[i] = i;
for (uint8_t i = 0; i < _size; i++)
{
_p[i] = i;
}
}
// adds a new value to the data-set
@ -72,17 +74,40 @@ float RunningMedian::getMedian()
if (_sorted == false) sort();
if (_cnt & 0x01) return _ar[_p[_cnt/2]];
else return (_ar[_p[_cnt/2]] + _ar[_p[_cnt/2 - 1]]) / 2;
if (_cnt & 0x01) // is it odd sized?
{
return _ar[_p[_cnt / 2]];
}
return (_ar[_p[_cnt / 2]] + _ar[_p[_cnt / 2 - 1]]) / 2;
}
float RunningMedian::getQuantile(float q)
{
if (_cnt == 0) return NAN;
if ((q < 0) || (q > 1)) return NAN;
if (_sorted == false) sort();
const float id = (_cnt - 1) * q;
const uint8_t lo = floor(id);
const uint8_t hi = ceil(id);
const float qs = _ar[_p[lo]];
const float h = (id - lo);
return (1.0 - h) * qs + h * _ar[_p[hi]];
}
#ifdef RUNNING_MEDIAN_ALL
float RunningMedian::getAverage()
{
if (_cnt == 0) return NAN;
float sum = 0;
for (uint8_t i=0; i< _cnt; i++) sum += _ar[i];
for (uint8_t i = 0; i < _cnt; i++)
{
sum += _ar[i];
}
return sum / _cnt;
}
@ -97,7 +122,10 @@ float RunningMedian::getAverage(uint8_t nMedians)
if (_sorted == false) sort();
float sum = 0;
for (uint8_t i = start; i < stop; i++) sum += _ar[_p[i]];
for (uint8_t i = start; i < stop; i++)
{
sum += _ar[_p[i]];
}
return sum / nMedians;
}
@ -124,34 +152,30 @@ float RunningMedian::getSortedElement(const uint8_t n)
// n can be max <= half the (filled) size
float RunningMedian::predict(const uint8_t n)
{
if ((_cnt == 0) || (n >= _cnt/2)) return NAN;
if ((_cnt == 0) || (n >= _cnt / 2)) return NAN;
float med = getMedian(); // takes care of sorting !
if (_cnt & 0x01)
{
return max(med - _ar[_p[_cnt/2-n]], _ar[_p[_cnt/2+n]] - med);
}
else
{
float f1 = (_ar[_p[_cnt/2 - n]] + _ar[_p[_cnt/2 - n - 1]])/2;
float f2 = (_ar[_p[_cnt/2 + n]] + _ar[_p[_cnt/2 + n - 1]])/2;
return max(med - f1, f2 - med)/2;
return max(med - _ar[_p[_cnt / 2 - n]], _ar[_p[_cnt / 2 + n]] - med);
}
float f1 = (_ar[_p[_cnt / 2 - n]] + _ar[_p[_cnt / 2 - n - 1]]) / 2;
float f2 = (_ar[_p[_cnt / 2 + n]] + _ar[_p[_cnt / 2 + n - 1]]) / 2;
return max(med - f1, f2 - med) / 2;
}
#endif
void RunningMedian::sort()
{
// bubble sort with flag
for (uint8_t i = 0; i < _cnt-1; i++)
for (uint8_t i = 0; i < _cnt - 1; i++)
{
bool flag = true;
for (uint8_t j = 1; j < _cnt-i; j++)
for (uint8_t j = 1; j < _cnt - i; j++)
{
if (_ar[_p[j-1]] > _ar[_p[j]])
if (_ar[_p[j - 1]] > _ar[_p[j]])
{
uint8_t t = _p[j-1];
_p[j-1] = _p[j];
uint8_t t = _p[j - 1];
_p[j - 1] = _p[j];
_p[j] = t;
flag = false;
}
@ -161,4 +185,4 @@ void RunningMedian::sort()
_sorted = true;
}
// END OF FILE
// -- END OF FILE --

View File

@ -1,72 +1,66 @@
#pragma once
//
// FILE: RunningMedian.h
// AUTHOR: Rob dot Tillaart at gmail dot com
// PURPOSE: RunningMedian library for Arduino
// VERSION: 0.1.15
// VERSION: 0.2.1
// URL: https://github.com/RobTillaart/RunningMedian
// URL: http://arduino.cc/playground/Main/RunningMedian
// HISTORY: See RunningMedian.cpp
//
// Released to the public domain
//
#ifndef RunningMedian_h
#define RunningMedian_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <inttypes.h>
#define RUNNING_MEDIAN_VERSION "0.1.15"
#define RUNNING_MEDIAN_VERSION "0.2.1"
// prepare for dynamic version
// not tested use at own risk :)
// #define RUNNING_MEDIAN_USE_MALLOC
// conditional compile to minimize lib
// by removeing a lot of functions.
#ifndef RUNNING_MEDIAN_ALL
#define RUNNING_MEDIAN_ALL
#endif
// not tested ==> use at own risk :)
#define RUNNING_MEDIAN_USE_MALLOC
// should at least be 5 to be practical
// odd size results in a 'real' middle element.
// even size takes the lower of the two middle elements
#ifndef MEDIAN_MIN_SIZE
#define MEDIAN_MIN_SIZE 1
#endif
#ifndef MEDIAN_MAX_SIZE
#define MEDIAN_MAX_SIZE 19 // adjust if needed
#endif
// should at least be 5 to be practical,
// odd sizes results in a 'real' middle element and will be a bit faster.
// even sizes takes the average of the two middle elements as median
#define MEDIAN_MIN_SIZE 5
#define MEDIAN_MAX_SIZE 19
class RunningMedian
{
public:
explicit RunningMedian(const uint8_t size); // # elements in the internal buffer
~RunningMedian(); // destructor
// # elements in the internal buffer
explicit RunningMedian(const uint8_t size);
~RunningMedian();
void clear(); // resets internal buffer and var
void add(const float value); // adds a new value to internal buffer, optionally replacing the oldest element.
float getMedian(); // returns the median == middle element
// resets internal buffer and var
void clear();
// adds a new value to internal buffer, optionally replacing the oldest element.
void add(const float value);
// returns the median == middle element
float getMedian();
// returns the Quantile
float getQuantile(const float q);
// returns average of the values in the internal buffer
float getAverage();
// returns average of the middle nMedian values, removes noise from outliers
float getAverage(uint8_t nMedian);
#ifdef RUNNING_MEDIAN_ALL
float getAverage(); // returns average of the values in the internal buffer
float getAverage(uint8_t nMedian); // returns average of the middle nMedian values, removes noise from outliers
float getHighest() { return getSortedElement(_cnt - 1); };
float getLowest() { return getSortedElement(0); };
float getElement(const uint8_t n); // get n'th element from the values in time order
float getSortedElement(const uint8_t n); // get n'th element from the values in size order
float predict(const uint8_t n); // predict the max change of median after n additions
// get n'th element from the values in time order
float getElement(const uint8_t n);
// get n'th element from the values in size order
float getSortedElement(const uint8_t n);
// predict the max change of median after n additions
float predict(const uint8_t n);
uint8_t getSize() { return _size; };
// returns current used elements, getCount() <= getSize()
uint8_t getCount() { return _cnt; };
uint8_t getSize() { return _size; }; // returns size of internal buffer
uint8_t getCount() { return _cnt; }; // returns current used elements, getCount() <= getSize()
#endif
protected:
boolean _sorted;
@ -84,5 +78,4 @@ protected:
void sort();
};
#endif
// END OF FILE

View File

@ -1,18 +1,15 @@
//
// FILE: RunningMedian.ino
// AUTHOR: Rob Tillaart ( kudos to Sembazuru)
// VERSION: 0.1.01
// PURPOSE: demo
// VERSION: 0.1.2
// PURPOSE: demo basic usage
// DATE: 2013-10-17
// URL:
//
// Released to the public domain
// URL: https://github.com/RobTillaart/RunningMedian
//
#include <RunningMedian.h>
RunningMedian samples = RunningMedian(5);
RunningMedian samples2 = RunningMedian(9);
void setup()
{
@ -50,3 +47,4 @@ void test1()
delay(100);
}
// -- END OF FILE --

View File

@ -1,12 +1,10 @@
//
// FILE: RunningMedian2.ino
// AUTHOR: Rob Tillaart ( kudos to Sembazuru)
// VERSION: 0.1.01
// PURPOSE: demo
// VERSION: 0.1.2
// PURPOSE: demo most functions
// DATE: 2013-10-17
// URL:
//
// Released to the public domain
// URL: https://github.com/RobTillaart/RunningMedian
//
#include "RunningMedian.h"
@ -29,7 +27,10 @@ void loop()
void test1()
{
if (count % 20 == 0) Serial.println(F("\nmsec \tAnR \tSize \tCnt \tLow \tAvg \tAvg(7) \tAvg(3) \tMed \tHigh \tPre(1) \tPre(2)"));
if (count % 20 == 0)
{
Serial.println(F("\nmsec \tAnR \tSize \tCnt \tLow \tAvg \tAvg(7) \tAvg(3) \tMed \tHigh \tPre(1) \tPre(2)"));
}
count++;
long x = analogRead(A0);

View File

@ -0,0 +1,40 @@
//
// FILE: RunningMedianQuantileTest.ino
// AUTHOR: f-s ( derived from Rob Tillaart )
// VERSION: 0.1.2
// PURPOSE: demo basic quantile usage
// DATE: 2020-09-02
// URL: https://github.com/RobTillaart/RunningMedian
//
#include <RunningMedian.h>
RunningMedian samples = RunningMedian(5);
void setup()
{
Serial.begin(115200);
Serial.print("Running Median Version: ");
Serial.println(RUNNING_MEDIAN_VERSION);
}
void loop()
{
test1();
}
void test1()
{
int x = analogRead(A0);
samples.add(x);
// calculate the 5% quantile => 0.05
long q = samples.getQuantile(0.05);
Serial.print(millis());
Serial.print("\t");
Serial.println(q);
delay(100);
}
// -- END OF FILE --

View File

@ -1,15 +1,11 @@
//
// FILE: runningMedianTest1.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// VERSION: 0.1.1
// PURPOSE: test functionality
// DATE: 2013-10-28
// URL:
// URL: https://github.com/RobTillaart/RunningMedian
//
// Released to the public domain
//
// RunningMedianTest1.ino
#include <RunningMedian.h>
@ -32,135 +28,136 @@ void setup()
delay(1000); // Simply to allow time for the ERW versions of the IDE time to automagically open the Serial Monitor. 1 second chosen arbitrarily.
Serial.print(F("Running Median Version: "));
Serial.println(RUNNING_MEDIAN_VERSION);
#ifdef RUNNING_MEDIAN_ALL
Serial.println(F("All methods available"));
#else
Serial.println(F("Only constructor, destructor, clear(), add(), and getMedian() available"));
#endif
#ifdef RUNNING_MEDIAN_USE_MALLOC
Serial.println(F("Dynamic version using malloc() enabled"));
#else
Serial.print(F("Static version, will always allocate an array of "));
Serial.print(MEDIAN_MAX_SIZE,DEC);
Serial.print(MEDIAN_MAX_SIZE, DEC);
Serial.println(F(" floats."));
#endif
test1();
Serial.println("\ndone..\n");
}
void loop()
{
test1();
while (1);
}
void test1()
{
unsigned long timerStart = 0;
unsigned long timerStop = 0;
float resultFLOAT = 0;
byte resultBYTE = 0;
uint32_t start = 0;
uint32_t stop = 0;
float result = 0;
Serial.print(F("Requested median array size = "));
Serial.println(sourceSize,DEC);
Serial.print(F("Actual allocated size = "));
Serial.println(samples.getSize(),DEC);
Serial.println(sourceSize);
Serial.print(F(" Actual allocated size = "));
Serial.println(samples.getSize());
Serial.println();
for(byte i = 0; i <= (sourceSize - 1); i++)
// 50 iterations !!
for (uint8_t i = 0; i <= (sourceSize - 1); i++)
{
Serial.print(F("Loop number "));
Serial.println((i + 1),DEC);
Serial.print(F("Loop number : "));
Serial.println(i + 1);
timerStart = micros();
start = micros();
samples.add(sourceData[i]);
timerStop = micros();
stop = micros();
Serial.print(F("Time to add the next element to the array = "));
Serial.print(timerStop - timerStart);
Serial.println(F(" microseconds."));
Serial.println(stop - start);
Serial.println(F("Cumulative source data added:"));
Serial.print(F(" "));
for(byte j = 0; j <= i; j++)
for (uint8_t j = 0; j <= i; j++)
{
Serial.print(sourceData[j]);
Serial.print(F(" "));
}
Serial.println();
Serial.println(F("Unsorted accumulated array:"));
Serial.print(F(" "));
for(byte j = 0; j < samples.getCount(); j++)
for (uint8_t j = 0; j < samples.getCount(); j++)
{
Serial.print(samples.getElement(j));
Serial.print(F(" "));
}
Serial.println();
timerStart = micros();
resultFLOAT = samples.getSortedElement(0);
timerStop = micros();
start = micros();
result = samples.getSortedElement(0);
stop = micros();
Serial.print(F("Time to sort array and return element number zero = "));
Serial.print(timerStop - timerStart);
Serial.println(F(" microseconds."));
Serial.println(stop - start);
Serial.println(F("Sorted accumulated array:"));
Serial.print(F(" "));
for(byte j = 0; j < samples.getCount(); j++)
for (uint8_t j = 0; j < samples.getCount(); j++)
{
Serial.print(samples.getSortedElement(j));
Serial.print(F(" "));
}
Serial.println();
timerStart = micros();
resultFLOAT = samples.getMedian();
timerStop = micros();
Serial.print(F("getMedian() result = "));
Serial.println(resultFLOAT);
Serial.print(F("Time to execute getMedian() = "));
Serial.print(timerStop - timerStart);
Serial.println(F(" microseconds."));
timerStart = micros();
resultFLOAT = samples.getAverage();
timerStop = micros();
start = micros();
result = samples.getMedian();
stop = micros();
Serial.print(F("getMedian() result = "));
Serial.println(result);
Serial.print(F("Time to execute getMedian() = "));
Serial.println(stop - start);
start = micros();
result = samples.getAverage();
stop = micros();
Serial.print(F("getAverage() result = "));
Serial.println(resultFLOAT);
Serial.println(result);
Serial.print(F("Time to execute getAverage() = "));
Serial.print(timerStop - timerStart);
Serial.println(F(" microseconds."));
Serial.println(stop - start);
Serial.println(F("getAverage(x) results where:"));
for(byte j = 1; j <= samples.getCount(); j++)
for (uint8_t j = 1; j <= samples.getCount(); j++)
{
timerStart = micros();
resultFLOAT = samples.getAverage(j);
timerStop = micros();
start = micros();
result = samples.getAverage(j);
stop = micros();
Serial.print(F(" x = "));
Serial.print(j);
Serial.print(F(" => "));
Serial.print(resultFLOAT);
Serial.print(result);
Serial.print(F(" Time to execute = "));
Serial.print(timerStop - timerStart);
Serial.println(F(" microseconds."));
Serial.println(stop - start);
}
Serial.println(F("predict(x) results where:"));
for(byte j = 1; j <= (samples.getCount() / 2); j++)
for (uint8_t j = 1; j <= (samples.getCount() / 2); j++)
{
timerStart = micros();
resultFLOAT = samples.predict(j);
timerStop = micros();
start = micros();
result = samples.predict(j);
stop = micros();
Serial.print(F(" x = "));
Serial.print(j);
Serial.print(F(" => "));
Serial.print(resultFLOAT);
Serial.print(result);
Serial.print(F(" Time to execute = "));
Serial.print(timerStop - timerStart);
Serial.println(F(" microseconds."));
Serial.println(stop - start);
}
Serial.println();
Serial.println();
}
}
}
// -- END OF FILE --

View File

@ -1,21 +1,13 @@
#######################################
# Syntax Coloring Map for RunningMedian
# "traditional" and template variant
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
RunningMedian KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
add KEYWORD2
clear KEYWORD2
getMedian KEYWORD2
getQuantile KEYWORD2
getAverage KEYWORD2
getHighest KEYWORD2
getLowest KEYWORD2
@ -26,8 +18,6 @@ getSortedElement KEYWORD2
predict KEYWORD2
getStatus KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
OK LITERAL1
NOK LITERAL1

View File

@ -1,6 +1,6 @@
{
"name": "RunningMedian",
"keywords": "running,moving,median,average,outliers",
"keywords": "running, moving, median, average, outliers",
"description": "The library stores the last N individual values in a buffer to select the median. It filters outliers.",
"authors":
[
@ -13,12 +13,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/RunningMedian.git"
},
"version":"0.1.15",
"version":"0.2.1",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/RunningMedian"
}
"platforms": "*"
}

View File

@ -1,9 +1,11 @@
name=RunningMedian
version=0.1.15
version=0.2.1
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 buffer to select the median.
paragraph=This way it filters outliers.
paragraph=This will filter outliers in a chain of samples very well.
category=Data Processing
url=https://github.com/RobTillaart/Arduino/tree/master/libraries/
architectures=*
url=https://github.com/RobTillaart/RunningMedian
architectures=*
includes=RunningMedian.h
depends=

21
libraries/SHT31/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

25
libraries/SHT31/README.md Normal file
View File

@ -0,0 +1,25 @@
# SHT31
Arduino library for the SHT31 temperature and humidity sensor
# Description
The SHT3x family of sensors should work up to 1 MHz I2C
This library should also work for SHT30 and SHT35 but these are
not tested yet.
| SENSOR | Temperature accuracy | Humidity accuracy |
|:----:|:----:|:----:|
| SHT30 | ~0.3 | 2 |
| SHT31 | ~0.3 | 1.5 |
| SHT35 | ~0.2 | 1.5 |
An elaborated library for the SHT31 sensor can be found here
https://github.com/hawesg/SHT31D_Particle_Photon_ClosedCube
# Operation
See examples

View File

@ -1,29 +1,36 @@
//
// FILE: SHT31.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.2
// VERSION: 0.2.2
// DATE: 2019-02-08
// PURPOSE: Class for SHT31 I2C temperature humidity sensor
// PURPOSE: Arduino library for the SHT31 temperature and humidity sensor
// https://www.adafruit.com/product/2857
// URL: https://github.com/RobTillaart/SHT31
//
// HISTORY:
// 0.1.0 - 2019-02-08 initial version
// 0.1.1 - 2019-02-18 add description readStatus(),
// 0.1.0 2019-02-08 initial version
// 0.1.1 2019-02-18 add description readStatus(),
// async interface
// 0.1.2 - 2019-03-05 fix issue #123 - error in humidity
// 0.1.2 2019-03-05 fix issue #123 - error in humidity
// stable version
//
// Released to the public domain
//
// 0.2.0 2020-05-12 made humidity & temperature private;
// support ESP32 I2C
// 0.2.1 2020-06-19 fix library.json
// 0.2.2 2020-07-05 fix compiling for ESP
#include "SHT31.h"
// SUPPORTED COMMANDS - single shot mode only
#define SHT31_READ_STATUS 0xF32D
#define SHT31_CLEAR_STATUS 0x3041
#define SHT31_SOFT_RESET 0x30A2
#define SHT31_HARD_RESET 0x0006
#define SHT31_MEASUREMENT_FAST 0x2416
#define SHT31_MEASUREMENT_SLOW 0x2400
#define SHT31_MEASUREMENT_FAST 0x2416 // page 10 datasheet
#define SHT31_MEASUREMENT_SLOW 0x2400 // no clock stretching
#define SHT31_HEAT_ON 0x306D
#define SHT31_HEAT_OFF 0x3066
@ -34,58 +41,57 @@ SHT31::SHT31()
_lastRead = 0;
temperature = 0;
humidity = 0;
_heaterStart = 0;
}
bool SHT31::begin(const uint8_t address)
#if defined(ESP8266) || defined(ESP32)
bool SHT31::begin(const uint8_t address, const uint8_t dataPin, const uint8_t clockPin)
{
if (address != 0x44 && address != 0x45) return false;
_addr = address;
_wire = &Wire;
if ((dataPin < 255) && (clockPin < 255))
{
_wire->begin(dataPin, clockPin);
} else {
_wire->begin();
}
reset();
return true;
}
#endif
bool SHT31::begin(const uint8_t address)
{
return begin(address, &Wire);
}
bool SHT31::begin(const uint8_t address, TwoWire *wire)
{
if (address != 0x44 && address != 0x45) return false;
_addr = address;
_wire = wire;
_wire->begin();
reset();
return true;
}
bool SHT31::read(bool fast)
{
bool rv = true;
uint8_t buffer[6];
if (fast)
{
writeCmd(SHT31_MEASUREMENT_FAST);
delay(4); // table 4 datasheet
}
else
{
writeCmd(SHT31_MEASUREMENT_SLOW);
delay(15); // table 4 datasheet
}
// TODO 5 read bytes would be sufficient when not fast / no CRC...
readBytes(6, (uint8_t*) &buffer[0]);
if (!fast)
{
// TODO check CRC here
// TODO rv = false;
}
uint16_t raw = (buffer[0] << 8) + buffer[1];
temperature = raw * (175.0 / 65535) - 45;
raw = (buffer[3] << 8) + buffer[4];
humidity = raw * (100.0 / 65535);
_lastRead = millis();
return rv;
writeCmd(fast ? SHT31_MEASUREMENT_FAST : SHT31_MEASUREMENT_SLOW);
delay(fast ? 4 : 15); // table 4 datasheet
return readData(fast);
}
uint16_t SHT31::readStatus()
{
uint32_t status = 0;
writeCmd(SHT31_READ_STATUS); // page 13 datasheet
readBytes(3, (uint8_t*) &status); // 16 bit status + CRC
// TODO CRC check
return status;
return (uint16_t) (status >> 8);
// bit - description
// ==================
@ -106,7 +112,7 @@ uint16_t SHT31::readStatus()
// 9:5 Reserved '00000
// 4 System reset detected
// '0': no reset since last clear status register command
// '1': reset detected (hard or soft reset command or supply fail)
// '1': reset detected (hard or soft reset command or supply fail) - default
// 3:2 Reserved 00
// 1 Command status
// '0': last cmd executed successfully
@ -116,20 +122,42 @@ uint16_t SHT31::readStatus()
// '1': checksum of last write transfer failed
}
void SHT31::reset()
void SHT31::reset(bool hard)
{
writeCmd(SHT31_SOFT_RESET); // SHT31_HARD_RESET not implemented yet
delay(1); // table 4 datasheet // 100ms for hardreset
if (hard)
{
writeCmd(SHT31_HARD_RESET);
} else {
writeCmd(SHT31_SOFT_RESET);
}
delay(1); // table 4 datasheet
}
void SHT31::setHeatTimeout(uint8_t seconds)
{
_heatTimeOut = seconds;
if (_heatTimeOut > 180) _heatTimeOut = 180;
}
void SHT31::heatOn()
{
writeCmd(SHT31_HEAT_ON);
_heaterStart = millis();
}
void SHT31::heatOff()
{
writeCmd(SHT31_HEAT_OFF);
_heaterStart = 0;
}
bool SHT31::heatUp()
{
if (_heaterStart == 0) return false;
// did not exceed time out
if (millis() - _heaterStart < (_heatTimeOut * 1000UL)) return true;
heatOff();
return false;
}
void SHT31::requestData()
@ -143,35 +171,65 @@ bool SHT31::dataReady()
return ((millis() - _lastRequest) > 15);
}
void SHT31::readData()
bool SHT31::readData(bool fast)
{
uint8_t buffer[6];
readBytes(6, (uint8_t*) &buffer[0]);
float raw = (buffer[0] << 8) + buffer[1];
if (!fast)
{
if (buffer[2] != crc8(buffer, 2) ||
buffer[5] != crc8(buffer + 3, 2))
{
return false;
}
}
uint16_t raw = (buffer[0] << 8) + buffer[1];
temperature = raw * (175.0 / 65535) - 45;
raw = (buffer[3] << 8) + buffer[4];
humidity = raw * (100.0 / 65535);
_lastRead = millis();
return true;
}
//////////////////////////////////////////////////////////
uint8_t SHT31::crc8(const uint8_t *data, int len)
{
// CRC-8 formula from page 14 of SHT spec pdf
const uint8_t POLY(0x31);
uint8_t crc(0xFF);
for (int j = len; j; --j)
{
crc ^= *data++;
for (int i = 8; i; --i)
{
crc = (crc & 0x80) ? (crc << 1) ^ POLY : (crc << 1);
}
}
return crc;
}
void SHT31::writeCmd(uint16_t cmd)
{
Wire.beginTransmission(_addr);
Wire.write(cmd >> 8 );
Wire.write(cmd & 0xFF);
Wire.endTransmission();
_wire->beginTransmission(_addr);
_wire->write(cmd >> 8 );
_wire->write(cmd & 0xFF);
_wire->endTransmission();
}
void SHT31::readBytes(uint8_t n, uint8_t *val)
{
Wire.requestFrom(_addr, (uint8_t) n);
_wire->requestFrom(_addr, (uint8_t) n);
for (uint8_t i = 0; i < n; i++)
{
val[i] = Wire.read();
val[i] = _wire->read();
}
}
// -- END OF FILE --
// -- END OF FILE --

View File

@ -1,61 +1,80 @@
#pragma once
//
// FILE: SHT31.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.2
// VERSION: 0.2.2
// DATE: 2019-02-08
// PURPOSE: Class for SHT31 I2C temperature humidity sensor
// PURPOSE: Arduino library for the SHT31 temperature and humidity sensor
// https://www.adafruit.com/product/2857
// URL: https://github.com/RobTillaart/Arduino.git
// URL: https://github.com/RobTillaart/SHT31
//
// Released to the public domain
//
#ifndef SHT31_h
#define SHT31_h
#include "Arduino.h"
#include "Wire.h"
#define SHT31_LIB_VERSION "0.1.2"
#define SHT31_LIB_VERSION "0.2.2"
// fields readStatus
#define SHT31_STATUS_ALERT_PENDING (1 << 15)
#define SHT31_STATUS_HEATER_ON (1 << 13)
#define SHT31_STATUS_HUM_TRACK_ALERT (1 << 11)
#define SHT31_STATUS_TEMP_TRACK_ALERT (1 << 10)
#define SHT31_STATUS_SYSTEM_RESET (1 << 4)
#define SHT31_STATUS_COMMAND_STATUS (1 << 1)
#define SHT31_STATUS_WRITE_CRC_STATUS (1 << 0)
class SHT31
{
public:
SHT31();
#if defined(ESP8266) || defined(ESP32)
bool begin(const uint8_t address, uint8_t dataPin, uint8_t clockPin);
#endif
bool begin(const uint8_t address);
bool begin(const uint8_t address, TwoWire *wire);
// blocks 15 milliseconds + actual read + math
bool read(bool fast = true);
// details see datasheet
// details see datasheet; summary in SHT31.cpp file
uint16_t readStatus();
// lastRead is in MilliSeconds since start sketch
// lastRead is in milliSeconds since start
uint32_t lastRead() { return _lastRead; };
void reset();
void reset(bool hard = false);
// do not use heater for long periods,
// use it for max 3 minutes to heat up
// and let it cool down an equal period.
void setHeatTimeout(uint8_t seconds);
void heatOn();
void heatOff();
bool heatUp(); // is the sensor still heating up?
float humidity;
float temperature;
float getHumidity() { return humidity; };
float getTemperature() { return temperature; };
// ASYNC INTERFACE
void requestData();
bool dataReady();
void readData();
bool readData(bool fast = true);
private:
uint8_t crc8(const uint8_t *data, int len);
void writeCmd(uint16_t cmd);
void readBytes(uint8_t n, uint8_t *val);
TwoWire* _wire;
uint8_t _addr;
uint8_t _heatTimeOut; // seconds
uint32_t _lastRead;
uint32_t _lastRequest; // for async interface
uint32_t _heaterStart;
float humidity;
float temperature;
};
#endif
// -- END OF FILE --
// -- END OF FILE --

View File

@ -1,10 +1,9 @@
//
// FILE: SHT31_I2Cspeed
// AUTHOR: Rob Tillaart
// VERSION: 0.0.1
// PURPOSE: demo
//
// HISTORY:
// VERSION: 0.0.2
// PURPOSE: testing the performance at different I2C speeds
// URL: https://github.com/RobTillaart/SHT31
#include "Wire.h"
#include "SHT31.h"
@ -24,8 +23,10 @@ void setup()
Wire.begin();
sht.begin(0x44);
Wire.setClock(100000);
uint16_t stat = sht.readStatus();
Serial.print(stat, HEX);
Serial.println();
}
void loop()
@ -47,8 +48,10 @@ void test()
Serial.print("\t");
Serial.print(stop - start);
Serial.print("\t");
Serial.print(sht.temperature, 1);
Serial.print(sht.getTemperature(), 1);
Serial.print("\t");
Serial.println(sht.humidity, 1);
Serial.println(sht.getHumidity(), 1);
delay(100);
}
}
// -- END OF FILE --

View File

@ -1,16 +1,16 @@
//
// FILE: SHT31_I2Cspeed
// FILE: SHT31_async.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.0.1
// PURPOSE: demo
//
// HISTORY:
// VERSION: 0.0.2
// PURPOSE: demo async interface
// URL: https://github.com/RobTillaart/SHT31
#include "Wire.h"
#include "SHT31.h"
uint32_t start;
uint32_t stop;
uint32_t cnt;
SHT31 sht;
@ -24,31 +24,42 @@ void setup()
Wire.begin();
sht.begin(0x44);
Wire.setClock(100000);
uint16_t stat = sht.readStatus();
Serial.print(stat, HEX);
Serial.println();
sht.requestData();
cnt = 0;
}
void loop()
{
for (uint32_t I2Cfreq = 100000; I2Cfreq < 900000; I2Cfreq += 50000)
if (sht.dataReady())
{
Serial.print(I2Cfreq/1000);
Wire.setClock(I2Cfreq);
test();
start = micros();
bool success = sht.readData(); // default = true = fast
stop = micros();
sht.requestData(); // request for next sample
Serial.print("\t");
Serial.print(stop - start);
Serial.print("\t");
if (success == false)
{
Serial.println("Failed read");
}
else
{
Serial.print(sht.getTemperature(), 1);
Serial.print("\t");
Serial.print(sht.getHumidity(), 1);
Serial.print("\t");
Serial.println(cnt);
cnt = 0;
}
}
cnt++; // simulate activity
}
void test()
{
start = micros();
sht.read(true); // default = true/fast slow = false
stop = micros();
Serial.print("\t");
Serial.print(stop - start);
Serial.print("\t");
Serial.print(sht.temperature, 1);
Serial.print("\t");
Serial.println(sht.humidity, 1);
delay(100);
}
// -- END OF FILE --

View File

@ -1,10 +1,9 @@
//
// FILE: SHT31_demo.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.0.1
// VERSION: 0.0.2
// PURPOSE: demo
//
// HISTORY:
// URL: https://github.com/RobTillaart/SHT31
#include "Wire.h"
#include "SHT31.h"
@ -26,6 +25,7 @@ void setup()
Wire.setClock(100000);
uint16_t stat = sht.readStatus();
Serial.print(stat, HEX);
Serial.println();
}
void loop()
@ -37,8 +37,10 @@ void loop()
Serial.print("\t");
Serial.print(stop - start);
Serial.print("\t");
Serial.print(sht.temperature, 1);
Serial.print(sht.getTemperature(), 1);
Serial.print("\t");
Serial.println(sht.humidity, 1);
Serial.println(sht.getHumidity(), 1);
delay(100);
}
}
// -- END OF FILE --

View File

@ -0,0 +1,63 @@
//
// FILE: SHT31_heater.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.0.1
// PURPOSE: demo heater functions
// URL: https://github.com/RobTillaart/SHT31
#include "Wire.h"
#include "SHT31.h"
SHT31 sht;
uint16_t stat;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("SHT31_LIB_VERSION: \t");
Serial.println(SHT31_LIB_VERSION);
Wire.begin();
sht.begin(0x44);
Wire.setClock(100000);
sht.setHeatTimeout(30); // heater timeout 30 seconds, just for demo.
stat = sht.readStatus();
printHeaterStatus(stat);
sht.heatOn();
while (sht.heatUp())
{
stat = sht.readStatus();
printHeaterStatus(stat);
sht.read();
Serial.println(sht.getTemperature());
delay(10000);
}
Serial.println("switched off");
}
void loop()
{
// forced switch off
if (stat & SHT31_STATUS_HEATER_ON) sht.heatOff();
}
void printHeaterStatus(uint16_t stat)
{
Serial.print(millis());
Serial.print("\tHEATER: ");
if (stat & SHT31_STATUS_HEATER_ON)
{
Serial.println("ON");
} else {
Serial.println("OFF");
}
}
// -- END OF FILE --

View File

@ -1,10 +1,9 @@
//
// FILE: SHT31_lastRead.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.0.1
// VERSION: 0.0.2
// PURPOSE: demo
//
// HISTORY:
// URL: https://github.com/RobTillaart/SHT31
#include "Wire.h"
#include "SHT31.h"
@ -24,8 +23,10 @@ void setup()
Wire.begin();
sht.begin(0x44);
Wire.setClock(100000);
uint16_t stat = sht.readStatus();
Serial.print(stat, HEX);
Serial.println();
}
void loop()
@ -34,8 +35,10 @@ void loop()
Serial.print("\t");
Serial.print(sht.lastRead());
Serial.print("\t");
Serial.print(sht.temperature, 1);
Serial.print(sht.getTemperature(), 1);
Serial.print("\t");
Serial.println(sht.humidity, 1);
Serial.println(sht.getHumidity(), 1);
delay(100);
}
}
// -- END OF FILE --

View File

@ -1,10 +1,9 @@
//
// FILE: SHT31_slowRead.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.0.1
// VERSION: 0.0.2
// PURPOSE: demo
//
// HISTORY:
// URL: https://github.com/RobTillaart/SHT31
#include "Wire.h"
#include "SHT31.h"
@ -24,8 +23,10 @@ void setup()
Wire.begin();
sht.begin(0x44);
Wire.setClock(100000);
uint16_t stat = sht.readStatus();
Serial.print(stat, HEX);
Serial.println();
}
void loop()
@ -36,8 +37,10 @@ void loop()
Serial.print("\t");
Serial.print(stop - start);
Serial.print("\t");
Serial.print(sht.temperature, 1);
Serial.print(sht.getTemperature(), 1);
Serial.print("\t");
Serial.println(sht.humidity, 1);
Serial.println(sht.getHumidity(), 1);
delay(100);
}
}
// -- END OF FILE --

View File

@ -1,22 +1,32 @@
#######################################
# Syntax Coloring Map For AnalogKeypad
#######################################
# Syntax Coloring Map For SHT31
#######################################
# Datatypes (KEYWORD1)
#######################################
SHT31 KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
read KEYWORD2
readStatus KEYWORD2
lastRead KEYWORD2
reset KEYWORD2
setHeatTimeout KEYWORD2
heatOn KEYWORD2
heatOff KEYWORD2
heatUp KEYWORD2
getHumidity KEYWORD2
getTemperature KEYWORD2
requestData KEYWORD2
dataReady KEYWORD2
readData KEYWORD2
#######################################
# Instances (KEYWORD2)
#######################################
#######################################
# Constants (LITERAL1)
#######################################
SHT31_LIB_VERSION LITERAL1
SHT31_STATUS_ALERT_PENDING LITERAL1
SHT31_STATUS_HEATER_ON LITERAL1
SHT31_STATUS_HUM_TRACK_ALERT LITERAL1
SHT31_STATUS_TEMP_TRACK_ALERT LITERAL1
SHT31_STATUS_SYSTEM_RESET LITERAL1
SHT31_STATUS_COMMAND_STATUS LITERAL1
SHT31_STATUS_WRITE_CRC_STATUS LITERAL1

View File

@ -1,7 +1,7 @@
{
"name": "SHT31",
"keywords": "SHT31 Temperature Humidity I2C",
"description": "Class for SHT31 sensor, e.g. Adafruit I2C",
"keywords": "SHT31 Temperature Humidity I2C SHT30 SHT35",
"description": "Arduino library for the I2C SHT31 temperature and humidity sensor",
"authors":
[
{
@ -13,12 +13,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/SHT31",
},
"version":"0.1.2",
"version":"0.2.2",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/SHT31"
}
"platforms": "*"
}

View File

@ -1,9 +1,11 @@
name=SHT31
version=0.1.2
version=0.2.2
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library for SHT31 Temperature Humidity
sentence=Arduino library for the SHT31 temperature and humidity sensor
paragraph=Class for SHT31 Temperature Humidity Adafruit I2C
category=Signal Input/Output
url=https://github.com/RobTillaart/Arduino/tree/master/libraries
architectures=*
category=Sensor
url=https://github.com/RobTillaart/SHT31
architectures=*
includes=Wire.h,SHT31.h
depends=

21
libraries/Set/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2014-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

46
libraries/Set/README.md Normal file
View File

@ -0,0 +1,46 @@
# SET
Arduino library to implement simple SET data structure.
# Description
The set library implements the set data structure for integers 0..255.
This limit is chosen because of the memory limitations of an Arduino UNO,
however these numbers can be used as indices to a table of strings or other
datatypes.
Set level
- **clr()** empty the set
- **invert()** flip all elements in the set.
- **count()** returns number of elements
- **isEmpty()** idem
- **isFull()** idem
Element level
- **add(n)** add element to the Set
- **sub(n)** emove element from Set
- **invert(n)** flip element in Set
- **has(n)** element is in Set
- **add(n)**
Operators
- union + +=
- diff - -=
- intersection * *=
Equality
- equal ==
- not equal !=
- is subSet <=
A superSet B is not implemented as one could say B subSet A (B <= A)
Iterators - all returns value or -1 if not exist
- **first()** find first element
- **next()** find next element
- **prev()** find previous element
- **last()** find last element
# Operational
See examples

View File

@ -1,11 +1,14 @@
//
// FILE: Set.cpp
// FILE: set.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.11
// VERSION: 0.2.1
// DATE: 2014-09-11
// PURPOSE: SET library for Arduino
// URL:
// URL: https://github.com/RobTillaart/SET
//
// HISTORY:
// 0.2.1 2020-06-19 fix library.json
// 0.2.0 2020-05-02 refactored, removed pre 1.0 support
// 0.1.11 2017-07-16 fix count() --> 16 bit when set is full !
// 0.1.10 2017-07-16 performance refactor. isEmpty()
// 0.1.09 2015-07-12 const + constructor
@ -20,10 +23,8 @@
// 0.1.01 extending/refactor etc (09/11/2014)
// 0.1.00 initial version by Rob Tillaart (09/11/2014)
//
// Released to the public domain
//
#include "Set.h"
#include "set.h"
/////////////////////////////////////////////////////
//
@ -40,7 +41,7 @@ Set::Set(const bool clear)
Set::Set(const Set &t)
{
for (uint8_t i=0; i<32; i++)
for (uint8_t i = 0; i < 32; i++)
{
_mem[i] = t._mem[i];
}
@ -54,39 +55,42 @@ Set::Set(const Set &t)
void Set::add(const uint8_t v)
{
uint8_t idx = v / 8;
_mem[idx] |= masks[v&7];
_mem[idx] |= masks[v & 7];
}
void Set::sub(const uint8_t v)
{
uint8_t idx = v / 8;
_mem[idx] &= ~masks[v&7];
_mem[idx] &= ~masks[v & 7];
}
void Set::invert(const uint8_t v)
{
uint8_t idx = v / 8;
_mem[idx] ^= masks[v&7];;
_mem[idx] ^= masks[v & 7];
}
bool Set::has(const uint8_t v)
{
uint8_t idx = v / 8;
return (_mem[idx] & masks[v&7]) > 0;
return (_mem[idx] & masks[v & 7]) > 0;
}
uint16_t Set::count() const
{
uint16_t cnt = 0;
for (uint8_t i=0; i<32; i++)
uint8_t i = 32;
do
{
// kerningham bit count trick
uint8_t b = _mem[i];
uint8_t b = _mem[--i];
for (; b; cnt++)
{
b &= b-1;
}
}
while (i != 0);
return cnt;
}
@ -97,33 +101,48 @@ void Set::clr()
void Set::invert()
{
for (uint8_t i=0; i<32; i++)
uint8_t i = 32;
do
{
_mem[i] ^= 0xFF;
}
_mem[--i] ^= 0xFF;
}
while (i != 0);
}
bool Set::isEmpty()
{
for (uint8_t i=0; i<32; i++)
uint8_t i = 32;
do
{
if (_mem[i]) return false;
}
if (_mem[--i] > 0) return false;
}
while (i != 0);
return true;
}
bool Set::isFull()
{
for (uint8_t i=0; i<32; i++)
// check two elements per loop
// is faster for full sets but slower for empty set.
// footprint is ~25 bytese larger
// overal performance gain
uint8_t i = 32;
do
{
if (_mem[i] != 255) return false;
}
if ((_mem[--i]) != 255) return false;
}
while (i != 0);
return true;
}
int Set::first()
{
return findNext(0,0);
if (has(0))
{
_current = 0;
return _current;
}
return findNext(0, 0);
}
int Set::next()
@ -135,6 +154,37 @@ int Set::next()
return findNext(p, q);
}
// pointer math version ~12% faster but not for previous
// needs investigation.
// int Set::findNext(const uint8_t p, const uint8_t q)
// {
// uint8_t * pp = &_mem[p];
// uint8_t mask = 1 << q;
// uint8_t j = q;
// do
// {
// if (*pp != 0)
// {
// while (j < 8)
// {
// if (*pp & mask)
// {
// _current = (pp - _mem) * 8 + j;
// return _current;
// }
// mask <<= 1;
// j++;
// }
// }
// j = 0;
// mask = 1;
// pp++;
// }
// while (pp != &_mem[31]);
// _current = -1;
// return _current;
// }
int Set::findNext(const uint8_t p, uint8_t q)
{
for (uint8_t i = p; i < 32; i++)
@ -142,7 +192,7 @@ int Set::findNext(const uint8_t p, uint8_t q)
uint8_t b = _mem[i];
if (b != 0)
{
uint8_t mask = 1 << q;
uint8_t mask = 1 << q; // masks[q]
for (uint8_t j = q; j < 8; j++)
{
if (b & mask)
@ -170,6 +220,11 @@ int Set::prev()
int Set::last()
{
if (has(255))
{
_current = 255;
return _current;
}
return findPrev(31, 7);
}
@ -192,7 +247,7 @@ int Set::findPrev(const uint8_t p, uint8_t q)
mask >>= 1;
}
}
m = 1 << 7;
m = 128; // 1 << 7;
q = 7;
}
_current = -1;
@ -285,6 +340,5 @@ bool Set::operator <= (const Set &t) const // subSet
}
return true;
}
//
// END OF FILE
//
// -- END OF FILE --

View File

@ -1,24 +1,19 @@
#pragma once
//
// FILE: Set.h
// FILE: set.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.11
// VERSION: 0.2.1
// DATE: 2014-09-11
// PURPOSE: SET library for Arduino
// URL:
// URL: https://github.com/RobTillaart/SET
//
// HISTORY:
// see Set.cpp file
//
#ifndef Set_h
#define Set_h
#if ARDUINO < 100
#include <WProgram.h>
#else
#include <Arduino.h>
#endif
#define SET_LIB_VERSION "0.1.11"
#define SET_LIB_VERSION "0.2.1"
class Set
{
@ -63,11 +58,10 @@ public:
private:
uint8_t _mem[32]; // can hold 0..255
uint8_t masks[8] = {1, 2, 4, 8, 16, 32, 64, 128};
int _current;
int _current = -1;
int findNext(const uint8_t, const uint8_t); // helper for first, next
int findPrev(const uint8_t, const uint8_t); // helper for last, prev
};
#endif
//
// END OF FILE
//
// -- END OF FILE --

View File

@ -9,11 +9,13 @@
// Released to the public domain
//
#include "Set.h"
#include "set.h"
Set setA, setB;
volatile bool b;
uint32_t start, stop;
void setup()
{
Serial.begin(115200);
@ -42,47 +44,47 @@ void timingTest()
Serial.println("TIMING TEST");
Serial.print("100x clr():\t");
uint32_t start = micros();
for (uint8_t i=0; i<100; i++) myset.clr();
uint32_t stop = micros();
Serial.println(stop-start);
start = micros();
for (uint8_t i = 0; i < 100; i++) myset.clr();
stop = micros();
Serial.println(stop - start);
Serial.print("100x add():\t");
start = micros();
for (uint8_t i=0; i<100; i++) myset.add(i);
for (uint8_t i = 0; i < 100; i++) myset.add(i);
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("100x sub():\t");
start = micros();
for (uint8_t i=0; i<100; i++) myset.sub(i);
for (uint8_t i = 0; i < 100; i++) myset.sub(i);
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("100x has():\t");
start = micros();
for (uint8_t i=0; i<100; i++) b = myset.has(i);
for (uint8_t i = 0; i < 100; i++) b = myset.has(i);
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("100x invert(v):\t");
start = micros();
for (uint8_t i=0; i<100; i++) myset.invert(i);
for (uint8_t i = 0; i < 100; i++) myset.invert(i);
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("invert():\t");
start = micros();
myset.invert();
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("count() empty:\t");
myset.clr();
start = micros();
myset.count();
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("count() full:\t");
myset.clr();
@ -90,42 +92,45 @@ void timingTest()
start = micros();
myset.count();
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.println();
Serial.print("100x isEmpty(): empty\t");
myset.clr();
start = micros();
for (uint8_t i=0; i<100; i++) b = myset.isEmpty();
for (uint8_t i = 0; i < 100; i++) b = myset.isEmpty();
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("100x isEmpty(): full\t");
myset.clr();
myset.invert();
start = micros();
for (uint8_t i=0; i<100; i++) b = myset.isEmpty();
for (uint8_t i = 0; i < 100; i++) b = myset.isEmpty();
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("100x isFull(): empty\t");
myset.clr();
start = micros();
for (uint8_t i=0; i<100; i++) b = myset.isFull();
for (uint8_t i = 0; i < 100; i++) b = myset.isFull();
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("100x isFull(): full\t");
myset.clr();
myset.invert();
start = micros();
for (uint8_t i=0; i<100; i++) b = myset.isFull();
for (uint8_t i = 0; i < 100; i++) b = myset.isFull();
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.println();
randomSeed(1);
setA.clr();
setB.clr();
for (int i=0; i<150; i++)
for (int i = 0; i<150; i++)
{
setA.add(random(256));
setB.add(random(256));
@ -135,95 +140,101 @@ void timingTest()
start = micros();
myset = setA + setB;
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("a = b - c:\t");
start = micros();
myset = setA - setB;
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("a = b * c:\t");
start = micros();
myset = setA * setB;
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("a += b:\t");
start = micros();
myset += setA;
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("a -= b:\t");
start = micros();
myset -= setA;
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("a *= b:\t");
start = micros();
myset *= setA;
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("a == b:\t");
start = micros();
b = (setA == setB);
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("a != b:\t");
start = micros();
b = (setA != setB);
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("a <= b:\t");
start = micros();
b = (setA <= setB);
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.println();
Serial.println("iteration 10 elements");
Serial.print("first:\t");
setA.clr();
randomSeed(1);
for (int i=0; i<10; i++)
for (int i = 0; i < 10; i++)
{
setA.add(random(256));
}
start = micros();
int n = setA.first();
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("next:\t");
start = micros();
n = setA.next();
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("first + next until -1 :\t");
Serial.print("100x first + next until -1 :\t");
start = micros();
n = setA.first();
while (n != -1)
for (uint8_t i = 0; i < 100; i++)
{
n = setA.next();
n = setA.first();
while (n != -1)
{
n = setA.next();
}
}
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.print("last + prev until -1 :\t");
Serial.print("100x last + prev until -1 :\t");
start = micros();
n = setA.last();
while (n != -1)
for (uint8_t i = 0; i < 100; i++)
{
n = setA.prev();
n = setA.last();
while (n != -1)
{
n = setA.prev();
}
}
stop = micros();
Serial.println(stop-start);
Serial.println(stop - start);
Serial.println();
Serial.println();
@ -262,7 +273,7 @@ void intersectionTest()
randomSeed(1);
setA.clr();
setB.clr();
for (int i=0; i<150; i++)
for (int i = 0; i < 150; i++)
{
setA.add(random(256));
setB.add(random(256));
@ -277,7 +288,7 @@ void intersectionTest()
randomSeed(1);
setA.clr();
setB.clr();
for (int i=0; i<150; i++)
for (int i = 0; i < 150; i++)
{
setA.add(random(256));
setB.add(random(256));
@ -292,7 +303,7 @@ void intersectionTest()
randomSeed(1);
setA.clr();
setB.clr();
for (int i=0; i<150; i++)
for (int i = 0; i < 150; i++)
{
setA.add(random(256));
setB.add(random(256));
@ -311,7 +322,7 @@ void intersection2Test()
randomSeed(1);
setA.clr();
setB.clr();
for (int i=0; i<150; i++)
for (int i = 0; i < 150; i++)
{
setA.add(random(256));
setB.add(random(256));
@ -342,7 +353,7 @@ void subsetTest()
{
Serial.println("SUBSET TEST");
Set setE;
for (int i=0; i<5; i++) setE.add(i);
for (int i = 0; i < 5; i++) setE.add(i);
Set setF(setE);
@ -365,33 +376,47 @@ void subsetTest()
void iterationTest()
{
Serial.println("ITERATE OVER SET TEST");
Serial.println("10x ITERATE OVER SET TEST");
randomSeed(1);
setA.clr();
for (int i=0; i<10; i++)
for (int i = 0; i < 10; i++)
{
setA.add(random(256));
}
Serial.println(setA.count());
int n = setA.first();
while (n != -1)
start = micros();
for (int i = 0; i < 10; i++)
{
Serial.print(n);
Serial.print('\t');
n = setA.next();
int n = setA.first();
while (n != -1)
{
Serial.print(n);
Serial.print('\t');
n = setA.next();
}
Serial.println();
}
stop = micros();
Serial.println();
n = setA.last();
while (n != -1)
Serial.println(stop - start);
Serial.println();
start = micros();
for (int i = 0; i < 10; i++)
{
Serial.print(n);
Serial.print('\t');
n = setA.prev();
int n = setA.last();
while (n != -1)
{
Serial.print(n);
Serial.print('\t');
n = setA.prev();
}
Serial.println();
}
stop = micros();
Serial.println();
Serial.println(stop - start);
Serial.println();
}
//
// END OF FILE
//
// -- END OF FILE --

View File

@ -0,0 +1,53 @@
//
// FILE: equalTest.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// PURPOSE: demo equality operators
// DATE: 2014-11-09
// URL: https://github.com/RobTillaart/SET
//
// Released to the public domain
//
#include "set.h"
Set setA, setB;
volatile bool b;
void setup()
{
Serial.begin(115200);
Serial.print("Start set_demo : ");
Serial.println(SET_LIB_VERSION);
Serial.println();
Serial.println("\n\nequal test");
randomSeed(1);
setA.clr();
setB.clr();
Serial.println(setA == setB?"true":"false");
setB.add(0);
Serial.println(setA == setB?"true":"false");
Serial.println(setA == setA?"true":"false");
Set setC(setB);
Serial.println(setC == setB?"true":"false");
Serial.println(setC.count());
Set setD = setB;
Serial.println(setD != setB?"unequal":"equal");
Serial.println(setD == setB?"true":"false");
Serial.println(setD.count());
setD = setA;
Serial.println(setD == setB?"true":"false");
Serial.println(setD.count());
Serial.println("done...");
Serial.println();
}
void loop()
{
}

View File

@ -0,0 +1,102 @@
//
// FILE: set_demo.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// PURPOSE: demo set intersection union and diff
// DATE: 2014-11-09
// URL: https://github.com/RobTillaart/SET
//
// Released to the public domain
//
#include "set.h"
Set setA, setB;
volatile bool b;
void setup()
{
Serial.begin(115200);
Serial.print("Start set_demo : ");
Serial.println(SET_LIB_VERSION);
Serial.println();
Serial.println("\n\nintersection test");
randomSeed(1);
setA.clr();
setB.clr();
for (int i=0; i<150; i++)
{
setA.add(random(256));
setB.add(random(256));
}
Serial.println(setA.count());
Serial.println(setB.count());
setA *= setB;
for (int i=0; i<4; i++)
{
for (int j=0; j<64; j++)
{
Serial.print(setA.has(i*64+j));
}
Serial.println();
}
Serial.println(setA.count());
Serial.println();
Serial.println("\n\nunion test");
randomSeed(1);
setA.clr();
setB.clr();
for (int i=0; i<150; i++)
{
setA.add(random(256));
setB.add(random(256));
}
Serial.println(setA.count());
Serial.println(setB.count());
setA += setB;
for (int i=0; i<4; i++)
{
for (int j=0; j<64; j++)
{
Serial.print(setA.has(i*64+j));
}
Serial.println();
}
Serial.println(setA.count());
Serial.println();
Serial.println("\n\ndiff test");
randomSeed(1);
setA.clr();
setB.clr();
for (int i=0; i<150; i++)
{
setA.add(random(256));
setB.add(random(256));
}
Serial.println(setA.count());
Serial.println(setB.count());
setA -= setB;
for (int i=0; i<4; i++)
{
for (int j=0; j<64; j++)
{
Serial.print(setA.has(i*64+j));
}
Serial.println();
}
Serial.println(setA.count());
Serial.println();
Serial.println("done...");
Serial.println();
}
void loop()
{
}

View File

@ -0,0 +1,60 @@
//
// FILE: iterationTest.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE: demo first, next, last, prev
// DATE: 2014-11-09
// URL:
//
// Released to the public domain
//
#include "set.h"
Set myset;
Set setA, setB;
volatile bool b;
void setup()
{
Serial.begin(115200);
Serial.print("Start set_demo : ");
Serial.println(SET_LIB_VERSION);
Serial.println();
Serial.println("\n\niterate over set test");
randomSeed(1);
setA.clr();
for (int i=0; i<10; i++)
{
setA.add(random(256));
}
Serial.println(setA.count());
int n = setA.first();
while (n != -1)
{
Serial.print(n);
Serial.print('\t');
n = setA.next();
}
Serial.println();
n = setA.last();
while (n != -1)
{
Serial.print(n);
Serial.print('\t');
n = setA.prev();
}
Serial.println();
Serial.println("done...");
Serial.println();
}
void loop()
{
}

View File

@ -0,0 +1,50 @@
//
// FILE: subsetTest.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// PURPOSE: demo
// DATE: 2014-11-09
// URL: https://github.com/RobTillaart/SET
//
// Released to the public domain
//
#include "set.h"
void setup()
{
Serial.begin(115200);
Serial.print("Start set_demo : ");
Serial.println(SET_LIB_VERSION);
Serial.println();
Serial.println("\n\nSubSet test");
Set setE;
for (int i = 0; i < 5; i++) setE.add(i);
Set setF(setE);
Serial.println(setE.count());
Serial.println(setF.count());
Serial.println(setE <= setF?"subset":"no subset");
Serial.println(setF <= setE?"subset":"no subset");
setF.add(6);
Serial.println(setE <= setF?"subset":"no subset");
Serial.println(setF <= setE?"subset":"no subset");
setF.sub(3);
Serial.println(setE <= setF?"subset":"no subset");
Serial.println(setF <= setE?"subset":"no subset");
Serial.println();
Serial.println("done...");
Serial.println();
}
void loop()
{
}

View File

@ -0,0 +1,81 @@
//
// FILE: timingTest.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// PURPOSE: timing test for set class methods
// DATE: 2014-11-09
// URL: https://github.com/RobTillaart/SET
//
// Released to the public domain
//
#include "set.h"
Set myset;
Set setA, setB;
uint32_t start;
uint32_t stop;
volatile bool b;
void setup()
{
Serial.begin(115200);
Serial.print("Start set_demo : ");
Serial.println(SET_LIB_VERSION);
Serial.println();
Serial.println("\n\ntiming test");
Serial.print("myset.clr():\t");
start = micros();
myset.clr();
stop = micros();
Serial.println(stop - start);
Serial.print("myset.add():\t");
start = micros();
for (int i = 0; i < 256; i++) myset.add(i);
stop = micros();
Serial.println(stop - start);
Serial.print("myset.sub():\t");
start = micros();
for (int i = 0; i < 256; i++) myset.sub(i);
stop = micros();
Serial.println(stop - start);
Serial.print("myset.has():\t");
start = micros();
for (int i = 0; i < 256; i++) b = myset.has(i);
stop = micros();
Serial.println(stop - start);
Serial.print("myset.invert(v):\t");
start = micros();
for (int i = 0; i < 256; i++) myset.invert(i);
stop = micros();
Serial.println(stop - start);
Serial.print("myset.invert():\t");
start = micros();
myset.invert();
stop = micros();
Serial.println(stop - start);
Serial.print("myset.count():\t");
start = micros();
myset.count();
stop = micros();
Serial.println(stop - start);
Serial.println();
Serial.println("done...");
Serial.println();
}
void loop()
{
}

View File

@ -1,6 +1,6 @@
{
"name": "Set",
"keywords": "Set,union,diff,intersection,equal,subset",
"name": "SET",
"keywords": "Set,add,sub,union,diff,intersection,equal,subset",
"description": "Library to implement SET datastructure.",
"authors":
[
@ -13,12 +13,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/SET.git"
},
"version":"0.1.11",
"version":"0.2.1",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/Set"
}
"platforms": "*"
}

View File

@ -1,9 +1,11 @@
name=Set
version=0.1.11
name=SET
version=0.2.1
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library to implement SET datastructure.
paragraph=Supports union diff intersection equal subset
sentence=Arduino library to implement simple SET datastructure.
paragraph=Supports union diff intersection equal subset. Limited to numbers 0..255.
category=Data Processing
url=https://github.com/RobTillaart/Arduino/tree/master/libraries/
architectures=*
url=https://github.com/RobTillaart/Set
architectures=*
includes=set.h
depends=

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2010-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,81 @@
# Statistic
Statistic library for Arduino includes sum, average, variance and std deviation
# Description
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.
The stability of the formulas is improved by the help of Gil Ross (Thanks!)
The functions implemented are:
* **clear(useStdDev)**
* **add(value)**
* **count()** returns zero if count == zero (of course)
* **sum()** returns zero if count == zero
* **minimum()** returns zero if count == zero
* **maximum()** returns zero if count == zero
* **average()** returns NAN if count == zero
These three functions only work id useStdDev == true:
* **variance()** returns NAN if count == zero
* **pop_stdev()** population stdev, returns NAN if count == zero
* **unbiased_stdev()** returnsNAN if count == zero
# Operational
See examples
# FAQ
### Q: Are individual samples still available?
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
calculate the most important statistics.
### 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.
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**
which is the sum of the squared values. Both can overflow especially **_ssq**
can and probably will grow fast. The library does not protect against it.
There is a workaround for this (to some extend) if one knows the approx
average of the samples before. Before adding values to the lib subtract
the expected average. The sum of the samples would move to around zero.
This workaround has no influence on the standard deviation.
!! Do not forget to add the expected average to the calculated average.
*(Q: should this subtraction trick be build into the lib?)*
### Q: How about the precision of the library?
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
a large value, adding relative small values to the dataset wouldn't
change its value any more. Same is true for **_ssq**. One might argue that
statistically speaking these values are less significant, but in fact it is wrong.
There is a workaround for this (to some extend). If one has the samples in an
array or on disk, one can sort the samples in increasing order (abs value)
and add them from this sorted list. This will minimize the error,
but it works only if the samples are available and the they may be added
in the sorted increasing order.
### Q: When will internal var's overflow? esp. squared sum
IEEE754 floats have a max value of about **+-3.4028235E+38**
### Q: Why are there two functions for 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.

View File

@ -2,7 +2,7 @@
// FILE: Statistic.cpp
// AUTHOR: Rob dot Tillaart at gmail dot com
// modified at 0.3 by Gil Ross at physics dot org
// VERSION: 0.3.5
// VERSION: 0.4.1
// PURPOSE: Recursive statistical library for Arduino
//
// NOTE: 2011-01-07 Gill Ross
@ -29,50 +29,49 @@
// -------------
//
// HISTORY:
// 0.1 - 2010-10-29 initial version
// 0.2 - 2010-10-29 stripped to minimal functionality
// 0.2.01 - 2010-10-30
// added minimim, maximum, unbiased stdev,
// changed counter to long -> int overflows @32K samples
// 0.3 - 2011-01-07
// branched from 0.2.01 version of Rob Tillaart's code
// 0.3.1 - minor edits
// 0.3.2 - 2012-11-10
// minor edits
// changed count -> unsigned long allows for 2^32 samples
// added variance()
// 0.3.3 - 2015-03-07
// float -> double to support ARM (compiles)
// moved count() sum() min() max() to .h; for optimizing compiler
// 0.3.4 - 2017-07-31
// Refactored const in many places
// [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.
// 0.3.5 - 2017-09-27
// Added #include <Arduino.h> to fix uint32_t bug
//
// Released to the public domain
// 0.1 2010-10-29 initial version
// 0.2 2010-10-29 stripped to minimal functionality
// 0.2.01 2010-10-30
// added minimim, maximum, unbiased stdev,
// changed counter to long -> int overflows @32K samples
// 0.3 2011-01-07
// branched from 0.2.01 version of Rob Tillaart's code
// 0.3.1 2012-11-10 minor edits
// 0.3.2 2012-11-10 minor edits
// changed count -> unsigned long allows for 2^32 samples
// added variance()
// 0.3.3 2015-03-07
// float -> double to support ARM (compiles)
// moved count() sum() min() max() to .h; for optimizing compiler
// 0.3.4 2017-07-31
// Refactored const in many places
// [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.
// 0.3.5 2017-09-27
// Added #include <Arduino.h> to fix uint32_t bug
// 0.4.0 2020-05-13
// refactor
// Added flag to switch on the use of stdDev runtime. [idea marc.recksiedl]
// 0.4.1 2020-06-19 fix library.json
//
#include "Statistic.h"
Statistic::Statistic()
Statistic::Statistic(bool useStdDev)
{
clear();
clear(useStdDev);
}
// resets all counters
void Statistic::clear()
void Statistic::clear(bool useStdDev) // useStdDev default true.
{
_cnt = 0;
_sum = 0;
_min = 0;
_max = 0;
#ifdef STAT_USE_STDEV
_ssqdif = 0.0; // not _ssq but sum of square differences
// which is SUM(from i = 1 to N) of
// (f(i)-_ave_N)**2
#endif
_useStdDev = useStdDev;
_ssqdif = 0.0;
// note not _ssq but sum of square differences
// which is SUM(from i = 1 to N) of f(i)-_ave_N)**2
}
// adds a new value to the data-set
@ -89,46 +88,48 @@ void Statistic::add(const float value)
_sum += value;
_cnt++;
#ifdef STAT_USE_STDEV
if (_cnt > 1)
if (_useStdDev && (_cnt > 1))
{
float _store = (_sum / _cnt - value);
_ssqdif = _ssqdif + _cnt * _store * _store / (_cnt-1);
_ssqdif = _ssqdif + _cnt * _store * _store / (_cnt - 1);
// ~10% faster but limits the amount of samples to 65K as _cnt*_cnt overflows
// float _store = _sum - _cnt * value;
// _ssqdif = _ssqdif + _store * _store / (_cnt*_cnt - _cnt);
//
// solution: TODO verify
// _ssqdif = _ssqdif + (_store * _store / _cnt) / (_cnt - 1);
}
#endif
}
// returns the average of the data-set added sofar
float Statistic::average() const
{
if (_cnt == 0) return NAN; // original code returned 0
if (_cnt == 0) return NAN; // prevent DIV0 error
return _sum / _cnt;
}
// Population standard deviation = s = sqrt [ S ( Xi - µ )2 / N ]
// http://www.suite101.com/content/how-is-standard-deviation-used-a99084
#ifdef STAT_USE_STDEV
float Statistic::variance() const
{
if (_cnt == 0) return NAN; // otherwise DIV0 error
if (!_useStdDev) return NAN;
if (_cnt == 0) return NAN; // prevent DIV0 error
return _ssqdif / _cnt;
}
float Statistic::pop_stdev() const
{
if (_cnt == 0) return NAN; // otherwise DIV0 error
if (!_useStdDev) return NAN;
if (_cnt == 0) return NAN; // prevent DIV0 error
return sqrt( _ssqdif / _cnt);
}
float Statistic::unbiased_stdev() const
{
if (_cnt < 2) return NAN; // otherwise DIV0 error
if (!_useStdDev) return NAN;
if (_cnt < 2) return NAN; // prevent DIV0 error
return sqrt( _ssqdif / (_cnt - 1));
}
#endif
// END OF FILE
// -- END OF FILE --

View File

@ -1,54 +1,45 @@
#ifndef Statistic_h
#define Statistic_h
#pragma once
//
// FILE: Statistic.h
// AUTHOR: Rob dot Tillaart at gmail dot com
// modified at 0.3 by Gil Ross at physics dot org
// VERSION: 0.3.5
// VERSION: 0.4.1
// PURPOSE: Recursive Statistical library for Arduino
// HISTORY: See Statistic.cpp
//
// Released to the public domain
//
// the standard deviation increases the lib (<100 bytes)
// it can be in/excluded by un/commenting next line (compile time)
#define STAT_USE_STDEV 1
#include <Arduino.h>
#include <math.h>
#define STATISTIC_LIB_VERSION "0.3.5"
#define STATISTIC_LIB_VERSION "0.4.1"
class Statistic
{
public:
Statistic(); // "switches on/off" stdev run time
void clear(); // "switches on/off" stdev run time
Statistic(bool useStdDev = true); // "switches on/off" stdev run time
void clear(bool useStdDev = true); // "switches on/off" stdev run time
void add(const float);
// returns the number of values added
uint32_t count() const { return _cnt; }; // zero if empty
float sum() const { return _sum; }; // zero if empty
float minimum() const { return _min; }; // zero if empty
float maximum() const { return _max; }; // zero if empty
float average() const; // NAN if empty
uint32_t count() const { return _cnt; }; // zero if count == zero
float sum() const { return _sum; }; // zero if count == zero
float minimum() const { return _min; }; // zero if count == zero
float maximum() const { return _max; }; // zero if count == zero
float average() const; // NAN if count == zero
#ifdef STAT_USE_STDEV
float variance() const; // NAN if empty
float pop_stdev() const; // population stdev // NAN if empty
float unbiased_stdev() const; // NAN if empty
#endif
// useStdDev must be true to use next three
float variance() const; // NAN if count == zero
float pop_stdev() const; // population stdev // NAN if count == zero
float unbiased_stdev() const; // NAN if count == zero
protected:
uint32_t _cnt;
float _sum;
float _min;
float _max;
#ifdef STAT_USE_STDEV
float _ssqdif; // sum of squares difference
#endif
bool _useStdDev;
float _ssqdif; // sum of squares difference
};
#endif
// END OF FILE
// -- END OF FILE --

View File

@ -1,7 +1,7 @@
//
// FILE: Average.ino
// AUTHOR: Rob dot Tillaart at gmail dot com
// VERSION: 0.3
// VERSION: 0.4
// PURPOSE: Sample sketch for statistic library Arduino
//
@ -37,15 +37,12 @@ void loop(void)
Serial.println(myStats.maximum(), 4);
Serial.print(" Average: ");
Serial.println(myStats.average(), 4);
// uncomment in Statistic.h file to use stdev
#ifdef STAT_USE_STDEV
Serial.print(" variance: ");
Serial.println(myStats.variance(), 4);
Serial.print(" pop stdev: ");
Serial.println(myStats.pop_stdev(), 4);
Serial.print(" unbias stdev: ");
Serial.println(myStats.unbiased_stdev(), 4);
#endif
Serial.print(" time(ms): ");
Serial.println(stop - start);
Serial.println("=====================================");

View File

@ -0,0 +1,45 @@
//
// FILE: StatisticArray.ino
// AUTHOR: Rob dot Tillaart at gmail dot com
// VERSION: 0.1
// PURPOSE: Sample sketch for statistic library Arduino
//
#include "Statistic.h"
Statistic stats[4];
void setup(void)
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("Demo Statistics lib ");
Serial.println(STATISTIC_LIB_VERSION);
for (int i=0; i<4; i++)
{
stats[i].clear(); //explicitly start clean
}
}
void loop(void)
{
long rn = random(0, 9999);
int idx = random(0, 4);
stats[idx].add(rn / 100.0 + 1);
if (stats[idx].count() == 10000)
{
Serial.print("IDX: ");
Serial.println(idx);
Serial.print(" Count: ");
Serial.println(stats[idx].count());
Serial.print(" Min: ");
Serial.println(stats[idx].minimum(), 4);
Serial.print(" Max: ");
Serial.println(stats[idx].maximum(), 4);
Serial.print(" Average: ");
Serial.println(stats[idx].average(), 4);
Serial.println("=====================================");
stats[idx].clear();
}
}

View File

@ -0,0 +1,60 @@
//
// FILE: TimingTest.ino
// AUTHOR: Rob dot Tillaart at gmail dot com
// VERSION: 0.2.0
// PURPOSE: measure time difference for runtime stddev toggle.
// add is 1024 millis faster for 10K adds ==> ~ 100uSec per add faster.
#include "Statistic.h"
Statistic myStats;
uint32_t start;
uint32_t stop;
bool useStdDev = true;
void setup(void)
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("Demo Statistics lib ");
Serial.println(STATISTIC_LIB_VERSION);
myStats.clear(useStdDev);
start = millis();
}
void loop(void)
{
long rn = random(0, 9999);
myStats.add(rn / 100.0 + 1);
if (myStats.count() == 10000)
{
stop = millis();
Serial.print(" Count: ");
Serial.println(myStats.count());
Serial.print(" Min: ");
Serial.println(myStats.minimum(), 4);
Serial.print(" Max: ");
Serial.println(myStats.maximum(), 4);
Serial.print(" Average: ");
Serial.println(myStats.average(), 4);
if (useStdDev)
{
Serial.print(" variance: ");
Serial.println(myStats.variance(), 4);
Serial.print(" pop stdev: ");
Serial.println(myStats.pop_stdev(), 4);
Serial.print(" unbias stdev: ");
Serial.println(myStats.unbiased_stdev(), 4);
}
Serial.print(" time(ms): ");
Serial.println(stop - start);
Serial.println("=====================================");
useStdDev = !useStdDev;
myStats.clear(useStdDev);
start = millis();
}
}
// -- END OF FILE --

View File

@ -0,0 +1,21 @@
# Syntax Coloring Map For Statistic
# Datatypes (KEYWORD1)
Statistic KEYWORD1
# Methods and Functions (KEYWORD2)
clear KEYWORD2
add KEYWORD2
count KEYWORD2
sum KEYWORD2
minimum KEYWORD2
maximum KEYWORD2
average KEYWORD2
variance KEYWORD2
pop_stdev KEYWORD2
unbiased_stdev KEYWORD2
# Instances (KEYWORD2)
# Constants (LITERAL1)
STATISTIC_LIB_VERSION LITERAL1

View File

@ -16,12 +16,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/Statistic.git"
},
"version":"0.3.5",
"version":"0.4.1",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/Statistic"
}
"platforms": "*"
}

View File

@ -1,9 +1,11 @@
name=Statistics
version=0.3.5
name=Statistic
version=0.4.1
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library with basic statistical functions for Arduino.
paragraph=Supports
category=Data Processing
url=https://github.com/RobTillaart/Arduino/tree/master/libraries/
architectures=*
url=https://github.com/RobTillaart/Statistic
architectures=*
includes=Statistic.h
depends=

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2011-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,8 +1,10 @@
//
// FILE: StopWatch.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.5
// PURPOSE: Simple StopWatch library for Arduino
// VERSION: 0.2.2
// DATE: 2011-01-04
// PURPOSE: Arduino Library implementing a stopwatch including seconds, milliseconds microseconds
// URL: https://github.com/RobTillaart/StopWatch_RT
//
// The library is based upon millis() and therefore
// has the same restrictions as millis() has wrt overflow.
@ -15,30 +17,42 @@
// By mromani & Rob Tillaart
// 0.1.4 2017-07-16 refactored
// 0.1.5 2017-09-13 removed const from functions
//
// Released to the public domain
// 0.2.0 2020-05-07 updated metadata, removed pre 1.0 support; setResolution added, minutes added
// 0.2.1 2020-06-19 fix library.json
// 0.2.2 2020-07-14 fix #3 ESP support
//
#include "StopWatch.h"
StopWatch::StopWatch(const enum Resolution res)
{
setResolution(res);
}
void StopWatch::setResolution(const enum Resolution res)
{
reset();
_res = res;
switch(_res) {
switch(_res)
{
case MICROS:
_gettime = micros;
break;
case MILLIS:
_gettime = millis;
_gettime = _micros;
break;
case SECONDS:
_gettime = seconds;
break;
case MINUTES:
_gettime = minutes;
break;
case MILLIS:
default:
_gettime = millis;
_gettime = _millis;
_res = MILLIS; // for default!
break;
}
reset();
}
void StopWatch::reset()
@ -58,7 +72,7 @@ void StopWatch::start()
}
}
uint32_t StopWatch::value()
uint32_t StopWatch::elapsed()
{
if (_state == StopWatch::RUNNING)
{
@ -75,4 +89,5 @@ void StopWatch::stop()
_state = StopWatch::STOPPED;
}
}
// END OF FILE
// -- END OF FILE --

View File

@ -1,40 +1,47 @@
#ifndef StopWatch_h
#define StopWatch_h
#pragma once
//
// FILE: StopWatch.h
// AUTHOR: Rob Tillaart
// PURPOSE: Simple StopWatch library for Arduino
// VERSION: 0.2.2
// PURPOSE: Arduino Library implementing a stopwatch including seconds, milliseconds microseconds
// HISTORY: See StopWatch.cpp
// URL: http://playground.arduino.cc/Code/StopWatchClass
//
// Released to the public domain
// URL: https://github.com/RobTillaart/StopWatch_RT
// http://playground.arduino.cc/Code/StopWatchClass
//
#define STOPWATCH_LIB_VERSION "0.1.5"
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#define STOPWATCH_LIB_VERSION (F("0.2.2"))
// note - adjust divider can fix timing inaccuracies (to some extend)
#ifndef STOPWATCH_SECONDS_DIVIDER
#define STOPWATCH_SECONDS_DIVIDER 1000
#endif
#ifndef STOPWATCH_MINUTES_DIVIDER
#define STOPWATCH_MINUTES_DIVIDER 60000
#endif
class StopWatch
{
public:
enum State { RESET, RUNNING, STOPPED };
enum Resolution { MILLIS, MICROS, SECONDS };
enum Resolution { MICROS, MILLIS, SECONDS, MINUTES};
explicit StopWatch(const enum Resolution res = MILLIS);
void start();
void stop();
void reset();
uint32_t elapsed();
uint32_t value();
uint32_t elapsed() { return value(); };
bool isRunning() { return _state == StopWatch::RUNNING; };
enum State state() { return _state; };
void setResolution(const enum Resolution res);
enum Resolution resolution() { return _res; };
bool isRunning() { return _state == StopWatch::RUNNING; };
enum State state() { return _state; };
enum Resolution resolution() { return _res; };
// value will become obsolete in the future, elapsed() is more descriptive
uint32_t value() { return elapsed(); };
private:
enum State _state;
@ -44,8 +51,10 @@ private:
uint32_t _stoptime;
uint32_t (*_gettime)(void);
static uint32_t seconds() { return millis() / 1000; };
static uint32_t _micros() { return micros(); }; // wrapper for ESP proc.
static uint32_t _millis() { return millis(); };
static uint32_t seconds() { return millis() / STOPWATCH_SECONDS_DIVIDER; };
static uint32_t minutes() { return millis() / STOPWATCH_MINUTES_DIVIDER; };
};
#endif
// END OF FILE
// -- END OF FILE --

View File

@ -1,12 +1,10 @@
//
// FILE: sample.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// VERSION: 0.1.1
// PURPOSE: sample demo stopwatch class
// DATE:
// URL:
//
// Released to the public domain
// DATE: 2011-01-04
// URL: https://github.com/RobTillaart/StopWatch_RT
//
#include <StopWatch.h>
@ -35,7 +33,7 @@ void loop()
for(int i=0; i<5; i++)
{
delay(10);
Serial.println(MySW.value());
Serial.println(MySW.elapsed());
}
MySW.stop();
@ -44,7 +42,7 @@ void loop()
for(int i=0; i<5; i++)
{
delay(10);
Serial.println(MySW.value());
Serial.println(MySW.elapsed());
}
MySW.start();
@ -53,7 +51,7 @@ void loop()
for(int i=0; i<5; i++)
{
delay(10);
Serial.println(MySW.value());
Serial.println(MySW.elapsed());
}
MySW.reset();
Serial.println(MySW.isRunning());
@ -65,7 +63,7 @@ void loop()
for(int i=0; i<5; i++)
{
delay(10);
Serial.println(MySW.value());
Serial.println(MySW.elapsed());
}
switch(MySW.state())
@ -88,3 +86,5 @@ void loop()
Serial.print(" >>> laptime loop() : ");
Serial.println(SWarray[0].value());
}
// -- END OF FILE --

View File

@ -1,12 +1,10 @@
//
// FILE: sample2.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// VERSION: 0.1.1
// PURPOSE: sample demo stopwatch class
// DATE:
// URL:
//
// Released to the public domain
// DATE: 2011-01-04
// URL: https://github.com/RobTillaart/StopWatch_RT
//
#include <StopWatch.h>
@ -35,4 +33,6 @@ void loop()
Serial.println();
delay(1000);
}
}
// -- END OF FILE --

View File

@ -0,0 +1,50 @@
//
// FILE: stopwatch_resolution.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// PURPOSE: sample demo stopwatch class
// DATE: 2020-05-08
// URL: https://github.com/RobTillaart/StopWatch_RT
//
#include <StopWatch.h>
StopWatch MySW;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println(STOPWATCH_LIB_VERSION);
MySW.start();
delay(5000);
Serial.print("TIME: ");
Serial.println(MySW.elapsed());
Serial.print(" RES: ");
Serial.println(MySW.resolution());
Serial.println();
}
void loop()
{
simple_test(StopWatch::MICROS);
simple_test(StopWatch::MILLIS);
simple_test(StopWatch::SECONDS);
simple_test(StopWatch::MINUTES);
}
void simple_test(StopWatch::Resolution res)
{
MySW.setResolution(res); // note: includes an automatic reset()
MySW.start();
delay(2500);
Serial.print("TIME: ");
Serial.println(MySW.elapsed());
Serial.print(" RES: ");
Serial.println(MySW.resolution());
Serial.println();
}
// -- END OF FILE --

View File

@ -0,0 +1,22 @@
# Syntax Coloring Map for StopWatch
# Datatypes (KEYWORD1)
StopWatch KEYWORD1
# Methods and Functions (KEYWORD2)
start KEYWORD2
stop KEYWORD2
reset KEYWORD2
elapsed KEYWORD2
isRunning KEYWORD2
state KEYWORD2
setResolution KEYWORD2
resolution KEYWORD2
# Constants (LITERAL1)
RESET LITERAL1
RUNNING LITERAL1
STOPPED LITERAL1
MILLIS LITERAL1
MICROS LITERAL1
SECONDS LITERAL1

View File

@ -1,7 +1,7 @@
{
"name": "StopWatch",
"keywords": "StopWatch,start,stop,elapsed,millis,micros,seconds",
"description": "Library to implement a stopwatch.",
"description": "Arduino Library implementing a stopwatch including seconds, milliseconds microseconds.",
"authors":
[
{
@ -13,12 +13,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/StopWatch_RT"
},
"version":"0.1.5",
"version":"0.2.2",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/StopWatch"
}
"platforms": "*"
}

View File

@ -1,9 +1,11 @@
name=StopWatch
version=0.1.5
name=StopWatch_RT
version=0.2.2
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library to implement a stopwatch.
sentence=Arduino Library implementing a stopwatch.
paragraph=Supports millis micros seconds
category=Timing
url=https://github.com/RobTillaart/Arduino/tree/master/libraries/
architectures=*
url=https://github.com/RobTillaart/Stopwatch_RT
architectures=*
includes=StopWatch.h
depends=

View File

@ -1,4 +1,41 @@
# Stopwatch_RT
Arduino Library implementing a stopwatch including seconds, milliseconds microseconds
0.1.03 has a breaking interface
# Description
The stopwatch class allows one to create a stopwatch with 4 levels of resolution
* MICROS - microseconds
* MILLIS - milliseconds (default)
* SECONDS - seconds
* MINUTES - minutes (added 0.2.0)
Note that the resolution chosen implies the finest granularity of units measured.
E.g. if chosen minutes then one cannot measure half (30 sec) or other part of a minute.
The resolution is typically set in the constructor, however since 0.2.0 one can call
**setResolution()** to change the 'tick unit' of the clock runtime.
This way one can reuse the stopwatch object without creating a new one and thereby
save some memory.
**Warning:** Changing the resolution will reset the stopwatch
as start time and stop time will become meaningless.
The stopwatch will reset even when the resolution is the current resolution.
The other methods of the stopwatch are trivial
* start()
* stop()
* elapsed() - - will return the time in chosen units since last **start()**
* reset()
* isRunning()
* state()
* resolution()
This library is based upon millis() and micros() and therefore has the same
restrictions and limitations as these functions with respect to overflow
and precision.
This means minutes and seconds will overflow also after about 49 days.
# Operation
See examples

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,75 @@
//
// FILE: dewpoint_test.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
// DATE: 2020-04-04
//
#include "temperature.h"
uint32_t start;
uint32_t duration1;
uint32_t duration2;
float maxError;
volatile float dp;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println("takes ~40 seconds");
Serial.println(dewPoint(25, 50), 2);
Serial.println(dewPointFast(25, 50), 2);
Serial.println("\ndewPoint()");
start = millis();
for (int cel = -40; cel < 80; cel++)
{
for (int hum = 1; hum < 100; hum++)
{
dp = dewPoint(cel, hum);
}
}
duration1 = millis() - start;
Serial.println(duration1);
Serial.println("\ndewPointFast()");
start = millis();
for (int cel = -40; cel < 80; cel++)
{
for (int hum = 1; hum < 100; hum++)
{
dp = dewPointFast(cel, hum);
}
}
duration2 = millis() - start;
Serial.println(duration2);
Serial.print("RATIO:\t");
Serial.println((1.0 * duration1) / duration2, 3);
Serial.println("\ndewPointFast() vs dewPoint()");
for (int cel = -40; cel < 80; cel++)
{
for (int hum = 1; hum < 100; hum++)
{
float x = abs(dewPoint(cel, hum) - dewPointFast(cel, hum));
if (x > maxError) maxError = x;
}
}
Serial.print("ERROR:\t");
Serial.println(maxError, 3);
Serial.print("Done...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,51 @@
//
// FILE: heatindexC_table.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
// DATE: 2020-04-04
//
#include "temperature.h"
volatile float hi;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println();
for (int t = 25; t <= 45; t += 1)
{
Serial.print("\t");
Serial.print(t);
}
Serial.println();
Serial.println();
for (int hum = 40; hum <= 100; hum += 5)
{
Serial.print(hum);
for (int t = 25; t <= 45; t += 1)
{
float hi = heatIndexC(t, hum);
Serial.print("\t");
Serial.print(round(hi));
}
Serial.println();
}
Serial.println();
Serial.println();
Serial.print("Done...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,43 @@
//
// FILE: heatindexC_test.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
// DATE: 2020-04-04
//
#include "temperature.h"
uint32_t start;
uint32_t duration1;
volatile float hi;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println(heatIndexC(25, 50), 2);
start = millis();
for (int cel = 10; cel < 80; cel++)
{
for (int hum = 1; hum < 100; hum++)
{
hi = heatIndexC(cel, hum);
}
}
duration1 = millis() - start;
Serial.println(duration1);
Serial.print("Done...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,51 @@
//
// FILE: heatindex_table.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
// DATE: 2020-04-04
//
#include "temperature.h"
volatile float hi;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println();
for (int t = 80; t <= 110; t += 2)
{
Serial.print("\t");
Serial.print(t);
}
Serial.println();
Serial.println();
for (int hum = 40; hum <= 100; hum += 5)
{
Serial.print(hum);
for (int t = 80; t <= 110; t += 2)
{
float hi = heatIndex(t, hum);
Serial.print("\t");
Serial.print(round(hi));
}
Serial.println();
}
Serial.println();
Serial.println();
Serial.print("Done...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,43 @@
//
// FILE: heatIndex_test.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
// DATE: 2020-04-04
//
#include "temperature.h"
uint32_t start;
uint32_t duration1;
volatile float hi;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println(heatIndex(100, 50), 2);
start = millis();
for (int t = 40; t < 110; t++)
{
for (int hum = 1; hum < 100; hum++)
{
hi = heatIndex(t, hum);
}
}
duration1 = millis() - start;
Serial.println(duration1);
Serial.print("Done...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,49 @@
//
// FILE: humidex_table.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
// DATE: 2020-04-05
//
#include "temperature.h"
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println();
for (int cel = 20; cel < 45; cel++)
{
Serial.print("\t");
Serial.print(cel);
}
Serial.println();
Serial.println();
for (int hum = 100; hum > 15; hum -= 2)
{
Serial.print(hum);
for (int cel = 20; cel < 45; cel++)
{
float dp = dewPoint(cel, hum);
float hi = humidex(cel, dp);
Serial.print("\t");
Serial.print(round(hi));
}
Serial.println();
}
Serial.println();
Serial.println();
Serial.print("Done...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,44 @@
//
// FILE: humidex_test.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
// DATE: 2020-04-05
//
#include "temperature.h"
uint32_t start;
uint32_t duration1;
volatile float hi;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println(humidex(25, 50), 2);
start = millis();
for (int t = 25; t <= 45; t++)
{
for (int hum = 1; hum <= 100; hum++)
{
float dp = dewPoint(t, hum);
hi = humidex(t, dp);
}
}
duration1 = millis() - start;
Serial.println(duration1);
Serial.print("Done...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -1,6 +1,6 @@
{
"name": "Temperature",
"keywords": "Temperature,Kelvin,Celsius,Fahrenheit,dewPoint,humidex,heatIndex",
"keywords": "Temperature, Kelvin, Celsius, Fahrenheit, dewPoint, humidex, heatIndex, windChill",
"description": "Library with weather related functions.",
"authors":
[
@ -13,12 +13,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/Temperature"
},
"version":"0.1.1",
"version":"0.2.3",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/Temperature"
}
"platforms": "*"
}

View File

@ -1,9 +1,11 @@
name=Temperature
version=0.1.1
version=0.2.3
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library with weather related functions.
paragraph=Kelvin Celsius Fahrenheit dewPoint humidex heatIndex
paragraph=Kelvin Celsius Fahrenheit dewPoint humidex heatIndex windChill
category=Data Processing
url=https://github.com/RobTillaart/Arduino/tree/master/libraries
architectures=*
url=https://github.com/RobTillaart/Temperature
architectures=*
includes=temperature.h
depends=

View File

@ -1,7 +1,21 @@
# Temperature
Small collection of temperature related functions
Arduino library with dewPoint, humidex, heatIndex and windchill functions.
TODO:
- make all celsius variants of them
- Class with option F / K / C ?
## Description
This library contains some weather related functions. These functions
are approximations based on work of NOAA a.o.
These functions can be used with temperature and humidity sensors e.g.
DHT22 or Sensirion ones to make a weather station application.
## Operations
The functions have a limited scope so one cannot use it for all input values possible.
The user should be aware of that. Check the references mentioned in the code and or
wikipedia to confirm the applicability of the values generated.
The functions do not check the inputs.
See examples for typical usage.

View File

@ -1,123 +1,162 @@
#pragma once
//
// FILE: temperature.h
// VERSION: 0.1.1
// VERSION: 0.2.3
// PURPOSE: temperature functions
//
// HISTORY:
// 0.1.0 - 2015-03-29 initial version
// 0.1.1 - 2017-07-26 double to float (issue #33)
//
// 0.2.0 - 2020-04-04 #pragma once, removed WProgram.h, readme.md, comments
// replaced obsolete links with new ones,
// tested and removed some code
// 0.2.1 2020-05-26 added windchill formulas
// 0.2.2 2020-06-19 fix library.json
// 0.2.3 2020-08-27 fix #5 order of functions, typo, fixed 1 example
#ifndef TEMPERATURE
#define TEMPERATURE
#include "WProgram.h"
#define TEMPERATURE_VERSION "0.2.3"
#define TEMPERATURE_VERSION "0.1.1"
//Celsius to Fahrenheit conversion
float Fahrenheit(float celsius)
inline float Fahrenheit(float celsius)
{
return 1.8 * celsius + 32;
return 1.8 * celsius + 32; // 5.0 / 9.0 = 1.8
}
//Celsius to Kelvin conversion
float Kelvin(float celsius)
inline float Celsius(float fahrenheit)
{
return celsius + 273.15;
return (fahrenheit - 32) * 0.55555555555; // 5.0 / 9.0 = 0.555...
}
// dewPoint function NOAA
// reference: http://wahiduddin.net/calc/density_algorithms.htm
inline float Kelvin(float celsius)
{
return celsius + 273.15;
}
// reference:
// [1] https://wahiduddin.net/calc/density_algorithms.htm
// [2] https://web.archive.org/web/20100528030817/https://www.colorado.edu/geography/weather_station/Geog_site/about.htm
// dewPoint function based on code of [2]
// calculation of the saturation vapor pressure part is based upon NOAA ESGG(temp)
float dewPoint(float celsius, float humidity)
{
float A0= 373.15/(273.15 + celsius);
float SUM = -7.90298*(A0-1);
SUM += 5.02808 * log10(A0);
SUM += -1.3816e-7 * (pow(10, (11.344*(1-1/A0)))-1) ;
SUM += 8.1328e-3*(pow(10,(-3.49149*(A0-1)))-1) ;
SUM += log10(1013.246);
float VP = pow(10, SUM-3) * humidity;
float T = log(VP/0.61078); // temp var
return (241.88*T) / (17.558-T);
// Calculate saturation vapor pressure
// ratio 100C and actual temp in Kelvin
float A0 = 373.15 / (273.15 + celsius);
// SVP = Saturation Vapor Pressure - based on ESGG() NOAA
float SVP = -7.90298 * (A0 - 1.0);
SVP += 5.02808 * log10(A0);
SVP += -1.3816e-7 * (pow(10, (11.344 * ( 1.0 - 1.0/A0))) - 1.0 );
SVP += 8.1328e-3 * (pow(10, (-3.49149 * (A0 - 1.0 ))) - 1.0 ) ;
SVP += log10(1013.246);
// calculate actual vapor pressure VP;
// note to convert to KPa the -3 is used
float VP = pow(10, SVP - 3) * humidity;
float T = log( VP / 0.61078); // temp var
return (241.88 * T) / (17.558 - T);
}
// delta max = 0.6544
// 5x faster than dewPoint()
// reference: http://en.wikipedia.org/wiki/Dew_point
// dewPointFast() is > 5x faster than dewPoint() - run dewpoint_test.ino
// delta mdewPointFastax with dewpoint() - run dewpoint_test.ino ==> ~0.347
// (earlier version mentions ~0.6544 but that testcode is gone :(
// http://en.wikipedia.org/wiki/Dew_point
float dewPointFast(float celsius, float humidity)
{
float a = 17.271;
float b = 237.7;
float temp = (a * celsius) / (b + celsius) + log(humidity/100);
float Td = (b * temp) / (a - temp);
return Td;
float a = 17.271;
float b = 237.7;
float temp = (a * celsius) / (b + celsius) + log(humidity/100);
float Td = (b * temp) / (a - temp);
return Td;
}
// http://www.ccacac.com/wp-content/uploads/2010/06/Humidex-Graph.pdf -
// https://en.wikipedia.org/wiki/Humidex
float humidex(float celsius, float DewPoint)
{
float e = 19.833625 - 5417.753 /(273.16 + DewPoint);
float h = celsius + 3.3941 * exp(e) - 5.555;
return h;
float e = 19.833625 - 5417.753 /(273.16 + DewPoint);
float h = celsius + 3.3941 * exp(e) - 5.555;
return h;
}
// TF = temp in F
// https://en.wikipedia.org/wiki/Heat_index
// TODO add valid range for TF & R
// TF = temp in Fahrenheit
// R = humidity in %
float heatIndex(float TF, float R)
{
const float c1 = -42.379;
const float c2 = 2.04901523;
const float c3 = 10.14333127;
const float c4 = -0.22475541;
const float c5 = -0.00683783;
const float c6 = -0.05481717;
const float c7 = 0.00122874;
const float c8 = 0.00085282;
const float c9 = -0.00000199;
const float c1 = -42.379;
const float c2 = 2.04901523;
const float c3 = 10.14333127;
const float c4 = -0.22475541;
const float c5 = -0.00683783;
const float c6 = -0.05481717;
const float c7 = 0.00122874;
const float c8 = 0.00085282;
const float c9 = -0.00000199;
float A = (( c5 * TF) + c2) * TF + c1;
float B = (((c7 * TF) + c4) * TF + c3) * R;
float C = (((c9 * TF) + c8) * TF + c6) * R * R;
float A = (( c5 * TF) + c2) * TF + c1;
float B = (((c7 * TF) + c4) * TF + c3) * R;
float C = (((c9 * TF) + c8) * TF + c6) * R * R;
return A + B + C;
return A + B + C;
}
// less constants => faster but slightly inaccurate
// TF = temp in F
// R = humidity in %
float heatIndexFast(float TF, float R)
// https://en.wikipedia.org/wiki/Heat_index
// TODO add valid range for TF & R
float heatIndexC(float celcius, float humidity)
{
const float c1 = -42.379;
const float c2 = 2.04901523;
const float c3 = 10.14333127;
const float c4 = -0.22475541;
const float c1 = -8.78469475556;
const float c2 = 1.61139411;
const float c3 = 2.33854883889;
const float c4 = -0.14611605;
const float c5 = -0.012308094;
const float c6 = -0.0164248277778;
const float c7 = 0.002211732;
const float c8 = 0.00072546;
const float c9 = -0.000003582;
float A = c2 * TF + c1;
float B = (c4 * TF + c3) * R;
float A = (( c5 * celcius) + c2) * celcius + c1;
float B = (((c7 * celcius) + c4) * celcius + c3) * humidity;
float C = (((c9 * celcius) + c8) * celcius + c6) * humidity * humidity;
return A + B;
return A + B + C;
}
// integer version
// TF = temp in F
// R = humidity in %
int heatIndexFastInt(int TF, int R)
// https://en.wikipedia.org/wiki/Wind_chill
// US = Fahrenheit / miles
// METRIC = Celsius / meter/sec
// windspeed @ 10 meter,
// if convert is true => windspeed will be converted to 1.5 meter
// else ==> formula assumes windspeed @ 1.5 meter
// US
float WindChill_F_mph(const float fahrenheit, const float milesPerHour, const bool convert = true)
{
// consts multiplied by 1024
long c1 = -43396;
long c2 = 2098;
long c3 = 10387;
long c4 = -230;
long A = c2 * TF + c1; // so A is x 1024
long B = (c4 * TF + c3) * R; // and B too
return (A + B + 512) / 1024; // division becomes a shift; +512 is for rounding
float windSpeed = milesPerHour;
if (convert) windSpeed = pow(milesPerHour, 0.16);
return 35.74 + 0.6125 * fahrenheit + (0.4275 * fahrenheit - 35.75) * windSpeed;
}
#endif
//
// END OF FILE
//
// METRIC
float WindChill_C_kmph(const float celcius, const float kilometerPerHour, const bool convert = true)
{
float windSpeed = kilometerPerHour;
if (convert) windSpeed = pow(kilometerPerHour, 0.16);
return 13.12 + 0.6215 * celcius + (0.3965 * celcius - 11.37) * windSpeed;
}
float WindChill_C_mps(const float celcius, const float meterPerSecond, const bool convert = true)
{
return WindChill_C_kmph(celcius, meterPerSecond * 3.6, convert);
}
// -- END OF FILE --

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018-2020 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,25 @@
# Troolean
Arduino Library for a three state logic datatype supporting {True False Unknown}
# Description
Troolean is a datatype that implements three state logic with the values
{True False Unknown }
Logic operators are similar to boolean and behave the same for the familiar boolean values.
Trooleans can be used e.g. to indicate a value is valid, invald or unknown to be valid or not.
Imagine a monitoring application which has different sensors e.g. temperature. If the sensor
is sampled less than 1 minute ago one could say the value is valid, if the last sample is taken
more than an hour ago it could be changed (a lot) or not. So one does not know if the temperature
has become invalid or not. Boolean logic would make it invalid, but troolean allows to state we
just don't know. As long as there is no urgency ( a customer that needs a valid value)
one does not need to resample yet.
See also https://en.wikipedia.org/wiki/Three-valued_logic
# Operation
See examples

View File

@ -1,17 +1,18 @@
//
// FILE: Troolean.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// PURPOSE: class for troolean math (true false unknown)
// URL:
// VERSION: 0.1.3
// PURPOSE: Arduino Library for a three state logic datatype supporting {true false unknown}
// URL: https://github.com/RobTillaart/Troolean
//
// HISTORY:
// 0.1.0 initial version
// 0.1.1 adjust (in)equality so that unknown == unknown
// although there could be arguments that unknown != unknown
// added isTrue(), isFalse(), isUnknown()
// first public release
//
// 0.1.0 2018-01-10 initial version
// 0.1.1 2018-01-28 adjust (in)equality so that unknown == unknown
// although there could be arguments that unknown != unknown
// added isTrue(), isFalse(), isUnknown()
// first public release
// 0.1.2 2020-06-07 small refactor; updated keywords.txt; metadata
// 0.1.3 2020-06-19 fix library.json
#include "Troolean.h"
@ -37,7 +38,6 @@ Troolean::Troolean(const Troolean &t)
_value = t._value;
}
// PRINTING
size_t Troolean::printTo(Print& p) const
{
@ -99,7 +99,6 @@ Troolean::operator bool() const
return false;
}
// NEGATE
// t -> f
// f -> t
@ -124,7 +123,6 @@ Troolean Troolean::operator && (const bool &b)
if (_value == 0 || !b) return Troolean(0);
if (_value == 1 && b) return Troolean(1);
return Troolean(-1);
}
Troolean Troolean::operator || (const Troolean &t)
@ -141,7 +139,4 @@ Troolean Troolean::operator || (const bool &b)
return Troolean(-1);
}
// END OF FILE
// -- END OF FILE --

View File

@ -1,31 +1,29 @@
#pragma once
//
// FILE: Troolean.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// PURPOSE: class for Troolean math
// URL: https://en.wikipedia.org/wiki/Three-valued_logic
// VERSION: 0.1.3
// PURPOSE: Arduino Library for a three state logic datatype supporting {true false unknown}
// URL: https://github.com/RobTillaart/Troolean
// https://en.wikipedia.org/wiki/Three-valued_logic
// Kleene and Priest logics
//
// HISTORY:
// see Troolean.cpp file
//
#ifndef TROOLEAN_H
#define TROOLEAN_H
#include "Arduino.h"
#include "Printable.h"
#define TROOLEAN_LIB_VERSION (F("0.1.1"))
#define TROOLEAN_LIB_VERSION (F("0.1.3"))
// TODO:rvdt enum values in a separate type....
#define unknown -1
class Troolean: public Printable
{
public:
Troolean();
Troolean(const int8_t);
Troolean(const int8_t); // 0 = false, -1 = unknown anything else = true
Troolean(const Troolean&);
size_t printTo(Print&) const;
@ -52,9 +50,10 @@ public:
inline bool isUnknown() { return _value == -1; };
// ideas
// bool toBool(); // returns random true/false if unknown....
// Troolean operator &&=
// Troolean operator ||=
//
// bool toBool(); // returns random true/false if unknown....
// extend with dontcare ? ==> four state logic ? Foolean?
private:
@ -62,6 +61,4 @@ private:
};
#endif
// END OF FILE
// -- END OF FILE --

View File

@ -3,9 +3,7 @@
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// PURPOSE: test for troolean (tri state) math library for Arduino
// URL:
//
// Released to the public domain
// URL: https://github.com/RobTillaart/Troolean
//
#include "Troolean.h"

View File

@ -5,8 +5,6 @@
// PURPOSE: test for troolean (tri state) math library for Arduino
// URL:
//
// Released to the public domain
//
#include "Troolean.h"

View File

@ -1,18 +1,12 @@
#######################################
# Syntax Coloring Map for Troolean
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
Troolean KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
isTrue KEYWORD2
isFalse KEYWORD2
isUnknown KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
unknown LITERAL1

View File

@ -1,7 +1,7 @@
{
"name": "Troolean",
"keywords": "Troolean,numbers",
"description": "Library with Troolean math for Arduino.",
"description": "Arduino Library for a three state logic datatype supporting {true false unknown}",
"authors":
[
{
@ -13,12 +13,9 @@
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/Arduino.git"
"url": "https://github.com/RobTillaart/Troolean.git"
},
"version":"0.1.1",
"version":"0.1.3",
"frameworks": "arduino",
"platforms": "*",
"export": {
"include": "libraries/Troolean"
}
"platforms": "*"
}

View File

@ -1,9 +1,11 @@
name=Troolean
version=0.1.1
version=0.1.3
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library with troolean math for Arduino.
paragraph=
sentence=Arduino Library for a three state logic datatype
paragraph=supporting {true false unknown}
category=Data Processing
url=https://github.com/RobTillaart/Arduino/tree/master/libraries/
architectures=*
url=https://github.com/RobTillaart/Troolean
architectures=*
includes=Troolean.h
depends=

View File

@ -0,0 +1 @@
https://github.com/RobTillaart/ANSI

View File

@ -8,14 +8,13 @@ The XMLWriter class supports generating XML files and send these over a stream
like Ethernet SD.File or Serial.
When instantiating an XMLWriter one can define the internal buffer size.
This buffering makes the output faster, especially for Ethernet and SD.File.
The buffer size should be at least 2 bytes.
A bigger buffer is often faster but it also depends on the properties of the
stream to see real performance gains.
A bigger buffer will make the output faster, especially for Ethernet and SD.File.
The buffer size should be at least 2 bytes and max 250.
How much faster depends on the properties of the stream.
E.g. the baudrate and internal buffer of Serial, packet behaviour of Ethernet,
or paging of SD cards.
So if performance is an issue one should do some testruns with different sizes
for the buffer and choose one that is appropriate.
If performance is low one should do testruns with different sizes for the buffer
and choose one that is appropriate.
Indicative sizes based upon the examples.
Run your tests to find your application optimum.
@ -26,8 +25,87 @@ Run your tests to find your application optimum.
| Serial | 5 |
| SD File | 10-16 |
Important to know when usinig buffering is that your code should always include
a call to **XML.flush()** at the end of the XML generation to flush the buffer.
**Important** When using buffering you should always include a call to **XML.flush()**
at the end of the XML generation. This will flush the last bytes in the internal buffer.
## Interface
Constructor
- **XMLWriter(stream, bufsize);** Constructor defines the stream and the buffersize
to optimize performance vs memory usage.
Functions for manual layout control
- **setIndentSize(size = 2);** preferred a multiple of 2;
- **incrIndent()**
- **decrIndent()**
- **indent();**
- **raw(str)** inject any string
General settings
- **setConfig(cfg)** used to show/strip comment, indent, newLine.
use **setConfig(0);** to minimize the output
- **newLine(n)** add a number of newlines to the output, default = 1
----
Functions
- **reset()** resets internal state, to be called before new XML is written
- **Header()** injects standard XML header string, must be first line
- **comment(text, multiline)** \<!-- text --\>
if multiline == true it does not indent to allow bigger text blocks
- **flush()** call flush() at the end of writing to empty the internal buffer. **!!**
Functions to create simple tags with named fields
- **tagOpen(tag, newLine)** \<tag\>
- **tagOpen(tag, name, newLine)** \<tag name="name"\>
- **tagCLose()** \</tag\>
Functions to make up tags with multiple fields:
- **tagStart(tag)** \<tag
- **tagField(field, string);** field="string"
- **tagField(field, T value, base = DEC);** standard math types
- **tagEnd(newline = true, addSlash = true);** /\>
Functions to make a node
- **writeNode(tag, value);** \<tag\>value\</tag\>
- **writeNode(tag, T value, base = DEC);** standard math types
Helper
- **escape(str)** expands the xml chars: \"\'\<\>\&
Metrics (to optimize buffersize in combination with timing)
- **bufferIndex()** returns the size of the internal buffer
- **bytesWritten()** idem, since reset().
## Print interface
XMLWriter 0.2.4 implements the Print interface, so at any moment one can use
**print()** or **println()** to inject specific information.
E.g. Note that **tagField()** and **writeNode()** do not support 64 bit integer
types and large values of double.
My **printHelpers library** helps to convert these to strings which can be printed.
See example.
The Print interface can also be used to print objects that
implement the **Printable** interface. See example.
With the support of the Print interface, **raw()** is becoming obsolete as it only
can inject strings.
## Configuration flags
| Flag | Value | Meaning |
|:----|:----|:----|
|XMLWRITER_NONE | 0x00 | minimize output, smaller & faster |
|XMLWRITER_COMMENT | 0x01 | allow comments |
|XMLWRITER_INDENT | 0x02 | allow indentation |
|XMLWRITER_NEWLINE | 0x04 | allow newlines |
- **setConfig(XMLWRITER_NONE);** to minimize the output in bytes.
- **setConfig(XMLWRITER_NEWLINE);** to break an XML stream in lines.
- **setConfig(XMLWRITER_NEWLINE | XMLWRITER_INDENT);** to see XML structure.
- **setConfig(XMLWRITER_NEWLINE | XMLWRITER_INDENT | XMLWRITER_COMMENT);** to see XML structure + comments.
## Operation

View File

@ -1,7 +1,7 @@
//
// FILE: XMLWriter.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.2.2
// VERSION: 0.2.4
// DATE: 2013-11-06
// PURPOSE: Arduino library for creating XML
//
@ -19,7 +19,8 @@
// 0.2.0 2020-04-24 refactor, added examples, #pragma, print as base class
// 0.2.1 2020-04-26 performance optimized, setconfig() + newLine() added
// 0.2.2 2020-04-29 dynamic buffer size in constructor
//
// 0.2.3 2020-06-19 fix library.json
// 0.2.4 2020-07-07 fix #6 Print interface made public
#include <XMLWriter.h>
@ -51,6 +52,21 @@ void XMLWriter::header()
print(F("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"));
}
// void XMLWriter::meta()
// {
// print(F("<!-- "));
// print('\n');
// print(F(" VERSION: "));
// println(XMLWRITER_VERSION);
// print(F("MAXLEVEL: "));
// println(XMLWRITER_MAXLEVEL);
// print(F(" TAGSIZE: "));
// println(XMLWRITER_MAXTAGSIZE);
// print(F(" CONFIG: "));
// println(_config);
// print(F(" -->\n"));
// }
void XMLWriter::comment(const char* text, const bool multiLine)
{
if (_config & XMLWRITER_COMMENT)
@ -82,13 +98,20 @@ void XMLWriter::tagOpen(const char* tag, const char* name, const bool newline)
{
if (_tidx > XMLWRITER_MAXLEVEL)
{
comment("XMLWRITER_MAXLEVEL exceeded.");
comment("MAXLEVEL exceeded.");
comment(tag);
comment(name);
flush();
return;
}
// "unsafe" strcpy saves ~20 bytes
strncpy(_tagStack[_tidx++], tag, XMLWRITER_MAXTAGSIZE);
if (strlen(tag) > XMLWRITER_MAXTAGSIZE)
{
comment("MAXTAGSIZE exceeded.");
comment(tag);
flush();
return;
}
strcpy(_tagStack[_tidx++], tag);
tagStart(tag);
if (name[0] != 0) tagField("name", name);
tagEnd(newline, NOSLASH);
@ -102,7 +125,6 @@ void XMLWriter::tagClose(const bool ind)
print("</");
print(_tagStack[--_tidx]);
print(">\n");
delay(10);
}
void XMLWriter::tagStart(const char *tag)

View File

@ -2,14 +2,14 @@
//
// FILE: XMLWriter.h
// AUTHOR: Rob Tillaart
// VERSION: 0.2.2
// VERSION: 0.2.4
// DATE: 2013-11-06
// PURPOSE: Arduino library for creating XML
//
#include "Arduino.h"
#define XMLWRITER_VERSION "0.2.2"
#define XMLWRITER_VERSION "0.2.3"
// for comment()
#define NOMULTILINE false
@ -38,16 +38,16 @@
#define XMLWRITER_ESCAPE_SUPPORT
// configuration - setConfig
#define XMLWRITER_NONE 0x00
#define XMLWRITER_COMMENT 0x01
#define XMLWRITER_INDENT 0x02
#define XMLWRITER_NEWLINE 0x04
#define XMLWRITER_NONE 0x00
#define XMLWRITER_COMMENT 0x01
#define XMLWRITER_INDENT 0x02
#define XMLWRITER_NEWLINE 0x04
// uncomment next line to reduce ~30bytes RAM in escape() (AVR oonly)
// #define __PROGMEM__
class XMLWriter : Print
class XMLWriter : public Print
{
public:
// default = Serial
@ -63,6 +63,8 @@ public:
// standard XML header
void header();
// void meta();
// if multiline == true it does not indent to allow bigger text blocks
// <!-- text -->
void comment(const char* text, const bool multiLine = false);

View File

@ -0,0 +1,58 @@
//
// FILE: XMLWriterPrint_1.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo Print interface
// DATE: 2020-07-07
// URL: https://github.com/RobTillaart/XMLWriter
//
#include <XMLWriter.h>
XMLWriter XML(&Serial);
char buffer[24];
void setup()
{
Serial.begin(115200);
XML.newLine(0);
XML.print("\n");
XML.header();
XML.comment("XMLWriter Print interface");
XML.setConfig(0); // no indent, no (further) comments
// The {} are not mandatory shows the XML structure in the code...
XML.tagOpen("Order");
{
XML.println();
XML.tagOpen("Address stamp");
{
XML.println("Mr. D. Bowie\nSpiderstreet 42\n54321 Mars");
}
XML.tagClose();
XML.println();
XML.tagOpen("Actions");
{
XML.println("[ ] Two tickets for Central Park");
XML.println("[ ] Diner at the Ritz");
XML.println("[ ] Surprise Hotel");
}
XML.tagClose();
XML.println();
}
XML.tagClose();
XML.flush();
}
void loop()
{
}
// -- END OF FILE --

Some files were not shown because too many files have changed in this diff Show More