- 0.1.5 support > 256 buckets; robustness; check allocated data

This commit is contained in:
RobTillaart 2017-07-16 08:04:20 +02:00
parent 745cf64697
commit 0a93ce6c27
5 changed files with 149 additions and 88 deletions

View File

@ -10,13 +10,14 @@
// double b[] = { 0, 100, 200, 300, 325, 350, 375, 400, 500, 600, 700, 800, 900, 1000 };
// boundaries array does not need to be equally distributed.
double b[] = {
0, 100, 200, 300, 325, 350, 375 };
Histogram hist(7, b);
unsigned long lastTime = 0;
const unsigned long threshold = 50; // milliseconds, for updating display
uint32_t lastTime = 0;
const uint32_t threshold = 25; // milliseconds, for updating display
void setup()
{
@ -59,7 +60,7 @@ void loop()
hist.add(x);
// update output
unsigned long now = millis();
uint32_t now = millis();
if (now - lastTime > threshold)
{
lastTime = now;

View File

@ -0,0 +1,61 @@
//
// FILE: hist_test_graph.ino
// AUTHOR: Rob Tillaart
// DATE: 2017-07-16
//
// PUPROSE: test histogram frequency
//
#include "histogram.h"
// boundaries array does not need to be equally distributed.
double bounds[] = { 0, 100, 200, 300, 325, 350, 375, 400, 500, 600, 700, 800, 900, 1000 };
Histogram hist(14, bounds);
uint32_t lastTime = 0;
const uint32_t threshold = 1000; // milliseconds, for updating display
void setup()
{
Serial.begin(115200);
Serial.print(__FILE__);
Serial.print("\nHistogram version: ");
Serial.println(HISTOGRAM_LIB_VERSION);
Serial.print("# buckets: ");
Serial.println(hist.size());
Serial.println();
}
void loop()
{
// "generator" for histogram data
int x = analogRead(A0);
hist.add(x);
// update output
uint32_t now = millis();
if (now - lastTime > threshold)
{
lastTime = now;
for (int i = 0; i < hist.size(); i++)
{
Serial.print(i);
Serial.print("\t");
Serial.print(hist.frequency(i), 2);
Serial.print("\t");
int n = hist.frequency(i) * 50; // 0..50
for (int p = 0; p < n; p++);
{
Serial.print(']')
}
Serial.println();
}
if (hist.count() > 1000000UL) hist.clear();
}
}

View File

@ -2,7 +2,7 @@
//
// FILE: Histogram.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.04
// VERSION: 0.1.5
// PURPOSE: Histogram library for Arduino
// DATE: 2012-11-10
//
@ -12,85 +12,80 @@
// 0.1.0 - 2012-11-10 initial version
// 0.1.1 - 2012-11-10 added PMF() and CDF()
// 0.1.2 - 2012-12-23 changed float to double; some comments
// 0.1.03 - 2013-09-29 testing a lot & refactoring
// 0.1.04 - 2015-03-06 stricter interface
// 0.1.3 - 2013-09-29 testing a lot & refactoring
// 0.1.4 - 2015-03-06 stricter interface
// 0.1.5 - 2015-07-12 refactor, support for > 256 buckets; prevent alloc errors
//
// Released to the public domain
//
#include "histogram.h"
Histogram::Histogram(const uint8_t len, double *bounds)
Histogram::Histogram(const int16_t len, double *bounds)
{
_bounds = bounds;
_len = len + 1;
_data = (long*) malloc((_len) * sizeof(long));
clear();
_bounds = bounds;
_len = len + 1;
_data = (int32_t *) malloc((_len) * sizeof(int32_t));
if (_data) clear();
else _len = 0;
_cnt = 0;
}
Histogram::~Histogram()
{
free(_data); // free may still have a bug :(
if (_data) free(_data);
}
// resets all counters
void Histogram::clear()
{
for (uint8_t i = 0; i < _len; i++)
{
_data[i] = 0;
}
_cnt = 0;
for (int16_t i = 0; i < _len; i++) _data[i] = 0;
_cnt = 0;
}
// adds a new value to the histogram - increasing
void Histogram::add(const double f)
{
if (_len > 0)
{
_data[find(f)]++;
_cnt++;
}
}
// adds a new value to the histogram - decreasing
void Histogram::sub(const double f)
{
if (_len > 0)
{
_data[find(f)]--;
_cnt++;;
}
_cnt++;
}
// returns the number of buckets
uint8_t Histogram::size()
{
return _len;
}
// returns the number of values added
unsigned long Histogram::count()
{
return _cnt;
}
// returns the count of a bucket
long Histogram::bucket(const uint8_t idx)
int32_t Histogram::bucket(const int16_t idx)
{
if (idx > _len) return 0;
return _data[idx];
if (idx > _len) return 0;
return _data[idx];
}
// returns the relative frequency of a bucket
double Histogram::frequency(const uint8_t idx)
double Histogram::frequency(const int16_t idx)
{
if (_cnt == 0) return NAN;
if (idx > _len) return 0; // diff with PMF
return (1.0 * _data[idx]) / _cnt;
if (_cnt == 0 || _len == 0) return NAN;
if (idx > _len) return 0; // diff with PMF
return (1.0 * _data[idx]) / _cnt;
}
// EXPERIMENTAL
// returns the probability of the bucket of a value
double Histogram::PMF(const double val)
{
if (_cnt == 0) return NAN;
uint8_t idx = find(val);
return (1.0 *_data[idx]) / _cnt;
if (_cnt == 0 || _len == 0) return NAN;
int16_t idx = find(val);
return (1.0 * _data[idx]) / _cnt;
}
// EXPERIMENTAL
@ -98,14 +93,14 @@ double Histogram::PMF(const double val)
// values <= value
double Histogram::CDF(const double val)
{
if (_cnt == 0) return NAN;
uint8_t idx = find(val);
long sum = 0;
for (uint8_t i=0; i<= idx; i++)
{
sum += _data[i];
}
return (1.0 * sum) / _cnt;
if (_cnt == 0 || _len == 0) return NAN;
int16_t idx = find(val);
int32_t sum = 0;
for (int16_t i = 0; i <= idx; i++)
{
sum += _data[i];
}
return (1.0 * sum) / _cnt;
}
// EXPERIMENTAL
@ -113,32 +108,34 @@ double Histogram::CDF(const double val)
// which the CDF is at least prob.
double Histogram::VAL(const double prob)
{
if (_cnt == 0) return NAN;
double p = prob;
if (p < 0.0) p = 0.0;
if (p > 1.0) p = 1.0;
if (_cnt == 0 || _len == 0) return NAN;
double p = prob;
if (p < 0.0) p = 0.0;
if (p > 1.0) p = 1.0;
double value = p * _cnt;
long sum = 0;
for (uint8_t i = 0; i < _len; i++)
{
sum += _data[i];
if (sum >= value && (i <(_len-1)) ) return _bounds[i];
}
return INFINITY;
double probability = p * _cnt;
int32_t sum = 0;
for (int16_t i = 0; i < _len; i++)
{
sum += _data[i];
if (sum >= probability && (i <(_len-1)) ) return _bounds[i];
}
return INFINITY;
}
// returns the bucket number for value val
uint8_t Histogram::find(const double val)
int16_t Histogram::find(const double val)
{
for (uint8_t i = 0; i< (_len-1); i++)
{
if (_bounds[i] >= val) return i;
}
return _len-1;
// uint8_t i = 0;
// while ((i < (_len-1)) && (_bounds[i] < val)) i++;
// return i;
if (_len <= 0) return -1;
for (int16_t i = 0; i < (_len-1); i++)
{
if (_bounds[i] >= val) return i;
}
return _len-1; // len?
// int16_t i = 0;
// while ((i < (_len-1)) && (_bounds[i] < val)) i++;
// return i;
}
// END OF FILE

View File

@ -3,7 +3,7 @@
//
// FILE: Histogram.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.03
// VERSION: 0.1.5
// PURPOSE: Histogram library for Arduino
// DATE: 2012-11-10
//
@ -20,34 +20,36 @@
#include "WProgram.h"
#endif
#define HISTOGRAM_LIB_VERSION "0.1.04"
#define HISTOGRAM_LIB_VERSION "0.1.5"
class Histogram
{
public:
Histogram(const uint8_t len, double *bounds);
Histogram(const int16_t len, double *bounds);
~Histogram();
void clear();
void add(const double val);
void sub(const double val);
void clear();
void add(const double val);
void sub(const double val);
uint8_t size();
unsigned long count();
long bucket(const uint8_t idx);
// number of buckets
inline int16_t size() { return _len; };
// number of values added to all buckets
inline uint32_t count() { return _cnt; };
// number of values added to single bucket
int32_t bucket(const int16_t idx);
double frequency(const uint8_t idx);
double PMF(const double val);
double CDF(const double val);
double VAL(const double prob);
uint8_t find(const double f);
// void strategy();
double frequency(const int16_t idx);
double PMF(const double val);
double CDF(const double val);
double VAL(const double prob);
int16_t find(const double f);
protected:
double * _bounds;
long * _data;
uint8_t _len;
unsigned long _cnt;
double * _bounds;
int32_t * _data;
int16_t _len;
uint32_t _cnt;
};
#endif

View File

@ -1,5 +1,5 @@
name=Histogram
version=0.1.3
version=0.1.5
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library for creating histogram math.