Aight, this is what I'm seeing when fading secondary colors (Cyan, Yellow,

Aight, this is what I’m seeing when fading secondary colors (Cyan, Yellow, Magenta) using HSV value scale.

Actual code is:
#include “FastLED.h”

#define NUM_LEDS 48
CRGB leds[NUM_LEDS];

#define DATA_PIN 11
#define CLOCK_PIN 12

volatile uint8_t value = 255;
const uint8_t hue = 42; // yellow
//const uint8_t hue = 212; // magenta
//const uint8_t hue = 125; // cyan

void setup() {
LEDS.addLeds<LPD8806, DATA_PIN, CLOCK_PIN, BRG>(leds, NUM_LEDS);
}
void loop() {
fill_solid(&(leds[0]), 48, CHSV(hue, 255, value));
LEDS.show();
value -= 5;
delay(150);
}

My guess there is a rounding error going on here. Churning the array data out of the serial port in a suitable format and capturing it with a PC will probably show the flow of the numbers better than your eyes with the LEDs in place of the show(). Or as well.

I think this is pretty much predictable and will always crop up somewhere.

Imagine you have an RGB color like 100,90,0 - a yellow hue. If you scale it down by a factor of 10, you get 10,9,0 - perfect proportions, and identical hue. But if you scale it down by a factor of 20, your ideal result would be 5,4.5,0 - again with the color proportions unchanged. But the pixels themselves only operate on integer values, so what you get is 5,4(rounded down),0. Now the color proportions aren’t quite right, but maybe it’s the best integer match possible.

But go further: if we scale 100,90,0 down by a factor of (let’s say) one hundred, the ideal result you want would be 1.00,0.90,0. And again, since the output can only be integers, you get 1(.00),0(.90),0 aka 1,0,0. But soft, what light through yonder window breaks our approximation?! It is the integers, and 1,0,0 is RED, not yellow at all. This is what you’re seeing in the video. Yellow fades to dim yellow, to dimmest yellow, to red.

Now that I think about this though, oddly, we already know how to prevent this: use the “{blah}_video” variations of scaling functions instead of “{blah}_raw” to scale down the color channel values. Functions like scale8_video make sure never to round a non-zero channel value down to zero. They exist for exactly this reason.

I’ll see if I can see where in the data path we’re not using it; maybe we can improve things a bit.

@Mark_Kriegsman , can you give an example of scaling CHSV down to black using *_video?

Well, it’s supposed to be doing that already… I’ll look at it.

@Mark_Kriegsman I also believe the hsv code is using a perceptual brightness scale - which probably exacerbates things at lower brightnesses.

Yah. I believe it is. Time for some coffee and whiteboarding.

So my ultimate goal here is to be able to use the HSV color space on some of my generated patterns and be able to fade it to black an any given point, without seeing a color shift. If I can’t achieve that, it’s no big loss, I’ll just not fade anything out, or only do it on the primary LED colors. I realize a color mix of say 80% red with 35% blue won’t always get to zero at the same time … but there’s hope. :slight_smile:

The issue that you’re seeing (the un-even fading to black) is actually a bug in the HSV code - @Mark_Kriegsman popped open an issue on github[1] to track it down and I think he knows how to fix it. But first, he has to successfully not blow himself up while disassembling a lithium battery.

[1] https://github.com/FastLED/FastLED/issues/27

What has the battery done to him??

So far, merely deprived him of lunch.