You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
An EMA (**Exponential Moving Average**) filter behaves like an RC lowpass filter with RC = SamplePeriod((1-alpha)/alpha) see [here](https://en.wikipedia.org/wiki/Low-pass_filter#Simple_infinite_impulse_response_filter).<br/>
57
+
An EMA (**Exponential Moving Average**) filter behaves like an RC Lowpass filter with RC = SamplePeriod((1-alpha)/alpha) see [here](https://en.wikipedia.org/wiki/Low-pass_filter#Simple_infinite_impulse_response_filter).<br/>
58
58
An EMA filter is implemented by e.g. the following statement:
59
59
60
-
```c++
60
+
```c+
61
61
int16_t sLowpass3;
62
62
int16_t Lowpass5;
63
63
...
@@ -70,93 +70,102 @@ The alpha's for the implemented **ultra fast EMA filters** are 1/2, 1/4, 1/8, 1/
70
70
71
71
### For a 1 kHz sampling rate (1/1000s sampling interval) we get the following equivalent cutoff (-3db) frequencies:
72
72
Simplified formula for small alpha is CutoffFrequency = (SampleFrequency / (2π * ((1/alpha) - 1));
73
-
- For alpha 1/2 (shift 1) -> (160 Hz / 1) With 1 = (1/alpha) - 1
Using the [more exact formula](https://github.com/MakeMagazinDE/DigitaleFilter/blob/main/Filter-Berechnungen.xlsx), alpha = 1 - e ^ -((2π * CutoffFrequency) / SampleFrequency)
81
83
=> CutoffFrequency = (-ln(1-alpha) * SampleFrequency) / 2π we get the values:
82
-
- 110 Hz
83
-
- 46 Hz
84
-
- 21.2 Hz
85
-
- 10.3 Hz
86
-
- 5.05 Hz
84
+
-1/2 -> 110 Hz
85
+
-1/4 -> 46 Hz
86
+
-1/8 -> 21.2 Hz
87
+
-1/16 -> 10.3 Hz
88
+
-1/32 -> 5.05 Hz
87
89
88
90
The **maximum output value for integer filters** is: InputValue - ((1 << (ShiftValue -1)) -1), i.e **85 for InputValue 100 and ShiftValue 5** (Lowpass5).
89
91
90
92
### The [SimpleEMAFilters.hpp](https://github.com/ArminJo/Arduino-Utils/blob/master/src/SimpleEMAFilters.hpp#L66) contains:
91
93
- A set of **ultrafast** EMA (Exponential Moving Average) filters which require only **1 to 2 microseconds**.
92
-
- 3 highpass and bandpass filters, generated by just subtracting one lowpass from input (highpass) or from another lowpass (bandpass).
93
-
- 16 and 32 bit Biquad filters.
94
+
- 3 Highpass and Bandpass filters, generated by just subtracting one Lowpass from input (Highpass) or from another Lowpass (Bandpass).
95
+
- 16 and 32 bit Biquad filters / State Variable Filter (SVF).
94
96
- Display routines for Arduino Plotter.
95
97
96
98
All implemented filters are applied at once to the input test signal calling `doFiltersStep(int16_t aInput)` and the results can in turn easily be displayed in the Arduino Plotter.
97
99
98
-
### Plotter outputs representing e.g. a 42, 21, 10.5, 5.2 Hz square / sine wave at a sample rate of 1 ms (or 84, 42 ... Hz at a sample rate of 0.5 ms and so on)
100
+
### Arduino 1.8.19 plotter outputs are showing a 42, 21, 10.5, 5.2 Hz square / sine wave at a sample rate of 1 ms (or 84, 42 ... Hz at a sample rate of 0.5 ms and so on)
101
+
The outputs are generated by the EMAFilterDemo example of this library.
99
102
100
-
Arduino Plotter output for a rectangle input signal with a amplitude of +/- 100. E.g. LowP3 is the Lowpass with alpha 1/8 implemented by `>> 3` and the cutoff frequency of 21 Hz.
103
+
Output for a rectangle input signal with a amplitude of +/- 100.
104
+
E.g. LowP3 is the Lowpass implemented by `>> 3` corresponding to alpha = 1/8 with a cutoff frequency of 21 Hz.<br/>
-Therefore highpass -here HighP3_16- can have an overshoot of 100%.
106
-
- The output of DoubleLowpass3 and 4 is more and more resembling a delayed sine.
108
+
- Highpass is always Input - Lowpass, therefore Highpass -here HighP3_16- can have an overshoot of up to 100%.
109
+
-BandStop is always Input - Bandpass.
110
+
- The output of DoubleLowpass3 and 4 resembes a delayed sine the higher the frequency is.
107
111
- The output of LowP5_32 and DoubleLowP4_16 have almost the same amplitude but DoubleLowP4_16 is way more resembling a (delayed) sine.
108
112
- The output of TripleLowP3_16 has a higher amplitude than DoubleLowP4_16 with both looking quite like a (delayed) sine.
113
+
- The output of Lowpass8 behave like a integrator here, resulting in a triangle output, because it has a very low cutoff frequency.
114
+
- The output of BiQuad tends to oscillate with its resonance frequency.
109
115
110
116
<br/>
111
117
112
118
Arduino Plotter output for a rectangle input signal with very low amplitude of +/- 20 where you see clipping effects due to the limited resolution of the used 16 bit math.
The Lowpass3_int32 and Lowpass5_int32 are 32 bit fixed point implementations for higher resolution which requires **4.2 µs instead of the 1.8 / 2.5µs of 16 bit**.
The Lowpass3_int32 and Lowpass5_int32 are 32 bit fixed point implementations for higher resolution which requires **3.06 / 3.94 µs instead of the 2.0 / 2.63µs of 16 bit**.
115
121
<br/>
116
122
117
123
Arduino Plotter output for a sine input signal with a amplitude of +/- 100.
118
124

119
-
Note the **different attenuations** at different frequencies.
125
+
Note the **different attenuations** at different frequencies and the **different phase shifts** of the filters.
120
126
<br/><br/>
121
127
122
128
Arduino Plotter output for a triangle input signal with a amplitude of +/- 100.
| Bandpass and reject filters.<br/>Bandpass is generated by subtracting one lowpass from onother with different shift value.<br/>Reject filter is input minus bandpass.| High order Lowpass. |
| LowPass1, 3, 5 and 8.<br/>Lowpass8 behave like a integrator here, resulting in a triangle output. | LowPass3, 5 and 8.<br/>Comparison of different implementations with 16 bit integer, 32 bit integer and 32 bit float. |
| BiQuad filters with damping factor = 0.<br/>You see the overshoot. ||
145
-
|||
149
+
|||
150
+
| Bandpass and Bandstop filters.<br/>Bandpass is generated by subtracting one Lowpass from another with different shift value.<br/>Bandstop filter is input minus Bandpass.| Selected Lowpass.<br/>Lowpass8 behave like a integrator here, resulting in a triangle output. |
Lowpass5_int32 += ((((int32_t) InputValue) << 8) - Lowpass5_int32) >> 5; // Fixed point 4.0 us, value is Lowpass5_int32 >> 8
168
+
Lowpass8_int32 += ((((int32_t) InputValue) << 16) - Lowpass8_int32) >> 8; // Fixed point 2.13 us because of fast 8 bit shift, value is Lowpass8_int32 >> 16
160
169
```
161
170
162
171
**!Attention!** The 16 bit implementations are limited to a **maximum input value of +/- 16383** for rectangular input (which is the worst input case). The reason is, that the term `InputValue - Lowpass3` must always fit into a 16 bit signed integer.
0 commit comments