Skip to content

Commit 4ebfbc6

Browse files
committed
GNSS yaw: use NIS sequence to detect bias in state
A constant large value in the (signed) normalized innovation test ratio is a sign of bias in the state estimate. This metric can be used to trigger a covariance boost or reset
1 parent 3fe04a9 commit 4ebfbc6

File tree

3 files changed

+17
-14
lines changed

3 files changed

+17
-14
lines changed

src/modules/ekf2/EKF/estimator_interface.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ class EstimatorInterface
328328

329329
// innovation consistency check monitoring ratios
330330
float _yaw_test_ratio{}; // yaw innovation consistency check ratio
331+
AlphaFilter<float>_yaw_signed_test_ratio_lpf{0.1f}; // average signed test ratio used to detect a bias in the state
331332
Vector3f _mag_test_ratio{}; // magnetometer XYZ innovation consistency check ratios
332333
Vector2f _gps_vel_test_ratio{}; // GPS velocity innovation consistency check ratios
333334
Vector2f _gps_pos_test_ratio{}; // GPS position innovation consistency check ratios

src/modules/ekf2/EKF/gps_yaw_fusion.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -151,23 +151,23 @@ void Ekf::fuseGpsYaw()
151151

152152
if (_yaw_test_ratio > 1.0f) {
153153
_innov_check_fail_status.flags.reject_yaw = true;
154-
155-
// if we are in air we don't want to fuse the measurement
156-
// we allow to use it when on the ground because the large innovation could be caused
157-
// by interference or a large initial gyro bias
158-
if (_control_status.flags.in_air) {
159-
return;
160-
161-
} else {
162-
// constrain the innovation to the maximum set by the gate
163-
const float gate_limit = sqrtf((sq(innov_gate) * _heading_innov_var));
164-
_heading_innov = math::constrain(_heading_innov, -gate_limit, gate_limit);
165-
}
154+
return;
166155

167156
} else {
168157
_innov_check_fail_status.flags.reject_yaw = false;
169158
}
170159

160+
_yaw_signed_test_ratio_lpf.update(matrix::sign(_heading_innov) * _yaw_test_ratio);
161+
162+
if (!_control_status.flags.in_air
163+
&& fabsf(_yaw_signed_test_ratio_lpf.getState()) > 0.2f) {
164+
165+
// A constant large signed test ratio is a sign of wrong gyro bias
166+
// Reset the yaw gyro variance to converge faster and avoid
167+
// being stuck on a previous bad estimate
168+
resetZDeltaAngBiasCov();
169+
}
170+
171171
// calculate observation jacobian
172172
// Observation jacobian and Kalman gain vectors
173173
SparseVector24f<0,1,2,3> Hfusion;
@@ -213,6 +213,7 @@ bool Ekf::resetYawToGps()
213213
resetQuatStateYaw(measured_yaw, yaw_variance, true);
214214

215215
_time_last_gps_yaw_fuse = _time_last_imu;
216+
_yaw_signed_test_ratio_lpf.reset(0.f);
216217

217218
return true;
218219
}

src/modules/ekf2/test/test_EKF_gps_yaw.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ TEST_F(EkfGpsHeadingTest, yawConvergence)
141141
// AND WHEN: the the measurement changes
142142
gps_heading += math::radians(2.f);
143143
_sensor_simulator._gps.setYaw(gps_heading);
144-
_sensor_simulator.runSeconds(10);
144+
_sensor_simulator.runSeconds(20);
145145

146146
// THEN: the estimate slowly converges to the new measurement
147147
// Note that the process is slow, because the gyro did not detect any motion
@@ -225,11 +225,12 @@ TEST_F(EkfGpsHeadingTest, yaw_jump_on_ground)
225225
const int initial_quat_reset_counter = _ekf_wrapper.getQuaternionResetCounter();
226226
gps_heading = matrix::wrap_pi(_ekf_wrapper.getYawAngle() + math::radians(45.f));
227227
_sensor_simulator._gps.setYaw(gps_heading);
228-
_sensor_simulator.runSeconds(2);
228+
_sensor_simulator.runSeconds(8);
229229

230230
// THEN: the fusion should reset
231231
EXPECT_TRUE(_ekf_wrapper.isIntendingGpsHeadingFusion());
232232
EXPECT_EQ(_ekf_wrapper.getQuaternionResetCounter(), initial_quat_reset_counter + 1);
233+
EXPECT_LT(fabsf(matrix::wrap_pi(_ekf_wrapper.getYawAngle() - gps_heading)), math::radians(1.f));
233234
}
234235

235236
TEST_F(EkfGpsHeadingTest, yaw_jump_in_air)

0 commit comments

Comments
 (0)