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]¶
-
uint32_t i¶
-
GET_MILLIS()¶
- 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.
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