Linear filtering and nonlinear filtering experiments.

This is an automatically translated post by LLM. The original post is in Chinese. If you find any translation errors, please leave a comment to help me improve the translation. Thanks!

This article presents experiments on linear filtering and nonlinear filtering for estimating the free fall motion. The following figure is from Professor Cai Yuanli's course "Random Filtering and Control" at Xi'an Jiaotong University. The course mainly discusses various filtering methods related to estimation, smoothing, and prediction.

Map of Control Theory

Problem Description

  1. A object is in free fall motion, and its height has been measured 20 times. The measurement values are shown in the following table:

    image-20220617114332337
  2. Consider the same object in free fall motion, and use a radar (in the same horizontal plane as the object) for measurement. The measurement noise of radar range and angle is a Gaussian white noise sequence with a mean of 0 and a variance matrix \(R=\begin{bmatrix}0.04 &0\\0&0.01\end{bmatrix}\). Based on the following measurement data, determine the estimated values of the object's height and downward velocity over time:

    image-202206171202388
    image-202206171212236

    The descent motion and radar detection information are shown in the following figure:

    image-202206171212177

Model Introduction

1. Linear Estimation Problem

Assume that during free fall motion, the object's height is \(h\) and velocity is \(v\) (downward is positive). Let \(x_1=h\) and \(x_2=v\), then the system's state equation is:

\[ \begin{bmatrix} \dot x_1\\\dot x_2 \end{bmatrix}= \begin{bmatrix} 0&-1\\ 0&0\\ \end{bmatrix} \begin{bmatrix} x_1\\x_2 \end{bmatrix}+ \begin{bmatrix} 0\\1 \end{bmatrix}g\ \ (g=9.80m/s^2) \]

The state transfer function of the system can be solved from the above state equation:

\[ x(t)=\begin{bmatrix} 1&-t\\ 0&1 \end{bmatrix}x(0) +\begin{bmatrix} -t\\1 \end{bmatrix}u(t) \]

When the time step is 1s, the state transfer function of the system is:

\[ \Phi_{k+1,k}=\begin{bmatrix} 1&-1\\ 0&1 \end{bmatrix} \ \Psi_{k+1,k}=\begin{bmatrix} -1\\ 1 \end{bmatrix} \]

Therefore, the one-step prediction of the system is:

\[ x_{k+1,k}=\Phi_{k+1,k}x_{k|k}+\Psi_{k+1,k}u_k \]

Since the observation is a direct measurement of the object's height, and assuming the measurement error is a white noise with a mean of 0 and a variance of 1, the measurement equation is:

\[ y_k=H_kx_k+v_k \]

where:

\[ H_k\equiv \begin{bmatrix} 1\\0 \end{bmatrix}, \ v_k \sim N(0,1), \ R=1 \]

In this problem, the measurement height unit is \(km\), and the acceleration is \(9.8m/s^2\). For ease of calculation, the distance unit is unified to \(km\), and the time unit is unified to \(s\), so the gravity acceleration \(g=0.0098km/s\). Since the initial value of the filter is not given, the initial height is estimated as \(2km\) based on the measurement data, and the initial velocity is 0, i.e., \(x_{0|0}=\begin{bmatrix}2&0\end{bmatrix}\). Since the initial estimate value determined in this way is relatively rough, the variance is large. Therefore, the initial variance matrix of the system is set to \(P_{0|0}=\begin{bmatrix}10&0\\0&10\end{bmatrix}\).

Establish the Kalman filter equations: \[ x_{k+1,k}=\Phi_{k+1,k}x_{k|k}+\Psi_{k+1,k}u_k\\ P_{k+1|k}=\Phi_{k+1,k}P_{k|k}\Phi^\top_{k+1,k}\\ P_{k+1|k+1}=[P_{k+1|k}^{-1}+H_{k+1}^{\top} R_{k+1}^{-1}H_{k+1}]^{-1}\\ K_{k+1}=P_{k+1|k+1}H_{k+1}^\top R_{k+1}^{-1}\\ \hat x_{k+1|k+1}=\hat x_{k+1|k}+K_{k+1}(y_{k+1}-H_{k+1}\hat x_{k+1|k}) \] Calculate the descent height and velocity of the object, and the calculation results are shown in the experimental results section below.

2. Nonlinear Estimation Problem

