Skip to content

Feature request: Interpolation / antialiasing idea for moving points #1072

@ohnoitsalobo

Description

@ohnoitsalobo

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:

  1. I didn't want the point repeating over the LED strip.
  2. 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();
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions