Sound Byte Libs 0.5.1-121-g3358a44
C++ firmware library for audio applications on 32-bit ARM Cortex-M processors
Loading...
Searching...
No Matches
ewma.hpp
Go to the documentation of this file.
1/**
2 * @file ewma.hpp
3 * @brief Exponentially Weighted Moving Average filter
4 * @ingroup primitives
5 *
6 * Integer-only EWMA with Q16 internal state for sub-LSB precision.
7 * Uses power-of-2 shift for the smoothing factor (no division).
8 * Suitable for Cortex-M0+ (no FPU required).
9 *
10 * Alpha = 1 / 2^shift:
11 * shift=1 → alpha=1/2 (fast tracking, little smoothing)
12 * shift=3 → alpha=1/8 (good default for pots)
13 * shift=5 → alpha=1/32 (heavy smoothing)
14 *
15 * Usage:
16 * sbl::primitives::math::Ewma filter(3);
17 * uint16_t smoothed = filter.update(raw_adc_value);
18 */
19
20#ifndef SBL_HW_UTIL_EWMA_HPP_
21#define SBL_HW_UTIL_EWMA_HPP_
22
23#include <cstdint>
24
25namespace sbl {
26namespace primitives {
27namespace math {
28
29class Ewma {
30public:
31 /**
32 * @brief Construct EWMA filter
33 * @param shift Smoothing exponent (alpha = 1/2^shift). Range: 1–15.
34 */
35 explicit Ewma(uint8_t shift = 3) : shift_(shift), state_(0), primed_(false) {}
36
37 /**
38 * @brief Feed a new sample and return the smoothed value
39 *
40 * First call seeds the filter (no smoothing on first sample).
41 * Internal state uses Q16 fixed-point for sub-LSB precision.
42 *
43 * @param raw Raw input value (16-bit)
44 * @return Smoothed output (16-bit)
45 */
46 uint16_t update(uint16_t raw) {
47 uint32_t input_q16 = static_cast<uint32_t>(raw) << 16;
48
49 if (!primed_) {
50 state_ = input_q16;
51 primed_ = true;
52 } else {
53 // EWMA: state += (input - state) >> shift
54 // Signed delta handles both directions correctly
55 int32_t delta = static_cast<int32_t>(input_q16 - state_);
56 state_ += static_cast<uint32_t>(delta >> shift_);
57 }
58
59 return static_cast<uint16_t>(state_ >> 16);
60 }
61
62 /** @brief Return current smoothed value without updating */
63 uint16_t value() const {
64 return static_cast<uint16_t>(state_ >> 16);
65 }
66
67 /** @brief Change smoothing exponent without resetting filter state */
68 void set_shift(uint8_t shift) { shift_ = shift; }
69
70 /** @brief Reset filter state (next update will re-seed) */
71 void reset() {
72 state_ = 0;
73 primed_ = false;
74 }
75
76private:
77 uint8_t shift_;
78 uint32_t state_; // Q16 fixed-point accumulator (32-bit aligned → atomic on Cortex-M)
79 bool primed_;
80 // Atomicity note: On Cortex-M, 32-bit aligned reads/writes are atomic.
81 // It is safe to call update() from an ISR and value() from the main loop
82 // (or vice versa), provided only one context calls update() on a given
83 // instance. Do not call update() from multiple contexts simultaneously.
84};
85
86} // namespace math
87} // namespace primitives
88} // namespace sbl
89
90#endif // SBL_HW_UTIL_EWMA_HPP_
Ewma(uint8_t shift=3)
Construct EWMA filter.
Definition ewma.hpp:35
uint16_t update(uint16_t raw)
Feed a new sample and return the smoothed value.
Definition ewma.hpp:46
uint16_t value() const
Return current smoothed value without updating.
Definition ewma.hpp:63
void set_shift(uint8_t shift)
Change smoothing exponent without resetting filter state.
Definition ewma.hpp:68
void reset()
Reset filter state (next update will re-seed)
Definition ewma.hpp:71
Root namespace for all Sound Byte Libs code.
Definition assert.hpp:51