In the second problem, the measurement and estimation values are nonlinearly related. Consider using the Extended Kalman Filter (EKF) algorithm to estimate it. In this report, the Extended Kalman Filter algorithm is used.

Let the measured slant range be \(l(km)\), the elevation angle be \(\theta(rad)\), the height of the object be \(h(km)\), and the downward velocity be \(v(km/s)\) (downward is positive). The vertical projection of the object on the ground to the radar is \(d_0\).

For ease of subsequent linearization calculations, the system state variables are selected as: \[ x_1=h,\ x_2=v,\ x_3=d_0 \] Then the system's state equation is: \[ \dot x= \begin{bmatrix} 0&-1&0\\ 0&0&0\\ 0&0&0 \end{bmatrix}x+ \begin{bmatrix} 0\\ 1\\ 0 \end{bmatrix}g,\ where\ g=0.0098\ km/s \] Solving the equation, when the time interval is \(0.5s\), the discrete state transfer function of the system is: \[ \Phi_{k+1,k}=\begin{bmatrix} 1&-0.5&0\\ 0&1&0\\ 0&0&1 \end{bmatrix},\ \Psi_{k+1,k}=\begin{bmatrix} -0.125\\ 0.5\\ 0 \end{bmatrix} \] The observation of the system is the slant range and elevation angle measured by the radar, then: \[ y_1=l=\sqrt{h^2+d_0^2}=\sqrt{x_1^2+x_3^2}\\ y_2=\theta=\arctan(\frac{h}{d_0})=\arctan(\frac{x_1}{x_3}) \] Taking the derivative of the observation with respect to the state variables, we have: \[ \frac{\partial y_1}{\partial x_1}=\frac{x_1}{\sqrt{x_1^2+x_3^2}}\\ \frac{\partial y_1}{\partial x_2}=0\\ \frac{\partial y_1}{\partial x_3}=\frac{x_3}{\sqrt{x_1^2+x_3^2}}\\ \frac{\partial y_2}{\partial x_1}=\frac{x_3}{x_1^2+x_3^2}\\ \frac{\partial y_2}{\partial x_2}=0\\ \frac{\partial y_2}{\partial x_3}=-\frac{x_1}{x_1^2+x_3^2}\\ \] Therefore, the local linearization coefficients of the system are: \[ H=\begin{bmatrix} \frac{x_1}{\sqrt{x_1^2+x_3^2}}&0&\frac{x_3}{\sqrt{x_1^2+x_3^2}}\\ \frac{x_3}{x_1^2+x_3^2}&0&-\frac{x_1}{x_1^2+x_3^2} \end{bmatrix} \] The calculation process of the Extended Kalman Filter (EKF) is as follows: \[ x_{k+1,k}=\Phi_{k+1,k}x_{k|k}+\Psi_{k+1,k}u_k\\ P_{k+1|k}=\Phi_{k+1,k}P_{k|k}\Phi^\top_{k+1,k}\\ P_{k+1|k+1}=[P_{k+1|k}^{-1}+H_{k+1}^{\top} R_{k+1}^{-1}H_{k+1}]^{-1}\\ K_{k+1}=P_{k+1|k+1}H_{k+1}^\top R_{k+1}^{-1}\\ \hat x_{k+1|k+1}=\hat x_{k+1|k}+K_{k+1}(y_{k+1}-H_{k+1}\hat x_{k+1|k}) \] The difference between the Extended Kalman Filter and the Kalman Filter is that the coefficient matrix \(H\) is obtained by local linearization at the observation point. With the above steps, the nonlinear observation can be filtered and estimated.

Experimental Results

1. Linear Filtering Problem

Based on the given height observation data, linear Kalman filtering is performed, and the calculated results are as follows:

The estimated height data is:

Time 1 2 3 4 5 6 7
Height 1.9943 1.9791 1.9550 1.9211 1.8774 1.8244 1.7605
Time 8 9 10 11 12 13 14
Height 1.6870 1.6038 1.5103 1.4075 1.2947 1.1723 1.0400
Time 15 16 17 18 19 20
Height 0.8980 0.7460 0.5845 0.4129 0.2317 0.0405

The height change graph is shown below:

The filtered data of the downward velocity (positive downward) is as follows:

  Time | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
:: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
Velocity | 0.0078 | 0.0157 | 0.0247 | 0.0343 | 0.0439 | 0.0536 | 0.0635 |
  Time | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
:: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
Velocity | 0.0733 | 0.0831 | 0.0930 | 0.1028 | 0.1126 | 0.1224 | 0.1322 |
  Time | 15 | 16 | 17 | 18 | 19 | 20 | |
:: | :-: | :-: | :-: | :-: | :-: | :-: | :--: |
Velocity | 0.1420 | 0.1519 | 0.1616 | 0.1714 | 0.1812 | 0.1911 | |

The velocity change graph is shown below:

At the same time, the estimated variance of the height and velocity over time is:

Estimated Variance of Height
Estimated Variance of Velocity

From the above figures, it can be seen that the Kalman filter quickly reduces the estimation of the object's descent height and velocity as soon as the new information is added, and then gradually decreases to near 0 without further significant reduction. The height change curve of the object's free fall is a parabola, and the velocity changes uniformly, which conforms to the relevant physical laws of free fall.

2. Nonlinear Filtering Problem

Based on the given measurement data and the nonlinear filtering model mentioned above, the filtered height and velocity of the falling object are as follows.

The height change is:

The velocity change is:

The estimation error of the object's free fall height and velocity is:

Estimated Variance of Height
Estimated Variance of Velocity

From the above estimated results, it can be seen that the descent height decreases parabolically with time, and the descent velocity (downward is positive) increases uniformly with time, which conforms to the physical laws of free fall.

Some Findings During the Experiment

In the initial programming and experimental process, since the measurement data given in the problem is in units of \(km\), for ease of calculation, the distance unit is converted to \(km\). However, since the problem does not specify the unit of the measurement variance, the value is not converted and is treated as \(km\).

No anomalies were found during the solution of problem 1. However, when solving problem 2, if the measurement covariance is not converted, and the unit is treated as \(km\), the estimated results will be as shown in the following figure:

Height Change
Velocity Change

Comparing the calculated results in the above figure with the calculated results in the experimental results of problem 2, it can be seen that the nonlinear Kalman filter is more affected by the measurement error if the measurement covariance is large. This is because the coefficient matrix \(H\) in the nonlinear filter is obtained by local linearization, and if the measurement error itself is large, it will affect the calculation results of the Kalman coefficients, resulting in inaccurate estimation results.

Appendix

Constant Configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
'''
@ Author: Yu Zhao
@ Contact: yuzhaokz@163.com
@ Date: 2022-06-10 16:59:11
@ LastEditors: Yu Zhao
@ LastEditTime: 2022-06-17 21:02:09
@ Description: 知识因被记录而产生价值
@ Website: https://kezhi.tech
'''

import numpy as np

cache_dir="cache/"

# observation

observation_1=[
[1.9945],
[1.9794],
[1.9554],
[1.9214],
[1.8777],
[1.8250],
[1.7598],
[1.6867],
[1.6036],
[1.5092],
[1.4076],
[1.2944],
[1.1724],
[1.0399],
[0.8980],
[0.7455],
[0.5850],
[0.4125],
[0.2318],
[0.0399],
]

observation_2=[
[2.82741643781891,0.00075850435876],
[2.82519811729771,0.00083282260478],
[2.82066686966236,0.00067808241639],
[2.81487233105901,0.00085279036802],
[2.80671786536244,0.00072900768452],
[2.79725268974089,0.00080072481819],
[2.78664273475039,0.00075095576213],
[2.77320365026313,0.00065762725379],
[2.75919535464551,0.00081186148545],
[2.74331288628195,0.00079783727034],
[2.72538888482812,0.00073060712986],
[2.70664967712312,0.00063242006530],
[2.68632403406473,0.00063656524495],
[2.66386533852220,0.00080659845639],
[2.64093529707333,0.00067704740069],
[2.61621111727357,0.00076573767706],
[2.59038109850785,0.00054955759081],
[2.56298794272843,0.00058487913971],
[2.53498317950797,0.00055602747368],
[2.50647589372246,0.00033550412588],
[2.47571075016386,0.00056012688452],
[2.44560676000982,0.00056694491978],
[2.41403690772088,0.00059380631025],
[2.38252228611696,0.00053681916544],
[2.35016501182332,0.00065871960781],
[2.31790939837137,0.00068598344328],
[2.28597616656453,0.00060922471348],
[2.25418431681401,0.00057086018918],
[2.22259320219535,0.00041308535708],
[2.19237398969466,0.00047302026281],
[2.16290177997271,0.00030949309972],
[2.13441725793706,0.00040552624986],
[2.10811064690727,0.00037545033142],
[2.08322179823195,0.00017282319262],
[2.06148109026767,0.00020758327980],
[2.04219885094031,0.00037186464579],
[2.02610235314357,0.00018082163465],
[2.01290326863579,0.00023323830160],
[2.00463157388395,-0.00004536186964],
[2.00058143251913,0.00003246284068],
]

