lib8tion - Math functions specifically designed for LED programming

Note

This library was ported from FastLED

group lib8tion

A variety of functions for working with numbers.

Defines

GET_MILLIS()

Typedefs

typedef uint8_t fract8

ANSI unsigned short _Fract.

range is 0 to 0.99609375 in steps of 0.00390625 ANSI: unsigned short _Fract

typedef int8_t sfract7

ANSI: signed short _Fract.

range is -0.9921875 to 0.9921875 in steps of 0.0078125 ANSI: signed short _Fract

typedef uint16_t fract16

ANSI: unsigned _Fract.

range is 0 to 0.99998474121 in steps of 0.00001525878 ANSI: unsigned _Fract

typedef int16_t sfract15

ANSI: signed _Fract.

range is -0.99996948242 to 0.99996948242 in steps of 0.00003051757 ANSI: signed _Fract

typedef uint16_t accum88

ANSI: unsigned short _Accum. 8 bits int, 8 bits fraction.

typedef int16_t saccum78

ANSI: signed short _Accum. 7 bits int, 8 bits fraction.

typedef uint32_t accum1616

ANSI: signed _Accum. 16 bits int, 16 bits fraction.

typedef int32_t saccum1516

ANSI: signed _Accum. 15 bits int, 16 bits fraction.

typedef uint16_t accum124

no direct ANSI counterpart. 12 bits int, 4 bits fraction

typedef int32_t saccum114

no direct ANSI counterpart. 1 bit int, 14 bits fraction

Functions

LIB8STATIC float sfract15ToFloat (sfract15 y)

sfract15ToFloat: conversion from sfract15 fixed point to IEEE754 32-bit float.

LIB8STATIC sfract15 floatToSfract15 (float f)

conversion from IEEE754 float in the range (-1,1) to 16-bit fixed point.

Note that the extremes of one and negative one are NOT representable. The representable range is basically

LIB8STATIC uint8_t lerp8by8 (uint8_t a, uint8_t b, fract8 frac)

linear interpolation between two unsigned 8-bit values, with 8-bit fraction

LIB8STATIC uint16_t lerp16by16 (uint16_t a, uint16_t b, fract16 frac)

linear interpolation between two unsigned 16-bit values, with 16-bit fraction

LIB8STATIC uint16_t lerp16by8 (uint16_t a, uint16_t b, fract8 frac)

linear interpolation between two unsigned 16-bit values, with 8-bit fraction

LIB8STATIC int16_t lerp15by8 (int16_t a, int16_t b, fract8 frac)

linear interpolation between two signed 15-bit values, with 8-bit fraction

LIB8STATIC int16_t lerp15by16 (int16_t a, int16_t b, fract16 frac)

linear interpolation between two signed 15-bit values, with 8-bit fraction

LIB8STATIC uint8_t map8 (uint8_t in, uint8_t rangeStart, uint8_t rangeEnd)

map8: map from one full-range 8-bit value into a narrower range of 8-bit values, possibly a range of hues.

E.g. map myValue into a hue in the range blue..purple..pink..red hue = map8(myValue, HUE_BLUE, HUE_RED);

Combines nicely with the waveform functions (like sin8, etc) to produce continuous hue gradients back and forth:

     hue = map8(sin8(myValue), HUE_BLUE, HUE_RED);

Mathematically simiar to lerp8by8, but arguments are more like Arduino’s “map”; this function is similar to

     map(in, 0, 255, rangeStart, rangeEnd)

but faster and specifically designed for 8-bit values.

LIB8STATIC uint8_t ease8InOutQuad (uint8_t i)

ease8InOutQuad: 8-bit quadratic ease-in / ease-out function Takes around 13 cycles on AVR

LIB8STATIC uint16_t ease16InOutQuad (uint16_t i)

ease16InOutQuad: 16-bit quadratic ease-in / ease-out function

LIB8STATIC fract8 ease8InOutCubic (fract8 i)

ease8InOutCubic: 8-bit cubic ease-in / ease-out function Takes around 18 cycles on AVR

LIB8STATIC fract8 ease8InOutApprox (fract8 i)

ease8InOutApprox: fast, rough 8-bit ease-in/ease-out function shaped approximately like ‘ease8InOutCubic’, it’s never off by more than a couple of percent from the actual cubic S-curve, and it executes more than twice as fast.

