# How to make smooth LED transition.

Hi! I'm Thomas.

I can't find this idea with any topic I could search. So I need advises.

I'm making the LED panel for video lighting and I want it to have smoother dimming effect when I adjust the knob. Can you please advise of what code it need to achieve that?

I have read the fading code but I don't know how to make it react with new value read from potentiometer.

and I want it to have smoother dimming effect

Smoother than what?

TolpuddleSartre:
Smoother than what?

I'm sorry I mistype it. Smoother than read value from pot then analogwrite to LED.

You could use an EMA. Keep in mind that it introduces some latency (as do all real low-pass filters).

``````/*
Exponential Moving Average filter (single-pole IIR filter)

Difference equation:
y[n] = k*x[n] + (1-k)*y[n-1]

where y[n] is the filtered output at time n,
and x[n] the raw input at time n
y[n-1] is the previous filtered output.

k == 0.5^shiftFac

Fixed point arithmetic is used for speed.
1 == 1 << (2*shiftFac)
Two times shiftFac because otherwise, precision
would be lost when shifting (value - filtered).

Rounding is performed by adding 0.5 to the
fixed point representation before converting
to an integer.
0.5 == 1 << (2*shiftFac - 1)
*/
class EMA {
public:
/* Constructor: Initialize constants */
EMA(uint8_t shiftFac)
: shiftFac(shiftFac), fixedPointAHalf(1 << ((shiftFac * 2) - 1)) {}

/* Filter a new raw input value x[n] and return the filtered output y[n].
Should be called at regular intervals for best results. */
int32_t filter(int32_t value) {
value = value << (shiftFac * 2);
filtered = filtered + ((value - filtered) >> shiftFac);
return (filtered + fixedPointAHalf) >> (shiftFac * 2);
}

private:
/* Member variables */
const uint8_t shiftFac;
const int32_t fixedPointAHalf;
int32_t filtered = 0;
};

EMA ema(4); // k = 0.5^4 = 0.0625

const unsigned long interval = 10000; // sample every 10 milliseconds

void measureAndFilter() {
int y = ema.filter(x);
Serial.println(y);
}

void setup() {
Serial.begin(115200);
}

void loop() {
static unsigned long previousMicros = micros();
if (micros() - previousMicros > interval) { // sample at precise interval
measureAndFilter();
previousMicros += interval;
}
}
``````

Pieter

Thank you so much, Pieter. I did it on ESP32 with LEDC and it works. One last question. How to do multiple of this in each channel. I have 4 ch for RGBW. I have try to duplicate measure and filter and give them different name it won't work independently.

You mean like this?

