import numpy as np
import matplotlib.pyplot as plt
# Set the random seed for reproducibility
42)
np.random.seed(
# Simulate the ground truth position of the object
= 0.5 # units per time step
true_velocity = 50
num_steps = np.linspace(0, num_steps, num_steps)
time_steps = true_velocity * time_steps
true_positions
# Simulate the measurements with noise
= 5 #1#0 # increase this value to make measurements noisier
measurement_noise = true_positions + np.random.normal(0, measurement_noise, num_steps)
noisy_measurements
# Plot the true positions and the noisy measurements
=(10, 6))
plt.figure(figsize='True Position', color='green')
plt.plot(time_steps, true_positions, label='Noisy Measurements', color='red', marker='o')
plt.scatter(time_steps, noisy_measurements, label
'Time Step')
plt.xlabel('Position')
plt.ylabel('True Position and Noisy Measurements Over Time')
plt.title(
plt.legend() plt.show()
6 Example 3 - constant-velocity 1D position tracking
Kalman filters are extensively used in navigation and other GPS-based systems. These can be either linear or nonlinear. In the latter case, one usually resorts to the extended Kalman, filter (EKF) that is designed to deal better with nonlinear state equations—see below.
Process noise design for \(Q\)
- diagonal
- constant velocity model
- constant acceleration model
We begin with a very simple case of tracking a 1D position due to constant velocity motion, described by
\[\frac{\mathrm{d}x}{\mathrm{d}t} = v, \quad x(0) = x_0.\]
This equation can be written as a system of two equations
\[\frac{\mathrm{d}\mathbf{x}}{\mathrm{d}t} = F \mathbf{x} + L \mathbf{w} , \quad \mathbf{x}(0) = \mathbf{x}_0,\]
where
\[\mathbf{x}=\begin{bmatrix}x\\ \dot{x} \end{bmatrix},\quad F=\begin{bmatrix}0 & 1\\ 0 & 0 \end{bmatrix},\quad L=\begin{bmatrix}0\\ 1 \end{bmatrix},\quad \mathbf{w}=w.\]
In discrete-time, we introduce a time-step, \(\Delta t,\) that is sometimes just set equal to one, and obtain the discrete, state-space formulation
\[ \mathbf{x}_{k+1 } = F \mathbf{x}_{k} + L w_k, \]
where
\[ F=\begin{bmatrix}1 & \Delta t\\ 0 & 1 \end{bmatrix},\quad L=\begin{bmatrix} 1 \\ 0 \end{bmatrix}.\]
We begin by simulating the motion and generating noisy measurements of the position.
Now, we set up the inputs for the Kalman filter, run it, and plot the results of the estimation.
The process noise covariance matrix, \(Q,\) is taken here as
\[ Q = \begin{bmatrix}1 & 0\\ 0 & \sigma_w^2 \end{bmatrix}, \]
where we have supposed that
\[ w \sim \mathcal{N} (0, \sigma_w^2) . \]
This form for \(Q\) can be derived from the discretization of a Wiener process, as shown in {cite}Sarkka2023. We will consider a more general case in Example 4, below.
= measurement_noise
sig_v = 0.1 # np.sqrt(3) # process noise
sig_w # Kalman Filter Initialization
= np.array([[1, 1], [0, 1]]) # State transition matrix
F = np.array([[1, 0]]) # Measurement function
H = np.array([[1, 0], [0, sig_w**2]]) # Process noise covariance
Q = np.array([[sig_v**2]]) # Measurement noise covariance
R = np.array([[0], [0]]) # Initial state estimate
x0 = np.array([[1, 0], [0, 1]]) # Initial estimate covariance
P0
# Initialize the state estimate and covariance
= 2
nd = 50
T
= np.zeros((T, nd, 1))
x_hat = np.zeros((T, nd, nd))
P
0] = x0
x_hat[0] = P0 #Q
P[= noisy_measurements
y
# Run the Kalman filter
for t in range(1, T):
# Prediction step
= F @ x_hat[t-1]
x_hat[t] = F @ P[t-1] @ F.T + Q
P[t]
# Update step
= P[t] @ H.T @ np.linalg.inv(H @ P[t] @ H.T + R)
K = x_hat[t] + K @ (y[t] - H @ x_hat[t])
x_hat[t] = (np.eye(nd) - K @ H) @ P[t] P[t]
# Plot the true positions, noisy measurements, and the Kalman filter estimates
= range(T)
time_steps = x_hat[:,0,:]
estimated_positions = x_hat[:,1,:]
estimated_velocities =(10, 6))
plt.figure(figsize='True Position $x$', color='green')
plt.plot(time_steps, true_positions, label='Noisy Measurements $y$', color='red', marker='o')
plt.scatter(time_steps, noisy_measurements, label='Kalman Filter Estimate of $x$', color='blue')
plt.plot(time_steps, estimated_positions, label0.5,color='k',label='True velocity')
plt.axhline(='Kalman Filter Estimate of $\dot{x}$', color='orange')
plt.plot(time_steps, estimated_velocities, label'Time Step')
plt.xlabel('Position')
plt.ylabel('Kalman Filter Estimation Over Time')
plt.title(
plt.legend() plt.show()