mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
0.3.0 GAMMA
This commit is contained in:
parent
2510474149
commit
bca8166b68
@ -29,7 +29,7 @@ In short, choose the size that fits your application.
|
||||
|
||||
The library has a **setGamma(float gamma)** function that allows an application
|
||||
to change the gamma value runtime.
|
||||
This allows adjustments that a fixed table does not have.
|
||||
This allows adjustments that are not possible with a fixed table.
|
||||
|
||||
The class provides **dump()** to create a table e.g. to place in PROGMEM.
|
||||
Since 0.2.2 the library also has **dumpArray()** to generate a C-style array.
|
||||
@ -46,18 +46,22 @@ array as parameter. The default for size = 32 as this is a good balance between
|
||||
and size of the internal array.
|
||||
The size parameter must be in {2, 4, 8, 16, 32, 64, 128, 256 }.
|
||||
- **~GAMMA()** destructor.
|
||||
- **void begin()** The internal array is allocated and initialized with a gamma == 2.8.
|
||||
- **bool begin()** The internal array is allocated and initialized with a gamma == 2.8.
|
||||
This is an often used value to adjust light to human eye responses.
|
||||
Note that **begin()** must be called before any other function.
|
||||
Returns false if allocation fails.
|
||||
- **void setGamma(float gamma)** calculates and fills the array with new values.
|
||||
This can be done runtime so runtime adjustment of gamma mapping is possible.
|
||||
This calculation are relative expensive and takes quite some time (depending on size).
|
||||
If the array already is calculated for gamma, the calculation will be skipped.
|
||||
The parameter **gamma** must be > 0. The value 1 gives an 1:1 mapping.
|
||||
Returns false if gamma <= 0 or if no table is allocated.
|
||||
- **float getGamma()** returns the set gamma value.
|
||||
- **uint8_t operator \[\]** allows the GAMMA object to be accessed as an array.
|
||||
- **uint8_t operator \[uint8_t index\]** allows the GAMMA object to be accessed as an array.
|
||||
like ```x = G[40];``` Makes it easy to switch with a real array.
|
||||
The value returned is in the range 0 .. 255, so the user may need to scale it e.g. to 0.0 - 1.0
|
||||
The value returned is in the range 0 .. 255, so the user may need to scale it e.g. to 0.0 - 1.0.
|
||||
Note: if internal table not allocated the function returns 0.
|
||||
As this is a legitimate value the user should take care.
|
||||
|
||||
|
||||
### Development functions
|
||||
@ -66,9 +70,11 @@ The value returned is in the range 0 .. 255, so the user may need to scale it e.
|
||||
This is always a power of 2.
|
||||
- **uint16_t distinct()** returns the number of distinct values in the table.
|
||||
Especially with larger internal tables there will be duplicate numbers in the table.
|
||||
- **void dump(Stream \*str = &Serial)** dumps the internal table to a stream, default Serial.
|
||||
- **bool dump(Stream \*str = &Serial)** dumps the internal table to a stream, default Serial.
|
||||
Useful to create an array in RAM, PROGMEM, EEPROM, in a file or wherever.
|
||||
Returns false if no table is allocated.
|
||||
- **void dumpArray(Stream \*str = &Serial)** dumps the internal table to a stream, default Serial, as a C-style array. See example.
|
||||
Returns false if no table is allocated.
|
||||
|
||||
|
||||
## Operation
|
||||
@ -83,10 +89,8 @@ See example.
|
||||
- look for optimizations
|
||||
- getter \[\]
|
||||
- setGamma -> pow() is expensive
|
||||
- improvements (0.3.0)
|
||||
- return bool => begin() + setGamma() + dump()?
|
||||
- check \_table != NULL in functions
|
||||
- add gamma<=0 check in setGamma()
|
||||
- uint16 version?
|
||||
- GAMMA16, GAMMA32,
|
||||
- GAMMA_RGB ?
|
||||
-
|
||||
|
||||
|
@ -19,6 +19,7 @@ GAMMA gt8(2);
|
||||
uint32_t start, d1;
|
||||
volatile int x;
|
||||
|
||||
int total = 0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
@ -39,21 +40,22 @@ void setup()
|
||||
|
||||
Serial.println("\nError Analysis 256 elements = reference\n");
|
||||
Serial.println("Size\tErrors\tMaximum");
|
||||
test_error(gt1);
|
||||
test_error(gt2);
|
||||
test_error(gt3);
|
||||
test_error(gt4);
|
||||
test_error(gt5);
|
||||
test_error(gt6);
|
||||
test_error(gt7);
|
||||
test_error(gt8);
|
||||
Serial.println();
|
||||
total += test_error(gt1);
|
||||
total += test_error(gt2);
|
||||
total += test_error(gt3);
|
||||
total += test_error(gt4);
|
||||
total += test_error(gt5);
|
||||
total += test_error(gt6);
|
||||
total += test_error(gt7);
|
||||
// total += test_error(gt8);
|
||||
Serial.print("TOT\t");
|
||||
Serial.println(total);
|
||||
|
||||
Serial.println("\ndone...\n");
|
||||
}
|
||||
|
||||
|
||||
void test_error(GAMMA gt)
|
||||
int test_error(GAMMA gt)
|
||||
{
|
||||
int count = 0;
|
||||
int maxdiff = 0;
|
||||
@ -70,6 +72,7 @@ void test_error(GAMMA gt)
|
||||
Serial.print(count);
|
||||
Serial.print('\t');
|
||||
Serial.println(maxdiff);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
@ -79,4 +82,3 @@ void loop()
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
|
@ -0,0 +1,19 @@
|
||||
Arduino UNO
|
||||
IDE 1.8.19
|
||||
|
||||
GammaErrorAnalysis.ino
|
||||
GAMMA_LIB_VERSION: 0.2.2
|
||||
|
||||
Error Analysis 256 elements = reference
|
||||
|
||||
Size Errors Maximum
|
||||
257 0 0
|
||||
129 29 1
|
||||
65 38 2
|
||||
33 46 2
|
||||
17 58 2
|
||||
9 177 2
|
||||
5 233 8
|
||||
TOT 581
|
||||
|
||||
done...
|
@ -0,0 +1,19 @@
|
||||
Arduino UNO
|
||||
IDE 1.8.19
|
||||
|
||||
GammaErrorAnalysis.ino
|
||||
GAMMA_LIB_VERSION: 0.3.0
|
||||
|
||||
Error Analysis 256 elements = reference
|
||||
|
||||
Size Errors Maximum
|
||||
257 0 0
|
||||
129 29 1
|
||||
65 34 2
|
||||
33 32 2
|
||||
17 46 2
|
||||
9 159 2
|
||||
5 235 8
|
||||
TOT 535
|
||||
|
||||
done...
|
@ -0,0 +1,34 @@
|
||||
Arduino UNO
|
||||
IDE 1.8.19
|
||||
|
||||
GammaPerformance.ino
|
||||
GAMMA_LIB_VERSION: 0.3.0
|
||||
|
||||
timing in microseconds
|
||||
|
||||
SETGAMMA
|
||||
SIZE TIME TIME per element
|
||||
257 85872 334.13
|
||||
129 42696 330.98
|
||||
65 21172 325.72
|
||||
33 10420 315.76
|
||||
17 5052 297.18
|
||||
|
||||
SETGAMMA II
|
||||
SIZE TIME TIME per element
|
||||
257 8 0.03
|
||||
129 8 0.06
|
||||
65 8 0.12
|
||||
33 8 0.24
|
||||
17 8 0.47
|
||||
|
||||
GET[]
|
||||
SIZE TIME TIME per element
|
||||
257 460 1.80
|
||||
129 972 3.80
|
||||
65 1212 4.73
|
||||
33 1428 5.58
|
||||
17 1616 6.31
|
||||
|
||||
|
||||
done...
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// FILE: gamma.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.2.2
|
||||
// VERSION: 0.3.0
|
||||
// DATE: 2020-08-08
|
||||
// PURPOSE: Arduino Library to efficiently hold a gamma lookup table
|
||||
|
||||
@ -16,6 +16,13 @@
|
||||
// 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"
|
||||
@ -45,21 +52,25 @@ GAMMA::~GAMMA()
|
||||
};
|
||||
|
||||
|
||||
void GAMMA::begin()
|
||||
bool GAMMA::begin()
|
||||
{
|
||||
if (_table == NULL)
|
||||
{
|
||||
_table = (uint8_t *)malloc(_size + 1);
|
||||
}
|
||||
if (_table == NULL) return false;
|
||||
setGamma(2.8);
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
void GAMMA::setGamma(float gamma)
|
||||
bool GAMMA::setGamma(float gamma)
|
||||
{
|
||||
if (_table == NULL) return false;
|
||||
if (gamma <= 0) return false;
|
||||
if (_gamma != gamma)
|
||||
{
|
||||
yield(); // keep ESP happy
|
||||
yield(); // try to keep ESP happy
|
||||
_gamma = gamma;
|
||||
// marginally faster
|
||||
// uint16_t iv = _interval;
|
||||
@ -70,12 +81,15 @@ void GAMMA::setGamma(float gamma)
|
||||
// _table[i] = exp(x * _gamma) * 255 + 0.5;
|
||||
// }
|
||||
// REFERENCE
|
||||
for (uint16_t i = 0; i < _size; i++)
|
||||
// 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.5;
|
||||
_table[i] = pow(i * _interval * (1.0/ 255.0), _gamma) * 255 + 0.444;
|
||||
}
|
||||
_table[_size] = 255; // anchor for interpolation..
|
||||
_table[0] = 0;
|
||||
_table[_size] = 255; // anchor for interpolation.
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
@ -87,6 +101,8 @@ float GAMMA::getGamma()
|
||||
|
||||
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;
|
||||
@ -94,6 +110,8 @@ uint8_t GAMMA::operator[] (uint8_t index)
|
||||
// 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;
|
||||
@ -120,17 +138,20 @@ uint16_t GAMMA::distinct()
|
||||
};
|
||||
|
||||
|
||||
void GAMMA::dump(Stream *str)
|
||||
bool GAMMA::dump(Stream *str)
|
||||
{
|
||||
if (_table == NULL) return false;
|
||||
for (uint16_t i = 0; i <= _size; i++)
|
||||
{
|
||||
str->println(_table[i]);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
void GAMMA::dumpArray(Stream *str)
|
||||
bool GAMMA::dumpArray(Stream *str)
|
||||
{
|
||||
if (_table == NULL) return false;
|
||||
str->println();
|
||||
str->print("uint8_t gamma[");
|
||||
str->print(_size + 1);
|
||||
@ -143,8 +164,18 @@ void GAMMA::dumpArray(Stream *str)
|
||||
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 --
|
||||
|
||||
|
@ -2,14 +2,14 @@
|
||||
//
|
||||
// FILE: gamma.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.2.2
|
||||
// VERSION: 0.3.0
|
||||
// DATE: 2020-08-08
|
||||
// PURPOSE: Arduino Library to efficiently hold a gamma lookup table
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#define GAMMA_LIB_VERSION (F("0.2.2"))
|
||||
#define GAMMA_LIB_VERSION (F("0.3.0"))
|
||||
|
||||
#define GAMMA_DEFAULT_SIZE 32
|
||||
#define GAMMA_MAX_SIZE 256
|
||||
@ -25,12 +25,15 @@ public:
|
||||
|
||||
// allocates memory
|
||||
// sets default gamma = 2.8
|
||||
void begin();
|
||||
// Returns false if allocation fails
|
||||
bool begin();
|
||||
|
||||
// CORE
|
||||
void setGamma(float gamma);
|
||||
// Returns false if gamma <= 0
|
||||
bool setGamma(float gamma);
|
||||
float getGamma();
|
||||
// access values with index operator
|
||||
// index = 0 .. size
|
||||
uint8_t operator[] (uint8_t index);
|
||||
|
||||
// META INFO
|
||||
@ -38,8 +41,8 @@ public:
|
||||
uint16_t distinct();
|
||||
|
||||
// DEBUG
|
||||
void dump(Stream *str = &Serial);
|
||||
void dumpArray(Stream *str = &Serial);
|
||||
bool dump(Stream *str = &Serial);
|
||||
bool dumpArray(Stream *str = &Serial);
|
||||
|
||||
|
||||
private:
|
||||
@ -47,8 +50,10 @@ private:
|
||||
uint8_t _mask = 0;
|
||||
uint16_t _size = 0;
|
||||
uint8_t _interval = 0;
|
||||
float _gamma = 0;
|
||||
float _gamma = 1.0; // 1.0 == no gamma, linear.
|
||||
uint8_t * _table = NULL;
|
||||
|
||||
float fastPow(float a, float b);
|
||||
};
|
||||
|
||||
|
||||
|
@ -15,4 +15,6 @@ dumpArray KEYWORD2
|
||||
|
||||
# Constants (LITERAL1)
|
||||
GAMMA_LIB_VERSION LITERAL1
|
||||
GAMMA_DEFAULT_SIZE LITERAL1
|
||||
GAMMA_MAX_SIZE LITERAL1
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/GAMMA.git"
|
||||
},
|
||||
"version": "0.2.2",
|
||||
"version": "0.3.0",
|
||||
"license": "MIT",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "*",
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=GAMMA
|
||||
version=0.2.2
|
||||
version=0.3.0
|
||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
sentence=Arduino Library for the GAMMA function
|
||||
|
@ -49,43 +49,43 @@ unittest(test_constants)
|
||||
unittest(test_constructor)
|
||||
{
|
||||
GAMMA gt0; // uses default 32 size
|
||||
gt0.begin();
|
||||
assertTrue(gt0.begin());
|
||||
assertEqual(33, gt0.size());
|
||||
assertEqualFloat(2.8, gt0.getGamma(), 0.0001);
|
||||
assertEqual(29, gt0.distinct());
|
||||
|
||||
GAMMA gt1(256);
|
||||
gt1.begin();
|
||||
assertTrue(gt1.begin());
|
||||
assertEqual(257, gt1.size());
|
||||
assertEqualFloat(2.8, gt1.getGamma(), 0.0001);
|
||||
assertEqual(163, gt1.distinct());
|
||||
|
||||
GAMMA gt2(128);
|
||||
gt2.begin();
|
||||
assertTrue(gt2.begin());
|
||||
assertEqual(129, gt2.size());
|
||||
assertEqualFloat(2.8, gt2.getGamma(), 0.0001);
|
||||
assertEqual(98, gt2.distinct());
|
||||
assertEqual(97, gt2.distinct());
|
||||
|
||||
GAMMA gt3(64);
|
||||
gt3.begin();
|
||||
assertTrue(gt3.begin());
|
||||
assertEqual(65, gt3.size());
|
||||
assertEqualFloat(2.8, gt3.getGamma(), 0.0001);
|
||||
assertEqual(54, gt3.distinct());
|
||||
|
||||
GAMMA gt4(32); // default
|
||||
gt4.begin();
|
||||
assertTrue(gt4.begin());
|
||||
assertEqual(33, gt4.size());
|
||||
assertEqualFloat(2.8, gt4.getGamma(), 0.0001);
|
||||
assertEqual(29, gt4.distinct());
|
||||
|
||||
GAMMA gt5(16);
|
||||
gt5.begin();
|
||||
assertTrue(gt5.begin());
|
||||
assertEqual(17, gt5.size());
|
||||
assertEqualFloat(2.8, gt5.getGamma(), 0.0001);
|
||||
assertEqual(16, gt5.distinct());
|
||||
|
||||
GAMMA gt6(8);
|
||||
gt6.begin();
|
||||
assertTrue(gt6.begin());
|
||||
assertEqual(9, gt6.size());
|
||||
assertEqualFloat(2.8, gt6.getGamma(), 0.0001);
|
||||
assertEqual(9, gt6.distinct());
|
||||
@ -96,15 +96,37 @@ unittest(test_get_set)
|
||||
{
|
||||
GAMMA gt; // uses default 32 size
|
||||
|
||||
gt.begin();
|
||||
assertTrue(gt.begin());
|
||||
for (int i = 1; i < 20; i++)
|
||||
{
|
||||
gt.setGamma(i * 0.1);
|
||||
assertTrue(gt.setGamma(i * 0.1));
|
||||
assertEqualFloat(i * 0.1, gt.getGamma(), 0.001);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unittest(test_gamma_fail)
|
||||
{
|
||||
GAMMA gt; // uses default 32 size
|
||||
|
||||
// do not call begin() to force allocate error
|
||||
assertFalse(gt.setGamma(3.14));
|
||||
assertEqualFloat(1.0, gt.getGamma(), 0.001);
|
||||
|
||||
assertEqualFloat(0.0, gt[63], 0.0001);
|
||||
assertFalse(gt.dump());
|
||||
assertFalse(gt.dumpArray());
|
||||
|
||||
// allocate
|
||||
assertTrue(gt.begin());
|
||||
// still fails.
|
||||
assertFalse(gt.setGamma(-2.0));
|
||||
// this works now
|
||||
assertTrue(gt.setGamma(3.14));
|
||||
assertEqualFloat(3.14, gt.getGamma(), 0.001);
|
||||
}
|
||||
|
||||
|
||||
unittest_main()
|
||||
|
||||
// --------
|
||||
|
Loading…
Reference in New Issue
Block a user