Use when the cycles are more important than visual smoothness. Asm version takes around 7 cycles on AVR.

LIB8STATIC uint8_t triwave8 (uint8_t in)

triwave8: triangle (sawtooth) wave generator.

Useful for turning a one-byte ever-increasing value into a one-byte value that oscillates up and down.

input output 0..127 0..254 (positive slope) 128..255 254..0 (negative slope)

On AVR this function takes just three cycles.

LIB8STATIC uint8_t quadwave8 (uint8_t in)

quadwave8: quadratic waveform generator.

Spends just a little more time at the limits than ‘sine’ does.

LIB8STATIC uint8_t cubicwave8 (uint8_t in)

cubicwave8: cubic waveform generator.

Spends visibly more time at the limits than ‘sine’ does.

LIB8STATIC uint8_t squarewave8 (uint8_t in, uint8_t pulsewidth)

squarewave8: square wave generator.

Useful for turning a one-byte ever-increasing value into a one-byte value that is either 0 or 255. The width of the output ‘pulse’ is determined by the pulsewidth argument:

If pulsewidth is 255, output is always 255.
If pulsewidth < 255, then
  if input < pulsewidth  then output is 255
  if input >= pulsewidth then output is 0

the output looking like:

255   +--pulsewidth--+
 .    |              |
 0    0              +--------(256-pulsewidth)--------

Parameters
  • in

  • pulsewidth

Returns

square wave output

LIB8STATIC uint16_t beat88 (accum88 beats_per_minute_88, uint32_t timebase)

beat16 generates a 16-bit ‘sawtooth’ wave at a given BPM, with BPM specified in Q8.8 fixed-point format; e.g.

for this function, 120 BPM MUST BE specified as 120*256 = 30720. If you just want to specify “120”, use beat16 or beat8.

LIB8STATIC uint16_t beat16 (accum88 beats_per_minute, uint32_t timebase)

beat16 generates a 16-bit ‘sawtooth’ wave at a given BPM

LIB8STATIC uint8_t beat8 (accum88 beats_per_minute, uint32_t timebase)

beat8 generates an 8-bit ‘sawtooth’ wave at a given BPM

LIB8STATIC uint16_t beatsin88 (accum88 beats_per_minute_88, uint16_t lowest, uint16_t highest, uint32_t timebase, uint16_t phase_offset)

beatsin88 generates a 16-bit sine wave at a given BPM, that oscillates within a given range.

For this function, BPM MUST BE SPECIFIED as a Q8.8 fixed-point value; e.g. 120BPM must be specified as 120*256 = 30720. If you just want to specify “120”, use beatsin16 or beatsin8.

LIB8STATIC uint16_t beatsin16 (accum88 beats_per_minute, uint16_t lowest, uint16_t highest, uint32_t timebase, uint16_t phase_offset)

beatsin16 generates a 16-bit sine wave at a given BPM, that oscillates within a given range.

LIB8STATIC uint8_t beatsin8 (accum88 beats_per_minute, uint8_t lowest, uint8_t highest, uint32_t timebase, uint8_t phase_offset)

beatsin8 generates an 8-bit sine wave at a given BPM, that oscillates within a given range.

LIB8STATIC uint16_t seconds16 ()

Return the current seconds since boot in a 16-bit value.

Used as part of the “every N time-periods” mechanism

LIB8STATIC uint16_t minutes16 ()

Return the current minutes since boot in a 16-bit value.

Used as part of the “every N time-periods” mechanism

LIB8STATIC uint8_t hours8 ()

Return the current hours since boot in an 8-bit value.

Used as part of the “every N time-periods” mechanism

LIB8STATIC uint16_t div1024_32_16 (uint32_t in32)

Helper routine to divide a 32-bit value by 1024, returning only the low 16 bits.

You’d think this would be just result = (in32 >> 10) & 0xFFFF; and on ARM, that’s what you want and all is well. Used to convert millis to ‘binary seconds’ aka bseconds: one bsecond == 1024 millis.

LIB8STATIC uint16_t bseconds16 ()

bseconds16 returns the current time-since-boot in “binary seconds”, which are actually 1024/1000 of a second long.

union IEEE754binary32_t
#include <lib8tion.h>

typedef for IEEE754 “binary32” float type internals

Public Members

