Control Surface  1.1.0
MIDI Control Surface library for Arduino
EMA.hpp
Go to the documentation of this file.
1 /* ✔ */
2 
3 #pragma once
4 
6 AH_DIAGNOSTIC_WERROR() // Enable errors on warnings
7 
8 #include <stdint.h>
9 
10 /**
11  * @brief A class for single-pole infinite impulse response filters
12  * or exponential moving average filters.
13  *
14  * Optimized implementation of the difference equation with a slight
15  * optimization by using a factor of two as the pole location (this means
16  * that no division or floating point operations are required).
17  *
18  * Difference equation: @f$ y[n] = \alpha·x[n]+(1-\alpha)·y[n-1] @f$
19  * where @f$ \alpha = \left(\frac{1}{2}\right)^{K} @f$, @f$ x @f$ is the
20  * input sequence, and @f$ y @f$ is the output sequence.
21  *
22  * [An in-depth explanation of the EMA filter]
23  * (https://tttapa.github.io/Pages/Mathematics/Systems-and-Control-Theory/Digital-filters/Exponential%20Moving%20Average/)
24  *
25  * @tparam K
26  * The amount of bits to shift by. This determines the location
27  * of the pole in the EMA transfer function, and therefore the
28  * cut-off frequency.
29  * The higher this number, the more filtering takes place.
30  * The pole location is @f$ 1 - 2^{-K} @f$.
31  * @tparam uint_t
32  * The (signed) integer type to use for the input, intermediate values
33  * and the output.
34  * Should be at least @f$ M+K @f$ bits wide, where @f$ M @f$
35  * is the maximum number of bits of the input.
36  * In case of the Arduino's built-in ADC,
37  * @f$ M = 10 = \log_2(1024) @f$.
38  *
39  * @ingroup AH_Filters
40  */
41 template <uint8_t K, class uint_t>
42 class EMA {
43  public:
44  /**
45  * @brief Filter the input: Given @f$ x[n] @f$, calculate @f$ y[n] @f$.
46  *
47  * @param input
48  * The new raw input value.
49  * @return The new filtered output value.
50  */
51  uint_t filter(uint_t input) {
52  filtered += input;
53  uint_t output = (filtered + fixedPointAHalf) >> K;
54  filtered -= output;
55  return output;
56  }
57 
58  /**
59  * @brief Filter the input: Given @f$ x[n] @f$, calculate @f$ y[n] @f$.
60  *
61  * @param value
62  * The new raw input value.
63  * @return The new filtered output value.
64  */
65  uint_t operator()(uint_t value) { return filter(value); }
66 
67  static_assert(
68  uint_t(0) < uint_t(-1), // Check that `uint_t` is an unsigned type
69  "Error: the uint_t type should be an unsigned integer, otherwise, "
70  "the division using bit shifts is invalid.");
71 
72  private:
73  uint_t filtered = 0;
74  constexpr static uint_t fixedPointAHalf = 1 << (K - 1);
75 };
76 
77 // -------------------------------------------------------------------------- //
78 
79 /**
80  * @brief A class for single-pole infinite impulse response filters
81  * or exponential moving average filters.
82  *
83  * This version uses floating point maths.
84  *
85  * Difference equation: @f$ y[n] = \alpha·x[n]+(1-\alpha)·y[n-1] @f$
86  * @f$ x @f$ is the input sequence, and @f$ y @f$ is the output sequence.
87  *
88  * [An in-depth explanation of the EMA filter]
89  * (https://tttapa.github.io/Pages/Mathematics/Systems-and-Control-Theory/Digital-filters/Exponential%20Moving%20Average/)
90  *
91  * @ingroup AH_Filters
92  */
93 class EMA_f {
94  public:
95  /**
96  * @brief Create an exponential moving average filter with a pole at the
97  * given location.
98  *
99  * @param pole
100  * The pole of the filter (@f$1-\alpha@f$).
101  * Should be a value in the range
102  * @f$ \left[0,1\right) @f$.
103  * Zero means no filtering, and closer to one means more filtering.
104  */
105  EMA_f(float pole) : alpha(1 - pole) {}
106 
107  /**
108  * @brief Filter the input: Given @f$ x[n] @f$, calculate @f$ y[n] @f$.
109  *
110  * @param value
111  * The new raw input value.
112  * @return The new filtered output value.
113  */
114  float filter(float value) {
115  filtered += (value - filtered) * alpha;
116  return filtered;
117  }
118 
119  /**
120  * @brief Filter the input: Given @f$ x[n] @f$, calculate @f$ y[n] @f$.
121  *
122  * @param value
123  * The new raw input value.
124  * @return The new filtered output value.
125  */
126  float operator()(float value) { return filter(value); }
127 
128  private:
129  float alpha;
130  float filtered = 0;
131 };
132 
Warnings.hpp
EMA_f::filter
float filter(float value)
Filter the input: Given , calculate .
Definition: EMA.hpp:114
EMA_f::EMA_f
EMA_f(float pole)
Create an exponential moving average filter with a pole at the given location.
Definition: EMA.hpp:105
AH_DIAGNOSTIC_POP
#define AH_DIAGNOSTIC_POP()
Definition: Warnings.hpp:17
EMA_f::alpha
float alpha
Definition: EMA.hpp:129
EMA::operator()
uint_t operator()(uint_t value)
Filter the input: Given , calculate .
Definition: EMA.hpp:65
EMA::filtered
uint_t filtered
Definition: EMA.hpp:73
EMA_f
A class for single-pole infinite impulse response filters or exponential moving average filters.
Definition: EMA.hpp:93
EMA
A class for single-pole infinite impulse response filters or exponential moving average filters.
Definition: EMA.hpp:42
EMA::fixedPointAHalf
constexpr static uint_t fixedPointAHalf
Definition: EMA.hpp:74
EMA::filter
uint_t filter(uint_t input)
Filter the input: Given , calculate .
Definition: EMA.hpp:51
AH_DIAGNOSTIC_WERROR
#define AH_DIAGNOSTIC_WERROR()
Definition: Warnings.hpp:16
EMA_f::filtered
float filtered
Definition: EMA.hpp:130
EMA_f::operator()
float operator()(float value)
Filter the input: Given , calculate .
Definition: EMA.hpp:126