CogniPilot

MODELICA LIBRARY · ENGINEERING REFERENCE

Estimation/StrapdownINS/ESKF/correctBarometer.mo

Download original .moGitHub source

Documentation: Estimation.StrapdownINS.ESKF.correctBarometer

within Estimation.StrapdownINS.ESKF;

function correctBarometer
  "Correct vertical position from pressure altitude after bias compensation"
  input State predicted;
  input Avionics.BarometerSample measurement;
  input Real barometerBias_m;
  input Real barometerBiasVariance_m2;
  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 Boolean useSemiDirectBias = false;
  input Boolean useBarometerBiasConsider = false;
  input Real barometerBiasProcessNoise_m2_s = 0.0;
  output State corrected;
  output Boolean accepted;
  output Integer rejectionReason;
  output Real normalizedInnovationSquared;
protected
  Real delayedPosition[3];
  Real delayedQuaternion[4];
  Real delayedStateVector[16];
  Real currentToDelayed[TangentLength, TangentLength];
  Real rotationWorldBody[3, 3];
  Real residual[1];
  Real delayedH[1, TangentLength];
  Real H[1, TangentLength];
  Real measurementCovariance[1, 1];
  Real measurementStateCrossCovariance[TangentLength, 1];
  Real measurementBarometerCrossCovariance[1];
  Real observationBiasVariance_m2;
  Real bias_m;
  Real biasVariance_m2;
  Real verticalDirectionLocal[3];
  Real verticalVariance_m2;
  Real covarianceFloor[TangentLength, TangentLength];
  Real floorIncrement_m2;
  Real verticalRoot[TangentLength];
  Real floorColumns[TangentLength, TangentLength + 1];
  State candidate;
  Boolean candidateAccepted;
  Integer candidateRejectionReason;
  Real candidateNis;
algorithm
  delayedStateVector := retrodict(predicted,
    angularVelocityMeasuredBodyFlu_rad_s,
    specificForceMeasuredBodyFlu_m_s2, gravityWorldEnu_m_s2,
    max(measurementAge_s, 0.0));
  delayedPosition := delayedStateVector[1:3];
  delayedQuaternion := delayedStateVector[7:10];
  currentToDelayed := discreteTransition(continuousTransition(
    angularVelocityMeasuredBodyFlu_rad_s
      - predicted.gyroscopeBiasBodyFlu_rad_s,
    specificForceMeasuredBodyFlu_m_s2
      - predicted.accelerometerBiasBodyFlu_m_s2),
    -max(measurementAge_s, 0.0));
  rotationWorldBody := LieGroups.SO3.Quat.to_DCM(
    delayedQuaternion);
  bias_m := barometerBias_m;
  biasVariance_m2 := barometerBiasVariance_m2;
  if predicted.useJointBarometerBias then
    bias_m := predicted.barometerBias_m;
    biasVariance_m2 := predicted.barometerBiasVariance_m2;
  end if;
  residual[1] := measurement.altitudeWorldEnu_m - bias_m
    - delayedPosition[3];
  delayedH := zeros(1, TangentLength);
  delayedH[1, 1:3] := rotationWorldBody[3, :];
  H := delayedH * currentToDelayed;
  measurementCovariance[1, 1] := measurement.variance_m2
    + max(biasVariance_m2, 0.0);
  measurementStateCrossCovariance := zeros(TangentLength, 1);
  measurementBarometerCrossCovariance := zeros(1);
  observationBiasVariance_m2 := biasVariance_m2;
  if useBarometerBiasConsider or predicted.useJointBarometerBias then
    observationBiasVariance_m2 := biasVariance_m2
      - max(barometerBiasProcessNoise_m2_s, 0.0) * max(measurementAge_s, 0.0);
    measurementCovariance[1, 1] := measurement.variance_m2
      + observationBiasVariance_m2;
    measurementStateCrossCovariance :=
      transpose({predicted.barometerBiasCrossCovariance});
    measurementBarometerCrossCovariance[1] := observationBiasVariance_m2;
  end if;
  candidate := copyState(predicted);
  candidateAccepted := false;
  candidateNis := 0.0;
  if measurementAge_s < -1.0e-6
      or measurementAge_s > maximumAidingDelay_s then
    candidateRejectionReason := CorrectionRejectedTimestamp;
  elseif (useBarometerBiasConsider or predicted.useJointBarometerBias)
      and not (observationBiasVariance_m2 >= 0.0
      and observationBiasVariance_m2 < FiniteMagnitudeLimit) then
    candidateRejectionReason := CorrectionRejectedCovarianceUnusable;
  else
    (candidate, candidateAccepted, candidateRejectionReason, candidateNis) :=
      correctLinear(predicted, residual, H, measurementCovariance,
        innovationGate, zeros(3), measurementStateCrossCovariance,
        false, useSemiDirectBias, measurementBarometerCrossCovariance);
  end if;
  // The learned pressure datum is one common nuisance variable, not a new
  // independent error on every packet. Preserve its posterior uncertainty.
  verticalDirectionLocal := rotationWorldBody[3, :];
  if candidate.useSquareRootCovariance then
    verticalRoot := verticalDirectionLocal * candidate.covarianceRoot[1:3, :];
    verticalVariance_m2 := verticalRoot * verticalRoot;
  else
    verticalVariance_m2 := verticalDirectionLocal
      * candidate.covariance[1:3, 1:3] * verticalDirectionLocal;
  end if;
  floorIncrement_m2 := if candidateAccepted then
    max(barometerBiasVariance_m2 - verticalVariance_m2, 0.0) else 0.0;
  covarianceFloor := zeros(TangentLength, TangentLength);
  covarianceFloor[1:3, 1:3] := floorIncrement_m2
    * transpose({verticalDirectionLocal}) * {verticalDirectionLocal};
  if useBarometerBiasConsider or predicted.useJointBarometerBias then
    corrected := copyState(candidate);
  elseif candidate.useSquareRootCovariance then
    floorColumns := zeros(TangentLength, TangentLength + 1);
    floorColumns[:, 1:TangentLength] := candidate.covarianceRoot;
    floorColumns[:, TangentLength + 1] := cat(1,
      sqrt(floorIncrement_m2) * verticalDirectionLocal, zeros(TangentLength - 3));
    corrected := withCovarianceRoot(candidate,
      LinearAlgebra.covarianceRoot(floorColumns), candidate.barometerBiasCrossCovariance);
  else
    corrected := withDenseCovariance(candidate, LinearAlgebra.symmetrize(
      candidate.covariance + covarianceFloor), candidate.barometerBiasCrossCovariance);
  end if;
  accepted := candidateAccepted;
  rejectionReason := candidateRejectionReason;
  normalizedInnovationSquared := candidateNis;
end correctBarometer;