Q and R
The two numbers you actually choose, what they mean, and how to measure them.
Do this lesson in the simulatorTwo numbers, and they are the whole of tuning a Kalman filter.
R: how noisy the measurement is
R is the variance of the measurement noise, in squared units of whatever you are measuring. It is measurable, and you have already measured it: U4.1 was exactly this.
sigma = 5 cm -> R = 25
Measure it, do not guess it. Stand the robot still, take a hundred readings, take the variance. If the sensor's noise changes with range or with surface, R can change per reading, and a filter that adjusts R when the measurement is known to be worse is doing something genuinely useful.
Q: how wrong the model can be
Q is the process noise: how much the state can change between ticks in ways your prediction does not know about. Slip, a bump, a gust, an unmodelled acceleration.
It is not directly measurable, and it is the number people fiddle with. Some ways to think about it:
- If the model were perfect,
Qwould be zero, and the filter would eventually stop listening to measurements entirely. That is whyQ = 0is always wrong on a real machine. - Roughly,
Qis the square of how far the state can drift in one tick without you knowing. A robot that can slip 0.5 cm in a tick:Qabout 0.25. - Only the ratio
Q/Rmatters for the gain. Doubling both changes nothing.
from bugbot import *
connect()
readings = []
for i in range(60):
readings.append(distance())
wait(0.1)
mean = sum(readings) / len(readings)
R = sum((v - mean) ** 2 for v in readings) / len(readings)
print("measured R:", round(R, 1), "(sigma", round(R ** 0.5, 2), "cm)")
for Q in (0.01, 1.0, 100.0):
est, p = readings[0], 100.0
for v in readings:
p += Q
k = p / (p + R)
est += k * (v - est)
p = (1 - k) * p
print("Q", Q, "-> steady gain", round(p / (p + R), 3))
The two failure modes
Q too small, or R too large. The filter trusts its model and ignores measurements. It is smooth, confident and wrong, and it stays wrong: the estimate wanders off and the filter reports a small variance the whole time. This is called filter divergence and it is the dangerous failure, because the filter's own statement of its uncertainty is the thing that is broken.
Q too large, or R too small. The filter trusts every measurement. The output is as noisy as the raw sensor and you have gained nothing but complexity.
Between them: the estimate should look smoother than the measurement and should still track the truth when the truth moves.
Checking a filter honestly
The test is the innovation, again. The filter predicts that measured - est should have variance p + R. So:
normalised = (measured - est) ** 2 / (p + R)
should average about 1. Much less than 1 means the filter is claiming more uncertainty than it has, and could be tuned tighter. Much more than 1 means it is claiming less uncertainty than it has, which is the dangerous direction. This ratio has a name, the normalised innovation squared, and printing its running average is the single most useful diagnostic a filter can carry.
Task: tune Q and R
Standing still, measure R and print it as measured r:. Then run the filter at two or three values of Q and print what each does.
from bugbot import *
connect()
readings = []
Challenges
- Compute the normalised innovation squared for your filter and check it is near 1.
- Set
Q = 0and drive the robot. Watch the estimate stop listening. - Make
Rdepend on range: double it beyond 100 cm. Does the estimate improve?