Skip to content

Commit bbf32a5

Browse files
authored
EKF2: Improve Manual Position Reset Handling (#25885)
* reset by fusion: * state correction with tiny observation variance * covariance matrix upate with correct observation variance * reset wind to 0 on hard-reset during global-position-reset increase gate * adjust unittest: velocity gets now reset on resetGlobalPosToExternalObservation
1 parent 3e42521 commit bbf32a5

File tree

2 files changed

+24
-10
lines changed

2 files changed

+24
-10
lines changed

src/modules/ekf2/EKF/ekf.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ bool Ekf::resetGlobalPosToExternalObservation(const double latitude, const doubl
330330
const Vector2f innov = (_gpos - gpos_corrected).xy();
331331
const Vector2f innov_var = Vector2f(getStateVariance<State::pos>()) + obs_var;
332332

333-
const float sq_gate = sq(5.f); // magic hardcoded gate
333+
const float sq_gate = sq(10.f); // magic hardcoded gate
334334
const float test_ratio = sq(innov(0)) / (sq_gate * innov_var(0)) + sq(innov(1)) / (sq_gate * innov_var(1));
335335

336336
const bool innov_rejected = (test_ratio > 1.f);
@@ -344,24 +344,38 @@ bool Ekf::resetGlobalPosToExternalObservation(const double latitude, const doubl
344344
_information_events.flags.reset_pos_to_ext_obs = true;
345345

346346
resetHorizontalPositionTo(gpos_corrected.latitude_deg(), gpos_corrected.longitude_deg(), obs_var);
347+
348+
Vector2f new_vel = _state.vel.xy() - _state.wind_vel;
349+
resetHorizontalVelocityTo(new_vel, Vector2f(P(State::vel.idx, State::vel.idx), P(State::vel.idx + 1, State::vel.idx + 1)));
350+
351+
// bump up wind uncertainty to ensure velocity remains correct
352+
// eventual reset-by-fusion will have larger effect on wind state
353+
P.uncorrelateCovarianceSetVariance<2>(State::wind_vel.idx, 10.f);
354+
_state.wind_vel.setZero();
347355
_last_known_gpos.setLatLon(gpos_corrected);
348356

349357
} else {
350358
ECL_INFO("fuse external observation as position measurement");
351359

352360
VectorState H;
353361
VectorState K;
362+
Vector2f innov_var_temp = Vector2f(getStateVariance<State::pos>()) + 0.1f;
354363

355364
for (unsigned index = 0; index < 2; index++) {
356-
K = VectorState(P.row(State::pos.idx + index)) / innov_var(index);
365+
// Artificially setting the observation variance to a small value to
366+
// increase the Kalman gain to basically 1 to force a reset of the position
367+
// through fusion. This also enforces a strong correction of the correlated states
368+
// (e.g.: velocity, heading, wind)
369+
// The update of the covariance matrix is still performed with the correct observation variance
370+
// to not artificially reduce the state uncertainty and cross-correlations.
371+
K = VectorState(P.row(State::pos.idx + index)) / innov_var_temp(index);
357372
H(State::pos.idx + index) = 1.f;
358373

359-
// Artificially set the position Kalman gain to 1 in order to force a reset
360-
// of the position through fusion. This allows the EKF to use part of the information
361-
// to continue learning the correlated states (e.g.: velocity, heading, wind) while
362-
// performing a position reset.
363-
K(State::pos.idx + index) = 1.f;
364-
measurementUpdate(K, H, obs_var, innov(index));
374+
clearInhibitedStateKalmanGains(K);
375+
fuse(K, innov(index));
376+
377+
K = VectorState(P.row(State::pos.idx + index)) / innov_var(index);
378+
measurementUpdate(K, H, obs_var, 0.f);
365379
H(State::pos.idx + index) = 0.f; // Reset the whole vector to 0
366380
}
367381

src/modules/ekf2/test/test_EKF_airspeed.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ TEST_F(EkfAirspeedTest, testAirspeedDeadReckoningLatLonAltReset)
280280
reset_logging_checker.capturePostResetState();
281281
EXPECT_TRUE(reset_logging_checker.isVerticalVelocityResetCounterIncreasedBy(0));
282282
EXPECT_TRUE(reset_logging_checker.isVerticalPositionResetCounterIncreasedBy(1));
283-
EXPECT_TRUE(reset_logging_checker.isHorizontalVelocityResetCounterIncreasedBy(0));
283+
EXPECT_TRUE(reset_logging_checker.isHorizontalVelocityResetCounterIncreasedBy(1));
284284
EXPECT_TRUE(reset_logging_checker.isHorizontalPositionResetCounterIncreasedBy(1));
285285

286286
// AND WHEN: only the lat/lon is valid
@@ -293,7 +293,7 @@ TEST_F(EkfAirspeedTest, testAirspeedDeadReckoningLatLonAltReset)
293293
reset_logging_checker.capturePostResetState();
294294
EXPECT_TRUE(reset_logging_checker.isVerticalVelocityResetCounterIncreasedBy(0));
295295
EXPECT_TRUE(reset_logging_checker.isVerticalPositionResetCounterIncreasedBy(1));
296-
EXPECT_TRUE(reset_logging_checker.isHorizontalVelocityResetCounterIncreasedBy(0));
296+
EXPECT_TRUE(reset_logging_checker.isHorizontalVelocityResetCounterIncreasedBy(1));
297297
EXPECT_TRUE(reset_logging_checker.isHorizontalPositionResetCounterIncreasedBy(2));
298298
}
299299

0 commit comments

Comments
 (0)