Learning Goals 5 min
- Recognise the "jitter" of a raw
analogReadon a still sensor — even a held-still pot reading bounces ±2 around its true value. - Smooth a noisy reading with a running average — store the last N samples in an array, average them, and use the average instead of the raw value.
- Tune the window size
Nto trade off responsiveness (small N) against smoothness (large N).
Warm-Up 10 min
Plug your potentiometer in from yesterday. Open the Serial Plotter (Tools → Serial Plotter, baud 9600) instead of the Monitor. Upload the L02-07 pot-reader sketch. Don't touch the pot.
Predict
What does the plotter line look like with the pot held perfectly still?
Reveal
It should look like a flat horizontal line — but it isn't. The line wobbles up and down by a couple of units constantly. That wobble is real: thermal noise in the ADC, tiny vibrations in the pot, EMI from the USB cable. Even when nothing is "happening", the chip is reporting microscopic changes. Today we smooth them out.
New Concept · Running average 20 min
Why noise happens
Three sources you can't avoid:
- ADC noise — the chip's last bit or two is always uncertain. Inherent to the design.
- Power-rail ripple — your USB cable and laptop supply aren't a perfectly clean 5 V; small voltage wobbles drift the reading.
- Vibration / EMI — even a quiet desk has vibrations that nudge a pot wiper; a phone nearby radiates RF.
The result: a perfectly steady input still reports values that bounce ±1 to ±5 raw units. For a knob you're reading by hand, that's invisible — but if you drive an LED brightness from the raw value, you'll see it flicker constantly.
The fix — average over a short window
Instead of using the latest reading, keep the last N readings in an array and use their average. The random ±2 noise on each individual reading cancels out across the window.
const int N = 10;
int samples[N];
int idx = 0;
long total = 0; // running sum
void setup() {
Serial.begin(9600);
for (int i = 0; i < N; i++) samples[i] = 0;
}
void loop() {
total -= samples[idx]; // remove the oldest from the sum
samples[idx] = analogRead(A0);
total += samples[idx]; // add the newest
idx = (idx + 1) % N; // wrap-around index
int avg = total / N;
Serial.println(avg);
delay(20);
}The two ideas that make this fast
- Circular buffer. The
idxwalks 0, 1, 2, ..., N−1, 0, 1, 2, ... — overwriting the oldest sample each pass.idx = (idx + 1) % Ndoes the wrap. - Running sum. Instead of re-adding the whole array every time (a loop of N adds), keep a running total. When you replace a sample, subtract the old value and add the new. Two arithmetic ops, regardless of N.
How big should N be?
| N | Effect | When to use |
|---|---|---|
| 1 | No smoothing — raw value. | Never, in practice. |
| 3–5 | Mild smoothing — kills the worst spikes, feels responsive. | Knob driving an LED, joystick driving a servo. |
| 10–20 | Solid smoothing — flat line on the plotter. | Temperature readings, slow trends. |
| 50+ | Heavy smoothing — sluggish response. | Climate sensors, long-term logging. |
Rule of thumb: pick the smallest N that hides the noise you care about. Bigger N feels more "laggy" — turn the pot quickly and the smoothed reading takes a beat to catch up.
The long on total
Each sample is 0–1023. With N = 50, the worst-case sum is 1023 × 50 = 51,150 — well within a 32-bit long but over the 32,767 limit of a 16-bit int. Use long on the sum to be safe at any N.
Worked Example · Smoothing the pot reading 20 min
Step 1 — wiring
Same pot wiring as L02-07. Pot wiper → A0, outer legs to +5 V and GND. No new hardware today.
Step 2 — type the sketch
Save as pot-smooth.ino:
// L02-08: running-average smoother for the pot on A0
const int POT = A0;
const int N = 10;
int samples[N];
int idx = 0;
long total = 0;
void setup() {
Serial.begin(9600);
for (int i = 0; i < N; i++) samples[i] = 0;
}
void loop() {
total -= samples[idx];
samples[idx] = analogRead(POT);
total += samples[idx];
idx = (idx + 1) % N;
int raw = samples[(idx + N - 1) % N];
int avg = total / N;
Serial.print(raw);
Serial.print(",");
Serial.println(avg);
delay(20);
}Note the two-column Serial output (raw, avg, separated by a comma) — this is the format the Arduino Serial Plotter understands as "plot two lines".
Step 3 — upload and open the Serial Plotter
Tools → Serial Plotter (not Monitor). You should see two coloured lines:
- The first (orange-ish in default theme) is the raw reading — wobbly even when you don't touch the pot.
- The second (blue) is the smoothed average — much flatter.
Turn the knob slowly. Both lines follow, but the smoothed line trails slightly behind — that's the lag from averaging.
Step 4 — vary N and watch the effect
Change const int N = 10; to 3, then 20, then 50, re-uploading each time:
| N | What you see on the plotter |
|---|---|
| 3 | Smoothed line still wobbles a bit. Catches up to your knob turn almost instantly. |
| 10 | Smoothed line is clearly flat when still, follows your knob with a short delay. |
| 20 | Very flat when still, but turning the knob quickly leaves a visible lag on the smoothed line. |
| 50 | Like watching the knob through a slow camera — the smoothed line lazily follows after the raw line. |
This trade-off is fundamental: more smoothing always costs responsiveness. Pick the smallest N that hides the wobble.
Basic 7 min
Goal: Wire your LDR (10 kΩ pull-down) on A1. Add a second smoother for A1 — another array, another idx, another total — and print both averages side-by-side.
Challenge 1 7 min
Goal: Drive an LED on pin ~9 from the smoothed pot reading. The LED brightness should change smoothly as you turn the pot — no flicker at any position.
Challenge 2 6 min
Goal: Reduce the running-average code to a reusable helper function: int smoothed(int sensorPin). The function should keep its own internal state — meaning the buffer, idx and total are static inside the function, not global.
Challenge 3 · The ghost-detector display 15 min
Wire the LDR on A1 with its 10 kΩ pull-down. Smooth the reading with N = 20. If the smoothed value drops by more than 50 units within one second, blink an LED on pin 13 three times — like a ghost just passed in front of the sensor and cast a shadow.
It works if:
- The sensor sits steady when nothing moves — no false triggers from random noise.
- Wave your hand slowly across the sensor → LED blinks three times.
- Cover and uncover quickly → still triggers (the drop is fast and definitely > 50).
- Walk past quickly → triggers reliably.
Recap 5 min
Every analog input wobbles a little — that's physics, not bad code. A running average of the last N readings hides the wobble. Use a circular buffer + running sum so the cost stays constant no matter how large N is. Pick the smallest N that flattens the noise; bigger N = more lag. Next lesson — calibration: how to make a sensor figure out its own min and max during the first 5 seconds.
- Jitter / noise
- Tiny random fluctuations in a sensor reading. Caused by thermal noise, power-supply ripple and EMI.
- Running average
- The average of the last N readings. Smooths short-term noise while still tracking long-term changes.
- Circular buffer
- A fixed-size array used to store the most recent N values. The write index wraps around with
idx = (idx + 1) % N. - Running sum
- A maintained total so you don't re-add the whole buffer each pass. Subtract the value you're replacing, add the new value.
- Window size (N)
- How many recent samples to average. Trade-off: bigger N = smoother but laggier.
- Static variable
- A variable inside a function that keeps its value between calls instead of being re-initialised each time. Useful for "remember state" in a helper.
Extra Mission 5 min
Part 1 — Design a gadget that must not flicker
Some readings jump about. Pick a gadget where that would be a problem — a night-light, a fan dial, a shadow alarm. On paper, design how smoothing keeps it steady.
Your design must include:
- A name and a one-sentence job for the gadget.
- The sensor (pot or LDR) and its pin.
- The output, and what would go wrong without smoothing.
- Your
Nvalue, and why it is not too small (flicker) or too big (lag).
Part 2 — Make it
Build it with today's running-average smoother. Print the raw and smoothed values side by side. Open the Serial Plotter to compare the two lines.
Bring back next class: the uploaded sketch and a Serial Plotter screenshot showing both lines.