uint32_t i
float f
uint32_t mantissa
uint32_t exponent
uint32_t signbit
struct IEEE754binary32_t::[anonymous] [anonymous]
uint32_t mant7
uint32_t mant16
uint32_t exp_
uint32_t sb_
struct IEEE754binary32_t::[anonymous] [anonymous]
uint32_t mant_lo8
uint32_t mant_hi16_exp_lo1
uint32_t sb_exphi7
struct IEEE754binary32_t::[anonymous] [anonymous]
group Math

Fast, efficient 8-bit math functions specifically designed for high-performance LED programming.

Functions

LIB8STATIC_ALWAYS_INLINE uint8_t qadd8 (uint8_t i, uint8_t j)

add one byte to another, saturating at 0xFF

Parameters
  • i – - first byte to add

  • j – - second byte to add

Returns

the sum of i & j, capped at 0xFF

LIB8STATIC_ALWAYS_INLINE int8_t qadd7 (int8_t i, int8_t j)

Add one byte to another, saturating at 0x7F and -0x80.

Parameters
  • i – - first byte to add

  • j – - second byte to add

Returns

the sum of i & j, capped at 0xFF

LIB8STATIC_ALWAYS_INLINE uint8_t qsub8 (uint8_t i, uint8_t j)

subtract one byte from another, saturating at 0x00

Returns

i - j with a floor of 0

LIB8STATIC_ALWAYS_INLINE uint8_t add8 (uint8_t i, uint8_t j)

add one byte to another, with one byte result

LIB8STATIC_ALWAYS_INLINE uint16_t add8to16 (uint8_t i, uint16_t j)

add one byte to two bytes, with two bytes result

LIB8STATIC_ALWAYS_INLINE uint8_t sub8 (uint8_t i, uint8_t j)

subtract one byte from another, 8-bit result

LIB8STATIC_ALWAYS_INLINE uint8_t avg8 (uint8_t i, uint8_t j)

Calculate an integer average of two unsigned 8-bit integer values (uint8_t).

Fractional results are rounded down, e.g. avg8(20,41) = 30

LIB8STATIC_ALWAYS_INLINE uint16_t avg16 (uint16_t i, uint16_t j)

Calculate an integer average of two unsigned 16-bit integer values (uint16_t).

Fractional results are rounded down, e.g. avg16(20,41) = 30

LIB8STATIC_ALWAYS_INLINE uint8_t avg8r (uint8_t i, uint8_t j)

Calculate an integer average of two unsigned 8-bit integer values (uint8_t).

Fractional results are rounded up, e.g. avg8r(20,41) = 31

LIB8STATIC_ALWAYS_INLINE uint16_t avg16r (uint16_t i, uint16_t j)

Calculate an integer average of two unsigned 16-bit integer values (uint16_t).

Fractional results are rounded up, e.g. avg16r(20,41) = 31

LIB8STATIC_ALWAYS_INLINE int8_t avg7 (int8_t i, int8_t j)

Calculate an integer average of two signed 7-bit integers (int8_t) If the first argument is even, result is rounded down.

If the first argument is odd, result is rounded up.

LIB8STATIC_ALWAYS_INLINE int16_t avg15 (int16_t i, int16_t j)

Calculate an integer average of two signed 15-bit integers (int16_t) If the first argument is even, result is rounded down.

If the first argument is odd, result is rounded up.

LIB8STATIC_ALWAYS_INLINE uint8_t mod8 (uint8_t a, uint8_t m)

Calculate the remainder of one unsigned 8-bit value divided by anoter, aka A % M.

Implemented by repeated subtraction, which is very compact, and very fast if A is ‘probably’ less than M. If A is a large multiple of M, the loop has to execute multiple times. However, even in that case, the loop is only two instructions long on AVR, i.e., quick.

LIB8STATIC uint8_t addmod8 (uint8_t a, uint8_t b, uint8_t m)

Add two numbers, and calculate the modulo of the sum and a third number, M.

In other words, it returns (A+B) % M. It is designed as a compact mechanism for incrementing a ‘mode’ switch and wrapping around back to ‘mode 0’ when the switch goes past the end of the available range. e.g. if you have seven modes, this switches to the next one and wraps around if needed: mode = addmod8( mode, 1, 7); LIB8STATIC_ALWAYS_INLINESee ‘mod8’ for notes on performance.

LIB8STATIC uint8_t submod8 (uint8_t a, uint8_t b, uint8_t m)

