RTS Smoother¶
The Rauch-Tung-Striebel (RTS) Smoother is a post-processing algorithm that runs backward over the forward-pass results of a Kalman Filter to produce optimally smoothed state estimates.
Fundamental Concepts¶
Forward Filtering vs. Smoothing¶
| Filtering | Smoothing | |
|---|---|---|
| Uses | Past + current data | Past + current + future data |
| Processing | Real-time (online) | Post-processing (offline) |
| Accuracy | Good | Better (always ≤ filtering error) |
The RTS smoother takes the forward KF results and runs a backward pass to incorporate future information into every estimate:
\[G_k = P_{k|k} F^T P_{k+1|k}^{-1}\]
\[\hat{x}_{k|N} = \hat{x}_{k|k} + G_k (\hat{x}_{k+1|N} - \hat{x}_{k+1|k})\]
\[P_{k|N} = P_{k|k} + G_k (P_{k+1|N} - P_{k+1|k}) G_k^T\]
When to Use¶
| ✅ Use RTS when | ❌ Don't use when |
|---|---|
| Processing recorded data | Need real-time estimates |
| Want best possible accuracy | Data is streaming (use filter only) |
| Post-flight analysis | Memory is extremely limited |
How to Use¶
import numpy as np
from kalbee import KalmanFilter, RTSSmoother
# Setup
dt = 1.0
F = np.array([[1.0, dt], [0.0, 1.0]])
Q = np.eye(2) * 0.01
H = np.array([[1.0, 0.0]])
R = np.array([[1.0]])
state = np.array([[0.0], [1.0]])
cov = np.eye(2) * 10.0
kf = KalmanFilter(state, cov, F, Q, H, R)
# Step 1: Forward pass — store everything
filtered_states, filtered_covs = [], []
predicted_states, predicted_covs = [], []
np.random.seed(42)
for t in range(20):
kf.predict(dt=dt)
predicted_states.append(kf.state.copy())
predicted_covs.append(kf.covariance.copy())
z = np.array([[float(t + 1) + np.random.randn()]])
kf.update(z)
filtered_states.append(kf.state.copy())
filtered_covs.append(kf.covariance.copy())
# Step 2: Backward pass — smooth
smoothed_states, smoothed_covs = RTSSmoother.smooth(
filtered_states, filtered_covs,
predicted_states, predicted_covs,
F,
)
# Compare
for k in [0, 5, 10, 15, 19]:
f_err = abs(filtered_states[k][0, 0] - (k + 1))
s_err = abs(smoothed_states[k][0, 0] - (k + 1))
print(f"t={k+1:2d} Filtered error: {f_err:.3f} "
f"Smoothed error: {s_err:.3f} "
f"Improvement: {(f_err - s_err) / f_err * 100:.0f}%")
Smoothing always helps
The smoothed covariance is always ≤ the filtered covariance (element-wise). The improvement is most dramatic at the beginning of the sequence, where the filter had less data.