Help Understanding Patterns

Good Evening All,

I have spent about 2 hours beginning to get my head wrapped around how to code patterns on the pixel blaze, and I am doing fairly well except for one thing. In a lot of the patterns I see where the value is set using a formula such as v = vvv. Why is this done? Why not just take the value and use it.

Is this just to make the brightness fall off faster so that potentially all LEDs on the strip are not lit, or does it have something to do with gamma correction? I am guessing the first, but not quite sure.

Thanks in advance for the help

Hi RH!

You pretty much nailed it: It’s to make brightness fall off faster. It’s an aesthetic thing.

I find that to my eyes, v = 0.5 doesn’t look half as bright as v = 1 – it’s brighter than half as bright. Similarly, v = 0.25 isn’t half as bright as v = 0.5.

Someone else probably knows, but I’ve always guessed that it’s a human perception thing (we perceive brightness on something like a log scale). I kind of assume that when we send a brightness value down the data line and the chips decode it, they probably translate it linearly to PWM dimming. Then the linear PWM curve doesn’t map to our eyes’ perception of brightness.

Or, if the chips do attempt to adjust PWM output to be proportional to the log of the brightness values, they’re kind of bad at it or run out of dynamic range on the low end, which ends up with limited options for dim RGB mixing.

I’ve noticed, for example, it’s can be very tricky get a consistent dim warm white. The same HSV values will look different on Dotstars vs Neopixels, and very sensitive to the global brightness setting. I’m guessing that lowering the global brightness necessarily reduces resolution in the dynamic range.

1 Like

Ok, cool. That was baffling me for about an hour and then it hit me what it might be. Actually I had to sit here and graph it all out.

I am used to doing this from the Arduino where I have to worry about telling the code what pixel I am working on. It is not easy getting in your head that the controller has done the mapping and you are basically determining the color, brightness, etc. of the element. I am beginning to get it, though.

I have project I am gong to try this weekend to see if I have a good grasp of it.

Thanks again,

Longtime FastLED user here… Yep v = v * v is a poor man’s gamma correction.

Since PixelBlaze’s v goes from 0 to 1.0, that works out nicely.

In Arduino speak, you’d need to use v = v * v /256 because of those 8 bit values. Unfortunately, you also lose a bit of precision because of said 8 bit values.

What took me for a very long ride with PixelBlaze was his use of PID loops for audio reactive feedback. That was (and still is) killer and is something I haven’t completely got running right on the Arduino.

1 Like

Yeah, I wonder if adding a gamma correction function is worthwhile, especially if it would be faster than the math (since a gamma correction table would be a simple lookup)

@wizard ?

Pixelblaze internally uses 16 bit resolution for color values so that it can support the high dynamic range (HDR) of LEDs like the APA102/SK9822. I’ll definitely consider it. For now, it’s pretty fast to square the value, plus it depends a bit on the aesthetic you are going for since this is generated patterns designed for LEDs vs an image/video trying to accurately replicate on a screen (at least for now).

So I did some researching into LED gamma correction and then realized that using v (which is 0…1, not 0-255) meant the table approach was awkward (but doable), but decided to compare the v*v (and v * v * v) approach to the results from the gamma 2.8 version of the 0-255 table (converted to 0…1 format for v), and behold:

Screen Shot 2020-12-07 at 7.25.05 PM

v * v * v is so close as to make no difference, while v*v isn’t quite as good but is probably ‘good enough’ for most purposes.

While it might be nice if @wizard added a gamma function (especially for higher bits/HDR) for speed purposes, so long as you are ok with cubing v, you might as well do that.