CogniPilot

MODELICA LIBRARY · ENGINEERING REFERENCE

function

Tests.EstimationTests.run

Execute the static estimator assertions

Public declarations

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

RoleNameTypeDimensions / attributes / defaultDescription
outputpassedBoolean

Modelica declarations and implementation

Show parameters, interfaces and source

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

function run "Execute the static estimator assertions"
    output Boolean passed;
  protected
    constant Real tolerance = 1.0e-9;
    Estimation.MocapExternalOdometryErrorState.InitialVariances initialVariances;
    Estimation.MocapExternalOdometryErrorState.InitialVariances zeroVariances;
    Estimation.MocapExternalOdometryErrorState.ProcessNoise noProcessNoise;
    Estimation.MocapExternalOdometryErrorState.ProcessNoise processNoise;
    Estimation.MocapExternalOdometryErrorState.PoseMeasurement exactMeasurement;
    Estimation.MocapExternalOdometryErrorState.PoseMeasurement negativeQuaternionMeasurement;
    Estimation.MocapExternalOdometryErrorState.PoseMeasurementNoise measurementNoise;
    Estimation.MocapExternalOdometryErrorState.PoseMeasurementNoise zeroMeasurementNoise;
    Estimation.MocapExternalOdometryErrorState.State initialized;
    Estimation.MocapExternalOdometryErrorState.State moving;
    Estimation.MocapExternalOdometryErrorState.State zeroDtPrediction;
    Estimation.MocapExternalOdometryErrorState.State predicted;
    Estimation.MocapExternalOdometryErrorState.State corrected;
    Estimation.MocapExternalOdometryErrorState.State signCorrected;
    Estimation.MocapExternalOdometryErrorState.State zeroState;
    Estimation.MocapExternalOdometryErrorState.State rejectedState;
    Estimation.MocapExternalOdometryErrorState.State skippedState;
    Estimation.MocapExternalOdometryErrorState.NominalState injected;
    Estimation.MocapExternalOdometryErrorState.Covariance transition;
    Estimation.MocapExternalOdometryErrorState.Covariance discreteNoise;
    Estimation.MocapExternalOdometryErrorState.MeasurementMatrix measurementMatrix;
    Real expectedAttitudeTransition[3, 3];
    Boolean accepted;
    Boolean signAccepted;
    Boolean rejected;
    Boolean skippedAccepted;
  algorithm
  initialVariances := Estimation.MocapExternalOdometryErrorState.InitialVariances(
    attitude=0.04,
    velocity=0.09,
    position=0.16,
    angularVelocity=0.25);
  zeroVariances := Estimation.MocapExternalOdometryErrorState.InitialVariances(
    attitude=0.0,
    velocity=0.0,
    position=0.0,
    angularVelocity=0.0);
  noProcessNoise := Estimation.MocapExternalOdometryErrorState.ProcessNoise(
    attitude=0.0,
    velocity=0.0,
    position=0.0,
    angularVelocity=0.0);
  processNoise := Estimation.MocapExternalOdometryErrorState.ProcessNoise(
    attitude=1.0e-5,
    velocity=2.0e-4,
    position=3.0e-6,
    angularVelocity=4.0e-5);
  measurementNoise := Estimation.MocapExternalOdometryErrorState.PoseMeasurementNoise(
    attitude=1.0e-4,
    position=4.0e-4);
  zeroMeasurementNoise := Estimation.MocapExternalOdometryErrorState.PoseMeasurementNoise(
    attitude=0.0,
    position=0.0);

  initialized := Estimation.MocapExternalOdometryErrorState.initialize(
    {1.0, -2.0, 3.0},
    {2.0, 0.0, 0.0, 0.0},
    initialVariances);
  moving.attitude := initialized.attitude;
  moving.velocity := {2.0, -1.0, 0.5};
  moving.position := initialized.position;
  moving.angularVelocity := {0.1, -0.2, 0.3};
  moving.covariance := initialized.covariance;
  zeroDtPrediction := Estimation.MocapExternalOdometryErrorState.predict(
    moving,
    0.0,
    processNoise);
  predicted := Estimation.MocapExternalOdometryErrorState.predict(
    moving,
    0.1,
    processNoise);
  transition := Estimation.MocapExternalOdometryErrorState.tangentTransition(
    0.1, moving.angularVelocity);
  expectedAttitudeTransition := transpose(LieGroups.SO3.Quat.to_DCM(
    LieGroups.SO3.Quat.exp_map(0.1 * moving.angularVelocity)));
  discreteNoise := Estimation.MocapExternalOdometryErrorState.discreteProcessCovariance(
    0.1, processNoise);
  measurementMatrix := Estimation.MocapExternalOdometryErrorState.poseMeasurementMatrix();

  exactMeasurement := Estimation.MocapExternalOdometryErrorState.PoseMeasurement(
    position=predicted.position,
    attitude=predicted.attitude);
  negativeQuaternionMeasurement := Estimation.MocapExternalOdometryErrorState.PoseMeasurement(
    position=predicted.position,
    attitude=-predicted.attitude);
  (corrected, accepted) := Estimation.MocapExternalOdometryErrorState.correct(
    predicted,
    exactMeasurement,
    measurementNoise);
  (signCorrected, signAccepted) := Estimation.MocapExternalOdometryErrorState.correct(
    predicted,
    negativeQuaternionMeasurement,
    measurementNoise);

  zeroState := Estimation.MocapExternalOdometryErrorState.initialize(
    zeros(3),
    {1.0, 0.0, 0.0, 0.0},
    zeroVariances);
  (rejectedState, rejected) := Estimation.MocapExternalOdometryErrorState.correct(
    zeroState,
    Estimation.MocapExternalOdometryErrorState.PoseMeasurement(
      position=zeros(3),
      attitude={1.0, 0.0, 0.0, 0.0}),
    zeroMeasurementNoise);
  (skippedState, skippedAccepted) := Estimation.MocapExternalOdometryErrorState.step(
    moving,
    0.1,
    false,
    exactMeasurement,
    processNoise,
    measurementNoise);
  injected := Estimation.MocapExternalOdometryErrorState.inject(
    Estimation.MocapExternalOdometryErrorState.NominalState(
      attitude=moving.attitude,
      velocity=moving.velocity,
      position=moving.position,
      angularVelocity=moving.angularVelocity),
    {0.0, 0.0, 0.1, 1.0, 2.0, 3.0, -1.0, -2.0, -3.0, 0.4, 0.5, 0.6});

  assert(Tests.Assertions.maxAbsVector(initialized.attitude - {1, 0, 0, 0}) < tolerance,
    "geometric error-state EKF initialization did not normalize attitude");
  assert(Tests.Assertions.maxAbsVector(initialized.velocity) < tolerance,
    "geometric error-state EKF initialization velocity was not zero");
  assert(Tests.Assertions.maxAbsVector(initialized.position - {1, -2, 3}) < tolerance,
    "geometric error-state EKF initialization position was incorrect");
  assert(abs(initialized.covariance[1, 1] - 0.04) < tolerance and
         abs(initialized.covariance[4, 4] - 0.09) < tolerance and
         abs(initialized.covariance[7, 7] - 0.16) < tolerance and
         abs(initialized.covariance[10, 10] - 0.25) < tolerance,
    "geometric error-state EKF initialization covariance ordering was incorrect");
  assert(Tests.Assertions.maxAbsVector(zeroDtPrediction.position - moving.position) < tolerance and
         Tests.Assertions.maxAbsMatrix(zeroDtPrediction.covariance - moving.covariance) < tolerance,
    "geometric error-state EKF zero-duration prediction was not an identity");
  assert(Tests.Assertions.maxAbsVector(
      predicted.position - (moving.position + 0.1 * moving.velocity)) < tolerance,
    "geometric error-state EKF constant-velocity position prediction failed");
  assert(Tests.Assertions.maxAbsMatrix(
           transition[1:3, 1:3] - expectedAttitudeTransition) < tolerance and
         abs(transition[7, 4] - 0.1) < tolerance and
         abs(discreteNoise[1, 1] - 0.1 * processNoise.attitude) < tolerance and
         abs(measurementMatrix[1, 1] - 1.0) < tolerance and
         abs(measurementMatrix[4, 7] - 1.0) < tolerance,
    "Separated estimator transition/noise/measurement maps were inconsistent");
  assert(abs(predicted.attitude * predicted.attitude - 1.0) < tolerance,
    "geometric error-state EKF prediction did not preserve quaternion norm");
  assert(Tests.Assertions.maxAbsMatrix(
      predicted.covariance - transpose(predicted.covariance)) < tolerance,
    "geometric error-state EKF prediction covariance was not symmetric");
  assert(accepted and signAccepted,
    "geometric error-state EKF rejected a positive-definite innovation covariance");
  assert(Tests.Assertions.maxAbsVector(corrected.position - predicted.position) < tolerance and
         Tests.Assertions.maxAbsVector(signCorrected.position - predicted.position) < tolerance,
    "A zero-residual geometric error-state EKF correction changed the nominal position");
  assert(abs(abs(corrected.attitude * predicted.attitude) - 1.0) < tolerance and
         abs(abs(signCorrected.attitude * predicted.attitude) - 1.0) < tolerance,
    "A zero-residual or sign-equivalent quaternion correction changed attitude");
  assert(corrected.covariance[1, 1] < predicted.covariance[1, 1] and
         corrected.covariance[7, 7] < predicted.covariance[7, 7],
    "geometric error-state EKF correction did not reduce observed covariance");
  assert(Tests.Assertions.maxAbsMatrix(
      corrected.covariance - transpose(corrected.covariance)) < tolerance,
    "geometric error-state EKF corrected covariance was not symmetric");
  assert(not rejected and Tests.Assertions.maxAbsMatrix(
         rejectedState.covariance - zeroState.covariance) < tolerance,
    "geometric error-state EKF singular innovation handling failed");
  assert(not skippedAccepted and Tests.Assertions.maxAbsMatrix(
         skippedState.covariance - predicted.covariance) < tolerance,
    "geometric error-state EKF skipped correction did not return prediction");
  assert(Tests.Assertions.maxAbsVector(injected.velocity - (moving.velocity + {1, 2, 3})) < tolerance and
         Tests.Assertions.maxAbsVector(injected.position - (moving.position - {1, 2, 3})) < tolerance and
         Tests.Assertions.maxAbsVector(injected.angularVelocity - (moving.angularVelocity + {0.4, 0.5, 0.6})) < tolerance,
    "geometric error-state EKF tangent injection ordering failed");
  for i in 1:12 loop
    assert(corrected.covariance[i, i] >= -tolerance,
      "geometric error-state EKF corrected covariance had a negative diagonal");
  end for;
  passed := true;
  end run;