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

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.


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
// 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


void loop() {
 timer = millis(); // updating time
 int 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;

This site uses Akismet to reduce spam. Learn how your comment data is processed.

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


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?

April 22nd, 2020 at 18:11 by I love waves


Thanks for this great code, but there is an error that prevents the phase variable from working properly. You are missing a set of parenthesis to include PHASE in the cosine calculation. The line should be:
int ledValue = ledValue = OFFSET + AMPLITUDE*(cos((OMEGA*timer)+PHASE));

May 5th, 2020 at 11:04 by AndrewTosky


Thanks for pointing out 🙂

May 6th, 2020 at 12:06 by Mariano


Can you please explain what is the error

May 6th, 2020 at 12:25 by Mariano


What is the PHASE variable for or do? I have tried different values and cannot see the difference