python optimized implementation of two sensor Kalman filter

Posted by squariegoes on Sun, 02 Jan 2022 10:15:53 +0100

Two sensor filtering

A car moves in a variable speed straight line with a GPS locator and a speedometer. The data from the two sensors are optimally estimated by Kalman filter. Suppose the observed data is a vector z = [z1 z2] T. z1 is the GPS positioning position and z2 is the speed reading of the speedometer. The covariance matrix R~N(0,R) of Z. The noise of vehicle state equation is wk~N(0,Q). System state matrix A=[1], the predicted value is the previous position, the optimal estimation is the predicted value, plus the difference between the measured value and the predicted value multiplied by the proportion. The calculation formula of Kalman filter is as follows


Optimization: calculate Kk in advance

The key to calculate k is the distribution proportion of the measurement difference. k can be calculated through formula (1.11) (1.10) (1.13), and k is only related to the system noise mode Q
It is related to the measurement error covariance matrix R. Therefore, it can be iterated several times in advance to calculate k, but the location estimation can be calculated for a large number of data. Only equations (1.9) and (1.12) need to be calculated. k has been calculated in advance. The five steps of Kalman are simplified to two steps, which greatly reduces the amount of matrix calculation.

Python implementation

If the true equation of vehicle linear position is 100 *(1 - np.exp(-t/10)), the variance of sensor z1 is 2 and the variance of speedometer z2 is 0.2,
R=[[2 0], system noise variance Q=[1]. System state A=[1], observation matrix H = [1] T
[0 0.2]]

Function pre_kalman, the Kalman filter parameter K can be calculated in advance through the parameter A H Q R_ K. It converges after several iterations.
The function obv() generates the real position of the vehicle according to equation 100 *(1 - np.exp(-t/10)), then adds Gaussian distribution noise respectively, and returns to the sensor for observation
Data z. z0 is GPS position data and z1 is speed. You need to integrate z1 to get the position. Then according to z and k_k for Kalman filter estimation.

Generally, the variance of GPS disturbed position is large and the variance of speedometer is small, but the cumulative error after integration is large. From the figure, the estimated value of Kalman filter fits the real value very well. As shown in the figure

Attached procedure

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties

# Preset font
font = {'family': 'SimHei', "size": 14}
matplotlib.rc('font', **font)

'''
Kalman filter, 2-way observation
'''

'''
real
x_k = A*xk_1 + w_k  w_k variance Q
 observation
z_k = H*x_k + v_k   v_k variance R

forecast
x_k_predict = A*x_k_est
p_k_predict = A * p_k_est * A_T + Q
k_k = p_k_predict * H_T *( H*p_k_predict*H_T + R)^-1

Optimal estimation
x_k_est = x_k_predict + k_k *( z_k - H*x_k_predict)
p_k_est = (I - k_k * H) * p_k_predict 
'''

# System status A
A = np.mat([1])

# Observation matrix of two observation instruments
H = np.mat([[1], [1]])

#Observe the instrument variance sigma1 sigma2
sigma1 = 2
sigma2 = 0.2

#System noise wk variance Q
Q = np.mat(1)

'''from Q R count kk'''
def pre_kalman(A,H):
    R=np.mat([[sigma1, 0],[0, sigma2]])
    I=np.mat([1])
    p_est = np.mat([0]) #Estimated covariance matrix
    for _ in np.arange(0,10,1):
        p_predict = A * p_est * A.T + Q #Prediction covariance matrix
        kk = p_predict * H.T * (H * p_predict * H.T + R).I
        p_est = (I - kk * H) * p_predict
    return kk #Return k_k

'''
Two measuring instruments measure two sets of signals,z0 Is the position measurement, z1 Is the speed measurement
z0 The variance of is sigma1,z1 Variance is sigma2
 The true signal is 1-exp(t/10)
'''
def obv():
    t = np.linspace(1,100,100)
    real = 100 *(1 -  np.exp(-t/10))
    #real = t**2

    #Find the speed xdot
    dt = t[1:] - t[:-1]
    dx = real[1:] - real[:-1]
    xdot = dx / dt
    #Fill the 0-th alignment
    xdot = np.hstack([real[0],xdot])

    #Real signal, real noise, error noise of analog measuring instrument
    t = t[:-1]
    real=real[:-1]
    xdot=xdot[:-1]
    z1= real + np.random.normal(0,sigma1,size=t.shape[0])
    z2= xdot + np.random.normal(0,sigma2,size=t.shape[0])
    z = np.mat([(a,b) for (a,b) in zip(z1,z2)])
    return [t, dt, real,z]


'''
Computational Kalman
z Is the observed data
kk Is the Carl slow scale coefficient
'''
def calc_kalman(A,H,z_k,kk):
    global  x_est
    x_pred = A * x_est
    x_est = x_pred + kk * (z_k - H * x_pred)
    return x_est


global x_est #Best estimate
if __name__ == '__main__':

    #Calculate k value
    kk = pre_kalman(A,H)

    #Generate the observation instrument information Z, return time, true value and noisy value of two observation instruments
    [t, dt, xreal, z] = obv()

    x_est=np.mat([0])
    x_est_list=[]

    z1_integral=0
    for k in range(z.shape[0]):
        #Integrate the velocity
        z1_integral += z[k][0,1] * dt[k]
        z[k][0,1] = z1_integral

        #Calculate the Kalman, and the result is in x_est
        calc_kalman(A, H, z[k].T, kk)
        x_est_list.append(x_est[0,0])

    x_est_list=np.array(x_est_list)


    plt.title('Kalman filtering ')
    plt.plot(t, xreal, label='real',color='g')
    plt.plot(t, z[:,0], label='Position measurement',color='b')
    plt.plot(t, z[:,1], label='Velocity integral',color='y')
    plt.plot(t, x_est_list, label='estimate',color='r')
    plt.legend(loc="lower right")
    plt.show()


Topics: Python Sensor