One of the things we’re developing right now is a new product that will monitor architectural lighting installations (more on that soon!). We’re testing out the system in our shop, but before we could test it properly we needed to create a nice dataset to feed into the system. To do this, we decided to mock up a basic architectural lighting system and generate some random lighting effects, which our new prototype system could monitor.
Among the random things that live in our shop is a mockup of an architectural lighting system from a project we did last year, consisting of 30 feet of RGB iLight Hypnotica. The lights in that system didn’t do anything particularly useful for our purposes, but with some modifications it became the perfect testbed for our new product.
I wanted to create something like a realistic use case, so I started by writing a script that turns the lights on at sunrise and off at sunset (so our on and off times will drift as the season changes). Simply turning the lights on to a static look didn’t give us a lot of useful data to monitor, though, and it would have been difficult to detect whether the controller was still running or if it had crashed.
My solution was to create a generative lighting system, but rather than doing something complicated like a Forest Fire, I went with the simplest algorithm possible: a random walk.
Random walking is where you vary a value (or a position) based on a random input. So if we have a random walk over a range of -1 to 1 with integers, our possible inputs are -1, 0 and 1. A random selection of those inputs might be 0, 0, 0, -1, -1, 1, -1, -1, 0, -1, so if our value started at 0, it would do this:
0 0 0 -1 -2 -1 -2 -3 -3 -4
This is, of course, not a particularly useful function all by itself, but we can scale it up.
In this case, we took the 186 DMX channels of our lighting rig and simply produced a random walk for each value, continuously. The initial approach was a bit flickery because we didn’t handle the ends very well – variables just sort of wrapped around from 0 to 255, causing channels to bounce back and forth repeatedly from full to out. Adding some nudging on the ends smoothed things out, and we now have a rig that produces random colors continuously.
Here’s the key bit of code:
for i in range(len(self._data)):
if(self._data[i] < 25): self._data[i] = self._data[i] + random.randrange(0,20) elif(self._data[i] > 230):
self._data[i] = self._data[i] + random.randrange(-20,0)
self._data[i] = self._data[i] + random.randrange(-25, 25)
In short: if the current value is less than 25, add a random number between 0 and 20. If the current value is greater than 230 (25 less than 255, the maximum), subtract a number between 0 and 20. Otherwise add a random number between -25 and 25.
This executes 40 times per second, so the lights can change color rather quickly. Here’s a look at the finished test system:
In this case we’re doing a random walk on each of the Red Green Blue channels. This doesn’t always end up being particularly interesting, but on average it does – and it gives us some good data to monitor with our prototype. Another approach might be to run the random walk on the Hue channel of a Hue Saturation Lightness colorspace, and then map those into RGB. This would get you saturated colors at maximum brightness, but would not wander off into dark territory like the current software does.
For our testing purposes, we also need to track sun-up vs. sun-down. The way we handled that was through the python ephem module, which gives you access to all sorts of data for astronomical bodies and observers. In this case, we simply needed to calculate the sun’s angle to the horizon: if it’s above 0 the sun is up; if it’s below 0 the sun is down. It would be possible to add correction factors for dawn and dusk, but simply tracking day vs. night was enough for our purposes.