@@ -211,6 +211,13 @@ def __init__(self, imudata):
211
211
self .vel = []
212
212
self .pos = []
213
213
214
+ self .gyo_bias = []
215
+ self .acc_bias = []
216
+ self .gyo_fact = []
217
+ self .acc_fact = []
218
+
219
+ self .rot_ = None
220
+ self .qua_ = None
214
221
self .rot = None # Rotation matrix
215
222
self .qua = None # Quaternion
216
223
@@ -224,33 +231,50 @@ def load_initstatus(self, fp):
224
231
self .vel .append (self .imudata .init_vel )
225
232
self .pos .append (self .imudata .init_pos )
226
233
234
+ self .gyo_bias = self .config .GYO_BIA_VAL
235
+ self .acc_bias = self .config .ACC_BIA_VAL
236
+ self .gyo_fact = self .config .GYO_SCF_VAL
237
+ self .acc_fact = self .config .ACC_SCF_VAL
238
+
227
239
self .rot = com .euler2rotation (self .pos [- 1 ])
228
240
self .qua = com .euler2quater (self .pos [- 1 ])
229
241
230
242
self .Qx = np .zeros ((9 ,9 ))
231
-
243
+ self .load_gnssstatus ()
244
+
232
245
def load_gnssstatus (self ):
246
+ self .gtim = []
247
+ self .gloc = []
248
+ self .gloc_std = []
233
249
with open (self .gnssf ) as f :
234
250
for line in f :
235
251
linedata = [float (i ) for i in line .split ()]
236
- t = linedata [0 ]
237
- gnss_loc = np .asarray ([linedata [1 ] * glv .D2R , linedata [2 ] * glv .D2R , linedata [3 ]])
238
- loc_std = np .asarray (linedata [4 :])
239
- yield t , gnss_loc , loc_std
240
-
252
+ self .gtim .append (linedata [0 ])
253
+ self .gloc .append ([linedata [1 ] * glv .D2R , linedata [2 ] * glv .D2R , linedata [3 ]])
254
+ self .gloc_std .append (linedata [4 :])
255
+
256
+ def find_gpsref_data_index (self , index , reftime ):
257
+ n = len (self .gtim )
258
+ for i in range (index , n ):
259
+ t = self .gtim [i ]
260
+ if t - reftime < self .imudata .intv and t > reftime :
261
+ return 1 , i
262
+ elif t > reftime :
263
+ return 0 , i
264
+ return 0 , - 1
241
265
242
- def antenna_cor (self , imu_loc ):
243
- Dr_I = com .DrMat (imu_loc , 1 )
244
- gnss_imuloc = imu_loc + Dr_I @ self .rot @ self .config .antenna_arm
245
- return gnss_imuloc
266
+ def antenna_cor (self , imuloc , gloc ):
267
+ Dr_I = com .DrMat (imuloc , 1 )
268
+ gloc_c = gloc - Dr_I @ self .rot @ self .config .antenna_arm
269
+ return gloc_c
246
270
247
271
def updepoch_imu (self ):
248
272
for t ,ls_g ,ls_a in self .imudata .loadbinepoch (self .binf ):
249
273
if t < self .imudata .init_ts :
250
274
continue
251
275
self .iep += 1
252
276
if self .iep == 1 :
253
- yield self .tim [- 1 ], self .pos [- 1 ], self .vel [- 1 ], self .loc [- 1 ]
277
+ # yield self.tim[-1], self.pos[-1], self.vel[-1], self.loc[-1]
254
278
continue
255
279
self .tim .append (t )
256
280
loc_p = self .loc [- 1 ]
@@ -263,6 +287,8 @@ def updepoch_imu(self):
263
287
vel_m = vel_p + (vel_p - self .vel [- 2 ]) / 2
264
288
loc_m = loc_p + (loc_p - self .loc [- 2 ]) / 2
265
289
290
+ self .__cor_imu ()
291
+
266
292
omega_n_ie , omega_n_en = com .earthrotatvec (loc_m , vel_m )
267
293
grav_n = com .getgravity (loc_m [0 ], loc_m [2 ])
268
294
@@ -278,9 +304,13 @@ def updepoch_imu(self):
278
304
vel_m = (vel_n + vel_p ) / 2
279
305
loc_m = (loc_n + loc_p ) / 2
280
306
omega_n_ie , omega_n_en = com .earthrotatvec (loc_m , vel_m )
281
- q_b_n = self .__updpos (omega_n_ie , omega_n_en )
307
+ q_b_n = self .__updpos (omega_n_ie , omega_n_en )
308
+
309
+ self .qua_ = np .copy (self .qua )
310
+ self .rot_ = np .copy (self .rot )
282
311
self .qua = q_b_n
283
312
self .rot = com .quater2rotation (q_b_n )
313
+
284
314
pos_n = com .rotation2euler (self .rot )
285
315
self .pos .append (pos_n )
286
316
@@ -289,37 +319,42 @@ def updepoch_imu(self):
289
319
def updepoch (self ):
290
320
x = np .asarray (self .config .init_x )
291
321
Qx = np .asarray (self .config .init_Qx )
322
+ gps_refdata_index = 0
292
323
for t , pos_n , vel_n , loc_n in self .updepoch_imu ():
324
+ cloc_n = np .copy (loc_n )
293
325
dx = np .zeros (3 * 7 )
294
- PHI , Qw = self .get_status_equation_matrix ()
295
- # update status
296
- dx_ = PHI @ dx
297
- Qx_ = PHI @ Qx @ PHI .T + Qw
298
- for tg , gnss_pureloc , gloc_std in self .load_gnssstatus ():
299
- if np .abs (t - tg ) < 0.01 :
300
- Dr = com .DrMat (loc_n )
301
- Hr , Rk = self .get_observation_equation_matrix (Dr @ gloc_std )
302
- gnss_imuloc = self .antenna_cor (loc_n )
303
- Z = Dr @ (gnss_imuloc - gnss_pureloc )
304
- S = Hr @ Qx_ @ Hr .T + Rk
305
- K = Qx_ @ Hr .T @ np .linalg .inv (S )
306
- break
307
- elif t < tg :
308
- Hr = np .zeros ((3 , 21 ))
309
- Z = np .zeros (3 )
310
- Rk = np .zeros ((3 , 3 ))
311
- K = np .zeros ((21 , 3 ))
312
- break
313
- dx = dx_ + K @ (Z - Hr @ dx_ )
314
- temp = np .eye (len (x )) - K @ Hr
315
- Qx = temp @ Qx_ @ temp .T + K @ Rk @ K .T
316
- x += dx
317
- Dr_I = com .DrMat (loc_n , 1 )
318
- dx [:3 ] = Dr_I @ dx [:3 ]
319
- for i in range (3 ):
320
- self .loc [- 1 ][i ] += dx [i ]
321
- self .vel [- 1 ][i ] += dx [i + 3 ]
322
- self .pos [- 1 ][i ] += dx [i + 6 ]
326
+ ok , gps_refdata_index = self .find_gpsref_data_index (gps_refdata_index , t )
327
+ if ok :
328
+ # update status
329
+ PHI , Qw = self .get_status_equation_matrix ()
330
+ dx_ = PHI @ dx
331
+ Qx_ = PHI @ Qx @ PHI .T + Qw
332
+ gnss_pureloc = np .asarray (self .gloc [gps_refdata_index ])
333
+ gloc_std = np .asarray (self .gloc_std [gps_refdata_index ])
334
+ Dr = com .DrMat (cloc_n )
335
+ Hr , Rk = self .get_observation_equation_matrix (gloc_std )
336
+ gloc_c = self .antenna_cor (cloc_n , gnss_pureloc )
337
+ Z = Dr @ (cloc_n - gloc_c )
338
+ S = Hr @ Qx_ @ Hr .T + Rk
339
+ K = Qx_ @ Hr .T @ np .linalg .inv (S )
340
+ dx = dx_ + K @ (Z - Hr @ dx_ )
341
+ temp = np .eye (len (x )) - K @ Hr
342
+ Qx = temp @ Qx_ @ temp .T + K @ Rk @ K .T
343
+ else :
344
+ PHI , Qw = self .get_status_equation_matrix ()
345
+ dx = PHI @ dx
346
+ Qx = PHI @ Qx @ PHI .T + Qw
347
+ Rm ,Rn = com .mcucradius (cloc_n [0 ])
348
+ dx [0 ] /= Rm
349
+ dx [1 ] /= (Rn * np .cos (cloc_n [0 ]))
350
+ dx [2 ] /= - 1
351
+ self .loc [- 1 ] -= dx [:3 ]
352
+ self .vel [- 1 ] -= dx [3 :6 ]
353
+ self .pos [- 1 ] = com .rotation2euler (np .linalg .inv (com .rv2m (dx [6 :9 ])) @ self .rot )
354
+ self .gyo_bias += dx [9 :12 ]
355
+ self .gyo_fact += dx [12 :15 ]
356
+ self .acc_bias += dx [15 :18 ]
357
+ self .acc_fact += dx [18 :]
323
358
self .qua = com .euler2quater (self .pos [- 1 ])
324
359
self .rot = com .quater2rotation (self .qua )
325
360
yield x , Qx
@@ -336,10 +371,15 @@ def get_observation_equation_matrix(self, loc_std):
336
371
lb = self .config .antenna_arm
337
372
Hr = np .zeros ((3 , 3 * 7 ))
338
373
Hr [:,:3 ] = np .identity (3 )
339
- Hr [:,6 :9 ] = com . antisym ( self .rot @ lb )
374
+ Hr [:,6 :9 ] = self .rot @ com . antisym ( lb )
340
375
Rk = np .diag (loc_std ** 2 )
341
376
return Hr , Rk
342
377
378
+ def __cor_imu (self ):
379
+ dt = self .imudata .imu_tim [- 1 ] - self .imudata .imu_tim [- 2 ]
380
+ self .imudata .imu_acc [- 1 ] = (self .imudata .imu_acc [- 1 ] - self .acc_bias * dt ) # / (1 + self.acc_fact)
381
+ self .imudata .imu_gyo [- 1 ] = (self .imudata .imu_gyo [- 1 ] - self .gyo_bias * dt ) # / (1 + self.gyo_fact)
382
+
343
383
def __updpos (self , omega_n_ie , omega_n_en ):
344
384
dt = self .imudata .imu_tim [- 1 ] - self .imudata .imu_tim [- 2 ]
345
385
@@ -391,16 +431,16 @@ def __updloc(self):
391
431
392
432
loc_n = np .array ([lat , lon , h ])
393
433
return loc_n
394
-
395
-
434
+
435
+
396
436
397
437
def __transfer_mat (self ):
398
438
# get transfer matrix : PHI_k/k-1
399
439
dt = self .imudata .imu_tim [- 1 ] - self .imudata .imu_tim [- 2 ]
400
440
401
- loc_n = self .loc [- 1 ]
402
- vel_n = self .vel [- 1 ]
403
- pos_n = self .pos [- 1 ]
441
+ loc_n = self .loc [- 2 ]
442
+ vel_n = self .vel [- 2 ]
443
+ pos_n = self .pos [- 2 ]
404
444
405
445
406
446
lat , lon , h = loc_n
@@ -411,8 +451,8 @@ def __transfer_mat(self):
411
451
omega_n_ie , omega_n_en = com .earthrotatvec (loc_n , vel_n )
412
452
omega_n_in = omega_n_ie + omega_n_en
413
453
414
- ls_g = np .asarray (self .imudata .imu_gyo [- 1 ])
415
- ls_a = np .asarray (self .imudata .imu_acc [- 1 ])
454
+ ls_g = np .asarray (self .imudata .imu_gyo [- 2 ])
455
+ ls_a = np .asarray (self .imudata .imu_acc [- 2 ])
416
456
417
457
Frr = np .array ([
418
458
[- vd / (Rm + h ), 0 , vn / (Rm + h )],
@@ -446,34 +486,35 @@ def __transfer_mat(self):
446
486
F [3 :6 ,3 :6 ] = Fvv
447
487
F [6 :9 ,:3 ] = Fphir
448
488
F [6 :9 ,3 :6 ] = Fphiv
449
- F [3 :6 ,6 :9 ] = com .antisym (self .rot @ ls_a )
489
+ F [3 :6 ,6 :9 ] = com .antisym (self .rot_ @ ls_a )
450
490
F [6 :9 ,6 :9 ] = - com .antisym (omega_n_in )
451
- F [6 :9 ,9 :12 ] = - self .rot
452
- F [3 :6 ,12 :15 ] = self .rot
453
- F [3 :6 ,- 3 :] = self .rot @ np .diag (ls_a )
454
- F [6 :9 ,- 6 :- 3 ] = - self .rot @ np .diag (ls_g )
455
- F [9 :12 ,9 :12 ] = 1 / self .config .GYO_BIA_TAU * np .identity (3 )
456
- F [12 :15 ,12 :15 ] = 1 / self .config .ACC_BIA_TAU * np .identity (3 )
457
- F [- 6 :- 3 ,- 6 :- 3 ] = 1 / self .config .GYO_SCF_TAU * np .identity (3 )
458
- F [- 3 :,- 3 :] = 1 / self .config .ACC_SCF_TAU * np .identity (3 )
491
+ F [6 :9 ,9 :12 ] = - self .rot_
492
+ F [3 :6 ,12 :15 ] = self .rot_
493
+ F [3 :6 ,- 3 :] = self .rot_ @ np .diag (ls_a / dt )
494
+ F [6 :9 ,- 6 :- 3 ] = - self .rot_ @ np .diag (ls_g / dt )
495
+ F [9 :12 ,9 :12 ] = - 1 / self .config .GYO_BIA_TAU * np .identity (3 )
496
+ F [12 :15 ,12 :15 ] = - 1 / self .config .ACC_BIA_TAU * np .identity (3 )
497
+ F [- 6 :- 3 ,- 6 :- 3 ] = - 1 / self .config .GYO_SCF_TAU * np .identity (3 )
498
+ F [- 3 :,- 3 :] = - 1 / self .config .ACC_SCF_TAU * np .identity (3 )
459
499
return np .identity (21 ) + F * dt
460
500
461
501
def __sys_noise_cov (self ):
462
- qw = np .zeros ((18 , 18 ))
463
- qw [:3 ,:3 ] = self .config .GYOARW ** 2 * np .identity (3 )
464
- qw [3 :6 ,3 :6 ] = self .config .ACCVRW ** 2 * np .identity (3 )
465
- qw [6 :9 ,6 :9 ] = 2 * self .config .GYO_BIA_STD ** 2 / self .config .GYO_BIA_TAU * np .identity (3 )
466
- qw [9 :12 ,9 :12 ] = 2 * self .config .ACC_BIA_STD ** 2 / self .config .ACC_BIA_TAU * np .identity (3 )
502
+ qw = np .zeros ((21 , 21 ))
503
+ qw [:3 ,:3 ] = self .config .GYOARW ** 2 * np .identity (3 )
504
+ qw [3 :6 ,3 :6 ] = self .config .ACCVRW ** 2 * np .identity (3 )
505
+
506
+ qw [9 :12 ,9 :12 ] = 2 * self .config .GYO_BIA_STD ** 2 / self .config .GYO_BIA_TAU * np .identity (3 )
507
+ qw [12 :15 ,12 :15 ] = 2 * self .config .ACC_BIA_STD ** 2 / self .config .ACC_BIA_TAU * np .identity (3 )
467
508
qw [- 6 :- 3 ,- 6 :- 3 ] = 2 * self .config .GYO_SCF_STD ** 2 / self .config .GYO_SCF_TAU * np .identity (3 )
468
- qw [- 3 :,- 3 :] = 2 * self .config .ACC_SCF_STD ** 2 / self .config .ACC_SCF_TAU * np .identity (3 )
509
+ qw [- 3 :,- 3 :] = 2 * self .config .ACC_SCF_STD ** 2 / self .config .ACC_SCF_TAU * np .identity (3 )
469
510
return qw
470
511
471
512
def __sys_control_mat (self ):
472
- gc = np .zeros ((21 , 18 ))
473
- gc [3 : 6 ,:3 ] = self .rot
474
- gc [6 : 9 ,3 :6 ] = self .rot
475
- gc [9 :12 ,6 : 9 ] = np .identity (3 )
476
- gc [- 9 : - 6 , - 9 : - 6 ] = np .identity (3 )
477
- gc [- 6 : - 3 , - 6 : - 3 ] = np .identity (3 )
478
- gc [- 3 :, - 3 :] = np .identity (3 )
513
+ gc = np .zeros ((21 , 21 ))
514
+ gc [: 3 ,:3 ] = self .rot_
515
+ gc [3 : 6 ,3 :6 ] = - self .rot_
516
+ gc [9 :12 ,9 : 12 ] = np .identity (3 )
517
+ gc [12 : 15 , 12 : 15 ] = np .identity (3 )
518
+ gc [15 : 18 , 15 : 18 ] = np .identity (3 )
519
+ gc [18 :, 18 :] = np .identity (3 )
479
520
return gc
0 commit comments