CogniPilot

MODELICA LIBRARY · ENGINEERING REFERENCE

function

Estimation.StrapdownINS.UKF.correctUnscented

Unscented measurement correction in local navigation coordinates

Public declarations

Explicit source declarations; dimensions, modifications and defaults are shown as written, without evaluation.

RoleNameTypeDimensions / attributes / defaultDescription
inputpredictedState
inputsigmaMeasurementReal[:, SigmaCount]Measurement function evaluated at sigma states from predicted covariance
inputmeasurementReal[size(sigmaMeasurement, 1)]
inputmeasurementCovarianceReal[size(sigmaMeasurement, 1), size(sigmaMeasurement, 1)]
inputinnovationGateReal= 0.0
outputcorrectedState
outputacceptedBoolean
outputrejectionReasonInteger
outputnormalizedInnovationSquaredReal

Modelica declarations and implementation

Show parameters, interfaces and source

Parameters, inputs, outputs, defaults and equations from the source file.

function correctUnscented
  "Unscented measurement correction in local navigation coordinates"
  input State predicted;
  input Real sigmaMeasurement[:, SigmaCount]
    "Measurement function evaluated at sigma states from predicted covariance";
  input Real measurement[size(sigmaMeasurement, 1)];
  input Real measurementCovariance[size(sigmaMeasurement, 1),
    size(sigmaMeasurement, 1)];
  input Real innovationGate = 0.0;
  output State corrected;
  output Boolean accepted;
  output Integer rejectionReason;
  output Real normalizedInnovationSquared;
protected
  Integer measurementLength = size(sigmaMeasurement, 1);
  Real nominal[16];
  Real sigmaState[16, SigmaCount];
  Real correctedNominal[16];
  Real sigma[TangentLength, SigmaCount];
  Boolean sigmaFactorized;
  Boolean innovationFactorized;
  Boolean inputsUsable;
  Real measurementMean[measurementLength];
  Real measurementDeviation[measurementLength];
  Real stateDeviation[TangentLength];
  Real residual[measurementLength];
  Real innovationCovariance[measurementLength, measurementLength];
  Real crossCovariance[TangentLength, measurementLength];
  Real augmentedRhs[measurementLength, TangentLength + 1];
  Real augmentedSolution[measurementLength, TangentLength + 1];
  Real gain[TangentLength, measurementLength];
  Real correction[TangentLength];
  Real attitudeCorrection;
  Real trustScale;
  Real posteriorCovariance[TangentLength, TangentLength];
  Real correctedCovariance[TangentLength, TangentLength];
algorithm
  nominal := stateVector(predicted);
  (sigma, sigmaFactorized) := sigmaTangents(predicted.covariance);
  for sigmaIndex in 1:SigmaCount loop
    sigmaState[:, sigmaIndex] := injectVector(
      nominal, sigma[:, sigmaIndex]);
  end for;

  measurementMean := zeros(measurementLength);
  for sigmaIndex in 2:SigmaCount loop
    measurementMean := measurementMean
      + SigmaWeight * sigmaMeasurement[:, sigmaIndex];
  end for;
  residual := measurement - measurementMean;
  measurementDeviation := sigmaMeasurement[:, 1] - measurementMean;
  innovationCovariance := measurementCovariance
    + transpose({CentralCovarianceWeight * measurementDeviation})
      * {measurementDeviation};
  crossCovariance := zeros(TangentLength, measurementLength);
  for sigmaIndex in 2:SigmaCount loop
    stateDeviation := localErrorVector(nominal, sigmaState[:, sigmaIndex]);
    measurementDeviation := sigmaMeasurement[:, sigmaIndex] - measurementMean;
    crossCovariance := crossCovariance
      + transpose({SigmaWeight * stateDeviation}) * {measurementDeviation};
    innovationCovariance := innovationCovariance
      + transpose({SigmaWeight * measurementDeviation}) * {measurementDeviation};
  end for;
  innovationCovariance := LinearAlgebra.symmetrize(innovationCovariance);
  augmentedRhs := zeros(measurementLength, TangentLength + 1);
  augmentedRhs[:, 1:TangentLength] := transpose(crossCovariance);
  augmentedRhs[:, TangentLength + 1] := residual;
  (augmentedSolution, innovationFactorized) := LinearAlgebra.solveSPD(
    innovationCovariance, augmentedRhs);
  normalizedInnovationSquared := residual
    * augmentedSolution[:, TangentLength + 1];

  inputsUsable := true;
  for row in 1:measurementLength loop
    inputsUsable := inputsUsable
      and abs(residual[row]) < Estimation.StrapdownINS.ESKF.FiniteMagnitudeLimit
      and measurementCovariance[row, row] > 0.0;
    for column in 1:measurementLength loop
      inputsUsable := inputsUsable
        and abs(measurementCovariance[row, column])
          < Estimation.StrapdownINS.ESKF.FiniteMagnitudeLimit;
    end for;
  end for;
  accepted := sigmaFactorized and innovationFactorized and inputsUsable
    and normalizedInnovationSquared >= 0.0
    and normalizedInnovationSquared
      < Estimation.StrapdownINS.ESKF.FiniteMagnitudeLimit
    and (innovationGate <= 0.0 or normalizedInnovationSquared
      <= innovationGate * measurementLength);
  rejectionReason := if accepted then
      Estimation.StrapdownINS.CorrectionAccepted
    elseif not inputsUsable then
      Estimation.StrapdownINS.CorrectionRejectedCovarianceUnusable
    elseif not sigmaFactorized or not innovationFactorized then
      Estimation.StrapdownINS.CorrectionRejectedFactorization
    else Estimation.StrapdownINS.CorrectionRejectedGate;

  if accepted then
    gain := transpose(augmentedSolution[:, 1:TangentLength]);
    correction := gain * residual;
    attitudeCorrection := sqrt(correction[7:9] * correction[7:9]);
    trustScale := if attitudeCorrection
        > Estimation.StrapdownINS.ESKF.MaxAttitudeCorrection_rad then
      Estimation.StrapdownINS.ESKF.MaxAttitudeCorrection_rad
        / attitudeCorrection else 1.0;
    gain := cat(1, gain[1:6, :], trustScale * gain[7:9, :],
      gain[10:TangentLength, :]);
    correction := gain * residual;
    correctedNominal := injectVector(
      nominal, correction);
    // The attitude trust region row-scales the optimal unscented gain. Once
    // modified it is an arbitrary gain, so P-K*S*K' is no longer the valid
    // covariance update. Use the general form driven by the same gain that
    // generated the applied state correction.
    posteriorCovariance := LinearAlgebra.symmetrize(
      predicted.covariance
        - gain * transpose(crossCovariance)
        - crossCovariance * transpose(gain)
        + gain * innovationCovariance * transpose(gain));
    correctedCovariance := LinearAlgebra.symmetrize(
      Estimation.StrapdownINS.ESKF.conjugateReset(
        LieGroups.SE23.Quat.right_jacobian(correction[1:9]),
        posteriorCovariance));
  else
    correctedNominal := nominal;
    correctedCovariance := predicted.covariance;
  end if;
  corrected := State(
    positionWorldEnu_m=correctedNominal[1:3],
    velocityWorldEnu_m_s=correctedNominal[4:6],
    quaternionWorldBody=correctedNominal[7:10],
    gyroscopeBiasBodyFlu_rad_s=correctedNominal[11:13],
    accelerometerBiasBodyFlu_m_s2=correctedNominal[14:16],
    covariance=correctedCovariance);
end correctUnscented;