Welcome to Day 87! Today we learn how to decouple our code and write a professional, reusable Custom C++ Library for the Arduino IDE environment. As our practical example, we will implement an Exponential Moving Average (EMA) Filter library, which is the industry-standard algorithm for smoothing noisy sensor readings on resource-constrained microcontrollers.
In large embedded systems, keeping all code in a single .ino file leads to unmanageable code (spaghetti code) that is difficult to test, debug, and reuse across projects.
- Encapsulation & Modularity: Grouping related variables and functions into a C++ class hides internal mechanics and presents a clean, simple API to the main sketch.
- Reusability: Once written, you can import this library into any project without copy-pasting code.
- Namespace Safety: Prevents naming collisions between global variables in different files.
Sensors (analog inputs, IMUs, ultrasonic sensors) are prone to high-frequency electrical or environmental noise. To smooth the signal, we use filters.
An Exponential Moving Average (EMA) Filter is a first-order Infinite Impulse Response (IIR) filter. Unlike a Simple Moving Average (SMA) which requires storing a buffer of the last
The filter calculates a weighted sum of the current raw sensor reading and the previous filtered value:
Where:
-
$y[n]$ = current filtered value -
$x[n]$ = current raw input value -
$y[n-1]$ = previous filtered value -
$\alpha$ (alpha) = smoothing factor ($0.0 \le \alpha \le 1.0$ )
The behavior of the filter is entirely controlled by the smoothing coefficient
-
Small
$\alpha$ (e.g.,$0.05$ or$0.01$ ): Heavy smoothing. The filter heavily relies on past history. It rejects high-frequency noise very effectively, but introduces a large phase lag (delay in tracking the true signal). -
Large
$\alpha$ (e.g.,$0.80$ or$0.90$ ): Light smoothing. The filter responds rapidly to sudden changes with minimal lag, but passes most high-frequency noise through.
Low Alpha (0.05): ────── Noise blocked, but high delay (lag)
Medium Alpha (0.3): ─── Balanced smoothing and delay
High Alpha (0.9): ─ No delay, but noise passes through
No external hardware is strictly required! We run this sketch using the Arduino Serial Plotter which simulates a noisy analog sensor reading. To test on real-world inputs:
- Any analog sensor (e.g., Potentiometer, LDR, or LM35 Temperature Sensor).
For the default simulation mode:
- No wiring required. Connect your Arduino Uno to the PC via USB.
For real-world sensor testing (Optional):
- Connect the signal pin of your analog sensor to Analog Pin A0 of the Arduino.
| Filter Type | SRAM Overhead | CPU Overhead | Use Case | Limitations |
|---|---|---|---|---|
| EMA (Exponential) | O(1) - 4 bytes | O(1) - Very Low | General sensor smoothing, low-memory boards. | Introduces phase lag. |
| SMA (Simple Moving) | O(N) - Needs buffer | O(1) with running sum | Step response smoothing, equal weighting. | High memory usage for large window sizes ( |
| Median Filter | O(N) - Buffer & sorting | O(N log N) - Sorting | Removing sudden spikes (e.g. Ultrasonic spikes). | Modifies signal shapes, sorting takes CPU cycles. |
| Kalman Filter | O(1) - State space | High (Matrix/Floating math) | Sensor fusion (e.g., IMU + GPS). | Mathematically complex, difficult to tune. |
- Open the Arduino IDE, load Day_87_Custom_Library.ino.
- The library files EMAFilter.h and EMAFilter.cpp must be in the same folder as the
.inofile. They will open as tabs in the Arduino IDE. - Select your Arduino Uno board and upload the code.
- Visualizing the Filter (Serial Plotter):
- In the Arduino IDE, go to Tools > Serial Plotter (ensure baud rate is set to 115200).
- You will see three lines:
Raw(Blue): The noisy signal.Filtered(Red): The output of your EMA filter.Clean(Green): The underlying noiseless sine wave.
- Tuning parameters (Serial Monitor):
- Close the Serial Plotter and open the Serial Monitor at 115200 Baud.
- You will see the CLI output showing instructions.
- Send
+to increase alpha (makes the filter faster, less smooth). - Send
-to decrease alpha (makes the filter slower, smoother). - Send
nto toggle white noise generation on or off.
| Symptom | Likely Cause | Fix |
|---|---|---|
fatal error: EMAFilter.h: No such file or directory |
Library files are not in the same directory | Ensure EMAFilter.h and EMAFilter.cpp are inside the folder Day_87_Custom_Library. |
| Serial Monitor prints garbage characters | Baud rate mismatch | Change the Serial Monitor/Plotter baud rate setting to 115200. |
| Filter output starts at 0.0 and lags heavily on startup | Filter memory initialized to zero | In the library constructor or reset(), we check if it is the first sample (_isInitialized == false) and seed the memory with the raw input value to eliminate startup lag. |
Let's break down how we implement and package an Exponential Moving Average (EMA) filter:
- A Simple Moving Average requires a large array (e.g., 50 variables) to store past data, burning through the Arduino's tiny SRAM.
- The Exponential Moving Average (
$y[n] = �lpha \cdot x[n] + (1 - �lpha) \cdot y[n-1]$ ) requires only one variable of memory: the previous result!
float filteredSignal = myFilter.filter(rawSignal);- The
alphavalue (between 0.0 and 1.0) controls the filter's aggression. - Low Alpha (e.g., 0.1): We only trust 10% of the new raw sensor reading, and rely 90% on our historical smoothed data. This destroys high-frequency noise but creates a delayed response (lag).
- High Alpha (e.g., 0.8): We trust 80% of the new reading. This tracks fast movements perfectly but lets a lot of noise pass through.
- We abstracted the math into
EMAFilter.handEMAFilter.cpp. - By using a C++ Class, we encapsulate the memory state (
_lastOutput). This means we can instantiate ten differentEMAFilterobjects for ten different sensors without their math or memory overlapping!





