diff --git a/libraries/AP_NavEKF2/AP_NavEKF2_MagFusion.cpp b/libraries/AP_NavEKF2/AP_NavEKF2_MagFusion.cpp index 227ecfd893..6f522b1c9c 100644 --- a/libraries/AP_NavEKF2/AP_NavEKF2_MagFusion.cpp +++ b/libraries/AP_NavEKF2/AP_NavEKF2_MagFusion.cpp @@ -729,6 +729,11 @@ void NavEKF2_core::FuseMagnetometer() statesArray[j] = statesArray[j] - Kfusion[j] * innovMag[obsIndex]; } + // add table constraint here for faster convergence + if (have_table_earth_field && frontend->_mag_ef_limit > 0) { + MagTableConstrain(); + } + // the first 3 states represent the angular misalignment vector. This is // is used to correct the estimated quaternion on the current time step stateStruct.quat.rotate(stateStruct.angErr); diff --git a/libraries/AP_NavEKF2/AP_NavEKF2_core.cpp b/libraries/AP_NavEKF2/AP_NavEKF2_core.cpp index 48800a5258..096153a5a0 100644 --- a/libraries/AP_NavEKF2/AP_NavEKF2_core.cpp +++ b/libraries/AP_NavEKF2/AP_NavEKF2_core.cpp @@ -1407,6 +1407,22 @@ void NavEKF2_core::ConstrainVariances() for (uint8_t i=22; i<=23; i++) P[i][i] = constrain_float(P[i][i],0.0f,1.0e3f); // wind velocity } +// constrain states using WMM tables and specified limit +void NavEKF2_core::MagTableConstrain(void) +{ + // constrain to error from table earth field + float limit_ga = frontend->_mag_ef_limit * 0.001f; + stateStruct.earth_magfield.x = constrain_float(stateStruct.earth_magfield.x, + table_earth_field_ga.x-limit_ga, + table_earth_field_ga.x+limit_ga); + stateStruct.earth_magfield.y = constrain_float(stateStruct.earth_magfield.y, + table_earth_field_ga.y-limit_ga, + table_earth_field_ga.y+limit_ga); + stateStruct.earth_magfield.z = constrain_float(stateStruct.earth_magfield.z, + table_earth_field_ga.z-limit_ga, + table_earth_field_ga.z+limit_ga); +} + // constrain states to prevent ill-conditioning void NavEKF2_core::ConstrainStates() { @@ -1430,17 +1446,8 @@ void NavEKF2_core::ConstrainStates() // constrain to +/-1Ga for (uint8_t i=16; i<=18; i++) statesArray[i] = constrain_float(statesArray[i],-1.0f,1.0f); } else { - // constrain to error from table earth field - float limit_ga = frontend->_mag_ef_limit * 0.001f; - stateStruct.earth_magfield.x = constrain_float(stateStruct.earth_magfield.x, - table_earth_field_ga.x-limit_ga, - table_earth_field_ga.x+limit_ga); - stateStruct.earth_magfield.y = constrain_float(stateStruct.earth_magfield.y, - table_earth_field_ga.y-limit_ga, - table_earth_field_ga.y+limit_ga); - stateStruct.earth_magfield.z = constrain_float(stateStruct.earth_magfield.z, - table_earth_field_ga.z-limit_ga, - table_earth_field_ga.z+limit_ga); + // use table constrain + MagTableConstrain(); } // body magnetic field limit @@ -1511,7 +1518,11 @@ Quaternion NavEKF2_core::calcQuatAndFieldStates(float roll, float pitch) // don't do this if the earth field has already been learned if (!magFieldLearned) { initQuat.rotation_matrix(Tbn); - stateStruct.earth_magfield = Tbn * magDataDelayed.mag; + if (have_table_earth_field && frontend->_mag_ef_limit > 0) { + stateStruct.earth_magfield = table_earth_field_ga; + } else { + stateStruct.earth_magfield = Tbn * magDataDelayed.mag; + } // set the NE earth magnetic field states using the published declination // and set the corresponding variances and covariances diff --git a/libraries/AP_NavEKF2/AP_NavEKF2_core.h b/libraries/AP_NavEKF2/AP_NavEKF2_core.h index f12680cbad..eb08bf09ba 100644 --- a/libraries/AP_NavEKF2/AP_NavEKF2_core.h +++ b/libraries/AP_NavEKF2/AP_NavEKF2_core.h @@ -489,6 +489,9 @@ private: // constrain states void ConstrainStates(); + // constrain earth field using WMM tables + void MagTableConstrain(void); + // fuse selected position, velocity and height measurements void FuseVelPosNED();