Udacity-CarND UKF 学习笔记

Udacity 自动驾驶工程师纳米学位 第二学期 无迹卡尔曼(UKF)学习笔记

项目代码GitHub链接

CTRV

UKF 可采用匀速圆周运动模型,CTRV(Constant Turning Rate and Velocity model)

状态方程或过程模型(Process Model)

状态向量(state vector)选取
$$ x = (p_x, p_y, v, \psi, \dot {\psi}) $$

状态方程或过程模型(process model)如何得到,一个比较通用(general)的方法就是求解状态在两帧之间的变化量(Change Rate of State),其实就是状态量关于时间的微分。

$$
\dot x = (\dot p_x, \dot p_y, \dot v, \dot \psi, \ddot {\psi})
$$
$$
=(v\cdot cos\psi, v\cdot sin\psi, 0, \dot \psi, 0)
$$

Process Model:
PM

当yaw rate是0的时候,也就是直线运动时,因为状态转移方程中,前两项含有$\frac{v}{\dot \psi}$上述方程会发生奇异,所以当yaw rate为0时,转移矩阵要略作修改为:
$$
x_{k+1} = x_k + (v_k\cdot cos\psi_k\cdot \Delta t, v_k\cdot sin\psi_k \cdot \Delta t, 0, 0, 0)^T
$$

上述是过程模型确定部分(deterministic part),还要再加上随机部分(stochastic part),由于纵向加速度和角速度会因为各种情况随机地发生,根据中心极限定理,叠加的加速度会成高斯分布,所以可以将这两部分加速度处理成噪声加入到过程模型中。

Noise

Noise

假设在连续两帧之间,线加速度和角加速度都为常数,并且位置噪声噪声做一阶近似,那么可以得到上述

$$
a = 1/2\nu_{a,k} \cdot cos\psi_k \cdot \Delta t^2
$$

$$
b = 1/2\nu_{a,k} \cdot sin\psi_k \cdot \Delta t^2
$$

$$
c = \nu_{a,k} \cdot \Delta t
$$

$$
d = 1/2\nu_{\ddot \psi,k} \cdot \Delta t^2
$$

$$
e = \nu_{\ddot \psi, k} \cdot \Delta t
$$

Pipeline

pipeline

预测(Prediction)

生成Sigma 点

UKF也是为解决非线性模型诞生的(这个非线性有可能是状态转换的非线性也有可能是测量的非线性),但不同于EKF求解Jacob矩阵或是Hessian矩阵将非线性函数线性化(相当于将整个分布通过线性化的转移函数映射到了预测空间);相反,UKF选择的是将原状态空间里的某些具有代表性的点(这个代表性指的是这些点能代表整个分布的特点),即所谓Sigma点,通过非线性转移函数映射到预测空间,在预测空间中再去计算这个Sigma点的均值方差,用另一个高斯分布来近似数据在预测空间的分布。

generate sigma

generate sigma

Sigma点数量与当前状态向量维度($n_x$)有关:

$$
n_\sigma = 2n_x + 1
$$

sigma 点计算公式:

sigma formula

第一个sigma点就是均值点,$\sqrt {P_{k|k}}$是$n_x$个sigma点的方向,$\lambda$可以用来设置这些sigma点距离均值点的远近。

下面这张图假设状态量只有位置(x,y):

sigma example

