I am trying to use blend() to create a smooth hue transition in the full rgb color space instead of just increasing hue by one in hsv. While doing so I noticed some unexpected flickering in blend().
Here is a code sample with parts of its output:
#include "FastLED.h"
void setup() {
Serial.begin(115200);
}
void loop() {
CRGB l = CRGB(172,83,0);
CRGB r = CRGB(171,85,0);
static uint8_t step = 0;
CRGB current = blend(l, r, step++);
Serial.println("r: " + String(current.red) + ", g: " + String(current.green) + ", b: " + String(current.blue) + ", step: " + String(step));
}
Output:
r: 171, g: 85, b: 0, step: 0
r: 172, g: 83, b: 0, step: 1
r: 172, g: 82, b: 0, step: 2
r: 172, g: 82, b: 0, step: 3
r: 171, g: 83, b: 0, step: 4
r: 172, g: 82, b: 0, step: 5
r: 172, g: 82, b: 0, step: 6
r: 171, g: 83, b: 0, step: 7
r: 172, g: 82, b: 0, step: 8
r: 172, g: 82, b: 0, step: 9
r: 171, g: 83, b: 0, step: 10
r: 172, g: 82, b: 0, step: 11
r: 172, g: 82, b: 0, step: 12
r: 171, g: 83, b: 0, step: 13
r: 172, g: 82, b: 0, step: 14
r: 172, g: 82, b: 0, step: 15
r: 171, g: 83, b: 0, step: 16
r: 172, g: 82, b: 0, step: 17
r: 172, g: 82, b: 0, step: 18
r: 171, g: 83, b: 0, step: 19
r: 172, g: 82, b: 0, step: 20
r: 172, g: 82, b: 0, step: 21
r: 171, g: 83, b: 0, step: 22
r: 172, g: 82, b: 0, step: 23
r: 172, g: 82, b: 0, step: 24
r: 171, g: 83, b: 0, step: 25
r: 172, g: 82, b: 0, step: 26
r: 172, g: 82, b: 0, step: 27
r: 171, g: 83, b: 0, step: 28
r: 172, g: 82, b: 0, step: 29
r: 172, g: 82, b: 0, step: 30
r: 171, g: 83, b: 0, step: 31
r: 172, g: 82, b: 0, step: 32
r: 172, g: 82, b: 0, step: 33
r: 171, g: 83, b: 0, step: 34
r: 172, g: 82, b: 0, step: 35
r: 172, g: 82, b: 0, step: 36
r: 171, g: 83, b: 0, step: 37
r: 172, g: 83, b: 0, step: 38
r: 172, g: 82, b: 0, step: 39
r: 171, g: 83, b: 0, step: 40
r: 172, g: 83, b: 0, step: 41
r: 172, g: 82, b: 0, step: 42
r: 171, g: 83, b: 0, step: 43
r: 172, g: 83, b: 0, step: 44
r: 172, g: 82, b: 0, step: 45
r: 171, g: 83, b: 0, step: 46
r: 172, g: 83, b: 0, step: 47
r: 172, g: 82, b: 0, step: 48
r: 171, g: 83, b: 0, step: 49
r: 172, g: 83, b: 0, step: 50
r: 172, g: 82, b: 0, step: 51
r: 171, g: 83, b: 0, step: 52
r: 172, g: 83, b: 0, step: 53
r: 172, g: 82, b: 0, step: 54
r: 171, g: 83, b: 0, step: 55
r: 172, g: 83, b: 0, step: 56
r: 172, g: 82, b: 0, step: 57
r: 171, g: 83, b: 0, step: 58
r: 172, g: 83, b: 0, step: 59
r: 172, g: 82, b: 0, step: 60
You can see green change between 82 and 83 back and forth while it should actually not even reach the value of 82. Also it changes between 171 and 172 while it should actually only flip over to 171 after 255/2 steps.
Instead I would expect an output like
r: 172, g: 83, b: 0, step: 0
r: 172, g: 83, b: 0, step: 1
...
r: 172, g: 84, b: 0, step: 85
r: 172, g: 84, b: 0, step: 86
...
r: 171, g: 84, b: 0, step: 128
r: 171, g: 84, b: 0, step: 129
...
r: 171, g: 85, b: 0, step: 170
r: 171, g: 85, b: 0, step: 171
...
r: 171, g: 85, b: 0, step: 255
without rapid changes of values.
Is this a bug or just a compromise between expected behaviour and saving processing power? Anyways how could I solve the issue? I want to create a buttery smooth hue transition and this method currently causes minimal but noticable flickering.
Thanks for the bug report -- very nice, very clear. I'll try to take a look at the code this evening.
Just so that I know exactly where to start chasing down the math issue, @stnkl, were you seeing this problem on an AVR-based microcrontroller, an ARM-based microcontroller, or an ESP8266 ?
I was noticing it on an ESP8266 module. Thanks for looking into it!
Thank you. The underlying math is implemented differently on 8-bit AVR and on the 32-bit platforms (e.g. ESP8266). Knowing which implementation to dig into first really helps.
Alright, that makes sense! Just to be clear the two colors above are just random examples. It happens for other colors as well like
CRGB l = CRGB(242,13,0);
CRGB r = CRGB(239,16,0);
I'm mentioning this because at first I thought it was related to 171 being the point where the "rainbow" hue chart takes effect.
It's a rounding error coming from integer round-offs.

Read the 'sums' as 'sum of floats' and 'sum of ints'. The sum of floats is perfect. The sum of ints... shows the problem you highlighted.
I love 'blend' and I'd love to improve this function to not have this problem -- without 'costing' too much in terms of extra CPU cycles. Let me get some coffee and think about it.
I see. Unfortunately I don't consider myself experienced enough to come up with my own solution for this while keeping CPU cycles in mind. :/
I've got a couple of options brewing in my head, none of which are terribly 'expensive', but Dan and I do tend to obsess about cycles and bytes; I want to choose a great option. In any case, this bug was a good find, and I really appreciate the clarity and specificity of the bug report. As you can see, it helped isolate the underlying problem very quickly, so thank you again.
Just for reference and confirmation, here's the output of the current blend function, showing the bug, as it blends from "83" to "85" in 256 steps. Note especially that "82" should never show up, plus the jitter is definitely not desirable in this case.

And as noted above, I have a couple of solutions, and just want to test them for speed before committing anything.
Yes, getting rid of the jitter would make animations using blend much smoother. Take your time while chosing the right fix for this bug. I am glad I could help!
Thanks again for the exemplary bug fix, @stnkl. Not only should the latest library update solve the particular issue you were seeing, but everyone should get slightly smoother interpolation of palette colors using ColorFromPalette. Really a great bug find and report, thank you again. Tested on AVR, ARM, and ESP8266.
That is great! Thanks so much for fixing this. Saved me from having to figure out a way to work around this efficiently!
You're welcome. Looks nice, to my eye, too.
Most helpful comment
Thanks again for the exemplary bug fix, @stnkl. Not only should the latest library update solve the particular issue you were seeing, but everyone should get slightly smoother interpolation of palette colors using ColorFromPalette. Really a great bug find and report, thank you again. Tested on AVR, ARM, and ESP8266.