model
Tests.CorrelatedGpsTests
Held-input uncertainty and correlated delayed GPS correction
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 |
Modelica declarations and implementation
Show parameters, interfaces and source
Parameters, inputs, outputs, defaults and equations from the source file.
model CorrelatedGpsTests
"Held-input uncertainty and correlated delayed GPS correction"
function run
output Boolean passed;
protected
constant Real pi = 2.0 * asin(1.0);
Real A[15, 15];
Real forwardInput[15, 6];
Real backwardInput[15, 6];
Real inputCovariance[6, 6];
Real H[1, 15];
Real C[15, 1];
Estimation.StrapdownINS.ESKF.State prior;
Estimation.StrapdownINS.ESKF.State corrected;
Avionics.GpsSample gps;
Boolean accepted;
Integer reason;
Real nis;
Real seedVariances[3];
algorithm
seedVariances := Estimation.StrapdownINS.ESKF.seedPositionVariances(
0.25 * identity(3), {1.0, 0.0, 0.0, 0.0}, fill(0.04, 3));
assert(max(abs(seedVariances - fill(0.25, 3))) < 1e-12,
"A noisy GPS seed retained an overconfident configured position prior");
seedVariances := Estimation.StrapdownINS.ESKF.seedPositionVariances(
diagonal({0.01, 0.09, 0.04}),
{cos(pi / 8), 0.0, 0.0, sin(pi / 8)},
{0.02, 0.02, 0.10});
assert(max(abs(seedVariances - {0.09, 0.09, 0.10})) < 1e-12,
"Seed covariance rotation, off-diagonal majorant or configured floor is wrong");
seedVariances := Estimation.StrapdownINS.ESKF.seedPositionVariances(
zeros(3, 3), {1.0, 0.0, 0.0, 0.0}, {0.02, 0.03, 0.04});
assert(max(abs(seedVariances - {0.02, 0.03, 0.04})) < 1e-12,
"An absent seed covariance changed the configured initialization policy");
prior := Estimation.StrapdownINS.ESKF.initialize(
zeros(3), {1.0, 0.0, 0.0, 0.0},
Estimation.StrapdownINS.InitialVariances(
position_m2=fill(0.04, 3), velocity_m2_s2=fill(0.01, 3),
attitude_rad2=fill(0.01, 3), gyroscopeBias_rad2_s2=fill(0.01, 3),
accelerometerBias_m2_s4=fill(0.01, 3)),
zeros(3), zeros(3), zeros(3), 0.25 * identity(3));
assert(abs(prior.covariance[1, 1] - 0.25) < 1e-12,
"Initializer discarded the uncertainty of the supplied aiding seed");
A := Estimation.StrapdownINS.ESKF.continuousTransition(zeros(3), zeros(3));
forwardInput := Estimation.StrapdownINS.ESKF.heldInputJacobian(A, 0.01);
backwardInput := Estimation.StrapdownINS.ESKF.heldInputJacobian(A, -0.11);
assert(abs(forwardInput[4, 4] + 0.01) < 1e-12
and abs(forwardInput[1, 4] + 0.00005) < 1e-12
and abs(backwardInput[4, 4] - 0.11) < 1e-12
and abs(backwardInput[1, 4] + 0.00605) < 1e-12,
"Held-input transport has the wrong sign or integration interval");
prior := Estimation.StrapdownINS.ESKF.initialize(
zeros(3), {1.0, 0.0, 0.0, 0.0},
Estimation.StrapdownINS.InitialVariances(
position_m2=fill(0.01, 3), velocity_m2_s2=fill(0.0103, 3),
attitude_rad2=fill(0.01, 3), gyroscopeBias_rad2_s2=fill(0.01, 3),
accelerometerBias_m2_s4=fill(0.01, 3)));
H := zeros(1, 15);
H[1, 4] := 1.0;
C := zeros(15, 1);
C[4, 1] := -0.0033;
// P=0.0103, C=-0.0033, R=0.0463 give S=0.05 and K=0.14.
// The generalized Joseph posterior is P-(P+C)^2/S=0.00932.
(corrected, accepted, reason, nis) :=
Estimation.StrapdownINS.ESKF.correctLinear(
prior, {0.1}, H, {{0.0463}}, 0.0, zeros(3), C);
assert(accepted and abs(corrected.velocityWorldEnu_m_s[1] - 0.014) < 1e-10
and abs(corrected.covariance[4, 4] - 0.00932) < 1e-10
and abs(nis - 0.2) < 1e-10,
"Correlated observation gain, NIS or Joseph covariance is wrong");
C[4, 1] := 0.04;
(corrected, accepted, reason, nis) :=
Estimation.StrapdownINS.ESKF.correctLinear(
prior, {0.1}, H, {{0.01}}, 0.0, zeros(3), C);
assert(not accepted
and reason == Estimation.StrapdownINS.CorrectionRejectedCovarianceUnusable
and max(abs(corrected.covariance - prior.covariance)) == 0.0
and max(abs(corrected.velocityWorldEnu_m_s
- prior.velocityWorldEnu_m_s)) == 0.0,
"An impossible joint covariance passed a positive innovation check");
inputCovariance := cat(1, cat(2, zeros(3, 3), zeros(3, 3)),
cat(2, zeros(3, 3), 3.0 * identity(3)));
prior := Estimation.StrapdownINS.ESKF.State(
barometerBiasCrossCovariance=zeros(15),
barometerBias_m=0.0, barometerBiasVariance_m2=0.0, useJointBarometerBias=false,
positionWorldEnu_m=zeros(3), velocityWorldEnu_m_s=zeros(3),
quaternionWorldBody={1.0, 0.0, 0.0, 0.0},
gyroscopeBiasBodyFlu_rad_s=zeros(3), accelerometerBiasBodyFlu_m_s2=zeros(3),
covariance=0.01 * identity(15)
+ forwardInput * inputCovariance * transpose(forwardInput),
useSquareRootCovariance=false, covarianceRoot=zeros(15, 15));
gps := Avionics.GpsSample(valid=true, fresh=true, timestamp_s=-0.11,
positionValid=true, velocityValid=true, geodetic_deg_m=zeros(3),
positionWorldEnu_m=zeros(3), velocityWorldEnu_m_s={0.1, 0.0, 0.0},
positionCovarianceWorld_m2=0.25 * identity(3),
velocityCovarianceWorld_m2_s2=0.01 * identity(3));
(corrected, accepted, reason, nis) := Estimation.StrapdownINS.ESKF.correctGps(
prior, gps, 0.0, 0.11, zeros(3), zeros(3), zeros(3), 0.25,
inputCovariance, 0.01);
// Independent linear-Gaussian reference for each {position,velocity,bias}
// block, with the newest sample present in both forward and backward maps.
assert(accepted
and abs(corrected.positionWorldEnu_m[1] - 0.00017005291263822) < 1e-10
and abs(corrected.velocityWorldEnu_m_s[1] - 0.01395448391363927) < 1e-10
and abs(corrected.covariance[4, 4] - 0.00932104565798844) < 1e-10
and abs(nis - 0.1996211731027336) < 1e-10,
"Delayed GPS does not marginalize the held-input uncertainty and correlation");
passed := true;
end run;
parameter Boolean passed = run();
equation
assert(passed, "Correlated delayed GPS checks did not complete");
end CorrelatedGpsTests;