代码GenerateSigmaPoints()

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
void UKF::GenerateSigmaPoints(MatrixXd* Xsig_out) {
//set state dimension
int n_x = 5;
//define spreading parameter
double lambda = 3 - n_x;
//set example state
VectorXd x = VectorXd(n_x);
x << 5.7441,
1.3800,
2.2049,
0.5015,
0.3528;
//set example covariance matrix
MatrixXd P = MatrixXd(n_x, n_x);
P << 0.0043, -0.0013, 0.0030, -0.0022, -0.0020,
-0.0013, 0.0077, 0.0011, 0.0071, 0.0060,
0.0030, 0.0011, 0.0054, 0.0007, 0.0008,
-0.0022, 0.0071, 0.0007, 0.0098, 0.0100,
-0.0020, 0.0060, 0.0008, 0.0100, 0.0123;
//create sigma point matrix
MatrixXd Xsig = MatrixXd(n_x, 2 * n_x + 1);
//calculate square root of P
MatrixXd A = P.llt().matrixL();
/*******************************************************************************
* Student part begin
******************************************************************************/
//set first column of sigma point matrix
Xsig.col(0) = x;
//set remaining sigma points
for (int i = 0; i < n_x; i++)
{
Xsig.col(i+1) = x + sqrt(lambda+n_x) * A.col(i);
Xsig.col(i+1+n_x) = x - sqrt(lambda+n_x) * A.col(i);
}
/*******************************************************************************
* Student part end
******************************************************************************/
//print result
//std::cout << "Xsig = " << std::endl << Xsig << std::endl;
//write result
*Xsig_out = Xsig;
/* expected result:
Xsig =
5.7441 5.85768 5.7441 5.7441 5.7441 5.7441 5.63052 5.7441 5.7441 5.7441 5.7441
1.38 1.34566 1.52806 1.38 1.38 1.38 1.41434 1.23194 1.38 1.38 1.38
2.2049 2.28414 2.24557 2.29582 2.2049 2.2049 2.12566 2.16423 2.11398 2.2049 2.2049
0.5015 0.44339 0.631886 0.516923 0.595227 0.5015 0.55961 0.371114 0.486077 0.407773 0.5015
0.3528 0.299973 0.462123 0.376339 0.48417 0.418721 0.405627 0.243477 0.329261 0.22143 0.286879
*/
}

预测sigma点

接下来需要将sigma点通过非线性方程(如下)映射到预测空间的sigma点。

process formula

但是在这个过程中需要用到噪声$\nua$和$\nu{\ddot \psi}$。在UKF中对噪声的非线性处理非常简单,将其也加入到sigma点生成中,得到增广sigma点矩阵。

augmented sigma

这样子便可以将增广sigma矩阵中的每个sigma点代入到非线性过程函数$f(x_k, \nu_k)$中得到预测的状态量。

