Estimation/StrapdownINS/UKF/correctOpticalFlow.mo
Download original .moGitHub source
Documentation: Estimation.StrapdownINS.UKF.correctOpticalFlow
within Estimation.StrapdownINS.UKF;
function correctOpticalFlow
"Unscented body-velocity correction from co-timed flow and range"
input State predicted;
input Avionics.OpticalFlowSample measurement;
input Real innovationGate = 0.0;
input Real measurementAge_s(unit = "s") = 0.0;
input Real angularVelocityMeasuredBodyFlu_rad_s[3] = zeros(3);
input Real specificForceMeasuredBodyFlu_m_s2[3] = zeros(3);
input Real gravityWorldEnu_m_s2[3] = {0.0, 0.0, -9.81};
input Real maximumAidingDelay_s(unit = "s") = 0.25;
input Real minimumQuality = 0.2;
input Real minimumGroundDistance_m(unit = "m") = 0.2;
output State corrected;
output Boolean accepted;
output Integer rejectionReason;
output Real normalizedInnovationSquared;
protected
Real nominal[16];
Real sigmaState[16];
Real delayedSigmaState[16];
Real sigma[TangentLength, SigmaCount];
Boolean sigmaUsable;
Boolean geometryUsable;
Real rotationWorldBody[3, 3];
Real velocityBody[3];
Real sigmaMeasurement[2, SigmaCount];
Real compensatedFlow_rad[2];
Real measured[2];
Real flowCovariance_rad2[2, 2];
Real measurementCovariance[2, 2];
Real velocityRangeDerivative_s[2];
Real safeIntegrationTime_s;
Real safeGroundDistance_m;
Boolean measurementFinite;
Boolean covarianceUsable;
algorithm
measurementFinite := abs(measurement.timestamp_s)
< Estimation.StrapdownINS.ESKF.FiniteMagnitudeLimit
and abs(measurement.integrationTime_s)
< Estimation.StrapdownINS.ESKF.FiniteMagnitudeLimit
and abs(measurement.groundDistance_m)
< Estimation.StrapdownINS.ESKF.FiniteMagnitudeLimit
and abs(measurement.groundDistanceVariance_m2)
< Estimation.StrapdownINS.ESKF.FiniteMagnitudeLimit
and abs(measurement.quality)
< Estimation.StrapdownINS.ESKF.FiniteMagnitudeLimit;
covarianceUsable := measurement.groundDistanceVariance_m2 >= 0.0;
for row in 1:2 loop
measurementFinite := measurementFinite
and abs(measurement.integratedLineOfSight_rad[row])
< Estimation.StrapdownINS.ESKF.FiniteMagnitudeLimit
and abs(measurement.integratedGyroscopeBodyFlu_rad[row])
< Estimation.StrapdownINS.ESKF.FiniteMagnitudeLimit;
covarianceUsable := covarianceUsable
and measurement.integratedLineOfSightCovariance_rad2[row, row] > 0.0
and measurement.integratedGyroscopeCovariance_rad2[row, row] > 0.0;
for column in 1:2 loop
covarianceUsable := covarianceUsable
and abs(measurement.integratedLineOfSightCovariance_rad2[row, column])
< Estimation.StrapdownINS.ESKF.FiniteMagnitudeLimit
and abs(measurement.integratedGyroscopeCovariance_rad2[row, column])
< Estimation.StrapdownINS.ESKF.FiniteMagnitudeLimit;
end for;
end for;
measurementFinite := measurementFinite
and abs(measurement.integratedGyroscopeBodyFlu_rad[3])
< Estimation.StrapdownINS.ESKF.FiniteMagnitudeLimit;
covarianceUsable := covarianceUsable
and measurement.integratedGyroscopeCovariance_rad2[3, 3] > 0.0;
nominal := stateVector(predicted);
(sigma, sigmaUsable) := sigmaTangents(predicted.covariance);
geometryUsable := measurement.integrationTime_s > 0.0
and measurement.groundDistance_m >= minimumGroundDistance_m
and measurement.groundDistanceVariance_m2 >= 0.0;
for sigmaIndex in 1:SigmaCount loop
sigmaState := injectVector(nominal, sigma[:, sigmaIndex]);
delayedSigmaState := predictNominalVector(sigmaState,
angularVelocityMeasuredBodyFlu_rad_s,
specificForceMeasuredBodyFlu_m_s2, gravityWorldEnu_m_s2,
-max(measurementAge_s, 0.0));
rotationWorldBody := LieGroups.SO3.Quat.to_DCM(
delayedSigmaState[7:10]);
velocityBody := transpose(rotationWorldBody)
* delayedSigmaState[4:6];
sigmaMeasurement[:, sigmaIndex] := velocityBody[1:2];
end for;
compensatedFlow_rad := measurement.integratedLineOfSight_rad
+ measurement.integratedGyroscopeBodyFlu_rad[1:2];
safeIntegrationTime_s := max(abs(measurement.integrationTime_s), 1.0e-9);
safeGroundDistance_m := max(measurement.groundDistance_m,
minimumGroundDistance_m);
measured := safeGroundDistance_m / safeIntegrationTime_s
* {compensatedFlow_rad[2], -compensatedFlow_rad[1]};
flowCovariance_rad2 := measurement.integratedLineOfSightCovariance_rad2
+ measurement.integratedGyroscopeCovariance_rad2[1:2, 1:2];
measurementCovariance := (safeGroundDistance_m
/ safeIntegrationTime_s)^2 * [
flowCovariance_rad2[2, 2], -flowCovariance_rad2[2, 1];
-flowCovariance_rad2[1, 2], flowCovariance_rad2[1, 1]];
velocityRangeDerivative_s := {
compensatedFlow_rad[2] / safeIntegrationTime_s,
-compensatedFlow_rad[1] / safeIntegrationTime_s};
measurementCovariance := measurementCovariance
+ max(measurement.groundDistanceVariance_m2, 0.0)
* transpose({velocityRangeDerivative_s}) * {velocityRangeDerivative_s};
corrected := State(
positionWorldEnu_m=predicted.positionWorldEnu_m,
velocityWorldEnu_m_s=predicted.velocityWorldEnu_m_s,
quaternionWorldBody=predicted.quaternionWorldBody,
gyroscopeBiasBodyFlu_rad_s=predicted.gyroscopeBiasBodyFlu_rad_s,
accelerometerBiasBodyFlu_m_s2=predicted.accelerometerBiasBodyFlu_m_s2,
covariance=predicted.covariance);
accepted := false;
normalizedInnovationSquared := 0.0;
if not measurementFinite then
rejectionReason := Estimation.StrapdownINS.CorrectionRejectedNotFinite;
elseif measurementAge_s < -1.0e-6
or measurementAge_s > maximumAidingDelay_s then
rejectionReason := Estimation.StrapdownINS.CorrectionRejectedTimestamp;
elseif not sigmaUsable or not geometryUsable or not covarianceUsable
or measurement.quality < minimumQuality then
rejectionReason :=
Estimation.StrapdownINS.CorrectionRejectedCovarianceUnusable;
else
(corrected, accepted, rejectionReason, normalizedInnovationSquared) :=
correctUnscented(predicted, sigmaMeasurement,
measured, measurementCovariance, innovationGate);
end if;
end correctOpticalFlow;