``````[color=#00979c]class[/color] [color=#000000]EMA[/color] [color=#000000]{[/color]
[color=#00979c]public[/color][color=#434f54]:[/color]
[color=#95a5a6]/* Constructor: Initialize constants */[/color]
[color=#000000]EMA[/color][color=#000000]([/color][color=#00979c]uint8_t[/color] [color=#000000]shiftFac[/color][color=#000000])[/color]
[color=#434f54]:[/color] [color=#000000]shiftFac[/color][color=#000000]([/color][color=#000000]shiftFac[/color][color=#000000])[/color][color=#434f54],[/color] [color=#000000]fixedPointAHalf[/color][color=#000000]([/color][color=#000000]1[/color] [color=#434f54]<<[/color] [color=#000000]([/color][color=#000000]([/color][color=#000000]shiftFac[/color] [color=#434f54]*[/color] [color=#000000]2[/color][color=#000000])[/color] [color=#434f54]-[/color] [color=#000000]1[/color][color=#000000])[/color][color=#000000])[/color] [color=#000000]{[/color][color=#000000]}[/color]

[color=#95a5a6]/* Filter a new raw input value x[n] and return the filtered output y[n].[/color]
[color=#95a5a6]      Should be called at regular intervals for best results. */[/color]
[color=#00979c]int32_t[/color] [color=#d35400]filter[/color][color=#000000]([/color][color=#00979c]int32_t[/color] [color=#000000]value[/color][color=#000000])[/color] [color=#000000]{[/color]
[color=#000000]value[/color] [color=#434f54]=[/color] [color=#000000]value[/color] [color=#434f54]<<[/color] [color=#000000]([/color][color=#000000]shiftFac[/color] [color=#434f54]*[/color] [color=#000000]2[/color][color=#000000])[/color][color=#000000];[/color]
[color=#000000]filtered[/color] [color=#434f54]=[/color] [color=#000000]filtered[/color] [color=#434f54]+[/color] [color=#000000]([/color][color=#000000]([/color][color=#000000]value[/color] [color=#434f54]-[/color] [color=#000000]filtered[/color][color=#000000])[/color] [color=#434f54]>>[/color] [color=#000000]shiftFac[/color][color=#000000])[/color][color=#000000];[/color]
[color=#5e6d03]return[/color] [color=#000000]([/color][color=#000000]filtered[/color] [color=#434f54]+[/color] [color=#000000]fixedPointAHalf[/color][color=#000000])[/color] [color=#434f54]>>[/color] [color=#000000]([/color][color=#000000]shiftFac[/color] [color=#434f54]*[/color] [color=#000000]2[/color][color=#000000])[/color][color=#000000];[/color]
[color=#000000]}[/color]

[color=#00979c]private[/color][color=#434f54]:[/color]
[color=#95a5a6]/* Member variables */[/color]
[color=#00979c]const[/color] [color=#00979c]uint8_t[/color] [color=#000000]shiftFac[/color][color=#000000];[/color]
[color=#00979c]const[/color] [color=#00979c]int32_t[/color] [color=#000000]fixedPointAHalf[/color][color=#000000];[/color]
[color=#00979c]int32_t[/color] [color=#000000]filtered[/color] [color=#434f54]=[/color] [color=#000000]0[/color][color=#000000];[/color]
[color=#000000]}[/color][color=#000000];[/color]

[color=#000000]EMA[/color] [color=#000000]ema_R[/color][color=#000000]([/color][color=#000000]4[/color][color=#000000])[/color][color=#000000];[/color] [color=#434f54]// k = 0.5^4 = 0.0625[/color]
[color=#000000]EMA[/color] [color=#000000]ema_G[/color][color=#000000]([/color][color=#000000]4[/color][color=#000000])[/color][color=#000000];[/color]
[color=#000000]EMA[/color] [color=#000000]ema_B[/color][color=#000000]([/color][color=#000000]4[/color][color=#000000])[/color][color=#000000];[/color]
[color=#000000]EMA[/color] [color=#000000]ema_W[/color][color=#000000]([/color][color=#000000]4[/color][color=#000000])[/color][color=#000000];[/color]

[color=#00979c]const[/color] [color=#00979c]unsigned[/color] [color=#00979c]long[/color] [color=#d35400]interval[/color] [color=#434f54]=[/color] [color=#000000]10000[/color][color=#000000];[/color] [color=#434f54]// sample every 10 milliseconds[/color]

[color=#00979c]void[/color] [color=#000000]measureAndFilter[/color][color=#000000]([/color][color=#000000])[/color] [color=#000000]{[/color]
[color=#00979c]int[/color] [color=#000000]y_R[/color] [color=#434f54]=[/color] [color=#000000]ema_R[/color][color=#434f54].[/color][color=#d35400]filter[/color][color=#000000]([/color][color=#000000]x[/color][color=#434f54]/[/color][color=#000000]1[/color][color=#000000])[/color][color=#000000];[/color]
[color=#00979c]int[/color] [color=#000000]y_G[/color] [color=#434f54]=[/color] [color=#000000]ema_G[/color][color=#434f54].[/color][color=#d35400]filter[/color][color=#000000]([/color][color=#000000]x[/color][color=#434f54]/[/color][color=#000000]2[/color][color=#000000])[/color][color=#000000];[/color]
[color=#00979c]int[/color] [color=#000000]y_B[/color] [color=#434f54]=[/color] [color=#000000]ema_B[/color][color=#434f54].[/color][color=#d35400]filter[/color][color=#000000]([/color][color=#000000]x[/color][color=#434f54]/[/color][color=#000000]4[/color][color=#000000])[/color][color=#000000];[/color]
[color=#00979c]int[/color] [color=#000000]y_W[/color] [color=#434f54]=[/color] [color=#000000]ema_W[/color][color=#434f54].[/color][color=#d35400]filter[/color][color=#000000]([/color][color=#000000]x[/color][color=#434f54]/[/color][color=#000000]8[/color][color=#000000])[/color][color=#000000];[/color]
[b][color=#d35400]Serial[/color][/b][color=#434f54].[/color][color=#d35400]printf[/color][color=#000000]([/color][color=#005c5f]"%d\t%d\t%d\t%d\t%d\r\n"[/color][color=#434f54],[/color] [color=#000000]x[/color][color=#434f54],[/color] [color=#000000]y_R[/color][color=#434f54],[/color] [color=#000000]y_G[/color][color=#434f54],[/color] [color=#000000]y_B[/color][color=#434f54],[/color] [color=#000000]y_W[/color][color=#000000])[/color][color=#000000];[/color]
[color=#000000]}[/color]

[color=#00979c]void[/color] [color=#5e6d03]setup[/color][color=#000000]([/color][color=#000000])[/color] [color=#000000]{[/color]
[b][color=#d35400]Serial[/color][/b][color=#434f54].[/color][color=#d35400]begin[/color][color=#000000]([/color][color=#000000]115200[/color][color=#000000])[/color][color=#000000];[/color]
[color=#000000]}[/color]

[color=#00979c]void[/color] [color=#5e6d03]loop[/color][color=#000000]([/color][color=#000000])[/color] [color=#000000]{[/color]
[color=#00979c]static[/color] [color=#00979c]unsigned[/color] [color=#00979c]long[/color] [color=#000000]previousMicros[/color] [color=#434f54]=[/color] [color=#d35400]micros[/color][color=#000000]([/color][color=#000000])[/color][color=#000000];[/color]
[color=#5e6d03]if[/color] [color=#000000]([/color][color=#d35400]micros[/color][color=#000000]([/color][color=#000000])[/color] [color=#434f54]-[/color] [color=#000000]previousMicros[/color] [color=#434f54]>[/color] [color=#d35400]interval[/color][color=#000000])[/color] [color=#000000]{[/color] [color=#434f54]// sample at precise interval[/color]
[color=#000000]measureAndFilter[/color][color=#000000]([/color][color=#000000])[/color][color=#000000];[/color]
[color=#000000]previousMicros[/color] [color=#434f54]+=[/color] [color=#d35400]interval[/color][color=#000000];[/color]
[color=#000000]}[/color]
[color=#000000]}[/color]
``````

You may wish to consider working in another colour space, if you want to maintain the same colour throughout the fade.