代码AugmentedSigmaPoints()SigmaPointPrediction() :

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
void UKF::AugmentedSigmaPoints(MatrixXd* Xsig_out) {
//set state dimension
int n_x = 5;
//set augmented dimension
int n_aug = 7;
//Process noise standard deviation longitudinal acceleration in m/s^2
double std_a = 0.2;
//Process noise standard deviation yaw acceleration in rad/s^2
double std_yawdd = 0.2;
//define spreading parameter
double lambda = 3 - n_aug;
//set example state
VectorXd x = VectorXd(n_x);
x << 5.7441,
1.3800,
2.2049,
0.5015,
0.3528;
//create example covariance matrix
MatrixXd P = MatrixXd(n_x, n_x);
P << 0.0043, -0.0013, 0.0030, -0.0022, -0.0020,
-0.0013, 0.0077, 0.0011, 0.0071, 0.0060,
0.0030, 0.0011, 0.0054, 0.0007, 0.0008,
-0.0022, 0.0071, 0.0007, 0.0098, 0.0100,
-0.0020, 0.0060, 0.0008, 0.0100, 0.0123;
//create augmented mean vector
VectorXd x_aug = VectorXd(7);
//create augmented state covariance
MatrixXd P_aug = MatrixXd(7, 7);
//create sigma point matrix
MatrixXd Xsig_aug = MatrixXd(n_aug, 2 * n_aug + 1);
/*******************************************************************************
* Student part begin
******************************************************************************/
//create augmented mean state
x_aug.head(5) = x;
x_aug(5) = 0;
x_aug(6) = 0;
//create augmented covariance matrix
P_aug.fill(0.0);
P_aug.topLeftCorner(5,5) = P;
P_aug(5,5) = std_a*std_a;
P_aug(6,6) = std_yawdd*std_yawdd;
//create square root matrix
MatrixXd L = P_aug.llt().matrixL();
//create augmented sigma points
Xsig_aug.col(0) = x_aug;
for (int i = 0; i< n_aug; i++)
{
Xsig_aug.col(i+1) = x_aug + sqrt(lambda+n_aug) * L.col(i);
Xsig_aug.col(i+1+n_aug) = x_aug - sqrt(lambda+n_aug) * L.col(i);
}
/*******************************************************************************
* Student part end
******************************************************************************/
//print result
//write result
*Xsig_out = Xsig_aug;
/* expected result:
Xsig_aug =
5.7441 5.85768 5.7441 5.7441 5.7441 5.7441 5.7441 5.7441 5.63052 5.7441 5.7441 5.7441 5.7441 5.7441 5.7441
1.38 1.34566 1.52806 1.38 1.38 1.38 1.38 1.38 1.41434 1.23194 1.38 1.38 1.38 1.38 1.38
2.2049 2.28414 2.24557 2.29582 2.2049 2.2049 2.2049 2.2049 2.12566 2.16423 2.11398 2.2049 2.2049 2.2049 2.2049
0.5015 0.44339 0.631886 0.516923 0.595227 0.5015 0.5015 0.5015 0.55961 0.371114 0.486077 0.407773 0.5015 0.5015 0.5015
0.3528 0.299973 0.462123 0.376339 0.48417 0.418721 0.3528 0.3528 0.405627 0.243477 0.329261 0.22143 0.286879 0.3528 0.3528
0 0 0 0 0 0 0.34641 0 0 0 0 0 0 -0.34641 0
0 0 0 0 0 0 0 0.34641 0 0 0 0 0 0 -0.34641
*/
}
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
void UKF::SigmaPointPrediction(MatrixXd* Xsig_out) {
//set state dimension
int n_x = 5;
//set augmented dimension
int n_aug = 7;
//create example sigma point matrix
MatrixXd Xsig_aug = MatrixXd(n_aug, 2 * n_aug + 1);
Xsig_aug <<
5.7441, 5.85768, 5.7441, 5.7441, 5.7441, 5.7441, 5.7441, 5.7441, 5.63052, 5.7441, 5.7441, 5.7441, 5.7441, 5.7441, 5.7441,
1.38, 1.34566, 1.52806, 1.38, 1.38, 1.38, 1.38, 1.38, 1.41434, 1.23194, 1.38, 1.38, 1.38, 1.38, 1.38,
2.2049, 2.28414, 2.24557, 2.29582, 2.2049, 2.2049, 2.2049, 2.2049, 2.12566, 2.16423, 2.11398, 2.2049, 2.2049, 2.2049, 2.2049,
0.5015, 0.44339, 0.631886, 0.516923, 0.595227, 0.5015, 0.5015, 0.5015, 0.55961, 0.371114, 0.486077, 0.407773, 0.5015, 0.5015, 0.5015,
0.3528, 0.299973, 0.462123, 0.376339, 0.48417, 0.418721, 0.3528, 0.3528, 0.405627, 0.243477, 0.329261, 0.22143, 0.286879, 0.3528, 0.3528,
0, 0, 0, 0, 0, 0, 0.34641, 0, 0, 0, 0, 0, 0, -0.34641, 0,
0, 0, 0, 0, 0, 0, 0, 0.34641, 0, 0, 0, 0, 0, 0, -0.34641;
//create matrix with predicted sigma points as columns
MatrixXd Xsig_pred = MatrixXd(n_x, 2 * n_aug + 1);
double delta_t = 0.1; //time diff in sec
/*******************************************************************************
* Student part begin
******************************************************************************/
//predict sigma points
for (int i = 0; i< 2*n_aug+1; i++)
{
//extract values for better readability
double p_x = Xsig_aug(0,i);
double p_y = Xsig_aug(1,i);
double v = Xsig_aug(2,i);
double yaw = Xsig_aug(3,i);
double yawd = Xsig_aug(4,i);
double nu_a = Xsig_aug(5,i);
double nu_yawdd = Xsig_aug(6,i);
//predicted state values
double px_p, py_p;
//avoid division by zero
if (fabs(yawd) > 0.001) {
px_p = p_x + v/yawd * ( sin (yaw + yawd*delta_t) - sin(yaw));
py_p = p_y + v/yawd * ( cos(yaw) - cos(yaw+yawd*delta_t) );
}
else {
px_p = p_x + v*delta_t*cos(yaw);
py_p = p_y + v*delta_t*sin(yaw);
}
double v_p = v;
double yaw_p = yaw + yawd*delta_t;
double yawd_p = yawd;
//add noise
px_p = px_p + 0.5*nu_a*delta_t*delta_t * cos(yaw);
py_p = py_p + 0.5*nu_a*delta_t*delta_t * sin(yaw);
v_p = v_p + nu_a*delta_t;
yaw_p = yaw_p + 0.5*nu_yawdd*delta_t*delta_t;
yawd_p = yawd_p + nu_yawdd*delta_t;
//write predicted sigma point into right column
Xsig_pred(0,i) = px_p;
Xsig_pred(1,i) = py_p;
Xsig_pred(2,i) = v_p;
Xsig_pred(3,i) = yaw_p;
Xsig_pred(4,i) = yawd_p;
}
/*******************************************************************************
* Student part end
******************************************************************************/
//print result
std::cout << "Xsig_pred = " << std::endl << Xsig_pred << std::endl;
//write result
*Xsig_out = Xsig_pred;
}

