Skip to content

Instantly share code, notes, and snippets.

@zacharyvoase
Created November 24, 2012 01:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zacharyvoase/4137977 to your computer and use it in GitHub Desktop.
Save zacharyvoase/4137977 to your computer and use it in GitHub Desktop.
#define E 2.71828182846
// The ordered list of output pins, and the length thereof.
int pins[] = {3, 5, 6, 9, 10};
int pins_length = 5;
// This needs to be close to 30ms to be perceived as smooth (NTSC = 33.36ms)
int refresh_interval = 30;
// Intervals are useful for explicitly declaring the valid range for a value,
// and converting values between ranges (e.g. 0 - 1.0 => 0 - 255).
struct Interval {
float low;
float high;
};
// Map a value from one Interval to another.
float map_interval(float value, struct Interval source, struct Interval target) {
// normed will be a number between 0.0 - 1.0 inclusive.
double normed = (value - source.low) / (source.high - source.low);
return (normed * (target.high - target.low)) + target.low;
}
// Get an integer, modulo an interval.
// e.g. modulo_interval_i(22, (0..8)) => 6.
int modulo_interval_i(int value, struct Interval interval) {
while (value > interval.high) {
value -= (interval.high - interval.low);
}
return value;
}
// Same as `modulo_interval_i()`, but for floats.
float modulo_interval_f(float value, struct Interval interval) {
while (value > interval.high) {
value -= (interval.high - interval.low);
}
return value;
}
// Our clock ticks from 0 to 133, at 30ms intervals, for a total cycle length of ~4s.
Interval clockInterval = {0, 133};
// We'll map the clock onto the x interval (-2, 2) of the PDF of a normal distribution.
float stddev = 0.7;
Interval normXInterval = {-2, 2};
// The output of the normal PDF is in the y interval (0, 0.5699). Use 0.6 to be safe.
Interval normYInterval = {0, 0.6};
// The 'analog' value of the pin (therefore the brightness of the LED) will be an 8-bit integer.
// You can control the global brightness floor/ceiling by changing this.
Interval brightnessInterval = {0, 255};
// -- You shouldn't need to change anything below this line to get it to work. --
void setup() {
}
// PDF of a normal distribution.
float normdist(float avg, float stddev, float x) {
return (1 / (stddev * sqrt(2 * PI))) * (
pow(E, -0.5 * pow(((x - avg) / stddev), 2)));
}
// Get the brightness for a pin at a given time. The pin is provided as an index into `pins`,
// not the pin number itself.
int fade_value(int pin_index, int clock) {
int pin_phase = pin_index * (clockInterval.high - clockInterval.low) / pins_length;
clock = modulo_interval_i(clock + pin_phase, clockInterval);
return map_interval(normdist(0, stddev, map_interval(clock, clockInterval, normXInterval)),
normYInterval, brightnessInterval);
}
void loop() {
for (int clock = clockInterval.low; clock <= clockInterval.high; clock += 1) {
for (int i = 0; i < pins_length; i += 1) {
analogWrite(pins[i], fade_value(i, clock));
}
delay(refresh_interval);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment