does anyone have an example of using the fastLED "int16()" function?

does anyone have an example of using the fastLED “int16()” function? (this is part of the lib8tion library).
I am trying to get my led hat to show a “ripple” effect and am figuring out how to feed this function with values…

I created an emulator rig in html and javascript to get an easier handle on it, but it seems to always need very VERY large numbers to get the desired result.

Testing rig (resize the width of the result window to get proper display):
http://jsfiddle.net/jL8uP/1/

Any help/tips highly appreciated.
http://jsfiddle.net/jL8uP/1

Do you mean sin16 and cos16?

If so, then here’s what to know: instead of taking an argument in degrees (0-359) or radians (0-2pi aka 0-6.283), these functions take the input angle as a 16-bit unsigned integer (0-65535). Zero is same as zero degrees, 16384=90°, 32768=180°, etc.

The output is not a floating point number from -1.0…1.0, but rather a 16-but signed integer from -32768 to 32767.

These are (briefly) described on this page

Why is it all like this, you may ask?
Well, first of all you are of course free to use the Arduino built in floating point sin() and cos() functions. So we’re not taking anything away by offering these alternatives.

But the bottom-line reason is simple: Speed. The integer-based sin16 and cos16 are roughly forty (40) times faster than the floating point version on AVR Arduino, and they’re correct to within 1/2 of one percent. So in the time that you can calculate one pixel color using floating point cos(), you could calculate forty pixels’ colors using cos16().

So, the input range and output domain are different, but the shape of the curve is the same, and the execution is much much faster.

Hope I’m answering the right question!

yes, I mean this function.
Thank you for your answer, I will check out the documentation link after work and start working on the arduino code.

The reason why I will try to use this function is speed.

I’ve always been curious as to why sin16 takes a uint16_t and outputs an int16. I have not yet come across an application where I didn’t want a uint8_t for both.

Yeah. I mostly want u16 in, u8 out, or sometimes u8 in and u8 out. I have those already written up too. Maybe I’ll sneak them into lib8tion. Don’t tell anyone.

That would be useful. I don’t need super accurate numbers for the effects and working with smaller numbers should be easier on the Microcontroller

Until today I used to define/calculate a cos table with 256 byte values at the beginning and than grab only into the table. So far it was accurate enough for my purposes and really fast.

Yep that’s one way to do it. Surprisingly, it can be faster to do it in code on Arduino than to use a table (depending on a lot of different factors), and it definitely uses less RAM to use a cos routine than a 256 byte lookup table; on an Arduino Uno, that table alone uses up 12% of RAM.

It’s a good option (and a classic!) to know about; sometimes it is the right choice.

I got the code to work with the sin16 function (I will finally record and post a video this weekend, promised :wink: ), but it would definitely be faster to use smaller numbers…

+1 for a sin8 function in lib8tion.h please

Oh, I was not aware, that calculation can be faster. I’ll play with it!

Each situation is different; all I’ve really learned is to try several different things and actually time them!

I did some testing and was surprised:
To calculate all LEDs with my code

  • using sin16 takes 4-6ms
  • using sin takes 10-14ms
  • using a precalculated lookup table in ram (256 bytes) takes 6-8ms

I’m going to stick with the sin16 function :slight_smile:

Thanks for sharing the real-world timings you measured.

As you may have sensed by now, @Daniel_Garcia and I love making things fast. One of the lessons we’ve really taken to heart is: Measure! Measure! Measure! The real world is a complicated place, and the only certain way to find out what’s fastest is to try different approaches and measure the outcomes.

Thanks again for sharing the results.

sin8 and cos8 (and some other goodies) have been committed to github on the FastLED v2.1 branch. Discussion should be continued here: https://plus.google.com/112916219338292742137/posts/WJWGyYLZ8zR

