model
Tests.EstimationTests
Initialization, prediction, correction, and failure invariants
Public declarations
Explicit source declarations; dimensions, modifications and defaults are shown as written, without evaluation.
| Role | Name | Type | Dimensions / attributes / default | Description |
|---|---|---|---|---|
| parameter | passed | Boolean | = run() |
Members
| Name | Kind | Description |
|---|---|---|
| run | function | Execute the static estimator assertions |
Modelica declarations and implementation
Show parameters, interfaces and source
Parameters, inputs, outputs, defaults and equations from the source file.
model EstimationTests "Initialization, prediction, correction, and failure invariants"
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;
parameter Boolean passed = run();
equation
assert(passed, "Estimator assertion function did not complete");
end EstimationTests;