预测均值和方差

在预测空间计算新sigma点的均值和方差,均值是这些点的加权平均,方差也是加权方差,系数如下:

weights

代码PredictMeanAndCovariance() :

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
void UKF::PredictMeanAndCovariance(VectorXd* x_out, MatrixXd* P_out) {
//set state dimension
int n_x = 5;
//set augmented dimension
int n_aug = 7;
//define spreading parameter
double lambda = 3 - n_aug;
//create example matrix with predicted sigma points
MatrixXd Xsig_pred = MatrixXd(n_x, 2 * n_aug + 1);
Xsig_pred <<
5.9374, 6.0640, 5.925, 5.9436, 5.9266, 5.9374, 5.9389, 5.9374, 5.8106, 5.9457, 5.9310, 5.9465, 5.9374, 5.9359, 5.93744,
1.48, 1.4436, 1.660, 1.4934, 1.5036, 1.48, 1.4868, 1.48, 1.5271, 1.3104, 1.4787, 1.4674, 1.48, 1.4851, 1.486,
2.204, 2.2841, 2.2455, 2.2958, 2.204, 2.204, 2.2395, 2.204, 2.1256, 2.1642, 2.1139, 2.204, 2.204, 2.1702, 2.2049,
0.5367, 0.47338, 0.67809, 0.55455, 0.64364, 0.54337, 0.5367, 0.53851, 0.60017, 0.39546, 0.51900, 0.42991, 0.530188, 0.5367, 0.535048,
0.352, 0.29997, 0.46212, 0.37633, 0.4841, 0.41872, 0.352, 0.38744, 0.40562, 0.24347, 0.32926, 0.2214, 0.28687, 0.352, 0.318159;
//create vector for weights
VectorXd weights = VectorXd(2*n_aug+1);
//create vector for predicted state
VectorXd x = VectorXd(n_x);
//create covariance matrix for prediction
MatrixXd P = MatrixXd(n_x, n_x);
/*******************************************************************************
* Student part begin
******************************************************************************/
// set weights
double weight_0 = lambda/(lambda+n_aug);
weights(0) = weight_0;
for (int i=1; i<2*n_aug+1; i++) { //2n+1 weights
double weight = 0.5/(n_aug+lambda);
weights(i) = weight;
}
//predicted state mean
x.fill(0.0);
for (int i = 0; i < 2 * n_aug + 1; i++) { //iterate over sigma points
x = x+ weights(i) * Xsig_pred.col(i);
}
//predicted state covariance matrix
P.fill(0.0);
for (int i = 0; i < 2 * n_aug + 1; i++) { //iterate over sigma points
// state difference
VectorXd x_diff = Xsig_pred.col(i) - x;
//angle normalization
while (x_diff(3)> M_PI) x_diff(3)-=2.*M_PI;
while (x_diff(3)<-M_PI) x_diff(3)+=2.*M_PI;
P = P + weights(i) * x_diff * x_diff.transpose() ;
}
/*******************************************************************************
* Student part end
******************************************************************************/
//print result
std::cout << "Predicted state" << std::endl;
std::cout << x << std::endl;
std::cout << "Predicted covariance matrix" << std::endl;
std::cout << P << std::endl;
//write result
*x_out = x;
*P_out = P;
}

更新(Update)

预测观测值( Predict Measurement)

KF更新阶段需要将状态向量映射到观测空间,计算与观测量点残差进行状态更新。在UKF中,这一步的操作同样用sigma点来进行替代,将sigma点映射到观测空间的方法与预测阶段的相同,并且过程可以更简单。

  1. sigma点不需要重新生成,重复利用预测空间的sigma点(这些sigma点是从状态空间映射过来的)即可。
  2. 因为观测噪声是直接加在观测量上的(即观测噪声本来就在观测空间,映射关系中不会用到),所以映射过程不涉及观测噪声,也就无需计算增广sigma点矩阵。