Subtract two numbers, and calculate the modulo of the difference and a third number, M.

In other words, it returns (A-B) % M. It is designed as a compact mechanism for incrementing a ‘mode’ switch and wrapping around back to ‘mode 0’ when the switch goes past the end of the available range. e.g. if you have seven modes, this switches to the next one and wraps around if needed: mode = addmod8( mode, 1, 7); LIB8STATIC_ALWAYS_INLINESee ‘mod8’ for notes on performance.

LIB8STATIC_ALWAYS_INLINE uint8_t mul8 (uint8_t i, uint8_t j)

8x8 bit multiplication, with 8 bit result

LIB8STATIC_ALWAYS_INLINE uint8_t qmul8 (uint8_t i, uint8_t j)

saturating 8x8 bit multiplication, with 8 bit result

Returns

the product of i * j, capping at 0xFF

LIB8STATIC_ALWAYS_INLINE int8_t abs8 (int8_t i)

take abs() of a signed 8-bit uint8_t

LIB8STATIC uint8_t sqrt16 (uint16_t x)

square root for 16-bit integers About three times faster and five times smaller than Arduino’s general sqrt on AVR.

LIB8STATIC uint8_t blend8 (uint8_t a, uint8_t b, uint8_t amountOfB)

blend a variable proportion(0-255) of one byte to another

Parameters
  • a – - the starting byte value

  • b – - the byte value to blend toward

  • amountOfB – - the proportion (0-255) of b to blend

Returns

a byte value between a and b, inclusive

group Scaling

Fast, efficient 8-bit scaling functions specifically designed for high-performance LED programming.

Because of the AVR(Arduino) and ARM assembly language implementations provided, using these functions often results in smaller and faster code than the equivalent program using plain “C” arithmetic and logic.

Functions

LIB8STATIC_ALWAYS_INLINE uint8_t scale8 (uint8_t i, fract8 scale)

scale one byte by a second one, which is treated as the numerator of a fraction whose denominator is 256 In other words, it computes i * (scale / 256) 4 clocks AVR with MUL, 2 clocks ARM

LIB8STATIC_ALWAYS_INLINE uint8_t scale8_video (uint8_t i, fract8 scale)

The “video” version of scale8 guarantees that the output will be only be zero if one or both of the inputs are zero.

If both inputs are non-zero, the output is guaranteed to be non-zero. This makes for better ‘video’/LED dimming, at the cost of several additional cycles.

LIB8STATIC void nscale8x3 (uint8_t *r, uint8_t *g, uint8_t *b, fract8 scale)

scale three one byte values by a fourth one, which is treated as the numerator of a fraction whose demominator is 256 In other words, it computes r,g,b * (scale / 256)

THIS FUNCTION ALWAYS MODIFIES ITS ARGUMENTS IN PLACE

LIB8STATIC void nscale8x3_video (uint8_t *r, uint8_t *g, uint8_t *b, fract8 scale)

scale three one byte values by a fourth one, which is treated as the numerator of a fraction whose demominator is 256 In other words, it computes r,g,b * (scale / 256), ensuring that non-zero values passed in remain non zero, no matter how low the scale argument.

THIS FUNCTION ALWAYS MODIFIES ITS ARGUMENTS IN PLACE

LIB8STATIC void nscale8x2 (uint8_t *i, uint8_t *j, fract8 scale)

scale two one byte values by a third one, which is treated as the numerator of a fraction whose demominator is 256 In other words, it computes i,j * (scale / 256)

THIS FUNCTION ALWAYS MODIFIES ITS ARGUMENTS IN PLACE

LIB8STATIC void nscale8x2_video (uint8_t *i, uint8_t *j, fract8 scale)

scale two one byte values by a third one, which is treated as the numerator of a fraction whose demominator is 256 In other words, it computes i,j * (scale / 256), ensuring that non-zero values passed in remain non zero, no matter how low the scale argument.

THIS FUNCTION ALWAYS MODIFIES ITS ARGUMENTS IN PLACE

LIB8STATIC_ALWAYS_INLINE uint16_t scale16by8 (uint16_t i, fract8 scale)

scale a 16-bit unsigned value by an 8-bit value, considered as numerator of a fraction whose denominator is 256.

In other words, it computes i * (scale / 256)

LIB8STATIC uint16_t scale16 (uint16_t i, fract16 scale)

