36""" @example ukf-linear-example.py
37 Example of a simple linear use-case of the Unscented Kalman Filter (UKF). Using a UKF
38 in this case is not necessary, it is done for learning purpose only.
40 The system we are interested in is a system moving on a 2D-plane.
42 The state vector of the UKF is:
45 \textbf{x}[0] &=& x \\
46 \textbf{x}[1] &=& \dot{x} \\
47 \textbf{x}[1] &=& y \\
48 \textbf{x}[2] &=& \dot{y}
52 The measurement \f$ \textbf{z} \f$ corresponds to the position along the x-axis
53 and y-axis. The measurement vector can be written as:
56 \textbf{z}[0] &=& x \\
61 Some noise is added to the measurement vector to simulate a sensor which is
65from visp.core
import ColVector, Matrix, UnscentedKalman, UKSigmaDrawerMerwe
69 from visp.gui
import Plot
75def fx(x: ColVector, dt: float) -> ColVector:
77 Process function that projects in time the internal state of the UKF.
79 :param x: The internal state of the UKF.
80 :param dt: The sampling time: how far in the future are we projecting x.
82 :return ColVector: The updated internal state, projected in time, also known as the prior.
92def hx(x: ColVector) -> ColVector:
94 Measurement function that expresses the internal state of the UKF in the measurement space.
96 :param x: The internal state of the UKF.
98 :return ColVector: The internal state, expressed in the measurement space.
107 Method that permits to add two state vectors.
109 :param a: The first state vector to which another state vector must be added.
110 :param b: The other state vector that must be added to a.
112 :return ColVector: The sum a + b.
118 Method that permits to subtract a state vector to another.
120 :param a: The first state vector to which another state vector must be subtracted.
121 :param b: The other state vector that must be subtracted to a.
123 :return ColVector: The subtraction a - b.
129 Method that generates the process covariance matrix for a process for which the
130 state vector can be written as (x, dx/dt)^T
132 :param dt: The sampling period.
134 :return Matrix: The corresponding process covariance matrix.
137 [[dt**3/3, dt**2/2, 0, 0],
139 [0, 0, dt**3/3, dt**2/2],
140 [0, 0, dt**2/2, dt]])
142if __name__ ==
'__main__':
146 gt_dX = ColVector([gt_dx, gt_dy])
154 drawer = UKSigmaDrawerMerwe(n=4, alpha=0.3, beta=2, kappa=-1, resFunc=residual_state_vectors, addFunc=add_state_vectors)
156 P0 = Matrix(np.eye(4) * 1.)
157 R = Matrix(np.eye(2) * 0.01)
159 ukf = UnscentedKalman(Q, R, drawer, fx, hx)
162 ukf.init(ColVector([0., 0.75 * gt_vx, 0., 0.75 * gt_vy]), P0)
167 plot = Plot(num_plots)
169 'Position along X-axis',
'Velocity along X-axis',
170 'Position along Y-axis',
'Velocity along Y-axis'
173 'Position (m)',
'Velocity (m/s)',
174 'Position (m)',
'Velocity (m/s)'
176 plot_legends = [
'GT',
'Measure',
'Filtered']
179 for plot_index
in range(num_plots):
180 plot.initGraph(plot_index, len(plot_legends))
181 plot.setTitle(plot_index, plot_titles[plot_index])
182 plot.setUnitY(plot_index, plot_y_units[plot_index])
183 plot.setUnitX(plot_index,
'Time (s)')
184 for legend_index
in range(len(plot_legends)):
185 plot.setLegend(plot_index, legend_index, plot_legends[legend_index])
187 gt_X = ColVector(2, 0.)
188 z_prec = ColVector(2, 0.)
193 x_meas = gt_X[0] + np.random.normal(0.0, sigma_x_meas)
194 y_meas = gt_X[1] + np.random.normal(0.0, sigma_y_meas)
195 z = ColVector([x_meas, y_meas])
204 vX_meas = (x_meas - z_prec[0]) / dt
205 vY_meas = (y_meas - z_prec[1]) / dt
209 plot.plot(0, 0, i, gt_X[0])
210 plot.plot(0, 1, i, x_meas)
211 plot.plot(0, 2, i, Xest[0])
213 plot.plot(1, 0, i, gt_vx)
214 plot.plot(1, 1, i, vX_meas)
215 plot.plot(1, 2, i, Xest[1])
217 plot.plot(2, 0, i, gt_X[1])
218 plot.plot(2, 1, i, y_meas)
219 plot.plot(2, 2, i, Xest[2])
221 plot.plot(3, 0, i, gt_vy)
222 plot.plot(3, 1, i, vY_meas)
223 plot.plot(3, 2, i, Xest[3])
232 input(
'Press enter to quit')
ColVector add_state_vectors(a, b)
Matrix generate_Q_matrix(float dt)
ColVector fx(ColVector x, float dt)
ColVector hx(ColVector x)
ColVector residual_state_vectors(a, b)