GY-63_MS5611/libraries/Histogram/histogram.cpp

435 lines
7.5 KiB
C++
Raw Normal View History

//
2017-07-16 02:04:20 -04:00
// FILE: Histogram.cpp
// AUTHOR: Rob Tillaart
// DATE: 2012-11-10
2024-05-26 05:07:34 -04:00
// VERSION: 0.3.7
2024-01-04 05:07:07 -05:00
// PURPOSE: Histogram library for Arduino
// URL: https://github.com/RobTillaart/Histogram
2021-12-19 07:52:01 -05:00
#include "histogram.h"
2021-11-04 07:32:04 -04:00
Histogram::Histogram(const uint16_t length, float *bounds)
{
_bounds = bounds;
2021-11-04 07:32:04 -04:00
_length = length + 1;
_data = (int32_t *) malloc((_length) * sizeof(int32_t));
2023-02-22 04:34:45 -05:00
if (_data != NULL)
{
clear();
}
else
{
_length = 0;
}
2021-11-04 07:32:04 -04:00
_count = 0;
2023-07-24 06:51:25 -04:00
_status = HISTO_OK;
_maxBucket = 2147483647;
}
2021-11-04 07:32:04 -04:00
Histogram::~Histogram()
{
2023-02-22 04:34:45 -05:00
if (_data != NULL)
{
free(_data);
}
}
2021-11-04 07:32:04 -04:00
2022-11-09 04:42:12 -05:00
// resets all counters to value (default 0)
2023-07-24 06:51:25 -04:00
uint8_t Histogram::clear(int32_t value)
{
2023-02-22 04:34:45 -05:00
for (uint16_t i = 0; i < _length; i++)
{
_data[i] = value;
}
2021-11-04 07:32:04 -04:00
_count = 0;
2023-07-24 06:51:25 -04:00
_status = HISTO_OK;
if (value == _maxBucket) _status = HISTO_FULL;
return _status;
}
2021-11-04 07:32:04 -04:00
2023-07-24 06:51:25 -04:00
uint8_t Histogram::setBucket(const uint16_t index, int32_t value)
2023-02-22 04:34:45 -05:00
{
_data[index] = value;
2023-07-24 06:51:25 -04:00
_status = HISTO_OK;
if (value == _maxBucket) _status = HISTO_FULL;
return _status;
2023-02-22 04:34:45 -05:00
}
2022-11-09 04:42:12 -05:00
// adds a new value to the histogram - increasing
2023-07-24 06:51:25 -04:00
uint8_t Histogram::add(const float value)
{
2023-07-24 06:51:25 -04:00
if (_length == 0)
{
2023-07-24 06:51:25 -04:00
_status = HISTO_ERR_LENGTH;
return _status;
}
2023-07-24 06:51:25 -04:00
uint16_t index = find(value);
if (_data[index] == _maxBucket)
{
_status = HISTO_ERR_FULL;
return _status;
}
_data[index]++;
_count++;
_status = HISTO_OK;
if (_data[index] == _maxBucket) _status = HISTO_FULL;
return _status;
}
2021-11-04 07:32:04 -04:00
2022-11-09 04:42:12 -05:00
// adds a new value to the histogram - decreasing
2023-07-24 06:51:25 -04:00
uint8_t Histogram::sub(const float value)
{
2023-07-24 06:51:25 -04:00
if (_length == 0)
{
2023-07-24 06:51:25 -04:00
_status = HISTO_ERR_LENGTH;
return _status;
}
2023-07-24 06:51:25 -04:00
uint16_t index = find(value);
if (_data[index] == -_maxBucket)
{
_status = HISTO_ERR_FULL;
return _status;
}
_data[index]--;
_count++;
_status = HISTO_OK;
if (_data[index] == _maxBucket) _status = HISTO_FULL;
return _status;
}
uint8_t Histogram::status()
{
return _status;
}
2021-11-04 07:32:04 -04:00
2022-11-09 04:42:12 -05:00
// number of buckets
2023-02-22 04:34:45 -05:00
uint16_t Histogram::size()
{
return _length;
}
2022-11-09 04:42:12 -05:00
// number of values added to all buckets
uint32_t Histogram::count()
2023-02-22 04:34:45 -05:00
{
2022-11-09 04:42:12 -05:00
return _count;
2023-02-22 04:34:45 -05:00
}
2022-11-09 04:42:12 -05:00
// returns the count of a bucket
2021-11-04 07:32:04 -04:00
int32_t Histogram::bucket(const uint16_t index)
{
2021-11-04 07:32:04 -04:00
if (index > _length) return 0;
return _data[index];
}
2021-11-04 07:32:04 -04:00
2022-11-09 04:42:12 -05:00
// returns the relative frequency of a bucket
2021-11-04 07:32:04 -04:00
float Histogram::frequency(const uint16_t index)
{
2021-11-04 07:32:04 -04:00
if ((_count == 0) || (_length == 0)) return NAN;
2023-02-22 04:34:45 -05:00
if (index > _length) return 0; // differs from PMF()
2021-11-04 07:32:04 -04:00
return (1.0 * _data[index]) / _count;
}
2021-11-04 07:32:04 -04:00
2022-11-09 04:42:12 -05:00
// EXPERIMENTAL
// returns the probability of the bucket of a value
2021-11-04 07:32:04 -04:00
float Histogram::PMF(const float value)
{
2021-11-04 07:32:04 -04:00
if ((_count == 0) || (_length == 0)) return NAN;
2021-11-04 07:32:04 -04:00
uint16_t index = find(value);
return (1.0 * _data[index]) / _count;
}
2021-11-04 07:32:04 -04:00
2022-11-09 04:42:12 -05:00
// EXPERIMENTAL
// returns the cumulative probability of
// values <= value
2021-11-04 07:32:04 -04:00
float Histogram::CDF(const float value)
{
2021-11-04 07:32:04 -04:00
if ((_count == 0) || (_length == 0)) return NAN;
2022-11-09 04:42:12 -05:00
// TODO: could be done in one loop?
2021-11-04 07:32:04 -04:00
uint16_t index = find(value);
int32_t sum = 0;
for (uint16_t i = 0; i <= index; i++)
{
sum += _data[i];
}
2021-11-04 07:32:04 -04:00
return (1.0 * sum) / _count;
}
2021-11-04 07:32:04 -04:00
2022-11-09 04:42:12 -05:00
// EXPERIMENTAL
// returns the value of the original array for
2023-02-22 04:34:45 -05:00
// which the CDF is at least probability.
// must start at 0.
float Histogram::VAL(const float probability)
{
2021-11-04 07:32:04 -04:00
if ((_count == 0) || (_length == 0)) return NAN;
2023-02-22 04:34:45 -05:00
float prob = probability;
if (prob < 0.0) prob = 0.0;
else if (prob > 1.0) prob = 1.0;
2023-02-22 04:34:45 -05:00
prob *= _count;
int32_t sum = 0;
2021-11-04 07:32:04 -04:00
for (uint16_t i = 0; i < _length; i++)
{
sum += _data[i];
2023-02-22 04:34:45 -05:00
if ((sum >= prob) && (i < (_length - 1)))
2021-11-04 07:32:04 -04:00
{
return _bounds[i];
}
}
return INFINITY;
}
2021-11-04 07:32:04 -04:00
2023-07-24 06:51:25 -04:00
int32_t Histogram::sum()
{
int32_t _sum = 0;
for (uint16_t i = 0; i < _length; i++)
{
_sum += _data[i];
}
return _sum;
}
2024-01-04 05:07:07 -05:00
// returns the bucket number for value
// - binary search, more memory ; faster for #buckets > 20 ?
2021-11-04 07:32:04 -04:00
// uint16_t Histogram::find(const float value)
// {
// if (_length <= 0) return -1;
// uint16_t low = 0, high = _length;
// uint16_t mid;
// while (high - low > 1)
// {
// mid = (low + high)/2;
// if (_bounds[mid] > value)
// {
// high = mid;
// }
// else
// {
// low = mid;
// }
// }
// if (_bounds[mid] > value) return mid;
// return _length - 1;
// }
2022-11-09 04:42:12 -05:00
// returns the bucket number for value
2023-02-22 04:34:45 -05:00
// must start at 0.
2021-11-04 07:32:04 -04:00
uint16_t Histogram::find(const float value)
{
if (_length <= 0) return -1;
for (uint16_t i = 0; i < (_length - 1); i++)
{
if (_bounds[i] >= value)
{
return i;
}
}
return _length - 1;
}
2022-11-09 04:42:12 -05:00
// returns the (first) index of the bucket with minimum value.
2021-11-04 07:32:04 -04:00
uint16_t Histogram::findMin()
{
if (_length <= 0) return -1;
uint16_t index = 0;
2023-02-22 04:34:45 -05:00
uint16_t n = _length;
while (n > 1)
2021-11-04 07:32:04 -04:00
{
2023-02-22 04:34:45 -05:00
n--;
if (_data[n] < _data[index]) index = n;
2021-11-04 07:32:04 -04:00
}
return index;
}
2022-11-09 04:42:12 -05:00
// returns the (first) index of the bucket with maximum value.
2021-11-04 07:32:04 -04:00
uint16_t Histogram::findMax()
{
if (_length <= 0) return -1;
uint16_t index = 0;
2023-02-22 04:34:45 -05:00
uint16_t n = _length;
while (n > 1)
2021-11-04 07:32:04 -04:00
{
2023-02-22 04:34:45 -05:00
n--;
if (_data[n] > _data[index]) index = n;
2021-11-04 07:32:04 -04:00
}
return index;
}
2023-02-22 04:34:45 -05:00
// returns the number of buckets with an exact level.
2021-11-04 07:32:04 -04:00
uint16_t Histogram::countLevel(const int32_t level)
{
if (_length <= 0) return -1;
uint16_t buckets = 0;
2023-02-22 04:34:45 -05:00
uint16_t n = _length;
while (n > 0)
2021-11-04 07:32:04 -04:00
{
2023-02-22 04:34:45 -05:00
n--;
if (_data[n] == level) buckets++;
2021-11-04 07:32:04 -04:00
}
return buckets;
}
2022-11-09 04:42:12 -05:00
// returns the number of buckets above a certain level.
2021-11-04 07:32:04 -04:00
uint16_t Histogram::countAbove(const int32_t level)
{
2021-11-04 07:32:04 -04:00
if (_length <= 0) return -1;
2021-11-04 07:32:04 -04:00
uint16_t buckets = 0;
2023-02-22 04:34:45 -05:00
uint16_t n = _length;
while (n > 0)
{
2023-02-22 04:34:45 -05:00
n--;
if (_data[n] > level) buckets++;
}
2021-11-04 07:32:04 -04:00
return buckets;
}
2021-11-04 07:32:04 -04:00
2022-11-09 04:42:12 -05:00
// returns the number of buckets below a certain level.
2021-11-04 07:32:04 -04:00
uint16_t Histogram::countBelow(const int32_t level)
{
if (_length <= 0) return -1;
uint16_t buckets = 0;
2023-02-22 04:34:45 -05:00
uint16_t n = _length;
while (n > 0)
2021-11-04 07:32:04 -04:00
{
2023-02-22 04:34:45 -05:00
n--;
if (_data[n] < level) buckets++;
2021-11-04 07:32:04 -04:00
}
return buckets;
}
2024-01-04 05:07:07 -05:00
///////////////////////////////////////////////////
//
// experimental
//
// use with care
float Histogram::saturation()
{
return (1.0 * _count) / _length;
}
2023-07-24 06:51:25 -04:00
// experimental use with care
int32_t Histogram::getMaxBucket()
{
return _maxBucket;
}
void Histogram::setMaxBucket(int32_t value)
{
_maxBucket = value;
}
2021-11-04 07:32:04 -04:00
//////////////////////////////////////////////////////////////
//
2023-07-24 06:51:25 -04:00
// DERIVED CLASS - HISTOGRAM16
2021-11-04 07:32:04 -04:00
//
Histogram16::Histogram16(const uint16_t length, float *bounds) : Histogram(length, bounds)
{
2023-07-24 06:51:25 -04:00
_bounds = bounds;
_length = length + 1;
_data = (int16_t *) malloc((_length) * sizeof(int16_t));
if (_data != NULL)
{
clear();
}
else
{
_length = 0;
}
_count = 0;
_status = HISTO_OK;
_maxBucket = 32767;
}
Histogram16::~Histogram16()
{
if (_data) free(_data);
}
uint8_t Histogram16::setBucket(const uint16_t index, int16_t value)
{
_data[index] = value;
_status = HISTO_OK;
if (value == _maxBucket) _status = HISTO_FULL;
return _status;
2023-02-22 04:34:45 -05:00
}
2021-11-04 07:32:04 -04:00
2023-07-24 06:51:25 -04:00
//////////////////////////////////////////////////////////////
//
// DERIVED CLASS - HISTOGRAM8
//
2021-11-04 07:32:04 -04:00
Histogram8::Histogram8(const uint16_t length, float *bounds) : Histogram(length, bounds)
{
2023-07-24 06:51:25 -04:00
_bounds = bounds;
_length = length + 1;
_data = (int8_t *) malloc((_length) * sizeof(int8_t));
if (_data != NULL)
{
clear();
}
else
{
_length = 0;
}
_count = 0;
_status = HISTO_OK;
_maxBucket = 127;
}
Histogram8::~Histogram8()
{
if (_data) free(_data);
}
uint8_t Histogram8::setBucket(const uint16_t index, int8_t value)
{
_data[index] = value;
_status = HISTO_OK;
if (value == _maxBucket) _status = HISTO_FULL;
return _status;
2023-02-22 04:34:45 -05:00
}
2021-11-04 07:32:04 -04:00
2022-11-09 04:42:12 -05:00
2023-02-22 04:34:45 -05:00
// -- END OF FILE --
2021-11-04 07:32:04 -04:00