Waves of Intensity

Here’s an attempt to use the brightness of the lights to create a wave effect. It’s sort of OK but I was hoping it would be better. This year’s programs are available on GitHub, this one is “WavyWavy”.

First, a bit of maths 🙂

I want to get a couple of peaks and troughs in the “wave” between the centre of the lights and the ends. I can scale the range (half the lights for one string) so I get an interval of 0..2π. I’ll use a Sine function which goes 0..1..0..-1..0 at 0..π/2..π..3*π/2..2π. Negative numbers aren’t much use so we’ll use the absolute value. This is what it looks like (red curve):

abs(sin(bulb-origin))

abs(sin(bulb-origin))

For this example, I’ve scaled the answer by 0.9 and added 0.1 so we get intensities in the range 0.1*G35::MAX_INTENSITY to G35::MAX_INTENSITY. That’s really just because I prefer “very dim” to “off”.

If we change the value of “origin” then the curve shifts – like the green, blue, purple and cyan curves in the figure. We can just increment a notional bulb number in the main loop and the wave shifts by one bulb every iteration. The actual number doesn’t matter because the Sine function is periodic. That should give the illusion of movement.

That’s coded up in the WavyWavy sketch – with untested support for lucky people with 2 strings 😉

#include <G35String.h>

//#define TWO_STRINGS

#ifdef TWO_STRINGS
  #define LIGHT_COUNT 50
  #define G35_PIN1 9
  #define G35_PIN2 10
  G35String lights1(G35_PIN1, LIGHT_COUNT);
  G35String lights2(G35_PIN2, LIGHT_COUNT);
  const int middle = 0;
#else
  #define LIGHT_COUNT 49
  #define G35_PIN 9
  G35String lights(G35_PIN, LIGHT_COUNT);
  const int middle = LIGHT_COUNT/2;
#endif

// Simple function to get amount of RAM free
int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

// Colour table for rainbow
const int COLOURS[] = {COLOR_BLUE, COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN};
const int NCOLOURS = sizeof(COLOURS)/sizeof(int);

// Counter - to insert a long pause, occasionally
int pause = 0;

// Width of half a string
const float width = (float) LIGHT_COUNT/2.0;

// 2*pi, roughly
const float twoPi = 6.283185;

// pre-compute 2*pi/(half of LIGHT_COUNT)
const float mul = 2.0*twoPi/(float) LIGHT_COUNT;

int getIntensity(const int bulb, const int centre) {
  float x = mul * (float) (bulb-centre);
  return int(G35::MAX_INTENSITY*(0.95*abs(sin(x))+0.05));
}

void setup() {
  Serial.begin (115200);
  Serial.println(freeRam());
#ifdef TWO_STRINGS
  lights1.enumerate();
  lights2.enumerate();
#else
  lights.enumerate();
#endif
}

void loop() {
  int offset = 0;
  for (int colIndex=0; colIndex<NCOLOURS; colIndex++) {
    int colour = COLOURS[colIndex];
    for (int repeat=0; repeat < 250; repeat++) {
      // Update all bulbs
      #ifdef TWO_STRINGS
      for (int bulb=0; bulb < LIGHT_COUNT; bulb++) {
      #else
      for (int bulb=0; bulb <= LIGHT_COUNT/2; bulb++) {
      #endif
        int intensity = getIntensity(bulb,middle+offset);
        #ifdef TWO_STRINGS
          lights1.set_color(bulb, intensity, colour);
          lights2.set_color(bulb, intensity, colour);
        #else
          lights.set_color(middle+bulb, intensity, colour);
          lights.set_color(middle-bulb, intensity, colour);
        #endif
      }
      delay(100);
      offset++;
    }
  }
}

It could be worse, but it could be a lot better. I’m not entirely sure that these lights are amenable to using intensity in this way – I suspect that the lower intensities look too similar. Anyway, it’s something different to last night…

This entry was posted in Uncategorized and tagged , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*