Hey Mark, my first benchmark showed, that sin16 is faster than a lookup table, but for measuring i didn’t use the values, I just calculated them. So maybe the compiler did some optimizing? When really using the data I got the following results on an ATmega2560: Taking/calculating sin and writing data for 240 LEDs: 8 Bit lookup table: 228 - 236 µs, Sin16: 724 - 730 µs

This is the code I used:

#include <FastLED.h>

#define LED_PIN 23
#define COLOR_ORDER GRB
#define CHIPSET WS2811

#define BRIGHTNESS 150

const uint8_t WIDTH = 20;
const uint8_t HEIGHT = 12;

#define NUM_LEDS (WIDTH * HEIGHT)
CRGB leds[NUM_LEDS];

uint8_t const cos_wave[256]
{0,0,0,0,1,1,1,2,2,3,4,5,6,6,8,9,10,11,12,14,15,17,18,20,22,23,25,27,29,31,33,35,38,40,42,
45,47,49,52,54,57,60,62,65,68,71,73,76,79,82,85,88,91,94,97,100,103,106,109,113,116,119,
122,125,128,131,135,138,141,144,147,150,153,156,159,162,165,168,171,174,177,180,183,186,
189,191,194,197,199,202,204,207,209,212,214,216,218,221,223,225,227,229,231,232,234,236,
238,239,241,242,243,245,246,247,248,249,250,251,252,252,253,253,254,254,255,255,255,255,
255,255,255,255,254,254,253,253,252,252,251,250,249,248,247,246,245,243,242,241,239,238,
236,234,232,231,229,227,225,223,221,218,216,214,212,209,207,204,202,199,197,194,191,189,
186,183,180,177,174,171,168,165,162,159,156,153,150,147,144,141,138,135,131,128,125,122,
119,116,113,109,106,103,100,97,94,91,88,85,82,79,76,73,71,68,65,62,60,57,54,52,49,47,45,
42,40,38,35,33,31,29,27,25,23,22,20,18,17,15,14,12,11,10,9,8,6,6,5,4,3,2,2,1,1,1,0,0,0,0
};

unsigned long timestamp[4];

void setup() {
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness( BRIGHTNESS );
Serial.begin(9600);
}

void loop () {
timestamp[0] = micros();

for (int i=0; i < NUM_LEDS; i++) {
leds[i] = cos_wave[i];}

timestamp[1] = micros();
FastLED.show();
delay(1000);

timestamp[2] = micros();

for (int i=0; i < NUM_LEDS; i++) {
leds[i] = sin16(i);}

timestamp[3] = micros();
FastLED.show();
delay(1000);

showResults();
}

void showResults()
{
Serial.print(timestamp[1]-timestamp[0]); //lookup table
Serial.print(‘\t’);
Serial.print(timestamp[3]-timestamp[2]); //sin16
Serial.print(‘\t’);
Serial.println();
}

Most of the time a lookup table in RAM (as shown) will be fastest, but it’s not guaranteed to always be so; it depends what else is going on at the same time register-wise.

Also, it takes up 256 bytes of precious RAM, which may or may not be available depending on circumstances. The Adafruit Trinket (ATtiny85) only has 512 bytes of RAM total.

You could move the precalculated table into PROGMEM (flash), but each access there takes three times as long as access to RAM, so you get the RAM back but lose speed. Also, you’ve now used 256 bytes of flash storage; the new sin8 routine itself only uses about 70 bytes of flash. quadwave8() is even smaller and faster, and returns similar visual results.

So yes, normally I would expect a precalculated table in RAM to be fastest under most (but not all) circumstances. We provide other options (sin16,sin8,quadwave8,etc.) so that you have many options and can make the best trade off for each project that you create.

Thanks again for experimenting and sharing your data!

with the new sin8 function, the same function (see tests above) is down to 3ms and does not use floating point operations (so the code compiles to a size around 200 byte smaller than before)
I am very happy with the new functions, thank you very much, @Mark_Kriegsman :smiley:

Thanks for the feedback-- glad it’s working out!

Let me know if you play with the other functions too. Should be drop-in replacements, and ease to try.