scale a 16-bit unsigned value by a 16-bit value, considered as numerator of a fraction whose denominator is 65536.

In other words, it computes i * (scale / 65536)

group Dimming

Dimming and brightening functions.

The eye does not respond in a linear way to light. High speed PWM’d LEDs at 50% duty cycle appear far brighter then the ‘half as bright’ you might expect.

If you want your midpoint brightness leve (128) to appear half as bright as ‘full’ brightness (255), you have to apply a ‘dimming function’.

Functions

LIB8STATIC uint8_t dim8_raw (uint8_t x)

Adjust a scaling value for dimming.

LIB8STATIC uint8_t dim8_video (uint8_t x)

Adjust a scaling value for dimming for video (value will never go below 1)

LIB8STATIC uint8_t dim8_lin (uint8_t x)

Linear version of the dimming function that halves for values < 128.

LIB8STATIC uint8_t brighten8_raw (uint8_t x)

inverse of the dimming function, brighten a value

LIB8STATIC uint8_t brighten8_video (uint8_t x)

inverse of the dimming function, brighten a value

LIB8STATIC uint8_t brighten8_lin (uint8_t x)

inverse of the dimming function, brighten a value

group Random

Fast 8- and 16- bit unsigned random numbers.

Significantly faster than Arduino random(), but also somewhat less random. You can add entropy.

Defines

FASTLED_RAND16_2053
FASTLED_RAND16_13849
APPLY_FASTLED_RAND16_2053(x)

Functions

LIB8STATIC uint8_t random8 ()

Generate an 8-bit random number.

LIB8STATIC uint16_t random16 ()

Generate a 16 bit random number.

LIB8STATIC uint8_t random8_to (uint8_t lim)

Generate an 8-bit random number between 0 and lim.

Parameters

lim – the upper bound for the result

LIB8STATIC uint8_t random8_between (uint8_t min, uint8_t lim)

Generate an 8-bit random number in the given range.

Parameters
  • min – the lower bound for the random number

  • lim – the upper bound for the random number

LIB8STATIC uint16_t random16_to (uint16_t lim)

Generate an 16-bit random number between 0 and lim.

Parameters

lim – the upper bound for the result

LIB8STATIC uint16_t random16_between (uint16_t min, uint16_t lim)

Generate an 16-bit random number in the given range.

Parameters
  • min – the lower bound for the random number

  • lim – the upper bound for the random number

LIB8STATIC void random16_set_seed (uint16_t seed)

Set the 16-bit seed used for the random number generator.

LIB8STATIC uint16_t random16_get_seed ()

Get the current seed value for the random number generator.

LIB8STATIC void random16_add_entropy (uint16_t entropy)

Add entropy into the random number generator.

Variables

uint16_t rand16seed

random number seed

group Trig

Fast 8 and 16-bit approximations of sin(x) and cos(x).

Don’t use these approximations for calculating the trajectory of a rocket to Mars, but they’re great for art projects and LED displays.

On Arduino/AVR, the 16-bit approximation is more than 10X faster than floating point sin(x) and cos(x), while the 8-bit approximation is more than 20X faster.

Functions

LIB8STATIC int16_t sin16 (uint16_t theta)

Fast 16-bit approximation of sin(x).

This approximation never varies more than 0.69% from the floating point value you’d get by doing

float s = sin(x) * 32767.0;

Parameters

theta – input angle from 0-65535

Returns

sin of theta, value between -32767 to 32767.

LIB8STATIC int16_t cos16 (uint16_t theta)

Fast 16-bit approximation of cos(x).

This approximation never varies more than 0.69% from the floating point value you’d get by doing

float s = cos(x) * 32767.0;

Parameters

theta – input angle from 0-65535

Returns

sin of theta, value between -32767 to 32767.

LIB8STATIC uint8_t sin8 (uint8_t theta)

Fast 8-bit approximation of sin(x).

This approximation never varies more than 2% from the floating point value you’d get by doing

float s = (sin(x) * 128.0) + 128;

Parameters

theta – input angle from 0-255

Returns

sin of theta, value between 0 and 255

LIB8STATIC uint8_t cos8 (uint8_t theta)

Fast 8-bit approximation of cos(x).

This approximation never varies more than 2% from the floating point value you’d get by doing

float s = (cos(x) * 128.0) + 128;

Parameters

theta – input angle from 0-255

Returns

sin of theta, value between 0 and 255