GY-63_MS5611/libraries/GAMMA/gamma.cpp
2022-07-26 13:16:03 +02:00

182 lines
3.9 KiB
C++

//
// FILE: gamma.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.3.0
// DATE: 2020-08-08
// PURPOSE: Arduino Library to efficiently hold a gamma lookup table
// 0.1.0 2020-08-08 initial release
// 0.1.1 2020-12-24 Arduino-CI + unit test
//
// 0.2.0 2021-11-02 update build-CI, badges
// add begin() - fixes ESP32 crash.
// 0.2.1 2021-12-18 update library.json, license,
// add constants, minor edits.
// 0.2.2 2022-07-25 split in .h and .cpp
// add Stream parameter to dump()
// add dumpArray(Stream)
// fix distinct()
//
// 0.3.0 2022-07-26 change return type begin() + setGamma()
// add test gamma <=0 in setGamma()
// add _table == NULL tests
// fixed type of index in [] operator.
// adjust rounding in setGamma() to minimize errors.
// update build-CI
#include "gamma.h"
GAMMA::GAMMA(uint16_t size)
{
_shift = 7;
// force power of 2; get shift & mask right
for (uint16_t s = 2; s <= GAMMA_MAX_SIZE; s <<= 1)
{
if (size <= s)
{
_size = s;
break;
}
_shift--;
}
_mask = (1 << _shift) - 1;
_interval = GAMMA_MAX_SIZE / _size;
};
GAMMA::~GAMMA()
{
if (_table) free(_table);
};
bool GAMMA::begin()
{
if (_table == NULL)
{
_table = (uint8_t *)malloc(_size + 1);
}
if (_table == NULL) return false;
setGamma(2.8);
return true;
};
bool GAMMA::setGamma(float gamma)
{
if (_table == NULL) return false;
if (gamma <= 0) return false;
if (_gamma != gamma)
{
yield(); // try to keep ESP happy
_gamma = gamma;
// marginally faster
// uint16_t iv = _interval;
// _table[0] = 0;
// for (uint16_t i = 1; i < _size; i++)
// {
// float x = log(i * iv) + log(1.0 / 255);
// _table[i] = exp(x * _gamma) * 255 + 0.5;
// }
// REFERENCE
// rounding factor 0.444 optimized with error example.
for (uint16_t i = 1; i < _size; i++)
{
_table[i] = pow(i * _interval * (1.0/ 255.0), _gamma) * 255 + 0.444;
}
_table[0] = 0;
_table[_size] = 255; // anchor for interpolation.
}
return true;
};
float GAMMA::getGamma()
{
return _gamma;
};
uint8_t GAMMA::operator[] (uint8_t index)
{
// 0.3.0 _table test slows performance ~0.4 us.
if (_table == NULL) return 0;
if (_interval == 1) return _table[index];
// else interpolate
uint8_t i = index >> _shift;
uint8_t m = index & _mask;
// exact element shortcut
if ( m == 0 ) return _table[i];
// interpolation
// delta must be uint16_t to prevent overflow. (small tables)
// delta * m can be > 8 bit.
uint16_t delta = _table[i+1] - _table[i];
delta = (delta * m + _interval/2) >> _shift; // == /_interval;
return _table[i] + delta;
};
uint16_t GAMMA::size()
{
return _size + 1;
};
uint16_t GAMMA::distinct()
{
uint8_t last = _table[0];
uint16_t count = 1;
for (uint16_t i = 1; i <= _size; i++)
{
if (_table[i] == last) continue;
last = _table[i];
count++;
}
return count;
};
bool GAMMA::dump(Stream *str)
{
if (_table == NULL) return false;
for (uint16_t i = 0; i <= _size; i++)
{
str->println(_table[i]);
}
return true;
};
bool GAMMA::dumpArray(Stream *str)
{
if (_table == NULL) return false;
str->println();
str->print("uint8_t gamma[");
str->print(_size + 1);
str->print("] = {");
for (uint16_t i = 0; i <= _size; i++)
{
if (i % 8 == 0) str->print("\n ");
str->print(_table[i]);
if (i < _size) str->print(", ");
}
str->print("\n };\n\n");
return true;
};
// performance investigation
// https://stackoverflow.com/questions/43429238/using-boost-cpp-int-for-functions-like-pow-and-rand
inline float GAMMA::fastPow(float a, float b)
{
// reference
return pow(a, b);
}
// -- END OF FILE --