Covariance inconsistency with BoundedPropagator and different initial state epoch

Hi everyone,

We recently stumbled upon an issue related to the StateCovarianceMatrixProvider in combination with a generated ephemeris (BoundedPropagator). The problem is that the initial state of the BoundedPropagator might be at a different epoch than the initial covariance. When propagate is called, the StateCovarianceMatrixProvider is initialised again, based on the wrong initial state.

Below is a minimal example to reproduce the problem, but I’ll list the steps as well:

  • Create an initial state and Cartesian covariance at time t_0.
  • Create a numerical propagator with EQUINOCTIAL orbit type
  • Set up MatricesHarvester and add StateCovarianceMatrixProvider to the propagator
  • Now generate an ephemeris for the interval [t_0 - \Delta t, t_0 + \Delta t]
    • This correctly calls init on the StateCovarianceMatrixProvider, which internally converts the initial covariance to EQUINOCTIAL elements using the initial state at time t_0
  • From the ephemeris, get the covariance matrix at time t_0 – this should be the same as the initial covariance that was originally provided.
    • BoundedPropagator.propagate(t_0) incorrectly calls init again, passing its initial state (which is at t_0 - \Delta t) and the initial covariance (provided at t_0) is now wrongly converted to EQUINOCTIAL elements again.
   @Test
  void testInconsistentCovarianceBoundedPropagator() {

    // Some constants
    final Frame frame = FramesFactory.getGCRF();
    final PositionAngleType angleType = PositionAngleType.MEAN;
    final AbsoluteDate initialDate = AbsoluteDate.ARBITRARY_EPOCH;
    final double mu = Constants.GRS80_EARTH_MU;
    final String stmName = "STM";
    final String covName = "CART_COV";
    final double dt = 3600.0; // seconds

    // Setup initial state and covariance
    final Orbit initOrbit = new KeplerianOrbit(7.0e6, 1.e-4, 0.1, 0., 0., 0., angleType, frame, initialDate, mu);
    final SpacecraftState initState = new SpacecraftState(initOrbit);
    final RealMatrix initCartCovariance = MatrixUtils.createRealDiagonalMatrix(new double[]{1., 1., 1., 1.e-3, 1.e-3, 1.e-3});
    final StateCovariance initStateCovariance =
        new StateCovariance(initCartCovariance, initialDate, frame, OrbitType.CARTESIAN, angleType);

    // Numerical propagator with EQUINOCTIAL ELEMENTS
    NumericalPropagator propagator = new NumericalPropagator(new ClassicalRungeKuttaIntegrator(60.));
    propagator.setOrbitType(OrbitType.EQUINOCTIAL);
    propagator.setInitialState(initState);

    // Create covariance matrix provider with initial covariance in CARTESIAN elements
    final MatricesHarvester harvester =
        propagator.setupMatricesComputation(stmName, null, null);
    final StateCovarianceMatrixProvider provider =
        new StateCovarianceMatrixProvider(covName, stmName, harvester, initStateCovariance);
    propagator.addAdditionalDataProvider(provider);

    // Propagate and store ephemeris on [t0 - dt, t0 + dt]
    final EphemerisGenerator generator = propagator.getEphemerisGenerator();
    propagator.propagate(initialDate.shiftedBy(-dt), initialDate.shiftedBy(dt));
    final BoundedPropagator ephemeris = generator.getGeneratedEphemeris();

    // Propagate ephemeris
    SpacecraftState propagated = ephemeris.propagate(initState.getDate());
    final StateCovariance propagatedStateCov = provider.getStateCovariance(propagated);

    // Verify that both covariances are equal
    Assertions.assertEquals(initState.getDate(), propagatedStateCov.getDate());
    Assertions.assertEquals(provider.getCovarianceOrbitType(), propagatedStateCov.getOrbitType());
    compareCovariance(initCartCovariance, propagatedStateCov.getMatrix(), 1.e-4);
  }

This produces the following error:

[ERROR] org.orekit.propagation.covariance.TmpTest.testInconsistentCovarianceBoundedPropagator -- Time elapsed: 0.602 s <<< FAILURE!
org.opentest4j.AssertionFailedError: expected: <1.0> but was: <10805.9618930703>

A minimal fix that makes the test pass could be to add an early return in StateCovarianceMatrixProvider.init(...) if it was already initialised before. However, I’m wondering if there might be reasons why this would be a bad idea.

Best,
Simon

Hi Simon,

thanks for reporting this.
I think there are several problems here actually.
The test still doesn’t pass if you only add the covariance provider on the BoundedPropagator, so it’s not just a question of calling init twice.
Looking at the init function, I see that the initialState has no reason to be at the same epoch than the original input covariance matrix… but what to do then? I need to look further.

Cheers,
Romain.

Hi Romain,

Thanks for your response.

What do you mean by this? The init method calls .changeCovarianceType. Internally, this computes the Jacobian of the orbital elements (EQUINOCTIAL in the test case), w.r.t. the Cartesian state. This will be different if the initialOrbit is at an inconsistent epoch, right?

    @Override
    public void init(final SpacecraftState initialState, final AbsoluteDate target) {

        // Convert the initial state covariance in the same orbit type and frame as the STM
        final Orbit initialOrbit = initialState.getOrbit();
        StateCovariance covariance = covInit.changeCovarianceFrame(initialOrbit, initialState.getFrame());
        covariance = covariance.changeCovarianceType(initialOrbit, stmOrbitType, stmAngleType);

        covMatrixInit = covariance.getMatrix();
    }

Do you mean ephemeris.addAdditionalDataProvider(provider);? I think it is expected that this does not pass, because the ephemeris initial state is at t_0 - \Delta t. So, inconsistent with the initial covariance in the provider (at t_0).

The test passes for me if I add this early return at the start of the init method:

        // Early return if the matrix provider is already initialised
        if (covMatrixInit != null) {
            // Maybe good to check that the frame and orbit type used to initialise are consistent with the initialState.
            return;
        }
        // If it still needs to be initialised, the initial state epoch should be consistent

Cheers,
Simon

Hi,

There was confusion between covariance Epoch and initial propagation time. I’ve done a fix, covering your case, that will be released in the next patch.

Cheers,
Romain.

Thank you very much, Romain!