AP_NavEKF2: Add missing vertical position derivative calculation

Use a third order order complementary filter to estimate the rate of change of vertical position output.
This commit is contained in:
Paul Riseborough 2019-09-22 15:09:58 +10:00 committed by Randy Mackay
parent 4a1247b9f7
commit c26c6fd078
6 changed files with 39 additions and 7 deletions

View File

@ -574,6 +574,14 @@ const AP_Param::GroupInfo NavEKF2::var_info[] = {
// @Units: mGauss
AP_GROUPINFO("MAG_EF_LIM", 52, NavEKF2, _mag_ef_limit, 50),
// @Param: HRT_FILT
// @DisplayName: Height rate filter crossover frequency
// @Description: Specifies the crossover frequency of the complementary filter used to calculate the output predictor height rate derivative.
// @Range: 0.1 100.0
// @Units: Hz
// @RebootRequired: False
AP_GROUPINFO("HRT_FILT", 53, NavEKF2, _hrt_filt_freq, 2.0f),
AP_GROUPEND
};

View File

@ -417,6 +417,7 @@ private:
AP_Int8 _extnavDelay_ms; // effective average delay of external nav system measurements relative to inertial measurements (msec)
AP_Int8 _flowUse; // Controls if the optical flow data is fused into the main navigation estimator and/or the terrain estimator.
AP_Int16 _mag_ef_limit; // limit on difference between WMM tables and learned earth field.
AP_Float _hrt_filt_freq; // frequency of output observer height rate complementary filter in Hz
// Possible values for _flowUse
#define FLOW_USE_NONE 0

View File

@ -217,7 +217,7 @@ float NavEKF2_core::getPosDownDerivative(void) const
{
// return the value calculated from a complementary filter applied to the EKF height and vertical acceleration
// correct for the IMU offset (EKF calculations are at the IMU)
return posDownDerivative + velOffsetNED.z;
return vertCompFiltState.vel + velOffsetNED.z;
}
// This returns the specific forces in the NED frame

View File

@ -159,6 +159,7 @@ void NavEKF2_core::ResetHeight(void)
for (uint8_t i=0; i<imu_buffer_length; i++) {
storedOutput[i].position.z = stateStruct.position.z;
}
vertCompFiltState.pos = stateStruct.position.z;
// Calculate the position jump due to the reset
posResetD = stateStruct.position.z - posResetD;
@ -189,6 +190,7 @@ void NavEKF2_core::ResetHeight(void)
}
outputDataNew.velocity.z = stateStruct.velocity.z;
outputDataDelayed.velocity.z = stateStruct.velocity.z;
vertCompFiltState.vel = outputDataNew.velocity.z;
// reset the corresponding covariances
zeroRows(P,5,5);
@ -385,6 +387,7 @@ void NavEKF2_core::SelectVelPosFusion()
// Add the offset to the output observer states
outputDataNew.position.z += posResetD;
vertCompFiltState.pos = outputDataNew.position.z;
outputDataDelayed.position.z += posResetD;
for (uint8_t i=0; i<imu_buffer_length; i++) {
storedOutput[i].position.z += posResetD;

View File

@ -241,8 +241,7 @@ void NavEKF2_core::InitialiseVariables()
gpsVertVelFilt = 0.0f;
gpsHorizVelFilt = 0.0f;
memset(&statesArray, 0, sizeof(statesArray));
posDownDerivative = 0.0f;
posDown = 0.0f;
memset(&vertCompFiltState, 0, sizeof(vertCompFiltState));
posVelFusionDelayed = false;
optFlowFusionDelayed = false;
airSpdFusionDelayed = false;
@ -751,6 +750,24 @@ void NavEKF2_core::calcOutputStates()
// sum delta velocities to get velocity
outputDataNew.velocity += delVelNav;
// Implement third order complementary filter for height and height rate
// Reference Paper :
// Optimizing the Gains of the Baro-Inertial Vertical Channel
// Widnall W.S, Sinha P.K,
// AIAA Journal of Guidance and Control, 78-1307R
// Perform filter calculation using backwards Euler integration
// Coefficients selected to place all three filter poles at omega
const float CompFiltOmega = M_2PI * constrain_float(frontend->_hrt_filt_freq, 0.1f, 100.0f);
float omega2 = CompFiltOmega * CompFiltOmega;
float pos_err = outputDataNew.position.z - vertCompFiltState.pos;
float integ1_input = pos_err * omega2 * CompFiltOmega * imuDataNew.delVelDT;
vertCompFiltState.acc += integ1_input;
float integ2_input = delVelNav.z + (vertCompFiltState.acc + pos_err * omega2 * 3.0f) * imuDataNew.delVelDT;
vertCompFiltState.vel += integ2_input;
float integ3_input = (vertCompFiltState.vel + pos_err * CompFiltOmega * 3.0f) * imuDataNew.delVelDT;
vertCompFiltState.pos += integ3_input;
// apply a trapezoidal integration to velocities to calculate position
outputDataNew.position += (outputDataNew.velocity + lastVelocity) * (imuDataNew.delVelDT*0.5f);
@ -1406,8 +1423,8 @@ void NavEKF2_core::StoreOutputReset()
}
outputDataDelayed = outputDataNew;
// reset the states for the complementary filter used to provide a vertical position dervative output
posDown = stateStruct.position.z;
posDownDerivative = stateStruct.velocity.z;
vertCompFiltState.pos = stateStruct.position.z;
vertCompFiltState.vel = stateStruct.velocity.z;
}
// Reset the stored output quaternion history to current EKF state

View File

@ -951,8 +951,11 @@ private:
Vector3f posOffsetNED; // This adds to the earth frame position estimate at the IMU to give the position at the body origin (m)
// variables used to calculate a vertical velocity that is kinematically consistent with the verical position
float posDownDerivative; // Rate of chage of vertical position (dPosD/dt) in m/s. This is the first time derivative of PosD.
float posDown; // Down position state used in calculation of posDownRate
struct {
float pos;
float vel;
float acc;
} vertCompFiltState;
// variables used by the pre-initialisation GPS checks
struct Location gpsloc_prev; // LLH location of previous GPS measurement