I ran this code on an ESP32, where I have plenty of computational power to spare. For others using smaller controllers, or if I wanted to do this with a large matrix - is there a 'cheaper' way to do this? I really like the look of what I've done and I bet you could do a better job of implementing it.
I came up with this code because I made a LED ring clock and I wanted the 'hands' to move smoothly fading in and out around the ring, rather the visible 'tick tick tick' motion that is usually done. I apologize if a similar function already exists somewhere, I didn't find what I need using the wave functions because:
- I didn't want the point repeating over the LED strip.
- The peaks of the wave functions were just too wide, not precise enough to light up only a couple of LEDs at a time.
This code uses an exponential function y=(2^a) where a is a quadratic function of the form (x-b)^2, and b is the distance you want a point to move. This generates a 'bell curve' "underneath" the existing LED strip which fades adjacent LEDs in and out, and gives the illusion that there are more LEDs than actual. (In my 'cylon' code snippet below, I've set it to 10x the number of LEDs and it is extremely smooth on my 60 LED/m strip).
#define temp 5.0 // set this for the "resolution" of the bell curve temp*NUM_LEDS
#define width 15 // set this for the "width" of the bell curve (how many LEDs to light)
#define _smear = 4.0*sqrt(1.0/(width*width*width)); // this calculates the necessary coefficient for a width of w
void cylon(){
EVERY_N_MILLISECONDS( 55 ) { gHue1++; }
nscale8( leds, NUM_LEDS, 20);
int pos = beatsin16(25, width*temp, (NUM_LEDS-width)*temp); // range of input. the 'width' prevents it from hitting the sides
double scaledpos = pos/(NUM_LEDS*temp) * NUM_LEDS; // range scaled down to working length
for(int i = 0; i < NUM_LEDS/2; i++){
double a = i-scaledpos; //
a = -_smear*a*a; // generate bell curve with coefficient calculated above for chosen width
int val = 255.0*pow(2, a); //
leds[i] |= CHSV(gHue1, 255, val);
}
}
In a more generalized sense, for example, in code I might want to run an animation on a LED strip of 500 pixels, but smoothly output it on my 144-LED strip, so an anti-aliasing scaling function similar to this would be really cool.
Here's my clock code that started this idea.
void drawClock(){
nscale8( leds, NUM_LEDS, 200);
int sec = millis()%(60*1000);
double secPos = sec/60000.0 * NUM_LEDS/2;
int min = sec%(60*60);
double minPos = min/(60.0*60.0) * NUM_LEDS/2;
int _hour = sec%(60*60*12);
double hourPos = _hour/(60.0*60.0*12.0) * NUM_LEDS/2;
for(int i = 0; i < NUM_LEDS; i++){
double a, b, c, y, w = 0.4;
int bri = 255;
a = i+secPos; a = -w*a*a; // main pulse (seconds)
b = i+secPos-NUM_LEDS; b = -w*b*b; // prev pulse to fade in opposite end
c = i+secPos+NUM_LEDS; c = -w*c*c; // next pulse to fade out opposite end
y = pow(2, a)+pow(2, b)+pow(2, c); // sum
leds[i] |= CHSV(160, 255, bri*y);
a = i+minPos; a = -w*a*a; // main pulse (minutes)
b = i+minPos-NUM_LEDS; b = -w*b*b; // prev pulse
c = i+minPos+NUM_LEDS; c = -w*c*c; // next pulse
y = pow(2, a)+pow(2, b)+pow(2, c); // sum
leds[i] |= CHSV( 96, 255, bri*y);
a = i+hourPos; a = -w*a*a; // main pulse (hours)
b = i+hourPos-NUM_LEDS; b = -w*b*b; // prev pulse
c = i+hourPos+NUM_LEDS; c = -w*c*c; // next pulse
y = pow(2, a)+pow(2, b)+pow(2, c); // sum
leds[i] |= CHSV( 0, 255, bri*y);
}
FastLED.show();
}
I ran this code on an ESP32, where I have plenty of computational power to spare. For others using smaller controllers, or if I wanted to do this with a large matrix - is there a 'cheaper' way to do this? I really like the look of what I've done and I bet you could do a better job of implementing it.
I came up with this code because I made a LED ring clock and I wanted the 'hands' to move smoothly fading in and out around the ring, rather the visible 'tick tick tick' motion that is usually done. I apologize if a similar function already exists somewhere, I didn't find what I need using the wave functions because:
This code uses an exponential function
y=(2^a)whereais a quadratic function of the form(x-b)^2, andbis the distance you want a point to move. This generates a 'bell curve' "underneath" the existing LED strip which fades adjacent LEDs in and out, and gives the illusion that there are more LEDs than actual. (In my 'cylon' code snippet below, I've set it to 10x the number of LEDs and it is extremely smooth on my 60 LED/m strip).In a more generalized sense, for example, in code I might want to run an animation on a LED strip of 500 pixels, but smoothly output it on my 144-LED strip, so an anti-aliasing scaling function similar to this would be really cool.
Here's my clock code that started this idea.