Fading Led with sine wave | Andrea Toscano 15th, February
Fading LEDs with sine wave

Hi everybody,
the purpose of this post is to explain a simple technique concerning LED fading.
One common issue in fading a LED is blocking the execution of the loop() in a for loop as long as it performs the fading.

void loop() {
// fade in from min to max in increments of 5 points:
for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
// sets the value (range from 0 to 255):
// wait for 30 milliseconds to see the dimming effect
delay(30);
}

This approach wastes a lot of resources since the microcontroller can only perform this action until the execution goes on after the for loop.

One possibile solution is to drive LED fading with a sin/cos wave.
This means that at each iteration a harmonic oscillator value is assigned to the LED.

The simple harmonic oscillator equation is: $x(t)=A\cos(\omega t + \phi)$

So, we basically need the amplitude A, ω the angular frequency $\omega =\frac{2\pi}{T}$ and finally the optional φ which determines the starting point on the sine wave.

Let’s take a common cos wave shown below.

This function oscillates in range [-1;1]. To perform a complete LED fading we need to simply modify our cos wave to our purpose.
Arduino’s output is always between [0;255] (256 values); for this reason we need a cos wave that start at 128 and oscillates oscillates between 1 and 255 to get a reasonable range (128±127).
The picture below shows y=128+127cos(x), which is the starting point to create our harmonic oscillator.
The OFFSET 128 shifts my cos wave from 0 to 128 and the AMPLITUDE 127cos(..) tells me that we want to amplifier our wave by 127x.

What happens if we modify the OFFSET or the AMPLITUDE?
Let’s say we assign OFFSET = 150. This means that our wave OFFSET is shifted from 128 to 150 and it will oscillate in range [23;277] (note! same AMPLITUDE=127, oscillation 150±127) exceeding the upper bound and having 23 as min value. This means our led will never assume 0 value.
The upper and lower bound issues are easily fixed with a check function which clips the current value to 0 or 255 when it exceeds the bounds.

Modifying the AMPLITUDE, i.e. AMPLITUDE = 100, will cause a smaller oscillation around my OFFSET.
Play with these coefficients to get your best result!

Here there’s a sample code.

/*
FADING A LED WITH SINE WAVE
Andrea Toscano 2016
*/

// Arduino LED PIN
#define LED_PIN 10
// Baudrate for Serial Communication
#define SERIAL_BAUD 115200

// Time period of fading in millisecs
#define PERIOD 2000
// Angular Frequency by definition
#define OMEGA 2*PI/PERIOD
// No Phase
#define PHASE 0
// Offset of the sine wave
#define OFFSET 128
// Amplitude of the sine wave
#define AMPLITUDE 127

// Used to generate time for the cos wave
unsigned long timer = 0;

void setup() {
// Uncomment for serial monitor
Serial.begin(SERIAL_BAUD);

}

void loop() {
timer = millis(); // updating time
int ledValue = ledValue = OFFSET + AMPLITUDE*(cos(OMEGA*timer)+PHASE);
analogWrite(LED_PIN, checkValue(ledValue));
}

// Useful to avoid LED values outside the bounds [0;255]
int checkValue(int val) {
if (val > 255)
val = 255;
else if(val < 0)
val = 0;
return val;
} July 2nd, 2017 at 05:54 by Results Point

Do you mind if I quote a few of your posts as long as I provide credit and sources back to your site?
My blog is in the exact same area of interest as yours and my users would truly
benefit from some of the information you provide here. Please let me know if this okay
with you. Thank you! July 3rd, 2017 at 08:01 by AndrewTosky

Hi!
Sure,no problem.
Just provide credits and links to my website where needed, thank you! May 3rd, 2019 at 11:17 by Mariano

Brilliant code!! How would you implement a “fade up – on for a period of time-fade down – off for a period” without delay()? May 3rd, 2019 at 12:33 by Mariano

What is the PHASE variable for?