1
+ % -------------------------------------------------------------------------
2
+ %
3
+ % File : Unscented KalmanFilterLocalization.m
4
+ %
5
+ % Discription : Mobible robot localization sample code with
6
+ % Unscented Kalman Filter (UKF)
7
+ %
8
+ % Environment : Matlab
9
+ %
10
+ % Author : Atsushi Sakai
11
+ %
12
+ % Copyright (c): 2014 Atsushi Sakai
13
+ %
14
+ % License : Modified BSD Software License Agreement
15
+ % -------------------------------------------------------------------------
16
+
17
+ function [] = UnscentedKalmanFilterLocalization()
18
+
19
+ close all ;
20
+ clear all ;
21
+
22
+ disp(' Unscented Kalman Filter (UKF) sample program start!!' )
23
+
24
+ time = 0 ;
25
+ endtime = 80 ; % [sec]
26
+ global dt ;
27
+ dt = 0.5 ; % [sec]
28
+
29
+ nSteps = ceil((endtime - time )/dt );
30
+
31
+ result.time= [];
32
+ result.xTrue= [];
33
+ result.xd= [];
34
+ result.xEst= [];
35
+ result.z= [];
36
+ result.PEst= [];
37
+ result.u= [];
38
+
39
+ % State Vector [x y yaw v]'
40
+ xEst= [1 1 0 0.65 ]' ;
41
+
42
+ % True State
43
+ xTrue= xEst ;
44
+
45
+ % Dead Reckoning
46
+ xd= xTrue ;
47
+
48
+ % Observation vector [x y yaw v]'
49
+ z= [1 1 0 0.65 ]' ;
50
+
51
+ % Covariance Matrix for predict
52
+ Q= diag([0.1 0.1 toRadian(1 ) 0.05 ]).^2 ;
53
+
54
+ % Covariance Matrix for observation
55
+ R= diag([1.5 1.5 toRadian(3 ) 0.05 ]).^2 ;
56
+
57
+ % Simulation parameter
58
+ global Qsigma
59
+ Qsigma= diag([0.1 toRadian(20 )]).^2 ;
60
+
61
+ global Rsigma
62
+ Rsigma= diag([1.5 1.5 toRadian(3 ) 0.05 ]).^2 ;
63
+
64
+ % UKF Parameter
65
+ alpha= 0.001 ;
66
+ beta = 2 ;
67
+ kappa= 0 ;
68
+
69
+ n= length(xEst );% size of state vector
70
+ lamda= alpha ^ 2 *(n + kappa )-n ;
71
+
72
+ % calculate weights
73
+ wm= [lamda /(lamda + n )];
74
+ wc= [(lamda /(lamda + n ))+(1 - alpha ^ 2 + beta )];
75
+ for i= 1 : 2 * n
76
+ wm= [wm 1 /(2 *(n + lamda ))];
77
+ wc= [wc 1 /(2 *(n + lamda ))];
78
+ end
79
+ gamma= sqrt(n + lamda );
80
+
81
+ PEst = eye(4 );
82
+ tic ;
83
+ % Main loop
84
+ for i= 1 : nSteps
85
+ time = time + dt ;
86
+ % Input
87
+ u= doControl(time );
88
+ % Observation
89
+ [z ,xTrue ,xd ,u ]=Observation(xTrue , xd , u );
90
+
91
+ % ------ Unscented Kalman Filter --------
92
+ % Predict
93
+ sigma= GenerateSigmaPoints(xEst ,PEst ,gamma );
94
+ sigma= PredictMotion(sigma ,u );
95
+ xPred= (wm * sigma ' )' ;
96
+ PPred= CalcSimgaPointsCovariance(xPred ,sigma ,wc ,Q );
97
+
98
+ % Update
99
+ y = z - h(xPred );
100
+ sigma= GenerateSigmaPoints(xPred ,PPred ,gamma );
101
+ zSigma= PredictObservation(sigma );
102
+ zb= (wm * sigma ' )' ;
103
+ St= CalcSimgaPointsCovariance(zb ,zSigma ,wc ,R );
104
+ Pxz= CalcPxz(sigma ,xPred ,zSigma ,zb ,wc );
105
+ K= Pxz * inv(St );
106
+ xEst = xPred + K * y ;
107
+ PEst= PPred - K * St * K ' ;
108
+
109
+ % Simulation Result
110
+ result.time= [result .time ; time ];
111
+ result.xTrue= [result .xTrue ; xTrue ' ];
112
+ result.xd= [result .xd ; xd ' ];
113
+ result.xEst= [result .xEst ;xEst ' ];
114
+ result.z= [result .z ; z ' ];
115
+ result.PEst= [result .PEst ; diag(PEst )' ];
116
+ result.u= [result .u ; u ' ];
117
+
118
+ % Animation (remove some flames)
119
+ if rem(i ,5 )==0
120
+ plot(xTrue(1 ),xTrue(2 ),' .b' );hold on ;
121
+ plot(z(1 ),z(2 ),' .g' );hold on ;
122
+ plot(xd(1 ),xd(2 ),' .r' );hold on ;
123
+ plot(xEst(1 ),xEst(2 ),' .k' );hold on ;
124
+ ShowErrorEllipse(xEst ,PEst );
125
+ axis equal ;
126
+ grid on ;
127
+ drawnow ;
128
+
129
+ end
130
+
131
+
132
+ end
133
+ toc
134
+
135
+
136
+ DrawGraph(result );
137
+
138
+
139
+
140
+ function ShowErrorEllipse(xEst ,PEst )
141
+ % ????????????????
142
+ Pxy= PEst(1 : 2 ,1 : 2 );% x,y???????
143
+ [eigvec , eigval ]=eig(Pxy );% ?????????????
144
+ % ??????????????????
145
+ if eigval(1 ,1 )>=eigval(2 ,2 )
146
+ bigind= 1 ;
147
+ smallind= 2 ;
148
+ else
149
+ bigind= 2 ;
150
+ smallind= 1 ;
151
+ end
152
+
153
+ chi= 9.21 ;% ??????????????99%
154
+
155
+ % ????
156
+ t= 0 : 10 : 360 ;
157
+ a= sqrt(eigval(bigind ,bigind )*chi );
158
+ b= sqrt(eigval(smallind ,smallind )*chi );
159
+ x= [a * cosd(t );
160
+ b * sind(t )];
161
+ % ??????????
162
+ angle = atan2(eigvec(bigind ,2 ),eigvec(bigind ,1 ));
163
+ if (angle < 0 )
164
+ angle = angle + 2 * pi ;
165
+ end
166
+
167
+ % ???????
168
+ R= [cos(angle ) sin(angle );
169
+ - sin(angle ) cos(angle )];
170
+ x= R * x ;
171
+ plot(x(1 ,: )+xEst(1 ),x(2 ,: )+xEst(2 ))
172
+
173
+ function sigma = PredictMotion(sigma ,u )
174
+ % Sigma Points predition with motion model
175
+ for i= 1 : length(sigma(1 ,: ))
176
+ sigma(: ,i )=f(sigma(: ,i ),u );
177
+ end
178
+
179
+ function sigma = PredictObservation(sigma )
180
+ % Sigma Points predition with observation model
181
+ for i= 1 : length(sigma(1 ,: ))
182
+ sigma(: ,i )=h(sigma(: ,i ));
183
+ end
184
+
185
+ function P = CalcSimgaPointsCovariance(xPred ,sigma ,wc ,N )
186
+ nSigma= length(sigma(1 ,: ));
187
+ d= sigma - repmat(xPred ,1 ,nSigma );
188
+ P= N ;
189
+ for i= 1 : nSigma
190
+ P= P + wc(i )*d(: ,i )*d(: ,i )' ;
191
+ end
192
+
193
+ function P = CalcPxz(sigma ,xPred ,zSigma ,zb ,wc )
194
+ nSigma= length(sigma(1 ,: ));
195
+ dx= sigma - repmat(xPred ,1 ,nSigma );
196
+ dz= zSigma - repmat(zb ,1 ,nSigma );
197
+ P= zeros(length(sigma(: ,1 )));
198
+ for i= 1 : nSigma
199
+ P= P + wc(i )*dx(: ,i )*dz(: ,i )' ;
200
+ end
201
+
202
+ function sigma = GenerateSigmaPoints(xEst ,PEst ,gamma )
203
+ sigma= xEst ;
204
+ Psqrt= sqrtm(PEst );
205
+ n= length(xEst );
206
+ % Positive direction
207
+ for ip= 1 : n
208
+ sigma= [sigma xEst + gamma * Psqrt(: ,ip )];
209
+ end
210
+ % Negative direction
211
+ for in= 1 : n
212
+ sigma= [sigma xEst - gamma * Psqrt(: ,in )];
213
+ end
214
+
215
+ function x = f(x , u )
216
+ % Motion Model
217
+
218
+ global dt ;
219
+
220
+ F = [1 0 0 0
221
+ 0 1 0 0
222
+ 0 0 1 0
223
+ 0 0 0 0 ];
224
+
225
+ B = [
226
+ dt * cos(x(3 )) 0
227
+ dt * sin(x(3 )) 0
228
+ 0 dt
229
+ 1 0 ];
230
+
231
+ x= F * x + B * u ;
232
+
233
+ function z = h(x )
234
+ % Observation Model
235
+
236
+ H = [1 0 0 0
237
+ 0 1 0 0
238
+ 0 0 1 0
239
+ 0 0 0 1 ];
240
+
241
+ z= H * x ;
242
+
243
+ function u = doControl(time )
244
+ % Calc Input Parameter
245
+ T= 10 ; % [sec]
246
+
247
+ % [V yawrate]
248
+ V= 1.0 ; % [m/s]
249
+ yawrate = 5 ; % [deg/s]
250
+
251
+ u = [ V *(1 - exp(-time / T )) toRadian(yawrate )*(1 - exp(-time / T ))]' ;
252
+
253
+
254
+ % Calc Observation from noise prameter
255
+ function [z , x , xd , u ] = Observation(x , xd , u )
256
+ global Qsigma ;
257
+ global Rsigma ;
258
+
259
+ x= f(x , u );% Ground Truth
260
+ u= u + Qsigma * randn(2 ,1 );% add Process Noise
261
+ xd= f(xd , u );% Dead Reckoning
262
+ z= h(x + Rsigma * randn(4 ,1 ));% Simulate Observation
263
+
264
+
265
+ function []=DrawGraph(result )
266
+ % Plot Result
267
+
268
+ figure(1 );
269
+ x= [ result .xTrue(: ,1 : 2 ) result .xEst(: ,1 : 2 ) result .z(: ,1 : 2 )];
270
+ set(gca , ' fontsize' ,12 , ' fontname' , ' times' );
271
+ % plot(x(:,5), x(:,6),'.g','linewidth', 1); hold on;%gps
272
+ plot(x(: ,1 ), x(: ,2 ),' -b' ,' linewidth' , 1 ); hold on ;% observação direta
273
+ plot(x(: ,3 ), x(: ,4 ),' -r' ,' linewidth' , 1 ); hold on ;% UKF
274
+ plot(result .xd(: ,1 ), result .xd(: ,2 ),' --k' ,' linewidth' , 1 ); hold on ;% DEAD recogn
275
+
276
+ title(' UKF - Comparação' , ' fontsize' , 16 , ' fontname' , ' times' );
277
+ xlabel(' X (m)' , ' fontsize' , 16 , ' fontname' , ' times' );
278
+ ylabel(' Y (m)' , ' fontsize' , 16 , ' fontname' , ' times' );
279
+ legend(' Observação Direta' ,' UKF' ,' Dead Reckoning' );
280
+ grid on ;
281
+ axis equal ;
282
+
283
+ function radian = toRadian(degree )
284
+ % degree to radian
285
+ radian = degree / 180 * pi ;
286
+
287
+ function degree = toDegree(radian )
288
+ % radian to degree
289
+ degree = radian / pi * 180 ;
0 commit comments