measurement sigma

augmented update

假设使用Radar数据作为观测量,

measurement sigma

代码PredictMeanAndCovariance() :

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
void UKF::PredictRadarMeasurement(VectorXd* z_out, MatrixXd* S_out) {
//set state dimension
int n_x = 5;
//set augmented dimension
int n_aug = 7;
//set measurement dimension, radar can measure r, phi, and r_dot
int n_z = 3;
//define spreading parameter
double lambda = 3 - n_aug;
//set vector for weights
VectorXd weights = VectorXd(2*n_aug+1);
double weight_0 = lambda/(lambda+n_aug);
weights(0) = weight_0;
for (int i=1; i<2*n_aug+1; i++) {
double weight = 0.5/(n_aug+lambda);
weights(i) = weight;
}
//radar measurement noise standard deviation radius in m
double std_radr = 0.3;
//radar measurement noise standard deviation angle in rad
double std_radphi = 0.0175;
//radar measurement noise standard deviation radius change in m/s
double std_radrd = 0.1;
//create example matrix with predicted sigma points
MatrixXd Xsig_pred = MatrixXd(n_x, 2 * n_aug + 1);
Xsig_pred <<
5.9374, 6.0640, 5.925, 5.9436, 5.9266, 5.9374, 5.9389, 5.9374, 5.8106, 5.9457, 5.9310, 5.9465, 5.9374, 5.9359, 5.93744,
1.48, 1.4436, 1.660, 1.4934, 1.5036, 1.48, 1.4868, 1.48, 1.5271, 1.3104, 1.4787, 1.4674, 1.48, 1.4851, 1.486,
2.204, 2.2841, 2.2455, 2.2958, 2.204, 2.204, 2.2395, 2.204, 2.1256, 2.1642, 2.1139, 2.204, 2.204, 2.1702, 2.2049,
0.5367, 0.47338, 0.67809, 0.55455, 0.64364, 0.54337, 0.5367, 0.53851, 0.60017, 0.39546, 0.51900, 0.42991, 0.530188, 0.5367, 0.535048,
0.352, 0.29997, 0.46212, 0.37633, 0.4841, 0.41872, 0.352, 0.38744, 0.40562, 0.24347, 0.32926, 0.2214, 0.28687, 0.352, 0.318159;
//create matrix for sigma points in measurement space
MatrixXd Zsig = MatrixXd(n_z, 2 * n_aug + 1);
/*******************************************************************************
* Student part begin
******************************************************************************/
//transform sigma points into measurement space
for (int i = 0; i < 2 * n_aug + 1; i++) { //2n+1 simga points
// extract values for better readibility
double p_x = Xsig_pred(0,i);
double p_y = Xsig_pred(1,i);
double v = Xsig_pred(2,i);
double yaw = Xsig_pred(3,i);
double v1 = cos(yaw)*v;
double v2 = sin(yaw)*v;
// measurement model
Zsig(0,i) = sqrt(p_x*p_x + p_y*p_y); //r
Zsig(1,i) = atan2(p_y,p_x); //phi
Zsig(2,i) = (p_x*v1 + p_y*v2 ) / sqrt(p_x*p_x + p_y*p_y); //r_dot
}
//mean predicted measurement
VectorXd z_pred = VectorXd(n_z);
z_pred.fill(0.0);
for (int i=0; i < 2*n_aug+1; i++) {
z_pred = z_pred + weights(i) * Zsig.col(i);
}
//measurement covariance matrix S
MatrixXd S = MatrixXd(n_z,n_z);
S.fill(0.0);
for (int i = 0; i < 2 * n_aug + 1; i++) { //2n+1 simga points
//residual
VectorXd z_diff = Zsig.col(i) - z_pred;
//angle normalization
while (z_diff(1)> M_PI) z_diff(1)-=2.*M_PI;
while (z_diff(1)<-M_PI) z_diff(1)+=2.*M_PI;
S = S + weights(i) * z_diff * z_diff.transpose();
}
//add measurement noise covariance matrix
MatrixXd R = MatrixXd(n_z,n_z);
R << std_radr*std_radr, 0, 0,
0, std_radphi*std_radphi, 0,
0, 0,std_radrd*std_radrd;
S = S + R;
/*******************************************************************************
* Student part end
******************************************************************************/
//print result
std::cout << "z_pred: " << std::endl << z_pred << std::endl;
std::cout << "S: " << std::endl << S << std::endl;
//write result
*z_out = z_pred;
*S_out = S;
}

