77from numpy .linalg import inv as mat_inv # matrix inverse
88import matplotlib .pyplot as plt
99from scipy .io import loadmat
10+ import pdb
1011
1112class Plotter ():
1213 def __init__ (self , times ):
@@ -35,6 +36,28 @@ def __init__(self, times):
3536 self .k_v = []
3637 self .k_x = []
3738
39+ # plotting the covariance in position after each measurement and prediction
40+ self .x_cov_times = []
41+ self .x_cov_vals = []
42+
43+ def save_iteration_data (self , model , timestep , k_gains = None ):
44+ """
45+ @type model: Model
46+ """
47+ self .v_sigma_pos .append (np .sqrt (model .sigma [0 , 0 ]) * 2 )
48+ self .v_sigma_neg .append (np .sqrt (model .sigma [0 , 0 ]) * 2 * - 1 )
49+ self .v_error .append (model .vtr [0 , timestep ] - model .mu [0 , 0 ])
50+ self .x_sigma_pos .append (np .sqrt (model .sigma [1 , 1 ]) * 2 )
51+ self .x_sigma_neg .append (np .sqrt (model .sigma [1 , 1 ]) * 2 * - 1 )
52+ self .x_error .append (model .xtr [0 , timestep ] - model .mu [1 , 0 ])
53+ self .v_true .append (model .vtr [0 , timestep ])
54+ self .x_true .append (model .xtr [0 , timestep ])
55+ self .v_pred .append (model .mu [0 , 0 ])
56+ self .x_pred .append (model .mu [1 , 0 ])
57+ if k_gains is not None :
58+ self .k_v .append (k_gains [0 , 0 ])
59+ self .k_x .append (k_gains [1 , 0 ])
60+
3861 def plot (self ):
3962 # increase vertical spacing between subplots
4063 # https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.subplots_adjust.html
@@ -45,54 +68,51 @@ def plot(self):
4568 # error covariance plots
4669 p1 = plt .figure (1 )
4770 plt .subplot (211 )
48- plt .plot (times , self .v_sigma_neg , 'r' , label = "Error Covariance" )
49- plt .plot (times , self .v_sigma_pos , 'r' )
50- plt .plot (times , self .v_error , 'b' , alpha = .5 , label = "Velocity Estimation Error" )
71+ plt .plot (self . times , self .v_sigma_neg , 'r' , label = "Error Covariance" )
72+ plt .plot (self . times , self .v_sigma_pos , 'r' )
73+ plt .plot (self . times , self .v_error , 'b' , label = "Velocity Estimation Error" )
5174 plt .title ("Estimation error and error covariance vs time" )
5275 plt .ylabel ("Error (velocity)" )
5376 plt .legend ()
5477 plt .subplot (212 )
55- plt .plot (times , self .x_sigma_neg , 'r' , label = "Error Covariance" )
56- plt .plot (times , self .x_sigma_pos , 'r' )
57- plt .plot (times , self .x_error , 'b' , alpha = .5 , label = "Position Estimation Error" )
78+ plt .plot (self . times , self .x_sigma_neg , 'r' , label = "Error Covariance" )
79+ plt .plot (self . times , self .x_sigma_pos , 'r' )
80+ plt .plot (self . times , self .x_error , 'b' , label = "Position Estimation Error" )
5881 plt .ylabel ("Error (position)" )
5982 plt .xlabel (x_label_str )
6083 plt .legend ()
6184 p1 .show ()
6285
6386 # state estimates vs ground truth plots
64- true_opacity = .6
65- pred_opacity = .75
6687 p2 = plt .figure (2 )
67- plt .subplot (211 )
68- plt .plot (times , self .v_true , alpha = true_opacity , label = "True Velocity" )
69- plt .plot (times , self .v_pred , alpha = pred_opacity , label = "Predicted Velocity" )
88+ plt .plot (self .times , self .v_true , label = "True Vel" )
89+ plt .plot (self .times , self .v_pred , label = "Predicted Vel" )
90+ plt .plot (self .times , self .x_true , label = "True Pos" )
91+ plt .plot (self .times , self .x_pred , label = "Predicted Pos" )
7092 plt .title ("State estimates and true states vs time" )
71- plt .ylabel ("Velocity" )
72- plt .legend ()
73- plt .subplot (212 )
74- plt .plot (times , self .x_true , alpha = true_opacity , label = "True Position" )
75- plt .plot (times , self .x_pred , alpha = pred_opacity , label = "Predicted Prosition" )
76- plt .ylabel ("Postion" )
7793 plt .xlabel (x_label_str )
94+ plt .ylabel ("Position (m) and Velocity (m / s^2)" )
7895 plt .legend ()
7996 p2 .show ()
8097
8198 # kalman gain plots
82- gain = "Gain"
99+ # no kalman gain at the first timestep since filtering starts at second timestep
83100 p3 = plt .figure (3 )
84- plt .subplot ( 211 )
85- plt .plot (times , self .k_v , label = "Velocity " )
101+ plt .plot ( self . times [ 1 :], self . k_v , label = "Velocity" )
102+ plt .plot (self . times [ 1 :] , self .k_x , label = "Position " )
86103 plt .title ("Kalman gain vs time" )
87- plt .ylabel (gain )
88- plt .legend ()
89- plt .subplot (212 )
90- plt .plot (times , self .k_x , label = "Position" )
91- plt .ylabel (gain )
104+ plt .ylabel ("Gain" )
92105 plt .xlabel (x_label_str )
93106 plt .legend ()
94107 p3 .show ()
95108
109+ p4 = plt .figure (4 )
110+ plt .plot (self .x_cov_times , self .x_cov_vals )
111+ plt .title ("Position covariance between prediction and measurement update" )
112+ plt .ylabel ("Covariance" )
113+ plt .xlabel (x_label_str )
114+ p4 .show ()
115+
96116 # keep the plots open until user enters Ctrl+D to terminal (EOF)
97117 try :
98118 input ()
@@ -117,6 +137,8 @@ def __init__(self, times, A, B, C, D, R, Q,
117137 """
118138 np .random .seed (seed ) # for debugging (removes randomness from noise)
119139
140+ self .times = times
141+
120142 # state space
121143 self .A = A
122144 self .B = B
@@ -155,18 +177,23 @@ def load_matlab_data(self):
155177 # try on the matlab data (for comparison)
156178 self .mu = mu0
157179 self .sigma = Sig0
180+ self .Q = Q
181+ self .R = R
158182 self .control_inputs = u
159183 self .vtr = vtr
160184 self .xtr = xtr
161185 self .measurements = z
162186
163187 def get_data (self ):
188+ # initial condition is v=0 and x=0
189+ curr_state = np .array ([[0 ] , [0 ]])
190+ # input and measurement at start at timestep 1 since KF starts at timestep 1
164191 vtr = np .zeros ((1 ,self .control_inputs .size ))
165192 xtr = np .zeros ((1 ,self .control_inputs .size ))
166193 measurements = np .zeros ((1 ,self .control_inputs .size ))
167194
168- curr_state = np . array ( self . mu )
169- for i in range (self .control_inputs .size ):
195+ # updates begin at timestep 1 since timestep 0 is the initial state
196+ for i in range (1 , self .control_inputs .size ):
170197 c_input = self .control_inputs [0 , i ]
171198 c_input = np .reshape (c_input , (1 ,1 ))
172199 # get the next state from the control input
@@ -197,17 +224,22 @@ def make_measurement_noise(self):
197224
198225 def kalman_filter (self ):
199226 # for plotting
200- self .plotter = Plotter (times )
227+ self .plotter = Plotter (self .times )
228+
229+ self .plotter .save_iteration_data (self , 0 , None )
230+ self .plotter .x_cov_times .append (0 )
231+ self .plotter .x_cov_vals .append (self .sigma [1 , 1 ])
232+ for timestep in range (1 ,self .control_inputs .size ):
201233
202- for timestep in range (self .control_inputs .size ):
203234 c_input = self .control_inputs [0 , timestep ]
204235 c_input = np .reshape (c_input , (1 ,1 ))
205236 z = self .measurements [0 , timestep ]
206237
207238 # prediction
208239 mu_bar = mm (self .A , self .mu ) + mm (self .B , c_input )
209240 sigma_bar = mm (self .A , mm (self .sigma , np .transpose (self .A ))) + self .R
210-
241+ self .plotter .x_cov_times .append (self .times [timestep ])
242+ self .plotter .x_cov_vals .append (sigma_bar [1 , 1 ])
211243 # correction
212244 c_transpose = np .transpose (self .C )
213245 matrix_one = mm (sigma_bar , c_transpose )
@@ -220,85 +252,74 @@ def kalman_filter(self):
220252 self .mu = mu
221253 self .sigma = sigma
222254
223- # save info for plotting
224- # error covariance and estimation error plots
225- self .plotter .v_sigma_pos .append (np .sqrt (sigma [0 , 0 ]) * 2 )
226- self .plotter .v_sigma_neg .append (np .sqrt (sigma [0 , 0 ]) * 2 * - 1 )
227- self .plotter .v_error .append (self .vtr [0 , timestep ] - mu [0 , 0 ])
228- self .plotter .x_sigma_pos .append (np .sqrt (sigma [1 , 1 ]) * 2 )
229- self .plotter .x_sigma_neg .append (np .sqrt (sigma [1 , 1 ]) * 2 * - 1 )
230- self .plotter .x_error .append (self .xtr [0 , timestep ] - mu [1 , 0 ])
231- # state estimation plots
232- self .plotter .v_pred .append (mu [0 , 0 ])
233- self .plotter .v_true .append (self .vtr [0 , timestep ])
234- self .plotter .x_pred .append (mu [1 , 0 ])
235- self .plotter .x_true .append (self .xtr [0 , timestep ])
236- # kalman gain plots
237- self .plotter .k_v .append (k [0 , 0 ])
238- self .plotter .k_x .append (k [1 , 0 ])
255+ self .plotter .save_iteration_data (self , timestep , k )
256+ self .plotter .x_cov_times .append (self .times [timestep ])
257+ self .plotter .x_cov_vals .append (sigma [1 , 1 ])
239258
240259 def plot_results (self ):
241260 self .plotter .plot ()
242261
243262
244- ########################################################################################
245- ############################## DEFINE PARAMETERS HERE ##################################
246- ########################################################################################
247- # use the data from the matlab file, or make our own?
248- use_file_data = False
249- # eliminate randomness in noise generation? (For debugging)
250- rand_seed = None
251- # measurement covariance (default = .001)
252- z_noise = .001
253- # process noise associated with velocity state (default = .01)
254- v_noise = .01
255- # process noise associated with position state (default = .0001)
256- x_noise = .0001
257- # timestep (seconds)
258- dt = .05
259- # initial belief (initial condition):
260- # starting v and x, [[v] , [x]]
261- mu = np .array ([[0 ] , [0 ]])
262- # starting covariance, [[v , 0] , [0 , x]]
263- sigma = np .array ([[1 , 0 ] , [0 , 1 ]])
264- ########################################################################################
265- ########################################################################################
266-
267-
268- # robot model parameters
269- b = 20 # drag coefficient
270- m = 100 # mass
271-
272- # define continuous state space model
273- A = np .array ([[(- b / m ) , 0 ] , [1 , 0 ]])
274- B = np .array ([[(1 / m )] , [0 ]])
275- C = np .array ([0 , 1 ])
276- D = np .array ([0 ])
277- dt = .05
278-
279- # get a discrete state space model
280- sys = control .ss (A , B , C , D )
281- sys_d = control .c2d (sys , dt )
282- sys_d .A = np .array (sys_d .A )
283- sys_d .B = np .array (sys_d .B )
284- sys_d .C = np .array (sys_d .C )
285- sys_d .D = np .array (sys_d .D )
286-
287- # get the system/measurement noise
288- R = np .array ([[v_noise , 0 ] , [0 , x_noise ]])
289- Q = np .array ([[z_noise ]])
290-
291- # set the ground truth control inputs
292- times = np .arange (0 , 50 + dt , dt )
293- control_inputs = np .zeros ((1 , times .size ))
294- control_inputs [0 , 0 :100 ] = 50
295- control_inputs [0 , 100 :500 ] = 0
296- control_inputs [0 , 500 :600 ] = - 50
297- control_inputs [0 , 600 :] = 0
298-
299- # make the robot model
300- uuv = Model (times , sys_d .A , sys_d .B , sys_d .C , sys_d .D , R , Q ,
301- mu , sigma , control_inputs , rand_seed , use_file_data )
302-
303- uuv .kalman_filter ()
304- uuv .plot_results ()
263+
264+ if __name__ == "__main__" :
265+ ########################################################################################
266+ ############################## DEFINE PARAMETERS HERE ##################################
267+ ########################################################################################
268+ # use the data from the matlab file, or make our own?
269+ use_file_data = True
270+ # eliminate randomness in noise generation? (For debugging)
271+ rand_seed = None
272+ # measurement covariance (default = .001)
273+ z_noise = .001
274+ # process noise associated with velocity state (default = .01)
275+ v_noise = .01
276+ # process noise associated with position state (default = .0001)
277+ x_noise = .0001
278+ # timestep (seconds)
279+ dt = .05
280+ # initial belief (initial condition):
281+ # starting v and x: [[v] , [x]]
282+ mu = np .array ([[0 ] , [0 ]])
283+ # starting covariance: [[v , 0] , [0 , x]]
284+ sigma = np .array ([[.75 , 0 ] , [0 , .05 ]])
285+ ########################################################################################
286+ ########################################################################################
287+
288+
289+ # robot model parameters
290+ b = 20 # drag coefficient
291+ m = 100 # mass
292+
293+ # define continuous state space model
294+ A = np .array ([[(- b / m ) , 0 ] , [1 , 0 ]])
295+ B = np .array ([[(1 / m )] , [0 ]])
296+ C = np .array ([0 , 1 ])
297+ D = np .array ([0 ])
298+ dt = .05
299+
300+ # get a discrete state space model
301+ sys = control .ss (A , B , C , D )
302+ sys_d = control .c2d (sys , dt )
303+ sys_d .A = np .array (sys_d .A )
304+ sys_d .B = np .array (sys_d .B )
305+ sys_d .C = np .array (sys_d .C )
306+ sys_d .D = np .array (sys_d .D )
307+
308+ # get the system/measurement noise
309+ R = np .array ([[v_noise , 0 ] , [0 , x_noise ]])
310+ Q = np .array ([[z_noise ]])
311+
312+ # set the ground truth control inputs
313+ input_times = np .arange (0 , 50 + dt , dt )
314+ control_inputs = np .zeros ((1 , input_times .size ))
315+ control_inputs [0 , 0 :100 ] = 50
316+ control_inputs [0 , 100 :500 ] = 0
317+ control_inputs [0 , 500 :600 ] = - 50
318+ control_inputs [0 , 600 :] = 0
319+
320+ # make the robot model
321+ uuv = Model (input_times , sys_d .A , sys_d .B , sys_d .C , sys_d .D , R , Q ,
322+ mu , sigma , control_inputs , rand_seed , use_file_data )
323+
324+ uuv .kalman_filter ()
325+ uuv .plot_results ()
0 commit comments