Agreed, I added a check and more comments on the page: https://tttapa.github.io/Pages/Math...Implementation.html#improved-c-implementationBe careful when using 16 bits - your input sample range is limited. For example, -1024 to 1023 (??) for the code in #21. Some comments or checks would be a good idea.
You can now verify the range:
Code:
EMA<5, int_fast16_t> filter;
static_assert(filter.supports_range(-1024, 1023),
"use a wider state or input type, or a smaller shift factor");
As mentioned by Nominal Animal, a 32-bit state is much slower on an 8-bit MCU, and since a common use is to filter 10-bit analogRead values with a relatively small K, a 16-bit state is preferable.if data are 16 bit, then IMO the state variable (effectively sample<<K) should be declared as 32 bit
I don't think this is an issue, especially if you explicitly cast the input to state_t before adding it. Even if you don't cast it, you're probably fine thanks to the usual arithmetic conversions:Note: It looks like the state has to be an exact-width type (so uintN_t and not uint_fastN_t), as any extra bits will mess up the modulo arithmetic.
Since the rank of the state type is never less than the rank of the input type, and since the state type is unsigned, the input will be converted to the unsigned state type before performing the addition.[...]
Otherwise, the operand has integer type and integral conversions are applied to produce the common type, as follows:
- If both operands are signed or both are unsigned, the operand with lesser conversion rank is converted to the operand with the greater integer conversion rank
- Otherwise, if the unsigned operand's conversion rank is greater or equal to the conversion rank of the signed operand, the signed operand is converted to the unsigned operand's type.
- Otherwise, if the signed operand's type can represent all values of the unsigned operand, the unsigned operand is converted to the signed operand's type
- Otherwise, both operands are converted to the unsigned counterpart of the signed operand's type.
The conversion rank above increases in order bool, signed char, short, int, long, long long. The rank of any unsigned type is equal to the rank of the corresponding signed type.
The conversion from a signed integer to an unsigned integer effectively sign extends the integer to the full size of the unsigned type because of integral promotion:
Once the type is converted, the C and C++ standards guarantee 2ⁿ modular arithmetic for unsigned types, so it's fine.If the destination type is unsigned, the resulting value is the smallest unsigned value equal to the source value modulo 2ⁿ where n is the number of bits used to represent the destination type.
The rules apply to the number of bits used to represent the type, which could be 32, for uint_fast16_t on ARM, for example.
uint_fast16_t doesn't guarantee arithmetic modulo 2¹⁶, but it does guarantee arithmetic modulo some power of two.