状态更新(State Update)

现在我们需要利用观测值进行状态更新了(是的,之前的步骤中都没有涉及到观测值)。

state update

state update

codeUpdateState()

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
141
142
143
144
145
146
147
148
149
void UKF::UpdateState(VectorXd* x_out, MatrixXd* P_out) {
//set state dimension
int n_x = 5;
//set augmented dimension
int n_aug = 7;
//set measurement dimension, radar can measure r, phi, and r_dot
int n_z = 3;
//define spreading parameter
double lambda = 3 - n_aug;
//set vector for weights
VectorXd weights = VectorXd(2*n_aug+1);
double weight_0 = lambda/(lambda+n_aug);
weights(0) = weight_0;
for (int i=1; i<2*n_aug+1; i++) { //2n+1 weights
double weight = 0.5/(n_aug+lambda);
weights(i) = weight;
}
//create example matrix with predicted sigma points
MatrixXd Xsig_pred = MatrixXd(n_x, 2 * n_aug + 1);
Xsig_pred <<
5.9374, 6.0640, 5.925, 5.9436, 5.9266, 5.9374, 5.9389, 5.9374, 5.8106, 5.9457, 5.9310, 5.9465, 5.9374, 5.9359, 5.93744,
1.48, 1.4436, 1.660, 1.4934, 1.5036, 1.48, 1.4868, 1.48, 1.5271, 1.3104, 1.4787, 1.4674, 1.48, 1.4851, 1.486,
2.204, 2.2841, 2.2455, 2.2958, 2.204, 2.204, 2.2395, 2.204, 2.1256, 2.1642, 2.1139, 2.204, 2.204, 2.1702, 2.2049,
0.5367, 0.47338, 0.67809, 0.55455, 0.64364, 0.54337, 0.5367, 0.53851, 0.60017, 0.39546, 0.51900, 0.42991, 0.530188, 0.5367, 0.535048,
0.352, 0.29997, 0.46212, 0.37633, 0.4841, 0.41872, 0.352, 0.38744, 0.40562, 0.24347, 0.32926, 0.2214, 0.28687, 0.352, 0.318159;
//create example vector for predicted state mean
VectorXd x = VectorXd(n_x);
x <<
5.93637,
1.49035,
2.20528,
0.536853,
0.353577;
//create example matrix for predicted state covariance
MatrixXd P = MatrixXd(n_x,n_x);
P <<
0.0054342, -0.002405, 0.0034157, -0.0034819, -0.00299378,
-0.002405, 0.01084, 0.001492, 0.0098018, 0.00791091,
0.0034157, 0.001492, 0.0058012, 0.00077863, 0.000792973,
-0.0034819, 0.0098018, 0.00077863, 0.011923, 0.0112491,
-0.0029937, 0.0079109, 0.00079297, 0.011249, 0.0126972;
//create example matrix with sigma points in measurement space
MatrixXd Zsig = MatrixXd(n_z, 2 * n_aug + 1);
Zsig <<
6.1190, 6.2334, 6.1531, 6.1283, 6.1143, 6.1190, 6.1221, 6.1190, 6.0079, 6.0883, 6.1125, 6.1248, 6.1190, 6.1188, 6.12057,
0.24428, 0.2337, 0.27316, 0.24616, 0.24846, 0.24428, 0.24530, 0.24428, 0.25700, 0.21692, 0.24433, 0.24193, 0.24428, 0.24515, 0.245239,
2.1104, 2.2188, 2.0639, 2.187, 2.0341, 2.1061, 2.1450, 2.1092, 2.0016, 2.129, 2.0346, 2.1651, 2.1145, 2.0786, 2.11295;
//create example vector for mean predicted measurement
VectorXd z_pred = VectorXd(n_z);
z_pred <<
6.12155,
0.245993,
2.10313;
//create example matrix for predicted measurement covariance
MatrixXd S = MatrixXd(n_z,n_z);
S <<
0.0946171, -0.000139448, 0.00407016,
-0.000139448, 0.000617548, -0.000770652,
0.00407016, -0.000770652, 0.0180917;
//create example vector for incoming radar measurement
VectorXd z = VectorXd(n_z);
z <<
5.9214,
0.2187,
2.0062;
//create matrix for cross correlation Tc
MatrixXd Tc = MatrixXd(n_x, n_z);
/*******************************************************************************
* Student part begin
******************************************************************************/
//calculate cross correlation matrix
Tc.fill(0.0);
for (int i = 0; i < 2 * n_aug + 1; i++) { //2n+1 simga points
//residual
VectorXd z_diff = Zsig.col(i) - z_pred;
//angle normalization
while (z_diff(1)> M_PI) z_diff(1)-=2.*M_PI;
while (z_diff(1)<-M_PI) z_diff(1)+=2.*M_PI;
// state difference
VectorXd x_diff = Xsig_pred.col(i) - x;
//angle normalization
while (x_diff(3)> M_PI) x_diff(3)-=2.*M_PI;
while (x_diff(3)<-M_PI) x_diff(3)+=2.*M_PI;
Tc = Tc + weights(i) * x_diff * z_diff.transpose();
}
//Kalman gain K;
MatrixXd K = Tc * S.inverse();
//residual
VectorXd z_diff = z - z_pred;
//angle normalization
while (z_diff(1)> M_PI) z_diff(1)-=2.*M_PI;
while (z_diff(1)<-M_PI) z_diff(1)+=2.*M_PI;
//update state mean and covariance matrix
x = x + K * z_diff;
P = P - K*S*K.transpose();
/*******************************************************************************
* Student part end
******************************************************************************/
//print result
std::cout << "Updated state x: " << std::endl << x << std::endl;
std::cout << "Updated state covariance P: " << std::endl << P << std::endl;
//write result
*x_out = x;
*P_out = P;
/* expected result x:
x =
5.92276
1.41823
2.15593
0.489274
0.321338
*/
/* expected result P:
P =
0.00361579 -0.000357881 0.00208316 -0.000937196 -0.00071727
-0.000357881 0.00539867 0.00156846 0.00455342 0.00358885
0.00208316 0.00156846 0.00410651 0.00160333 0.00171811
-0.000937196 0.00455342 0.00160333 0.00652634 0.00669436
-0.00071719 0.00358884 0.00171811 0.00669426 0.00881797
*/
}

