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 x = analogRead(A0);
  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]x[/color] [color=#434f54]=[/color] [color=#d35400]analogRead[/color][color=#000000]([/color][color=#00979c]A0[/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.