# dimension transform
observation_2=[[observation[0],observation[1]*1000] for observation in observation_2]


# the parameters of problem 1
param_1={

"Phi":np.matrix(
[
[1,-1],
[0, 1]
]
),

"Psi":np.matrix(
[
[-1],
[1],
]
),

"H":np.matrix(
[
[1,0],
]
),

"R":np.matrix(
[1/1000]
),
}

# the parameters of problem 2
param_2={

"Phi":np.matrix(
[
[1,-0.5,0],
[0,1,0],
[0,0,1],
]
),

"Psi":np.matrix(
[
[-0.125],
[0.5],
[0],
]
),

"R":np.matrix(
[
[0.04/1000,0],
[0,0.01],
]
)
}

Problem 1 Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
'''
@ Author: Yu Zhao
@ Contact: yuzhaokz@163.com
@ Date: 2022-06-10 14:44:08
@ LastEditors: Yu Zhao
@ LastEditTime: 2022-06-17 12:45:17
@ Description: 知识因被记录而产生价值
@ Website: https://kezhi.tech
'''

import os
from pprint import pprint
from matplotlib import pyplot as plt
import numpy as np

from config import cache_dir,observation_1,param_1

# Enable Chinese characters
plt.rcParams['font.sans-serif'] = ['SimHei'] # Used to display Chinese labels normally
plt.rcParams['axes.unicode_minus'] = False # Used to display negative signs normally

# Create the cache folder
if not os.path.exists(cache_dir):
os.mkdir(cache_dir)


# Kalman filter
def Kalman_filter(x_0:np.matrix, # the status of last step
P_0:np.matrix, # the variance of last step
y_1:np.matrix, # the observation of this step
u_0:np.matrix=None, # the input of system
Phi:np.matrix=None, # the status transform matrix
Psi:np.matrix=None, # coefficient of system input
Gamma:np.matrix=None, # coefficient of observing noise
H:np.matrix=None, # y=Hx+v
R:np.matrix=None, # the variance of observing noise
Q:np.matrix=None, # the variance of status noise
):
# Check variables
if u_0 is None:
u_0=np.matrix(0)
print("u_0 is missing, use the default value: {}".format(u_0))

if Phi is None:
Phi=np.matrix(np.eye(x_0.shape[0]))
print("Phi is missing, use the default value: {}".format(Phi))

if Psi is None:
Psi=np.matrix(np.zeros((x_0.shape[0],1)))
print("Psi is missing, use the default value: {}".format(Psi))

if Gamma is None:
Gamma=Psi.copy()
print("Gamma is missing, use the default value: {}".format(Gamma))

if H is None:
H=np.matrix(np.ones((y_1.shape[0],x_0.shape[0])))
print("H is missing, use the default value: {}".format(H))

if R is None:
R=np.matrix(np.zeros((y_1.shape[0],1)))
print("R is missing, use the default value: {}".format(R))

if Q is None:
Q=np.matrix(0)
print("Q is missing, use the default value: {}".format(Q))

# One-step prediction
x_10=Phi@x_0+Psi@u_0
P_10=Phi@P_0@Phi.T+Gamma@Q@Gamma.T
# Time update
P_11=(P_10.I+H.T@R.I@H).I
K_1=P_11@H.T@R.I
x_11=x_10+K_1@(y_1-H@x_10)
return x_11,P_11,K_1


def show_result(record:dict,problem):
pprint(record)
for key,value in record.items():
plt.title(key)
plt.xlabel("step")
if key=="h":
plt.ylabel("Height: km")
if key=="v":
plt.ylabel("Velocity: km/s (downward is positive)")
plt.plot(value)
plt.savefig(os.path.join(cache_dir,problem+"_"+key+".png?x-oss-process=style/webp"),dpi=600)
plt.clf()
plt.cla()


if __name__=="__main__":

