Trust Issues · Lesson 11
Trust, but verify
This is the written walk-through of the lesson: the idea, stage by stage, plus the deeper asides. The interactive version, where you write real Python in the browser and drive a simulated robot, lives on the lesson page.
One sensor, all jitter
Your robot’s senses are noisy. Teach it to not believe every twitch.
Point a real sensor at a steady world and the number it returns is not steady: it jitters around the truth, a fresh error every tick. You cannot stop that. What saves you is that noise and signal behave differently. The noise is new every tick and points anywhere; the signal is patient and keeps pointing the same way. Average in a little history and the noise cancels itself while the signal stays.
The driving is not your job this time. Press Run and the bot crawls on its own; the crawl is scenery. Your job is the believer: every tick your SmoothingFilter gets one raw noisy reading and returns what it believes the true signal is. A smooth signal is buried under that noise, and the two gates grade your belief against it.
Blend toward the reading
The whole filter is one move, the exponential moving average: keep a running value, and every tick move it a fraction of the way toward the new reading. The fraction is alpha. A noise spike only drags you part of the way toward it, and the next spike pulls the other way, so the jitter mostly cancels. The real signal never stops pulling in its own direction, so it wins.
Two details, and you have met both before. The running value lives on self, the same instance every tick, so it survives between updates. And the very first reading has nothing to blend into: seed the memory once, then blend forever after. Return the running value; the raw reading is what you are escaping.
One catch, and it is deliberate: the starter ships alpha=1.0, and a blend that moves the whole way to each new reading is no blend at all. Write the move and Run it, and the gate under this stage stays cold. The gain is the next stage’s business.
Beat the noise, keep tracking
Now the gain. It lives in your code: the alpha default in __init__ is the tuning surface, and the editor highlights it. At 1.0 you trust each new reading completely and the raw jitter sails straight through, so neither gate can latch. Lower the default (halve it, say) and press Run again. Each Run builds a fresh filter from your source, so the new gain drives from the first tick, and the jitter falls with it.
There is a floor. Drop alpha far enough (try 0.02) and the filter turns so calm it stops keeping up: your estimate trails behind the moving signal, late and wrong, and the gates grade you against the truth. Somewhere between too jumpy and too sleepy both gates hold at once, and that band is wide. Find it and the lesson is done.
Go deeper: what alpha trades
An exponential moving average is a dial on memory. Each update keeps 1 - alpha of what you believed and takes alpha of what you just heard, so the filter is effectively averaging its last few readings: roughly 1/alpha of them. At alpha=0.1 you are listening to the last ten ticks at once.
Averaging more readings shrinks the jitter, but only like the square root of the count, while the price is age: your estimate is centered on where the signal was half a window ago, and that lag grows in step with the window. Diminishing returns on one side, linear cost on the other. That is why the pass band is a band and not a point, and why every real robot has a gain like this somewhere, set by someone who watched it jitter, then watched it lag, and split the difference.
Ready to build it? The interactive lesson is where you write the code and watch the robot run.