参数与一致性(Parameter and Consistency)

不管是KF,EKF还是UKF我们都需要设定噪声参数,噪声都认为是标准高斯分布的,所以只需要设定噪声的标准差即可。

noise

测量噪声(Measurement Noise)

测量噪声一般需要查看传感器说明书,一般会有提供。若没有,可以通过静态试验的方法得到统计量,然后根据自己的实际需要测试,微调测量噪声。

过程噪声(Process Noise)

过程噪声只能根据物理意义来进行估计了。高斯分布95%的点落在$2\sigma$内,标准差量纲和噪声一致,所以这对估计很有用。

比如纵向加速度噪声$\nu_a$,一般汽车的加速度都在$6m/s^2$以内,所以取$\sigma_a = 6/2 = 3$,就比较合理了;如果追踪目标是自行车或是行人,那么$\sigma$值又要相应降低。

再比如角加速度$\nu_{\ddot {\psi}}$,用高中物理知识我们知道圆周运动角加速度和切向加速度关系是$a_r = \frac{a_t}{R}$,跟转弯半径关系很大。假设线加速度最大只能$6m/s^2$,转弯半径在10m左右,那么角加速度也只能是$0.6 s^{-2}$,那么加速度噪声

$$
\sigma_{\ddot {\psi}} = 0.6/2 =0.3
$$

是较为合理的。

一致性评估(Consistency)

噪声的参数选择是否合适,可以用正则化的平方新息NIS(Normalized Innovation Squared)进行评估。

NIS

NIS满足卡方分布,下面三种情况分别是 满足一致性要求,低估不确定性(underestimate uncertainty),高估不确定性(overestimate uncertainty)

consistent

underestimate

overestimate

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器