@@ -314,3 +314,68 @@ def test_benchmark_ains(self):
314314 euler_err_smth = np .std ((euler_smth - euler_ref )[warmup :], axis = 0 )
315315 euler_err_ains = np .std ((euler_ains - euler_ref )[warmup :], axis = 0 )
316316 np .testing .assert_array_less (euler_err_smth , euler_err_ains )
317+
318+ def test_benchmark_ahrs (self ):
319+ # Reference signal
320+ fs = 10.24 # sampling rate in Hz
321+ _ , pos , vel , euler , acc , gyro = benchmark_full_pva_beat_202311A (fs )
322+ head = euler [:, 2 ]
323+
324+ # IMU measurements
325+ err_acc = sf .constants .ERR_ACC_MOTION2 # m/s^2
326+ err_gyro = sf .constants .ERR_GYRO_MOTION2 # rad/s
327+ imu_noise = sf .noise .IMUNoise (err_acc , err_gyro )(fs , len (acc ))
328+ acc_imu = acc + imu_noise [:, :3 ]
329+ gyro_imu = gyro + imu_noise [:, 3 :]
330+
331+ # Aiding measurements
332+ pos_noise_std = 0.1 # m
333+ head_noise_std = 0.01 # rad
334+ rng = np .random .default_rng (0 )
335+ pos_aid = pos + pos_noise_std * rng .standard_normal (pos .shape )
336+ head_aid = head + head_noise_std * rng .standard_normal (head .shape )
337+
338+ # AINS
339+ p0 = pos [0 ] # position [m]
340+ v0 = vel [0 ] # velocity [m/s]
341+ q0 = sf .quaternion_from_euler (euler [0 ], degrees = False ) # unit quaternion
342+ ba0 = np .zeros (3 ) # accelerometer bias [m/s^2]
343+ bg0 = np .zeros (3 ) # gyroscope bias [rad/s]
344+ x0 = np .concatenate ((p0 , v0 , q0 , ba0 , bg0 ))
345+ P0 = np .eye (12 ) * 1e-3
346+ err_acc = sf .constants .ERR_ACC_MOTION2 # m/s^2
347+ err_gyro = sf .constants .ERR_GYRO_MOTION2 # rad/s
348+ ains = sf .AHRS (fs , x0 , P0 , err_acc , err_gyro )
349+
350+ smoother = sf .FixedIntervalSmoother (ains , cov_smoothing = True )
351+
352+ euler_ains = []
353+ for f_i , w_i , p_i , h_i in zip (acc_imu , gyro_imu , pos_aid , head_aid ):
354+ smoother .update (
355+ f_i ,
356+ w_i ,
357+ degrees = False ,
358+ head = h_i ,
359+ head_var = head_noise_std ** 2 ,
360+ head_degrees = False ,
361+ )
362+
363+ euler_ains .append (smoother .ains .euler (degrees = False ))
364+
365+ # Forward filter state estimates
366+ euler_ains = np .array (euler_ains )
367+
368+ # Smoothed state estimates
369+ euler_smth = smoother .euler (degrees = False )
370+
371+ # Half-sample shift
372+ # # (compensates for the delay introduced by Euler integration)
373+ euler_ains = resample_poly (euler_ains , 2 , 1 )[1 :- 1 :2 ]
374+ euler_smth = resample_poly (euler_smth , 2 , 1 )[1 :- 1 :2 ]
375+ euler = euler [:- 1 , :]
376+
377+ warmup = int (fs * 600.0 ) # truncate 600 seconds from the beginning
378+
379+ euler_err_smth = np .std ((euler_smth - euler )[warmup :], axis = 0 )
380+ euler_err_ains = np .std ((euler_ains - euler )[warmup :], axis = 0 )
381+ np .testing .assert_array_less (euler_err_smth , euler_err_ains )
0 commit comments