# Solve problem 1
x_0=np.matrix([[2],[0]])
P_0=np.matrix([[10,0],[0,10]])
x_record=[x_0]
P_record=[P_0]
K_record=[None]
for obs in observation_1:
y_1=np.matrix(obs).T
x_1,P_1,K_1=Kalman_filter(
x_0,
P_0,
y_1,
u_0=np.matrix(9.8/1000),
Phi=np.matrix(param_1["Phi"]),
Psi=np.matrix(param_1["Psi"]),
H=np.matrix(param_1["H"]),
R=np.matrix(param_1["R"]),
)

x_record.append(x_1)
P_record.append(P_1)
K_record.append(K_1)

x_0=x_1
P_0=P_1

result_record={
"h":[x[0,0] for x in x_record],
"v":[x[1,0] for x in x_record],
"P_0":[P[0,0] for P in P_record],
"P_1":[P[1,1] for P in P_record],
# "K":K_record,
}
show_result(result_record,problem="p1")

Problem 2 Code

```python ''' @ Author: Yu Zhao @ Contact: yuzhaokz@163.com @ Date: 2022-06-17 16:54:31 @ LastEditors: Yu Zhao @ LastEditTime: 2022-06-17 21:02:28 @ Description: 知识因被记录而产生价值 @ Website: https://kezhi.tech '''

import os from pprint import pprint from matplotlib import pyplot as plt import numpy as np

from config import cache_dir,observation_2,param_2

Enable Chinese characters

plt.rcParams['font.sans-serif'] = ['SimHei'] # Used to display Chinese labels normally plt.rcParams['axes.unicode_minus'] = False # Used to display negative signs normally

Create the cache folder

if not os.path.exists(cache_dir): os.mkdir(cache_dir)

Compute H in EKF

def get_H(x): l_2=x[0,0]2+x[2,0]2 return np.matrix( [ [x[0,0]/np.sqrt(l_2),0,x[2,0]/np.sqrt(l_2)], [x[2,0]/l_2,0,-x[0,0]/l_2], ] )

Function of observation

def y(x): return np.matrix( [ [np.sqrt(x[0,0]2+x[2,0]2)], [np.arctan(x[0,0]/x[2,0])], ] )

Kalman filter

def EKF(x_0:np.matrix, # the status of last step P_0:np.matrix, # the variance of last step y_1:np.matrix, # the observation of this step u_0:np.matrix=None, # the input of system Phi:np.matrix=None, # the status transform matrix Psi:np.matrix=None, # coefficient of system input Gamma:np.matrix=None, # coefficient of observing noise R:np.matrix=None, # the variance of observing noise Q:np.matrix=None, # the variance of status noise ): # Check variables if u_0 is None: u_0=np.matrix(0) print("u_0 is missing, use the default value: {}".format(u_0))

if Phi is None:
    Phi=np.matrix(np.eye(x_0.shape[0]))
    print("Phi is missing, use the default value: {}".format(Phi))

if Psi is None:
    Psi=np.matrix(np.zeros((x_0.shape[0],1)))
    print("Psi is missing, use the default value: {}".format(Psi))

if Gamma is None:
    Gamma=np.matrix(np.zeros((x_0.shape[0],1)))
    print("Gamma is missing, use the default value: {}".format(Gamma))
    
if R is None:
    R=np.matrix(np.zeros((y_1.shape[0],1)))
    print("R is missing, use the default value: {}".format(R))
    
if Q is None:
    Q=np.matrix(0)
    print("Q is missing, use the default value: {}".format(Q))
    
# One-step prediction
x_10=Phi@x_0+Psi@u_0
P_10=Phi@P_0@Phi.T+Gamma@Q@Gamma.T
# Local linearization
H=get_H(x_10)
# Time update
P_11=(P_10.I+H.T@R.I@H).I
K_1=P_11@H.T@R.I
x_11=x_10+K_1@(y_1-y(x_10))
return x_11,P_11,K_1

def mse(x_1:np.matrix,x_2:np.matrix): loss=0 for i in range(x_1.shape[0]): for j in range(x_1.shape[1]): loss+=(x_1[i,j]-x_2[i,j])**2 loss=loss/(x_1.shape[0]*x_1.shape[0]) return loss

Iteration EKF, which may have a worse result TAT

def EKF_iter( x_0:np.matrix, # the status of last step P_0:np.matrix, # the variance of last step y_1:np.matrix, # the observation of this step u_0:np.matrix=None, # the input of system Phi:np.matrix=None, # the status transform matrix Psi:np.matrix=None,