The algorithm that lets a robot figure out where it is by combining movement and sensing — the parent of every probabilistic filter you'll ever meet.
You're a robot in a hallway. You can't see yourself from above. You have no GPS. All you have is a noisy sensor that can detect whether you're next to a door, and wheels that sometimes slip. Where are you?
You don't know — not for certain. But you can believe. You start with a rough guess spread across every possible position. Then you sense something: "I see a door." Some positions have doors, some don't, so your belief shifts. Then you move forward and sense again. With each sense-move cycle, your belief sharpens until you're nearly certain where you are.
The robot starts with no idea where it is (uniform belief). Click Sense or Move to watch the belief evolve.
Before we build a filter, we need one formula. But let's not start with the formula — let's start with counting.
Imagine 100 people. 20 are programmers. Of those 20 programmers, 15 drink coffee. Of the 80 non-programmers, 40 drink coffee. You meet someone drinking coffee. What's the probability they're a programmer?
Total coffee drinkers: 15 + 40 = 55. Programmers among them: 15. So: P(programmer | coffee) = 15/55 ≈ 0.27. That's Bayes' theorem in action — you updated your belief about someone being a programmer after observing they drink coffee.
Adjust the overlap to see how P(A|B) changes. A = hypothesis, B = evidence.
The robot's world is a 1D hallway divided into discrete cells. At any moment, the robot's belief is a probability distribution — a number for each cell saying "how likely am I to be here?" All the numbers sum to 1.
When the robot knows nothing, the belief is uniform: equal probability everywhere. As it gathers evidence, some cells become more probable and others shrink. The belief is the robot's internal mental model of where it might be.
Click cells to manually assign probability. The histogram always renormalizes to sum to 1.
When the robot's wheels turn, it tries to move forward. But wheels slip. The robot might overshoot, undershoot, or stay put. The motion model P(x'|x,u) describes: "if I'm at cell x and I command motion u, what's the probability I end up at cell x'?"
Mathematically, applying the motion model to a belief is a convolution: each cell "spreads" its probability to neighboring cells according to the motion kernel. The result is that the belief shifts in the direction of motion and blurs due to uncertainty. Information is lost. Entropy increases.
Start with a spike belief, then apply motion. Watch how the belief blurs and shifts with each step.
The robot has a door sensor. It returns "door" or "no door." But it's not perfect — sometimes it says "door" when there's none (false positive), and sometimes it misses a real door (false negative). The sensor model P(z|x) encodes: "if I'm truly at cell x, what's the probability of reading z?"
This is the likelihood function. For each cell, it tells us how well the sensor reading "fits" that position. Cells with doors get a high likelihood when the sensor says "door." Cells without doors get a low likelihood. This is the information that sharpens belief.
The hallway has doors at specific cells (orange). Toggle the sensor reading to see how the likelihood changes.
The predict step applies the motion model to the current belief. Every cell's probability mass gets redistributed according to how the robot might move. The result is a blurred, shifted version of the old belief.
This is mathematically a convolution: bel¯(x') = Σx P(x'|x,u) bel(x). In the discrete case, we slide a small kernel across the histogram and sum. The output is always smoother (less certain) than the input.
The teal histogram is before prediction. Click Predict to apply one motion step. Watch the histogram blur and shift right.
The update step incorporates a sensor reading. It's pure Bayes' theorem applied to every cell: multiply the predicted belief by the sensor likelihood, then renormalize so the probabilities sum to 1.
Here η is the normalizing constant (1 / Σ P(z|xi) bel¯(xi)). The effect: cells that are consistent with the sensor reading get boosted; cells that are inconsistent get suppressed. The histogram sharpens. Uncertainty decreases.
Blue is predicted belief. Yellow is sensor likelihood. Green is the updated belief after multiply + normalize.
Now we put it all together. The Bayes filter is an infinite loop of Predict (move, blur) and Update (sense, sharpen). Below is the classic Probabilistic Robotics visualization: a 1D hallway with colored doors, a robot that moves, and a belief histogram that evolves in real-time.
Python def bayes_filter(bel, u, z, motion_model, sensor_model): """One cycle of the discrete Bayes filter.""" n = len(bel) # ── Predict (convolution) ── bel_bar = [0.0] * n for x_prime in range(n): for x in range(n): bel_bar[x_prime] += motion_model(x_prime, x, u) * bel[x] # ── Update (Bayes rule) ── for x in range(n): bel_bar[x] *= sensor_model(z, x) # ── Normalize ── eta = 1.0 / sum(bel_bar) return [b * eta for b in bel_bar]
A robot moves through a hallway with colored doors. Watch the belief histogram converge to the true position. The green bar marks the robot's true cell.
The Bayes filter is not one algorithm — it's the parent of an entire family. Every probabilistic filter is a special case of the Bayes filter, making different assumptions about the belief representation and the motion/sensor models.
| Filter | Belief | Assumption | Cost |
|---|---|---|---|
| Discrete Bayes | Histogram | Finite grid of cells | O(n) |
| Kalman (KF) | Gaussian (μ, Σ) | Linear + Gaussian noise | O(n³) |
| EKF | Gaussian | Locally linear (Jacobian) | O(n³) |
| UKF | Gaussian (sigma pts) | Smooth nonlinearity | O(n³) |
| Particle Filter | Weighted samples | Any distribution | O(N·n) |
You now understand Bayesian state estimation. Every sensor reading is noisy, every action is uncertain — but belief persists and refines. That's the Bayes filter.