In [3]:
%pylab inline
import sympy as sp
sp.init_printing()
In [321]:
dt = sp.Symbol('dt')
psi_k1_k1 = sp.Symbol('\psi_{k-1 | k-1}') # roll prior
psi_k_k1 = sp.Symbol('\psi_{k | k-1}') # roll predicted
psi_k_k = sp.Symbol('\psi_{k | k }') # roll post
d_psi = sp.Symbol('\dot{\psi}_{k-1}') # roll rate
psi_m = sp.Symbol('\psi_m') # mesured roll
In [387]:
x_k1_k1 = sp.Matrix([ psi_k1_k1 ]) # prior
x_k_k1 = sp.Matrix([ psi_k_k1 ]) # predicted
x_k_k = sp.Matrix([ psi_k_k ]) # post
x_k_k
Out[387]:
In [388]:
sigma = sp.Symbol('\sigma_{m}')
# Measurement noise covariance
R = sigma * sp.eye(1)
R
Out[388]:
In [389]:
z_k = sp.Matrix([ psi_m ])
z_k
Out[389]:
In [390]:
u_k1 = sp.Matrix([ d_psi ])
u_k1
Out[390]:
In [392]:
P_k1_k1 = sp.Matrix([ sp.Symbol('p_{k-1 | k-1}') ])
P_k_k1 = sp.Matrix([ sp.Symbol('p_{k | k-1}') ])
P_k_k = sp.Matrix([ sp.Symbol('p_{k | k}') ])
P_k_k
Out[392]:
In [393]:
Q = sp.Matrix([ sp.Symbol('q') ])
Q
Out[393]:
In [394]:
def f(x, u, dt):
return x + dt*u
x_k_k1 = f( x_k1_k1, u_k1, dt )
x_k_k1
Out[394]:
In [323]:
F = f( x_k1_k1, u_k1, dt ).jacobian( x_k1_k1 )
F
Out[323]:
In [324]:
P_k_k1 = F * P_k1_k1 * F.T + Q
P_k_k1
Out[324]:
In [338]:
def h(x):
return x
h(x_k_k1)
Out[338]:
In [339]:
H = h(x_k_k1).jacobian(x_k1_k1)
H
Out[339]:
In [328]:
y = z_k - h(x_k_k1)
y
Out[328]:
In [329]:
S = H * P_k_k1 * H.T + R
S
Out[329]:
In [330]:
K = P_k_k1 * H.T * S**(-1)
K
Out[330]:
In [352]:
P_k_k = (sp.eye(1) - K * H) * P_k_k1
P_k_k[0].simplify()
Out[352]:
In [386]:
x_k_k = x_k_k1 + K * y
x_k_k[0]
Out[386]:
In [384]:
# by reordering the terms, we see that the 1D kalman is equivalent to the complementary filter
x_k_k[0].expand().factor([psi_m, sigma])
Out[384]:
In [ ]: