Hi, I have been testing the CHSV function,

Hi,
I have been testing the CHSV function, and have some strange issues when changing the saturation. This is using a LPD8086 strip, teensy 3 with RC3.
My sketch first cycles through the hues, which seems to work as expected, then saturation, which seem to give me some strange results, depending on which color I start with. If I have a hue of 160, which is blue, it starts off with white, then flashes to yellow and then goes to cold white before ending up in the blue color.
The brightness cycle works more or less as expected, but the performance is kind of sluggish, it fades up to red, but some of the pixels hang for a bit when cutting to 0 brightness.

Does this mean that the conversion from HSV to RGB is slowing down things?

Another thing that indicates this is that when I upload the hsv code I need to disconnect my ledstrip to have a successful upload, this is not the case if I upload rgb based code that I normally use.

Or is my code example bad, giving the teensy too much to do?

Here is the code:

#include “FastSPI_LED2.h”

#define NUM_LEDS 120

struct CRGB leds[NUM_LEDS];

void setup() {
// sanity check delay - allows reprogramming if accidently blowing power w/leds
delay(2000);

FastLED.addLeds<LPD8806, BRG>(leds, NUM_LEDS); //my strip is BRG ordered

}

void loop() {

//HUE
for(int x = 0; x < 255; x++) {
LEDS.showColor(CHSV(x, 255, 255));
delay(20);
}

LEDS.showColor(CHSV(0, 0, 0));
delay(1000);

//SATURATION
for(int x = 0; x < 255; x++) {
LEDS.showColor(CHSV(160, x, 255));
delay(20);
}

LEDS.showColor(CHSV(0, 0, 0));
delay(1000);

//BRIGHTNESS
for(int x = 0; x < 255; x++) {
LEDS.showColor(CHSV(255, 255, x));
delay(20);
}

LEDS.showColor(CHSV(0, 0, 0));
delay(1000);

}

Sounds like there are electrical problems as well as a possible software puzzle. I’ll run your sample code tonight and see what I get.
As for the “few pixels” being stuck or sluggish… that’s quite odd, and smacks of a signal propagation issue. Can you isolate that condition at all, and figure out when it happens?
As for performance, the HSV to RGB conversion is so fast that you shouldn’t see it-- but it does take not cycles than NOT doing it. You could make the sample quicker by first converting a CHSV to a single CRGB and then assigning that to every pixel, instead of doing the conversion inside the loop. Eg:
CRGB rgbColor( CHSV( hue, sat, val));
for( etc ) {
leds[i] = rgbColor;
}

It seems to be easy to isolate in the code: If I only do the HSV fading followed by a RGB fading I can clearly see that the HSV is bumpy (mainly the downfade) while the RGB version is super smooth:

void loop() {

//BRIGHTNESS
for(int x = 0; x < 255; x++) {
LEDS.showColor(CHSV(255, 255, x));
delay(10);
}
for(int x = 255; x > 0; x–) {
LEDS.showColor(CHSV(255, 255, x));
delay(10);
}

LEDS.showColor(CHSV(0, 0, 0));
delay(1000);

for(int x = 0; x < 128; x++) {
// The showColor method sets all the leds in the strip to the same color
LEDS.showColor(CRGB(x, 0, 0));
delay(10);
}

// fade down
for(int x = 128; x >= 0; x–) {
LEDS.showColor(CRGB(x, 0, 0));
delay(10);
}
}

Ah sorry, misunderstood the description of the choppiness.

You might be seeing artifacts of the fact that LPD8806 is only 7 bits per pix, not 8.

In any case, I’ll run it tonight and let you know what I’m seeing.

Hmmm, original OP post mentions 8086 as opposed to 8806 … Typo or are the actually 8086?

sorry, yes, typo, I am using the 8806

Looking into it now with a test rig.

[tl;dr: you’re probably seeing 8-bit ‘loss of precision’ at low brightnesses, and there are a few ways to address it]

Me, I’m seeing a few different things, including spots before my eyes after staring directly into the pixels for 45 minutes:

  • First, make sure to check your R-G-B ordering using the RGBCalibrate sketch included with RC3. (I had it set wrong on my test setup, and EVEYRTHING looked wrong. Surprisingly wrong, even to me.)

  • Second, in your brightness ramp-up, you might want to set the hue to 160 (blue) just so you’re doing an apples-to-apples comparison.

  • That said: YES, you’re NOT crazy: doing a direct single-channel RGB (e.g., just Blue) ramp up or down will be smoother than doing the same thing in 8-bit HSV colorspace. That’s because three different 8-bit numbers all get calculated into the HSV-to-RGB conversion formula and there is some loss of precision; I’d say it amounts to a couple of bits, which is significant and visible in the code you have here, or anytime you’re at very dim brightnesses. It’s visibly chunky when you do this.

So, what to do about it?

  • Well, if you want to work in just RGB colorspace and that works for you, then you’re all set: no HSV precision issues, because no HSV at all.

  • If you want to just do brightness ramp-up of the whole strip (as you do here), and you still want to use HSV colors, try this:

    //BRIGHTNESS
    for(int x = 0; x < 255; x++) {
    LEDS.showColor( CHSV(160,255,255), x);
    delay(20);
    }

Note here that we’re using the SECOND parameter to showColor: the master brightness control. We’re converting CHSV(160,255,255) to RGB at a high brightness and high saturation (where these precision issues aren’t visible), and then using the master brightness control to do the ramp-up, and to my eye it’s silky smooth like this – as smooth as a plain RGB ramp.

Of course, if you choose a non-pure RGB hue (eg, hue 170 which is slightly purpler instead of 160 which is pure blue), and try to do this, then the visual color’s hue distorts slightly at dim brightnesses. How visible it is in your application, and how you want it to look are very situation-dependent.

  • Finally, you could do a higher-resolution (but slower) conversion from HSV to RGB. The built-in library conversions are designed to be so fast that they can be used everywhere, all the time, at least from a speed point of view. Previous implementations of hsv2rgb have been too slow for this, and we’ve really focused on speed – with the ‘cost’ being that at low brightnesses, there’s an “8-bit” loss of precision.

I’ve run into situations where I want smoother gradients, and I’ve sometimes been forced to use a 16-bit HSV to RGB conversion function; it’s nearly four times slower than the built-in 8-bit conversions, but doesn’t have this chunkiness at low brightnesses. I have the 16-bit conversion code around here somewhere, and I’m happy to share it if you wish. The NEXT big version of the FastLED library will have full built-in support for 16-bit-per-channel color depths (and 14 and 12 and 10) (probably), and Dan and I are already planning for it across the board, but I can share the 16-bit HSV-to-RGB if you want to try it out.

So. You’re not crazy – and the library is as fast as ever. But in the name of fastest-possible color conversions, all the math is done in 8-bit precision, and the result is some chunkiness if you do exactly this sort of ramp.

Hi Mark, thanks for the detailed answer!
Since I love slow changes I am always interested in tricks that can make a slow fade look smooth (both rgb and hsv based), but I guess the main obstacle for this is the hardware resolution (especially of the 8806 chip).