Go Back
Led Fading with Sin wave
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):
    analogWrite(ledPin, fadeValue);
    // 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.

Cosine wave

Cosine wave

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.

Cosine wave - fading LED

Cosine wave – fading LED

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;
}