Fix Improved fade linearity with gamma correction

This commit is contained in:
Hadinger 2020-01-01 16:11:36 +01:00
parent 287b3b97f1
commit 579a76ced6
2 changed files with 56 additions and 11 deletions

View File

@ -5,6 +5,7 @@
- Add support for ``AdcParam`` parameters to control ADC0 Current Transformer Apparent Power formula by Jodi Dillon (#7100) - Add support for ``AdcParam`` parameters to control ADC0 Current Transformer Apparent Power formula by Jodi Dillon (#7100)
- Fix LCD line and column positioning (#7387) - Fix LCD line and column positioning (#7387)
- Fix Display handling of hexadecimal escape characters (#7387) - Fix Display handling of hexadecimal escape characters (#7387)
- Fix Improved fade linearity with gamma correction
### 8.1.0.1 20191225 ### 8.1.0.1 20191225

View File

@ -185,9 +185,8 @@ const gamma_table_t gamma_table[] = { // don't put in PROGMEM for performance
// simplified Gamma table for Fade, cheating a little at low brightness // simplified Gamma table for Fade, cheating a little at low brightness
const gamma_table_t gamma_table_fast[] = { const gamma_table_t gamma_table_fast[] = {
{ 0, 0 }, { 384, 192 },
{ 384, 67 }, { 768, 576 },
{ 768, 467 },
{ 1023, 1023 }, { 1023, 1023 },
{ 0xFFFF, 0xFFFF } // fail-safe if out of range { 0xFFFF, 0xFFFF } // fail-safe if out of range
}; };
@ -264,6 +263,7 @@ struct LIGHT {
bool update = true; bool update = true;
bool pwm_multi_channels = false; // SetOption68, treat each PWM channel as an independant dimmer bool pwm_multi_channels = false; // SetOption68, treat each PWM channel as an independant dimmer
bool fade_initialized = false; // dont't fade at startup
bool fade_running = false; bool fade_running = false;
uint16_t fade_start_10[LST_MAX] = {0,0,0,0,0}; uint16_t fade_start_10[LST_MAX] = {0,0,0,0,0};
uint16_t fade_cur_10[LST_MAX]; uint16_t fade_cur_10[LST_MAX];
@ -1110,9 +1110,20 @@ uint16_t ledGamma_internal(uint16_t v, const struct gamma_table_t *gt_ptr) {
from_gamma = to_gamma; from_gamma = to_gamma;
} }
} }
// 10_10 bits, fast fade mode // Calculate the reverse gamma value for LEDS
uint16_t ledGamma10_10_fast(uint16_t v) { uint16_t ledGammaReverse_internal(uint16_t vg, const struct gamma_table_t *gt_ptr) {
return ledGamma_internal(v, gamma_table_fast); uint16_t from_src = 0;
uint16_t from_gamma = 0;
for (const gamma_table_t *gt = gt_ptr; ; gt++) {
uint16_t to_src = gt->to_src;
uint16_t to_gamma = gt->to_gamma;
if (vg <= to_gamma) {
return changeUIntScale(vg, from_gamma, to_gamma, from_src, to_src);
}
from_src = to_src;
from_gamma = to_gamma;
}
} }
// 10 bits in, 10 bits out // 10 bits in, 10 bits out
@ -1740,11 +1751,12 @@ void LightAnimate(void)
cur_col_10[i] = orig_col_10bits[Light.color_remap[i]]; cur_col_10[i] = orig_col_10bits[Light.color_remap[i]];
} }
if (!Settings.light_fade || power_off) { // no fade if (!Settings.light_fade || power_off || (!Light.fade_initialized)) { // no fade
// record the current value for a future Fade // record the current value for a future Fade
memcpy(Light.fade_start_10, cur_col_10, sizeof(Light.fade_start_10)); memcpy(Light.fade_start_10, cur_col_10, sizeof(Light.fade_start_10));
// push the final values at 8 and 10 bits resolution to the PWMs // push the final values at 8 and 10 bits resolution to the PWMs
LightSetOutputs(cur_col_10); LightSetOutputs(cur_col_10);
Light.fade_initialized = true; // it is now ok to fade
} else { // fade on } else { // fade on
if (Light.fade_running) { if (Light.fade_running) {
// if fade is running, we take the curring value as the start for the next fade // if fade is running, we take the curring value as the start for the next fade
@ -1768,6 +1780,33 @@ void LightAnimate(void)
} }
} }
bool isChannelGammaCorrected(uint32_t channel) {
if (!Settings.light_correction) { return false; } // Gamma correction not activated
if (channel >= Light.subtype) { return false; } // Out of range
if (PHILIPS == my_module_type) {
if ((LST_COLDWARM == Light.subtype) && (1 == channel)) { return false; } // PMW reserved for CT
if ((LST_RGBWC == Light.subtype) && (4 == channel)) { return false; } // PMW reserved for CT
}
return true;
}
// Calculate the Gamma correction, if any, for fading, using the fast Gamma curve (10 bits in+out)
uint16_t fadeGamma(uint32_t channel, uint16_t v) {
if (isChannelGammaCorrected(channel)) {
return ledGamma_internal(v, gamma_table_fast);
} else {
return v;
}
}
uint16_t fadeGammaReverse(uint32_t channel, uint16_t vg) {
if (isChannelGammaCorrected(channel)) {
return ledGammaReverse_internal(vg, gamma_table_fast);
} else {
return vg;
}
}
bool LightApplyFade(void) { // did the value chanegd and needs to be applied bool LightApplyFade(void) { // did the value chanegd and needs to be applied
static uint32_t last_millis = 0; static uint32_t last_millis = 0;
uint32_t now = millis(); uint32_t now = millis();
@ -1783,7 +1822,7 @@ bool LightApplyFade(void) { // did the value chanegd and needs to be applied
// compute the distance between start and and color (max of distance for each channel) // compute the distance between start and and color (max of distance for each channel)
uint32_t distance = 0; uint32_t distance = 0;
for (uint32_t i = 0; i < Light.subtype; i++) { for (uint32_t i = 0; i < Light.subtype; i++) {
int32_t channel_distance = Light.fade_end_10[i] - Light.fade_start_10[i]; int32_t channel_distance = fadeGammaReverse(i, Light.fade_end_10[i]) - fadeGammaReverse(i, Light.fade_start_10[i]);
if (channel_distance < 0) { channel_distance = - channel_distance; } if (channel_distance < 0) { channel_distance = - channel_distance; }
if (channel_distance > distance) { distance = channel_distance; } if (channel_distance > distance) { distance = channel_distance; }
} }
@ -1810,9 +1849,14 @@ bool LightApplyFade(void) { // did the value chanegd and needs to be applied
if (fade_current <= Light.fade_duration) { // fade not finished if (fade_current <= Light.fade_duration) { // fade not finished
//Serial.printf("Fade: %d / %d - ", fade_current, Light.fade_duration); //Serial.printf("Fade: %d / %d - ", fade_current, Light.fade_duration);
for (uint32_t i = 0; i < Light.subtype; i++) { for (uint32_t i = 0; i < Light.subtype; i++) {
Light.fade_cur_10[i] = changeUIntScale(fade_current, Light.fade_cur_10[i] = fadeGamma(i,
0, Light.fade_duration, changeUIntScale(fadeGammaReverse(i, fade_current),
Light.fade_start_10[i], Light.fade_end_10[i]); 0, Light.fade_duration,
fadeGammaReverse(i, Light.fade_start_10[i]),
fadeGammaReverse(i, Light.fade_end_10[i])));
// Light.fade_cur_10[i] = changeUIntScale(fade_current,
// 0, Light.fade_duration,
// Light.fade_start_10[i], Light.fade_end_10[i]);
} }
} else { } else {
// stop fade // stop fade