@ -8,6 +8,7 @@
@@ -8,6 +8,7 @@
# include "AP_NavEKF3_core.h"
# include <AP_AHRS/AP_AHRS.h>
# include <AP_Vehicle/AP_Vehicle.h>
# include <GCS_MAVLink/GCS.h>
extern const AP_HAL : : HAL & hal ;
@ -886,4 +887,627 @@ void NavEKF3_core::selectHeightForFusion()
@@ -886,4 +887,627 @@ void NavEKF3_core::selectHeightForFusion()
}
}
/*
* Fuse body frame velocity measurements using explicit algebraic equations generated with Matlab symbolic toolbox .
* The script file used to generate these and other equations in this filter can be found here :
* https : //github.com/PX4/ecl/blob/master/matlab/scripts/Inertial%20Nav%20EKF/GenerateNavFilterEquations.m
*/
void NavEKF3_core : : FuseBodyVel ( )
{
Vector24 H_VEL ;
Vector3f bodyVelPred ;
// Copy required states to local variable names
float q0 = stateStruct . quat [ 0 ] ;
float q1 = stateStruct . quat [ 1 ] ;
float q2 = stateStruct . quat [ 2 ] ;
float q3 = stateStruct . quat [ 3 ] ;
float vn = stateStruct . velocity . x ;
float ve = stateStruct . velocity . y ;
float vd = stateStruct . velocity . z ;
// Fuse X, Y and Z axis measurements sequentially assuming observation errors are uncorrelated
for ( uint8_t obsIndex = 0 ; obsIndex < = 2 ; obsIndex + + ) {
// calculate relative velocity in sensor frame including the relative motion due to rotation
bodyVelPred = ( prevTnb * stateStruct . velocity ) ;
// correct sensor offset body frame position offset relative to IMU
Vector3f posOffsetBody = ( * bodyOdmDataDelayed . body_offset ) - accelPosOffset ;
// correct prediction for relative motion due to rotation
// note - % operator overloaded for cross product
if ( imuDataDelayed . delAngDT > 0.001f ) {
bodyVelPred + = ( imuDataDelayed . delAng * ( 1.0f / imuDataDelayed . delAngDT ) ) % posOffsetBody ;
}
// calculate observation jacobians and Kalman gains
if ( obsIndex = = 0 ) {
// calculate X axis observation Jacobian
H_VEL [ 0 ] = q2 * vd * - 2.0f + q3 * ve * 2.0f + q0 * vn * 2.0f ;
H_VEL [ 1 ] = q3 * vd * 2.0f + q2 * ve * 2.0f + q1 * vn * 2.0f ;
H_VEL [ 2 ] = q0 * vd * - 2.0f + q1 * ve * 2.0f - q2 * vn * 2.0f ;
H_VEL [ 3 ] = q1 * vd * 2.0f + q0 * ve * 2.0f - q3 * vn * 2.0f ;
H_VEL [ 4 ] = q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3 ;
H_VEL [ 5 ] = q0 * q3 * 2.0f + q1 * q2 * 2.0f ;
H_VEL [ 6 ] = q0 * q2 * - 2.0f + q1 * q3 * 2.0f ;
for ( uint8_t index = 7 ; index < 24 ; index + + ) {
H_VEL [ index ] = 0.0f ;
}
// calculate intermediate expressions for X axis Kalman gains
float R_VEL = bodyOdmDataDelayed . velErr ;
float t2 = q0 * q3 * 2.0f ;
float t3 = q1 * q2 * 2.0f ;
float t4 = t2 + t3 ;
float t5 = q0 * q0 ;
float t6 = q1 * q1 ;
float t7 = q2 * q2 ;
float t8 = q3 * q3 ;
float t9 = t5 + t6 - t7 - t8 ;
float t10 = q0 * q2 * 2.0f ;
float t25 = q1 * q3 * 2.0f ;
float t11 = t10 - t25 ;
float t12 = q3 * ve * 2.0f ;
float t13 = q0 * vn * 2.0f ;
float t26 = q2 * vd * 2.0f ;
float t14 = t12 + t13 - t26 ;
float t15 = q3 * vd * 2.0f ;
float t16 = q2 * ve * 2.0f ;
float t17 = q1 * vn * 2.0f ;
float t18 = t15 + t16 + t17 ;
float t19 = q0 * vd * 2.0f ;
float t20 = q2 * vn * 2.0f ;
float t27 = q1 * ve * 2.0f ;
float t21 = t19 + t20 - t27 ;
float t22 = q1 * vd * 2.0f ;
float t23 = q0 * ve * 2.0f ;
float t28 = q3 * vn * 2.0f ;
float t24 = t22 + t23 - t28 ;
float t29 = P [ 0 ] [ 0 ] * t14 ;
float t30 = P [ 1 ] [ 1 ] * t18 ;
float t31 = P [ 4 ] [ 5 ] * t9 ;
float t32 = P [ 5 ] [ 5 ] * t4 ;
float t33 = P [ 0 ] [ 5 ] * t14 ;
float t34 = P [ 1 ] [ 5 ] * t18 ;
float t35 = P [ 3 ] [ 5 ] * t24 ;
float t79 = P [ 6 ] [ 5 ] * t11 ;
float t80 = P [ 2 ] [ 5 ] * t21 ;
float t36 = t31 + t32 + t33 + t34 + t35 - t79 - t80 ;
float t37 = t4 * t36 ;
float t38 = P [ 4 ] [ 6 ] * t9 ;
float t39 = P [ 5 ] [ 6 ] * t4 ;
float t40 = P [ 0 ] [ 6 ] * t14 ;
float t41 = P [ 1 ] [ 6 ] * t18 ;
float t42 = P [ 3 ] [ 6 ] * t24 ;
float t81 = P [ 6 ] [ 6 ] * t11 ;
float t82 = P [ 2 ] [ 6 ] * t21 ;
float t43 = t38 + t39 + t40 + t41 + t42 - t81 - t82 ;
float t44 = P [ 4 ] [ 0 ] * t9 ;
float t45 = P [ 5 ] [ 0 ] * t4 ;
float t46 = P [ 1 ] [ 0 ] * t18 ;
float t47 = P [ 3 ] [ 0 ] * t24 ;
float t84 = P [ 6 ] [ 0 ] * t11 ;
float t85 = P [ 2 ] [ 0 ] * t21 ;
float t48 = t29 + t44 + t45 + t46 + t47 - t84 - t85 ;
float t49 = t14 * t48 ;
float t50 = P [ 4 ] [ 1 ] * t9 ;
float t51 = P [ 5 ] [ 1 ] * t4 ;
float t52 = P [ 0 ] [ 1 ] * t14 ;
float t53 = P [ 3 ] [ 1 ] * t24 ;
float t86 = P [ 6 ] [ 1 ] * t11 ;
float t87 = P [ 2 ] [ 1 ] * t21 ;
float t54 = t30 + t50 + t51 + t52 + t53 - t86 - t87 ;
float t55 = t18 * t54 ;
float t56 = P [ 4 ] [ 2 ] * t9 ;
float t57 = P [ 5 ] [ 2 ] * t4 ;
float t58 = P [ 0 ] [ 2 ] * t14 ;
float t59 = P [ 1 ] [ 2 ] * t18 ;
float t60 = P [ 3 ] [ 2 ] * t24 ;
float t78 = P [ 2 ] [ 2 ] * t21 ;
float t88 = P [ 6 ] [ 2 ] * t11 ;
float t61 = t56 + t57 + t58 + t59 + t60 - t78 - t88 ;
float t62 = P [ 4 ] [ 3 ] * t9 ;
float t63 = P [ 5 ] [ 3 ] * t4 ;
float t64 = P [ 0 ] [ 3 ] * t14 ;
float t65 = P [ 1 ] [ 3 ] * t18 ;
float t66 = P [ 3 ] [ 3 ] * t24 ;
float t90 = P [ 6 ] [ 3 ] * t11 ;
float t91 = P [ 2 ] [ 3 ] * t21 ;
float t67 = t62 + t63 + t64 + t65 + t66 - t90 - t91 ;
float t68 = t24 * t67 ;
float t69 = P [ 4 ] [ 4 ] * t9 ;
float t70 = P [ 5 ] [ 4 ] * t4 ;
float t71 = P [ 0 ] [ 4 ] * t14 ;
float t72 = P [ 1 ] [ 4 ] * t18 ;
float t73 = P [ 3 ] [ 4 ] * t24 ;
float t92 = P [ 6 ] [ 4 ] * t11 ;
float t93 = P [ 2 ] [ 4 ] * t21 ;
float t74 = t69 + t70 + t71 + t72 + t73 - t92 - t93 ;
float t75 = t9 * t74 ;
float t83 = t11 * t43 ;
float t89 = t21 * t61 ;
float t76 = R_VEL + t37 + t49 + t55 + t68 + t75 - t83 - t89 ;
float t77 ;
// calculate innovation variance for X axis observation and protect against a badly conditioned calculation
if ( t76 > R_VEL ) {
t77 = 1.0f / t76 ;
faultStatus . bad_xvel = false ;
} else {
t76 = R_VEL ;
t77 = 1.0f / R_VEL ;
faultStatus . bad_xvel = true ;
return ;
}
varInnovBodyVel [ 0 ] = t77 ;
// calculate innovation for X axis observation
innovBodyVel [ 0 ] = bodyVelPred . x - bodyOdmDataDelayed . vel . x ;
// calculate Kalman gains for X-axis observation
Kfusion [ 0 ] = t77 * ( t29 + P [ 0 ] [ 5 ] * t4 + P [ 0 ] [ 4 ] * t9 - P [ 0 ] [ 6 ] * t11 + P [ 0 ] [ 1 ] * t18 - P [ 0 ] [ 2 ] * t21 + P [ 0 ] [ 3 ] * t24 ) ;
Kfusion [ 1 ] = t77 * ( t30 + P [ 1 ] [ 5 ] * t4 + P [ 1 ] [ 4 ] * t9 + P [ 1 ] [ 0 ] * t14 - P [ 1 ] [ 6 ] * t11 - P [ 1 ] [ 2 ] * t21 + P [ 1 ] [ 3 ] * t24 ) ;
Kfusion [ 2 ] = t77 * ( - t78 + P [ 2 ] [ 5 ] * t4 + P [ 2 ] [ 4 ] * t9 + P [ 2 ] [ 0 ] * t14 - P [ 2 ] [ 6 ] * t11 + P [ 2 ] [ 1 ] * t18 + P [ 2 ] [ 3 ] * t24 ) ;
Kfusion [ 3 ] = t77 * ( t66 + P [ 3 ] [ 5 ] * t4 + P [ 3 ] [ 4 ] * t9 + P [ 3 ] [ 0 ] * t14 - P [ 3 ] [ 6 ] * t11 + P [ 3 ] [ 1 ] * t18 - P [ 3 ] [ 2 ] * t21 ) ;
Kfusion [ 4 ] = t77 * ( t69 + P [ 4 ] [ 5 ] * t4 + P [ 4 ] [ 0 ] * t14 - P [ 4 ] [ 6 ] * t11 + P [ 4 ] [ 1 ] * t18 - P [ 4 ] [ 2 ] * t21 + P [ 4 ] [ 3 ] * t24 ) ;
Kfusion [ 5 ] = t77 * ( t32 + P [ 5 ] [ 4 ] * t9 + P [ 5 ] [ 0 ] * t14 - P [ 5 ] [ 6 ] * t11 + P [ 5 ] [ 1 ] * t18 - P [ 5 ] [ 2 ] * t21 + P [ 5 ] [ 3 ] * t24 ) ;
Kfusion [ 6 ] = t77 * ( - t81 + P [ 6 ] [ 5 ] * t4 + P [ 6 ] [ 4 ] * t9 + P [ 6 ] [ 0 ] * t14 + P [ 6 ] [ 1 ] * t18 - P [ 6 ] [ 2 ] * t21 + P [ 6 ] [ 3 ] * t24 ) ;
Kfusion [ 7 ] = t77 * ( P [ 7 ] [ 5 ] * t4 + P [ 7 ] [ 4 ] * t9 + P [ 7 ] [ 0 ] * t14 - P [ 7 ] [ 6 ] * t11 + P [ 7 ] [ 1 ] * t18 - P [ 7 ] [ 2 ] * t21 + P [ 7 ] [ 3 ] * t24 ) ;
Kfusion [ 8 ] = t77 * ( P [ 8 ] [ 5 ] * t4 + P [ 8 ] [ 4 ] * t9 + P [ 8 ] [ 0 ] * t14 - P [ 8 ] [ 6 ] * t11 + P [ 8 ] [ 1 ] * t18 - P [ 8 ] [ 2 ] * t21 + P [ 8 ] [ 3 ] * t24 ) ;
Kfusion [ 9 ] = t77 * ( P [ 9 ] [ 5 ] * t4 + P [ 9 ] [ 4 ] * t9 + P [ 9 ] [ 0 ] * t14 - P [ 9 ] [ 6 ] * t11 + P [ 9 ] [ 1 ] * t18 - P [ 9 ] [ 2 ] * t21 + P [ 9 ] [ 3 ] * t24 ) ;
Kfusion [ 10 ] = t77 * ( P [ 10 ] [ 5 ] * t4 + P [ 10 ] [ 4 ] * t9 + P [ 10 ] [ 0 ] * t14 - P [ 10 ] [ 6 ] * t11 + P [ 10 ] [ 1 ] * t18 - P [ 10 ] [ 2 ] * t21 + P [ 10 ] [ 3 ] * t24 ) ;
Kfusion [ 11 ] = t77 * ( P [ 11 ] [ 5 ] * t4 + P [ 11 ] [ 4 ] * t9 + P [ 11 ] [ 0 ] * t14 - P [ 11 ] [ 6 ] * t11 + P [ 11 ] [ 1 ] * t18 - P [ 11 ] [ 2 ] * t21 + P [ 11 ] [ 3 ] * t24 ) ;
Kfusion [ 12 ] = t77 * ( P [ 12 ] [ 5 ] * t4 + P [ 12 ] [ 4 ] * t9 + P [ 12 ] [ 0 ] * t14 - P [ 12 ] [ 6 ] * t11 + P [ 12 ] [ 1 ] * t18 - P [ 12 ] [ 2 ] * t21 + P [ 12 ] [ 3 ] * t24 ) ;
Kfusion [ 13 ] = t77 * ( P [ 13 ] [ 5 ] * t4 + P [ 13 ] [ 4 ] * t9 + P [ 13 ] [ 0 ] * t14 - P [ 13 ] [ 6 ] * t11 + P [ 13 ] [ 1 ] * t18 - P [ 13 ] [ 2 ] * t21 + P [ 13 ] [ 3 ] * t24 ) ;
Kfusion [ 14 ] = t77 * ( P [ 14 ] [ 5 ] * t4 + P [ 14 ] [ 4 ] * t9 + P [ 14 ] [ 0 ] * t14 - P [ 14 ] [ 6 ] * t11 + P [ 14 ] [ 1 ] * t18 - P [ 14 ] [ 2 ] * t21 + P [ 14 ] [ 3 ] * t24 ) ;
Kfusion [ 15 ] = t77 * ( P [ 15 ] [ 5 ] * t4 + P [ 15 ] [ 4 ] * t9 + P [ 15 ] [ 0 ] * t14 - P [ 15 ] [ 6 ] * t11 + P [ 15 ] [ 1 ] * t18 - P [ 15 ] [ 2 ] * t21 + P [ 15 ] [ 3 ] * t24 ) ;
if ( ! inhibitMagStates ) {
Kfusion [ 16 ] = t77 * ( P [ 16 ] [ 5 ] * t4 + P [ 16 ] [ 4 ] * t9 + P [ 16 ] [ 0 ] * t14 - P [ 16 ] [ 6 ] * t11 + P [ 16 ] [ 1 ] * t18 - P [ 16 ] [ 2 ] * t21 + P [ 16 ] [ 3 ] * t24 ) ;
Kfusion [ 17 ] = t77 * ( P [ 17 ] [ 5 ] * t4 + P [ 17 ] [ 4 ] * t9 + P [ 17 ] [ 0 ] * t14 - P [ 17 ] [ 6 ] * t11 + P [ 17 ] [ 1 ] * t18 - P [ 17 ] [ 2 ] * t21 + P [ 17 ] [ 3 ] * t24 ) ;
Kfusion [ 18 ] = t77 * ( P [ 18 ] [ 5 ] * t4 + P [ 18 ] [ 4 ] * t9 + P [ 18 ] [ 0 ] * t14 - P [ 18 ] [ 6 ] * t11 + P [ 18 ] [ 1 ] * t18 - P [ 18 ] [ 2 ] * t21 + P [ 18 ] [ 3 ] * t24 ) ;
Kfusion [ 19 ] = t77 * ( P [ 19 ] [ 5 ] * t4 + P [ 19 ] [ 4 ] * t9 + P [ 19 ] [ 0 ] * t14 - P [ 19 ] [ 6 ] * t11 + P [ 19 ] [ 1 ] * t18 - P [ 19 ] [ 2 ] * t21 + P [ 19 ] [ 3 ] * t24 ) ;
Kfusion [ 20 ] = t77 * ( P [ 20 ] [ 5 ] * t4 + P [ 20 ] [ 4 ] * t9 + P [ 20 ] [ 0 ] * t14 - P [ 20 ] [ 6 ] * t11 + P [ 20 ] [ 1 ] * t18 - P [ 20 ] [ 2 ] * t21 + P [ 20 ] [ 3 ] * t24 ) ;
Kfusion [ 21 ] = t77 * ( P [ 21 ] [ 5 ] * t4 + P [ 21 ] [ 4 ] * t9 + P [ 21 ] [ 0 ] * t14 - P [ 21 ] [ 6 ] * t11 + P [ 21 ] [ 1 ] * t18 - P [ 21 ] [ 2 ] * t21 + P [ 21 ] [ 3 ] * t24 ) ;
} else {
for ( uint8_t i = 16 ; i < = 21 ; i + + ) {
Kfusion [ i ] = 0.0f ;
}
}
if ( ! inhibitWindStates ) {
Kfusion [ 22 ] = t77 * ( P [ 22 ] [ 5 ] * t4 + P [ 22 ] [ 4 ] * t9 + P [ 22 ] [ 0 ] * t14 - P [ 22 ] [ 6 ] * t11 + P [ 22 ] [ 1 ] * t18 - P [ 22 ] [ 2 ] * t21 + P [ 22 ] [ 3 ] * t24 ) ;
Kfusion [ 23 ] = t77 * ( P [ 23 ] [ 5 ] * t4 + P [ 23 ] [ 4 ] * t9 + P [ 23 ] [ 0 ] * t14 - P [ 23 ] [ 6 ] * t11 + P [ 23 ] [ 1 ] * t18 - P [ 23 ] [ 2 ] * t21 + P [ 23 ] [ 3 ] * t24 ) ;
} else {
Kfusion [ 22 ] = 0.0f ;
Kfusion [ 23 ] = 0.0f ;
}
} else if ( obsIndex = = 1 ) {
// calculate Y axis observation Jacobian
H_VEL [ 0 ] = q1 * vd * 2.0f + q0 * ve * 2.0f - q3 * vn * 2.0f ;
H_VEL [ 1 ] = q0 * vd * 2.0f - q1 * ve * 2.0f + q2 * vn * 2.0f ;
H_VEL [ 2 ] = q3 * vd * 2.0f + q2 * ve * 2.0f + q1 * vn * 2.0f ;
H_VEL [ 3 ] = q2 * vd * 2.0f - q3 * ve * 2.0f - q0 * vn * 2.0f ;
H_VEL [ 4 ] = q0 * q3 * - 2.0f + q1 * q2 * 2.0f ;
H_VEL [ 5 ] = q0 * q0 - q1 * q1 + q2 * q2 - q3 * q3 ;
H_VEL [ 6 ] = q0 * q1 * 2.0f + q2 * q3 * 2.0f ;
for ( uint8_t index = 7 ; index < 24 ; index + + ) {
H_VEL [ index ] = 0.0f ;
}
// calculate intermediate expressions for Y axis Kalman gains
float R_VEL = bodyOdmDataDelayed . velErr ;
float t2 = q0 * q3 * 2.0f ;
float t9 = q1 * q2 * 2.0f ;
float t3 = t2 - t9 ;
float t4 = q0 * q0 ;
float t5 = q1 * q1 ;
float t6 = q2 * q2 ;
float t7 = q3 * q3 ;
float t8 = t4 - t5 + t6 - t7 ;
float t10 = q0 * q1 * 2.0f ;
float t11 = q2 * q3 * 2.0f ;
float t12 = t10 + t11 ;
float t13 = q1 * vd * 2.0f ;
float t14 = q0 * ve * 2.0f ;
float t26 = q3 * vn * 2.0f ;
float t15 = t13 + t14 - t26 ;
float t16 = q0 * vd * 2.0f ;
float t17 = q2 * vn * 2.0f ;
float t27 = q1 * ve * 2.0f ;
float t18 = t16 + t17 - t27 ;
float t19 = q3 * vd * 2.0f ;
float t20 = q2 * ve * 2.0f ;
float t21 = q1 * vn * 2.0f ;
float t22 = t19 + t20 + t21 ;
float t23 = q3 * ve * 2.0f ;
float t24 = q0 * vn * 2.0f ;
float t28 = q2 * vd * 2.0f ;
float t25 = t23 + t24 - t28 ;
float t29 = P [ 0 ] [ 0 ] * t15 ;
float t30 = P [ 1 ] [ 1 ] * t18 ;
float t31 = P [ 5 ] [ 4 ] * t8 ;
float t32 = P [ 6 ] [ 4 ] * t12 ;
float t33 = P [ 0 ] [ 4 ] * t15 ;
float t34 = P [ 1 ] [ 4 ] * t18 ;
float t35 = P [ 2 ] [ 4 ] * t22 ;
float t78 = P [ 4 ] [ 4 ] * t3 ;
float t79 = P [ 3 ] [ 4 ] * t25 ;
float t36 = t31 + t32 + t33 + t34 + t35 - t78 - t79 ;
float t37 = P [ 5 ] [ 6 ] * t8 ;
float t38 = P [ 6 ] [ 6 ] * t12 ;
float t39 = P [ 0 ] [ 6 ] * t15 ;
float t40 = P [ 1 ] [ 6 ] * t18 ;
float t41 = P [ 2 ] [ 6 ] * t22 ;
float t81 = P [ 4 ] [ 6 ] * t3 ;
float t82 = P [ 3 ] [ 6 ] * t25 ;
float t42 = t37 + t38 + t39 + t40 + t41 - t81 - t82 ;
float t43 = t12 * t42 ;
float t44 = P [ 5 ] [ 0 ] * t8 ;
float t45 = P [ 6 ] [ 0 ] * t12 ;
float t46 = P [ 1 ] [ 0 ] * t18 ;
float t47 = P [ 2 ] [ 0 ] * t22 ;
float t83 = P [ 4 ] [ 0 ] * t3 ;
float t84 = P [ 3 ] [ 0 ] * t25 ;
float t48 = t29 + t44 + t45 + t46 + t47 - t83 - t84 ;
float t49 = t15 * t48 ;
float t50 = P [ 5 ] [ 1 ] * t8 ;
float t51 = P [ 6 ] [ 1 ] * t12 ;
float t52 = P [ 0 ] [ 1 ] * t15 ;
float t53 = P [ 2 ] [ 1 ] * t22 ;
float t85 = P [ 4 ] [ 1 ] * t3 ;
float t86 = P [ 3 ] [ 1 ] * t25 ;
float t54 = t30 + t50 + t51 + t52 + t53 - t85 - t86 ;
float t55 = t18 * t54 ;
float t56 = P [ 5 ] [ 2 ] * t8 ;
float t57 = P [ 6 ] [ 2 ] * t12 ;
float t58 = P [ 0 ] [ 2 ] * t15 ;
float t59 = P [ 1 ] [ 2 ] * t18 ;
float t60 = P [ 2 ] [ 2 ] * t22 ;
float t87 = P [ 4 ] [ 2 ] * t3 ;
float t88 = P [ 3 ] [ 2 ] * t25 ;
float t61 = t56 + t57 + t58 + t59 + t60 - t87 - t88 ;
float t62 = t22 * t61 ;
float t63 = P [ 5 ] [ 3 ] * t8 ;
float t64 = P [ 6 ] [ 3 ] * t12 ;
float t65 = P [ 0 ] [ 3 ] * t15 ;
float t66 = P [ 1 ] [ 3 ] * t18 ;
float t67 = P [ 2 ] [ 3 ] * t22 ;
float t89 = P [ 4 ] [ 3 ] * t3 ;
float t90 = P [ 3 ] [ 3 ] * t25 ;
float t68 = t63 + t64 + t65 + t66 + t67 - t89 - t90 ;
float t69 = P [ 5 ] [ 5 ] * t8 ;
float t70 = P [ 6 ] [ 5 ] * t12 ;
float t71 = P [ 0 ] [ 5 ] * t15 ;
float t72 = P [ 1 ] [ 5 ] * t18 ;
float t73 = P [ 2 ] [ 5 ] * t22 ;
float t92 = P [ 4 ] [ 5 ] * t3 ;
float t93 = P [ 3 ] [ 5 ] * t25 ;
float t74 = t69 + t70 + t71 + t72 + t73 - t92 - t93 ;
float t75 = t8 * t74 ;
float t80 = t3 * t36 ;
float t91 = t25 * t68 ;
float t76 = R_VEL + t43 + t49 + t55 + t62 + t75 - t80 - t91 ;
float t77 ;
// calculate innovation variance for Y axis observation and protect against a badly conditioned calculation
if ( t76 > R_VEL ) {
t77 = 1.0f / t76 ;
faultStatus . bad_yvel = false ;
} else {
t76 = R_VEL ;
t77 = 1.0f / R_VEL ;
faultStatus . bad_yvel = true ;
return ;
}
varInnovBodyVel [ 1 ] = t77 ;
// calculate innovation for Y axis observation
innovBodyVel [ 1 ] = bodyVelPred . y - bodyOdmDataDelayed . vel . y ;
// calculate Kalman gains for Y-axis observation
Kfusion [ 0 ] = t77 * ( t29 - P [ 0 ] [ 4 ] * t3 + P [ 0 ] [ 5 ] * t8 + P [ 0 ] [ 6 ] * t12 + P [ 0 ] [ 1 ] * t18 + P [ 0 ] [ 2 ] * t22 - P [ 0 ] [ 3 ] * t25 ) ;
Kfusion [ 1 ] = t77 * ( t30 - P [ 1 ] [ 4 ] * t3 + P [ 1 ] [ 5 ] * t8 + P [ 1 ] [ 0 ] * t15 + P [ 1 ] [ 6 ] * t12 + P [ 1 ] [ 2 ] * t22 - P [ 1 ] [ 3 ] * t25 ) ;
Kfusion [ 2 ] = t77 * ( t60 - P [ 2 ] [ 4 ] * t3 + P [ 2 ] [ 5 ] * t8 + P [ 2 ] [ 0 ] * t15 + P [ 2 ] [ 6 ] * t12 + P [ 2 ] [ 1 ] * t18 - P [ 2 ] [ 3 ] * t25 ) ;
Kfusion [ 3 ] = t77 * ( - t90 - P [ 3 ] [ 4 ] * t3 + P [ 3 ] [ 5 ] * t8 + P [ 3 ] [ 0 ] * t15 + P [ 3 ] [ 6 ] * t12 + P [ 3 ] [ 1 ] * t18 + P [ 3 ] [ 2 ] * t22 ) ;
Kfusion [ 4 ] = t77 * ( - t78 + P [ 4 ] [ 5 ] * t8 + P [ 4 ] [ 0 ] * t15 + P [ 4 ] [ 6 ] * t12 + P [ 4 ] [ 1 ] * t18 + P [ 4 ] [ 2 ] * t22 - P [ 4 ] [ 3 ] * t25 ) ;
Kfusion [ 5 ] = t77 * ( t69 - P [ 5 ] [ 4 ] * t3 + P [ 5 ] [ 0 ] * t15 + P [ 5 ] [ 6 ] * t12 + P [ 5 ] [ 1 ] * t18 + P [ 5 ] [ 2 ] * t22 - P [ 5 ] [ 3 ] * t25 ) ;
Kfusion [ 6 ] = t77 * ( t38 - P [ 6 ] [ 4 ] * t3 + P [ 6 ] [ 5 ] * t8 + P [ 6 ] [ 0 ] * t15 + P [ 6 ] [ 1 ] * t18 + P [ 6 ] [ 2 ] * t22 - P [ 6 ] [ 3 ] * t25 ) ;
Kfusion [ 7 ] = t77 * ( - P [ 7 ] [ 4 ] * t3 + P [ 7 ] [ 5 ] * t8 + P [ 7 ] [ 0 ] * t15 + P [ 7 ] [ 6 ] * t12 + P [ 7 ] [ 1 ] * t18 + P [ 7 ] [ 2 ] * t22 - P [ 7 ] [ 3 ] * t25 ) ;
Kfusion [ 8 ] = t77 * ( - P [ 8 ] [ 4 ] * t3 + P [ 8 ] [ 5 ] * t8 + P [ 8 ] [ 0 ] * t15 + P [ 8 ] [ 6 ] * t12 + P [ 8 ] [ 1 ] * t18 + P [ 8 ] [ 2 ] * t22 - P [ 8 ] [ 3 ] * t25 ) ;
Kfusion [ 9 ] = t77 * ( - P [ 9 ] [ 4 ] * t3 + P [ 9 ] [ 5 ] * t8 + P [ 9 ] [ 0 ] * t15 + P [ 9 ] [ 6 ] * t12 + P [ 9 ] [ 1 ] * t18 + P [ 9 ] [ 2 ] * t22 - P [ 9 ] [ 3 ] * t25 ) ;
Kfusion [ 10 ] = t77 * ( - P [ 10 ] [ 4 ] * t3 + P [ 10 ] [ 5 ] * t8 + P [ 10 ] [ 0 ] * t15 + P [ 10 ] [ 6 ] * t12 + P [ 10 ] [ 1 ] * t18 + P [ 10 ] [ 2 ] * t22 - P [ 10 ] [ 3 ] * t25 ) ;
Kfusion [ 11 ] = t77 * ( - P [ 11 ] [ 4 ] * t3 + P [ 11 ] [ 5 ] * t8 + P [ 11 ] [ 0 ] * t15 + P [ 11 ] [ 6 ] * t12 + P [ 11 ] [ 1 ] * t18 + P [ 11 ] [ 2 ] * t22 - P [ 11 ] [ 3 ] * t25 ) ;
Kfusion [ 12 ] = t77 * ( - P [ 12 ] [ 4 ] * t3 + P [ 12 ] [ 5 ] * t8 + P [ 12 ] [ 0 ] * t15 + P [ 12 ] [ 6 ] * t12 + P [ 12 ] [ 1 ] * t18 + P [ 12 ] [ 2 ] * t22 - P [ 12 ] [ 3 ] * t25 ) ;
Kfusion [ 13 ] = t77 * ( - P [ 13 ] [ 4 ] * t3 + P [ 13 ] [ 5 ] * t8 + P [ 13 ] [ 0 ] * t15 + P [ 13 ] [ 6 ] * t12 + P [ 13 ] [ 1 ] * t18 + P [ 13 ] [ 2 ] * t22 - P [ 13 ] [ 3 ] * t25 ) ;
Kfusion [ 14 ] = t77 * ( - P [ 14 ] [ 4 ] * t3 + P [ 14 ] [ 5 ] * t8 + P [ 14 ] [ 0 ] * t15 + P [ 14 ] [ 6 ] * t12 + P [ 14 ] [ 1 ] * t18 + P [ 14 ] [ 2 ] * t22 - P [ 14 ] [ 3 ] * t25 ) ;
Kfusion [ 15 ] = t77 * ( - P [ 15 ] [ 4 ] * t3 + P [ 15 ] [ 5 ] * t8 + P [ 15 ] [ 0 ] * t15 + P [ 15 ] [ 6 ] * t12 + P [ 15 ] [ 1 ] * t18 + P [ 15 ] [ 2 ] * t22 - P [ 15 ] [ 3 ] * t25 ) ;
if ( ! inhibitMagStates ) {
Kfusion [ 16 ] = t77 * ( - P [ 16 ] [ 4 ] * t3 + P [ 16 ] [ 5 ] * t8 + P [ 16 ] [ 0 ] * t15 + P [ 16 ] [ 6 ] * t12 + P [ 16 ] [ 1 ] * t18 + P [ 16 ] [ 2 ] * t22 - P [ 16 ] [ 3 ] * t25 ) ;
Kfusion [ 17 ] = t77 * ( - P [ 17 ] [ 4 ] * t3 + P [ 17 ] [ 5 ] * t8 + P [ 17 ] [ 0 ] * t15 + P [ 17 ] [ 6 ] * t12 + P [ 17 ] [ 1 ] * t18 + P [ 17 ] [ 2 ] * t22 - P [ 17 ] [ 3 ] * t25 ) ;
Kfusion [ 18 ] = t77 * ( - P [ 18 ] [ 4 ] * t3 + P [ 18 ] [ 5 ] * t8 + P [ 18 ] [ 0 ] * t15 + P [ 18 ] [ 6 ] * t12 + P [ 18 ] [ 1 ] * t18 + P [ 18 ] [ 2 ] * t22 - P [ 18 ] [ 3 ] * t25 ) ;
Kfusion [ 19 ] = t77 * ( - P [ 19 ] [ 4 ] * t3 + P [ 19 ] [ 5 ] * t8 + P [ 19 ] [ 0 ] * t15 + P [ 19 ] [ 6 ] * t12 + P [ 19 ] [ 1 ] * t18 + P [ 19 ] [ 2 ] * t22 - P [ 19 ] [ 3 ] * t25 ) ;
Kfusion [ 20 ] = t77 * ( - P [ 20 ] [ 4 ] * t3 + P [ 20 ] [ 5 ] * t8 + P [ 20 ] [ 0 ] * t15 + P [ 20 ] [ 6 ] * t12 + P [ 20 ] [ 1 ] * t18 + P [ 20 ] [ 2 ] * t22 - P [ 20 ] [ 3 ] * t25 ) ;
Kfusion [ 21 ] = t77 * ( - P [ 21 ] [ 4 ] * t3 + P [ 21 ] [ 5 ] * t8 + P [ 21 ] [ 0 ] * t15 + P [ 21 ] [ 6 ] * t12 + P [ 21 ] [ 1 ] * t18 + P [ 21 ] [ 2 ] * t22 - P [ 21 ] [ 3 ] * t25 ) ;
} else {
for ( uint8_t i = 16 ; i < = 21 ; i + + ) {
Kfusion [ i ] = 0.0f ;
}
}
if ( ! inhibitWindStates ) {
Kfusion [ 22 ] = t77 * ( - P [ 22 ] [ 4 ] * t3 + P [ 22 ] [ 5 ] * t8 + P [ 22 ] [ 0 ] * t15 + P [ 22 ] [ 6 ] * t12 + P [ 22 ] [ 1 ] * t18 + P [ 22 ] [ 2 ] * t22 - P [ 22 ] [ 3 ] * t25 ) ;
Kfusion [ 23 ] = t77 * ( - P [ 23 ] [ 4 ] * t3 + P [ 23 ] [ 5 ] * t8 + P [ 23 ] [ 0 ] * t15 + P [ 23 ] [ 6 ] * t12 + P [ 23 ] [ 1 ] * t18 + P [ 23 ] [ 2 ] * t22 - P [ 23 ] [ 3 ] * t25 ) ;
} else {
Kfusion [ 22 ] = 0.0f ;
Kfusion [ 23 ] = 0.0f ;
}
} else if ( obsIndex = = 2 ) {
// calculate Z axis observation Jacobian
H_VEL [ 0 ] = q0 * vd * 2.0f - q1 * ve * 2.0f + q2 * vn * 2.0f ;
H_VEL [ 1 ] = q1 * vd * - 2.0f - q0 * ve * 2.0f + q3 * vn * 2.0f ;
H_VEL [ 2 ] = q2 * vd * - 2.0f + q3 * ve * 2.0f + q0 * vn * 2.0f ;
H_VEL [ 3 ] = q3 * vd * 2.0f + q2 * ve * 2.0f + q1 * vn * 2.0f ;
H_VEL [ 4 ] = q0 * q2 * 2.0f + q1 * q3 * 2.0f ;
H_VEL [ 5 ] = q0 * q1 * - 2.0f + q2 * q3 * 2.0f ;
H_VEL [ 6 ] = q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3 ;
for ( uint8_t index = 7 ; index < 24 ; index + + ) {
H_VEL [ index ] = 0.0f ;
}
// calculate intermediate expressions for Z axis Kalman gains
float R_VEL = bodyOdmDataDelayed . velErr ;
float t2 = q0 * q2 * 2.0f ;
float t3 = q1 * q3 * 2.0f ;
float t4 = t2 + t3 ;
float t5 = q0 * q0 ;
float t6 = q1 * q1 ;
float t7 = q2 * q2 ;
float t8 = q3 * q3 ;
float t9 = t5 - t6 - t7 + t8 ;
float t10 = q0 * q1 * 2.0f ;
float t25 = q2 * q3 * 2.0f ;
float t11 = t10 - t25 ;
float t12 = q0 * vd * 2.0f ;
float t13 = q2 * vn * 2.0f ;
float t26 = q1 * ve * 2.0f ;
float t14 = t12 + t13 - t26 ;
float t15 = q1 * vd * 2.0f ;
float t16 = q0 * ve * 2.0f ;
float t27 = q3 * vn * 2.0f ;
float t17 = t15 + t16 - t27 ;
float t18 = q3 * ve * 2.0f ;
float t19 = q0 * vn * 2.0f ;
float t28 = q2 * vd * 2.0f ;
float t20 = t18 + t19 - t28 ;
float t21 = q3 * vd * 2.0f ;
float t22 = q2 * ve * 2.0f ;
float t23 = q1 * vn * 2.0f ;
float t24 = t21 + t22 + t23 ;
float t29 = P [ 0 ] [ 0 ] * t14 ;
float t30 = P [ 6 ] [ 4 ] * t9 ;
float t31 = P [ 4 ] [ 4 ] * t4 ;
float t32 = P [ 0 ] [ 4 ] * t14 ;
float t33 = P [ 2 ] [ 4 ] * t20 ;
float t34 = P [ 3 ] [ 4 ] * t24 ;
float t78 = P [ 5 ] [ 4 ] * t11 ;
float t79 = P [ 1 ] [ 4 ] * t17 ;
float t35 = t30 + t31 + t32 + t33 + t34 - t78 - t79 ;
float t36 = t4 * t35 ;
float t37 = P [ 6 ] [ 5 ] * t9 ;
float t38 = P [ 4 ] [ 5 ] * t4 ;
float t39 = P [ 0 ] [ 5 ] * t14 ;
float t40 = P [ 2 ] [ 5 ] * t20 ;
float t41 = P [ 3 ] [ 5 ] * t24 ;
float t80 = P [ 5 ] [ 5 ] * t11 ;
float t81 = P [ 1 ] [ 5 ] * t17 ;
float t42 = t37 + t38 + t39 + t40 + t41 - t80 - t81 ;
float t43 = P [ 6 ] [ 0 ] * t9 ;
float t44 = P [ 4 ] [ 0 ] * t4 ;
float t45 = P [ 2 ] [ 0 ] * t20 ;
float t46 = P [ 3 ] [ 0 ] * t24 ;
float t83 = P [ 5 ] [ 0 ] * t11 ;
float t84 = P [ 1 ] [ 0 ] * t17 ;
float t47 = t29 + t43 + t44 + t45 + t46 - t83 - t84 ;
float t48 = t14 * t47 ;
float t49 = P [ 6 ] [ 1 ] * t9 ;
float t50 = P [ 4 ] [ 1 ] * t4 ;
float t51 = P [ 0 ] [ 1 ] * t14 ;
float t52 = P [ 2 ] [ 1 ] * t20 ;
float t53 = P [ 3 ] [ 1 ] * t24 ;
float t85 = P [ 5 ] [ 1 ] * t11 ;
float t86 = P [ 1 ] [ 1 ] * t17 ;
float t54 = t49 + t50 + t51 + t52 + t53 - t85 - t86 ;
float t55 = P [ 6 ] [ 2 ] * t9 ;
float t56 = P [ 4 ] [ 2 ] * t4 ;
float t57 = P [ 0 ] [ 2 ] * t14 ;
float t58 = P [ 2 ] [ 2 ] * t20 ;
float t59 = P [ 3 ] [ 2 ] * t24 ;
float t88 = P [ 5 ] [ 2 ] * t11 ;
float t89 = P [ 1 ] [ 2 ] * t17 ;
float t60 = t55 + t56 + t57 + t58 + t59 - t88 - t89 ;
float t61 = t20 * t60 ;
float t62 = P [ 6 ] [ 3 ] * t9 ;
float t63 = P [ 4 ] [ 3 ] * t4 ;
float t64 = P [ 0 ] [ 3 ] * t14 ;
float t65 = P [ 2 ] [ 3 ] * t20 ;
float t66 = P [ 3 ] [ 3 ] * t24 ;
float t90 = P [ 5 ] [ 3 ] * t11 ;
float t91 = P [ 1 ] [ 3 ] * t17 ;
float t67 = t62 + t63 + t64 + t65 + t66 - t90 - t91 ;
float t68 = t24 * t67 ;
float t69 = P [ 6 ] [ 6 ] * t9 ;
float t70 = P [ 4 ] [ 6 ] * t4 ;
float t71 = P [ 0 ] [ 6 ] * t14 ;
float t72 = P [ 2 ] [ 6 ] * t20 ;
float t73 = P [ 3 ] [ 6 ] * t24 ;
float t92 = P [ 5 ] [ 6 ] * t11 ;
float t93 = P [ 1 ] [ 6 ] * t17 ;
float t74 = t69 + t70 + t71 + t72 + t73 - t92 - t93 ;
float t75 = t9 * t74 ;
float t82 = t11 * t42 ;
float t87 = t17 * t54 ;
float t76 = R_VEL + t36 + t48 + t61 + t68 + t75 - t82 - t87 ;
float t77 ;
// calculate innovation variance for Z axis observation and protect against a badly conditioned calculation
if ( t76 > R_VEL ) {
t77 = 1.0f / t76 ;
faultStatus . bad_zvel = false ;
} else {
t76 = R_VEL ;
t77 = 1.0f / R_VEL ;
faultStatus . bad_zvel = true ;
return ;
}
varInnovBodyVel [ 2 ] = t77 ;
// calculate innovation for Z axis observation
innovBodyVel [ 2 ] = bodyVelPred . z - bodyOdmDataDelayed . vel . z ;
// calculate Kalman gains for X-axis observation
Kfusion [ 0 ] = t77 * ( t29 + P [ 0 ] [ 4 ] * t4 + P [ 0 ] [ 6 ] * t9 - P [ 0 ] [ 5 ] * t11 - P [ 0 ] [ 1 ] * t17 + P [ 0 ] [ 2 ] * t20 + P [ 0 ] [ 3 ] * t24 ) ;
Kfusion [ 1 ] = t77 * ( P [ 1 ] [ 4 ] * t4 + P [ 1 ] [ 0 ] * t14 + P [ 1 ] [ 6 ] * t9 - P [ 1 ] [ 5 ] * t11 - P [ 1 ] [ 1 ] * t17 + P [ 1 ] [ 2 ] * t20 + P [ 1 ] [ 3 ] * t24 ) ;
Kfusion [ 2 ] = t77 * ( t58 + P [ 2 ] [ 4 ] * t4 + P [ 2 ] [ 0 ] * t14 + P [ 2 ] [ 6 ] * t9 - P [ 2 ] [ 5 ] * t11 - P [ 2 ] [ 1 ] * t17 + P [ 2 ] [ 3 ] * t24 ) ;
Kfusion [ 3 ] = t77 * ( t66 + P [ 3 ] [ 4 ] * t4 + P [ 3 ] [ 0 ] * t14 + P [ 3 ] [ 6 ] * t9 - P [ 3 ] [ 5 ] * t11 - P [ 3 ] [ 1 ] * t17 + P [ 3 ] [ 2 ] * t20 ) ;
Kfusion [ 4 ] = t77 * ( t31 + P [ 4 ] [ 0 ] * t14 + P [ 4 ] [ 6 ] * t9 - P [ 4 ] [ 5 ] * t11 - P [ 4 ] [ 1 ] * t17 + P [ 4 ] [ 2 ] * t20 + P [ 4 ] [ 3 ] * t24 ) ;
Kfusion [ 5 ] = t77 * ( - t80 + P [ 5 ] [ 4 ] * t4 + P [ 5 ] [ 0 ] * t14 + P [ 5 ] [ 6 ] * t9 - P [ 5 ] [ 1 ] * t17 + P [ 5 ] [ 2 ] * t20 + P [ 5 ] [ 3 ] * t24 ) ;
Kfusion [ 6 ] = t77 * ( t69 + P [ 6 ] [ 4 ] * t4 + P [ 6 ] [ 0 ] * t14 - P [ 6 ] [ 5 ] * t11 - P [ 6 ] [ 1 ] * t17 + P [ 6 ] [ 2 ] * t20 + P [ 6 ] [ 3 ] * t24 ) ;
Kfusion [ 7 ] = t77 * ( P [ 7 ] [ 4 ] * t4 + P [ 7 ] [ 0 ] * t14 + P [ 7 ] [ 6 ] * t9 - P [ 7 ] [ 5 ] * t11 - P [ 7 ] [ 1 ] * t17 + P [ 7 ] [ 2 ] * t20 + P [ 7 ] [ 3 ] * t24 ) ;
Kfusion [ 8 ] = t77 * ( P [ 8 ] [ 4 ] * t4 + P [ 8 ] [ 0 ] * t14 + P [ 8 ] [ 6 ] * t9 - P [ 8 ] [ 5 ] * t11 - P [ 8 ] [ 1 ] * t17 + P [ 8 ] [ 2 ] * t20 + P [ 8 ] [ 3 ] * t24 ) ;
Kfusion [ 9 ] = t77 * ( P [ 9 ] [ 4 ] * t4 + P [ 9 ] [ 0 ] * t14 + P [ 9 ] [ 6 ] * t9 - P [ 9 ] [ 5 ] * t11 - P [ 9 ] [ 1 ] * t17 + P [ 9 ] [ 2 ] * t20 + P [ 9 ] [ 3 ] * t24 ) ;
Kfusion [ 10 ] = t77 * ( P [ 10 ] [ 4 ] * t4 + P [ 10 ] [ 0 ] * t14 + P [ 10 ] [ 6 ] * t9 - P [ 10 ] [ 5 ] * t11 - P [ 10 ] [ 1 ] * t17 + P [ 10 ] [ 2 ] * t20 + P [ 10 ] [ 3 ] * t24 ) ;
Kfusion [ 11 ] = t77 * ( P [ 11 ] [ 4 ] * t4 + P [ 11 ] [ 0 ] * t14 + P [ 11 ] [ 6 ] * t9 - P [ 11 ] [ 5 ] * t11 - P [ 11 ] [ 1 ] * t17 + P [ 11 ] [ 2 ] * t20 + P [ 11 ] [ 3 ] * t24 ) ;
Kfusion [ 12 ] = t77 * ( P [ 12 ] [ 4 ] * t4 + P [ 12 ] [ 0 ] * t14 + P [ 12 ] [ 6 ] * t9 - P [ 12 ] [ 5 ] * t11 - P [ 12 ] [ 1 ] * t17 + P [ 12 ] [ 2 ] * t20 + P [ 12 ] [ 3 ] * t24 ) ;
Kfusion [ 13 ] = t77 * ( P [ 13 ] [ 4 ] * t4 + P [ 13 ] [ 0 ] * t14 + P [ 13 ] [ 6 ] * t9 - P [ 13 ] [ 5 ] * t11 - P [ 13 ] [ 1 ] * t17 + P [ 13 ] [ 2 ] * t20 + P [ 13 ] [ 3 ] * t24 ) ;
Kfusion [ 14 ] = t77 * ( P [ 14 ] [ 4 ] * t4 + P [ 14 ] [ 0 ] * t14 + P [ 14 ] [ 6 ] * t9 - P [ 14 ] [ 5 ] * t11 - P [ 14 ] [ 1 ] * t17 + P [ 14 ] [ 2 ] * t20 + P [ 14 ] [ 3 ] * t24 ) ;
Kfusion [ 15 ] = t77 * ( P [ 15 ] [ 4 ] * t4 + P [ 15 ] [ 0 ] * t14 + P [ 15 ] [ 6 ] * t9 - P [ 15 ] [ 5 ] * t11 - P [ 15 ] [ 1 ] * t17 + P [ 15 ] [ 2 ] * t20 + P [ 15 ] [ 3 ] * t24 ) ;
if ( ! inhibitMagStates ) {
Kfusion [ 16 ] = t77 * ( P [ 16 ] [ 4 ] * t4 + P [ 16 ] [ 0 ] * t14 + P [ 16 ] [ 6 ] * t9 - P [ 16 ] [ 5 ] * t11 - P [ 16 ] [ 1 ] * t17 + P [ 16 ] [ 2 ] * t20 + P [ 16 ] [ 3 ] * t24 ) ;
Kfusion [ 17 ] = t77 * ( P [ 17 ] [ 4 ] * t4 + P [ 17 ] [ 0 ] * t14 + P [ 17 ] [ 6 ] * t9 - P [ 17 ] [ 5 ] * t11 - P [ 17 ] [ 1 ] * t17 + P [ 17 ] [ 2 ] * t20 + P [ 17 ] [ 3 ] * t24 ) ;
Kfusion [ 18 ] = t77 * ( P [ 18 ] [ 4 ] * t4 + P [ 18 ] [ 0 ] * t14 + P [ 18 ] [ 6 ] * t9 - P [ 18 ] [ 5 ] * t11 - P [ 18 ] [ 1 ] * t17 + P [ 18 ] [ 2 ] * t20 + P [ 18 ] [ 3 ] * t24 ) ;
Kfusion [ 19 ] = t77 * ( P [ 19 ] [ 4 ] * t4 + P [ 19 ] [ 0 ] * t14 + P [ 19 ] [ 6 ] * t9 - P [ 19 ] [ 5 ] * t11 - P [ 19 ] [ 1 ] * t17 + P [ 19 ] [ 2 ] * t20 + P [ 19 ] [ 3 ] * t24 ) ;
Kfusion [ 20 ] = t77 * ( P [ 20 ] [ 4 ] * t4 + P [ 20 ] [ 0 ] * t14 + P [ 20 ] [ 6 ] * t9 - P [ 20 ] [ 5 ] * t11 - P [ 20 ] [ 1 ] * t17 + P [ 20 ] [ 2 ] * t20 + P [ 20 ] [ 3 ] * t24 ) ;
Kfusion [ 21 ] = t77 * ( P [ 21 ] [ 4 ] * t4 + P [ 21 ] [ 0 ] * t14 + P [ 21 ] [ 6 ] * t9 - P [ 21 ] [ 5 ] * t11 - P [ 21 ] [ 1 ] * t17 + P [ 21 ] [ 2 ] * t20 + P [ 21 ] [ 3 ] * t24 ) ;
} else {
for ( uint8_t i = 16 ; i < = 21 ; i + + ) {
Kfusion [ i ] = 0.0f ;
}
}
if ( ! inhibitWindStates ) {
Kfusion [ 22 ] = t77 * ( P [ 22 ] [ 4 ] * t4 + P [ 22 ] [ 0 ] * t14 + P [ 22 ] [ 6 ] * t9 - P [ 22 ] [ 5 ] * t11 - P [ 22 ] [ 1 ] * t17 + P [ 22 ] [ 2 ] * t20 + P [ 22 ] [ 3 ] * t24 ) ;
Kfusion [ 23 ] = t77 * ( P [ 23 ] [ 4 ] * t4 + P [ 23 ] [ 0 ] * t14 + P [ 23 ] [ 6 ] * t9 - P [ 23 ] [ 5 ] * t11 - P [ 23 ] [ 1 ] * t17 + P [ 23 ] [ 2 ] * t20 + P [ 23 ] [ 3 ] * t24 ) ;
} else {
Kfusion [ 22 ] = 0.0f ;
Kfusion [ 23 ] = 0.0f ;
}
} else {
return ;
}
// calculate the innovation consistency test ratio
// TODO add tuning parameter for gate
bodyVelTestRatio [ obsIndex ] = sq ( innovBodyVel [ obsIndex ] ) / ( sq ( 5.0f ) * varInnovBodyVel [ obsIndex ] ) ;
// Check the innovation for consistency and don't fuse if out of bounds
// TODO also apply angular velocity magnitude check
if ( ( bodyVelTestRatio [ obsIndex ] ) < 1.0f ) {
// record the last time observations were accepted for fusion
prevBodyVelFuseTime_ms = imuSampleTime_ms ;
// notify first time only
if ( ! bodyVelFusionActive ) {
bodyVelFusionActive = true ;
GCS_MAVLINK : : send_statustext_all ( MAV_SEVERITY_INFO , " EKF3 IMU%u fusing odometry " , ( unsigned ) imu_index ) ;
}
// correct the covariance P = (I - K*H)*P
// take advantage of the empty columns in KH to reduce the
// number of operations
for ( unsigned i = 0 ; i < = stateIndexLim ; i + + ) {
for ( unsigned j = 0 ; j < = 6 ; j + + ) {
KH [ i ] [ j ] = Kfusion [ i ] * H_VEL [ j ] ;
}
for ( unsigned j = 7 ; j < = stateIndexLim ; j + + ) {
KH [ i ] [ j ] = 0.0f ;
}
}
for ( unsigned j = 0 ; j < = stateIndexLim ; j + + ) {
for ( unsigned i = 0 ; i < = stateIndexLim ; i + + ) {
ftype res = 0 ;
res + = KH [ i ] [ 0 ] * P [ 0 ] [ j ] ;
res + = KH [ i ] [ 1 ] * P [ 1 ] [ j ] ;
res + = KH [ i ] [ 2 ] * P [ 2 ] [ j ] ;
res + = KH [ i ] [ 3 ] * P [ 3 ] [ j ] ;
res + = KH [ i ] [ 4 ] * P [ 4 ] [ j ] ;
res + = KH [ i ] [ 5 ] * P [ 5 ] [ j ] ;
res + = KH [ i ] [ 6 ] * P [ 6 ] [ j ] ;
KHP [ i ] [ j ] = res ;
}
}
// Check that we are not going to drive any variances negative and skip the update if so
bool healthyFusion = true ;
for ( uint8_t i = 0 ; i < = stateIndexLim ; i + + ) {
if ( KHP [ i ] [ i ] > P [ i ] [ i ] ) {
healthyFusion = false ;
}
}
if ( healthyFusion ) {
// update the covariance matrix
for ( uint8_t i = 0 ; i < = stateIndexLim ; i + + ) {
for ( uint8_t j = 0 ; j < = stateIndexLim ; j + + ) {
P [ i ] [ j ] = P [ i ] [ j ] - KHP [ i ] [ j ] ;
}
}
// force the covariance matrix to be symmetrical and limit the variances to prevent ill-condiioning.
ForceSymmetry ( ) ;
ConstrainVariances ( ) ;
// correct the state vector
for ( uint8_t j = 0 ; j < = stateIndexLim ; j + + ) {
statesArray [ j ] = statesArray [ j ] - Kfusion [ j ] * innovBodyVel [ obsIndex ] ;
}
stateStruct . quat . normalize ( ) ;
} else {
// record bad axis
if ( obsIndex = = 0 ) {
faultStatus . bad_xvel = true ;
} else if ( obsIndex = = 1 ) {
faultStatus . bad_yvel = true ;
} else if ( obsIndex = = 2 ) {
faultStatus . bad_zvel = true ;
}
}
}
}
}
// select fusion of body odometry measurements
void NavEKF3_core : : SelectBodyOdomFusion ( )
{
// Check if the magnetometer has been fused on that time step and the filter is running at faster than 200 Hz
// If so, don't fuse measurements on this time step to reduce frame over-runs
// Only allow one time slip to prevent high rate magnetometer data preventing fusion of other measurements
if ( magFusePerformed & & ( dtIMUavg < 0.005f ) & & ! bodyVelFusionDelayed ) {
bodyVelFusionDelayed = true ;
return ;
} else {
bodyVelFusionDelayed = false ;
}
// Check for data at the fusion time horizon
if ( storedBodyOdm . recall ( bodyOdmDataDelayed , imuDataDelayed . time_ms ) ) {
// start performance timer
hal . util - > perf_begin ( _perf_FuseBodyOdom ) ;
// Fuse data into the main filter
FuseBodyVel ( ) ;
// stop the performance timer
hal . util - > perf_end ( _perf_FuseBodyOdom ) ;
}
}
# endif // HAL_CPU_CLASS