Using OrbitHermiteInterpolator with StateCovarianceBlender

Hello everyone!

I am currently working on orbit interpolation and i have come across the paper:
”ORBIT AND COVARIANCE INTERPOLATION/BLENDING
WITH OREKIT” from Vincent Cucchietti.
The conclusion ends with the a statement, that in some cases, a combination of the HermiteInterpolator for orbit interpolation together with the Blending Method for the Covariance shall be used.

If have tried to combine the StateCovarianceBlender with the OrbitHermiteInterpolator in Orekit, but it seems to me that StateCovarianceBlender defaults to 2 interpolations points for the orbit interpolation. This is obviously enough when using the OrbitBlender for orbit interpolation, but for the HermiteInterpolator, i want more data points for the interpolation.

Am i using the StateCovarianceBlender in the wrong way or could this be a limitation in the code?

Implementation_of_covariance_interpolation_in_Orekit.pdf (2.3 MB)

Hello @jeeenga and welcome to the Orekit forum !

It is neither one nor the other :slight_smile: ! Blending is a concept that is similar yet fundamentally different from interpolation. When i refactored interpolators, i decided to make blending a part of it for simplicity. Consequently, some things do not really make sense such as the “number of interpolation points” which is necessarily two in this case.

What happens when you mix a StateCovarianceBlender and an OrbitHermiteInterpolator and want to interpolate at, let’s say t, is that the OrbitHermiteInterpolator will interpolate the orbit at t (using its own configuration for interpolation) and then propagate the StateCovarianceMatrix (using STM) forward & backward from t0 < t and t1 > t. Finally, it uses a smoothstep function to blend both state covariance at time t to get the final state covariance.

I hope it’s clearer this way, feel free to ask any questions.

Cheers,
Vincent

Thank you @Vincent for your reply!
I have the following setup in my code

        String epochStr = "2025-09-14T23:55:51.000Z";
        AbsoluteDate targetDate = new AbsoluteDate(epochStr, utc);

        // Blending function
        SmoothStepFactory.SmoothStepFunction blendingFunction = SmoothStepFactory.getQuintic();
        
        // Create state vector interpolator
        OrbitHermiteInterpolator orbitInterpolator = new OrbitHermiteInterpolator(10, inertialFrame);
       
        // StateCovarianceBlender using Hermite interpolator
        StateCovarianceBlender covarianceBlender = new StateCovarianceBlender(
            blendingFunction,      // For covariance blending
            orbitInterpolator,     //
            LOFType.TNW
        );
        

        // Interpolate at target date
        TimeStampedPair<Orbit, StateCovariance> source_interpolatedPair = 
            covarianceBlender.interpolate(targetDate, source_samples);

This however causes the following error:

org.orekit.errors.OrekitIllegalArgumentException: too small number of cached neighbors: 2 (must be at least 10)

From what i could find out so far is that cached neighbours are used for the interpolations and the number of cached neighbors is defined by the number interpolation points. Using for example the StateCovarianceKeplarianHermiteInterpolator, i can set the number of interpolatoins points to be 10 and everything works. So yes:

but given that only 2 points are available when using the StateCovarianceBlender, OreKit throws the mentioned error.

I hope my explanation makes sense.

Given your code snippet, it looks like source_samples has a size of 2 which is too small as the OrbitHermiteInterpolator requires a minimum sample size of 10 in your case.

If you use an interpolator which itself use other interpolators, then the sample size shall be the highest number of interpolation points required among parent & sub interpolators.

Cheers,
Vincent

I have checked that and my sample size has more than 2 data points.

In org.orekit.propagation.covariance.AbstractStateCovarianceInterpolator the interpolate method is defined with

public TimeStampedPair<Orbit, StateCovariance> interpolate(final InterpolationData interpolationData) {

    // Interpolate orbit at interpolation date
    final Orbit interpolatedOrbit = interpolateOrbit(interpolationData.getInterpolationDate(),
                                                     interpolationData.getNeighborList());

So the interpolateOrbit method takes the neighbors of interpolationData as inputs.

In org.orekit.time.AbstractTimeInterpolator the neighbors are defined as

    /** Neighbor list around interpolation date. */
    private final List<T> neighborList;

And are created like this

if (sample.size() == interpolationPoints) {
    // shortcut for simple case
    // copy list to make neighborList immutable
    this.neighborList = Collections.unmodifiableList(new ArrayList<>(sample));
} else {
    // else, select sample.

    // Create immutable time stamped cache
    final ImmutableTimeStampedCache<T> cachedSamples =
            new ImmutableTimeStampedCache<>(interpolationPoints, sample);

    // Find neighbors
    final AbsoluteDate central = AbstractTimeInterpolator.getCentralDate(
            interpolationDate,
            cachedSamples,
            extrapolationThreshold);
    final Stream<T> neighborsStream = cachedSamples.getNeighbors(central);

    // Convert to unmodifiable list
    this.neighborList = Collections.unmodifiableList(neighborsStream.collect(Collectors.toList()));
}

As both constructor of the StateCovarianceBlender take the default number of interpolation points

public StateCovarianceBlender(final SmoothStepFactory.SmoothStepFunction blendingFunction,
                              final TimeInterpolator<Orbit> orbitInterpolator,
                              final LOFType outLOF) {
    super(DEFAULT_INTERPOLATION_POINTS, 0., orbitInterpolator, outLOF);
    this.blendingFunction = blendingFunction;
}

/**
 * Constructor.
 *
 * @param blendingFunction blending function
 * @param orbitInterpolator orbit interpolator
 * @param outFrame desired output covariance frame
 * @param outPositionAngleType desired output position angle
 * @param outOrbitType desired output orbit type
 *
 * @see Frame
 * @see OrbitType
 * @see PositionAngleType
 */
public StateCovarianceBlender(final SmoothStepFactory.SmoothStepFunction blendingFunction,
                              final TimeInterpolator<Orbit> orbitInterpolator,
                              final Frame outFrame,
                              final OrbitType outOrbitType,
                              final PositionAngleType outPositionAngleType) {
    super(DEFAULT_INTERPOLATION_POINTS, 0., orbitInterpolator, outFrame, outOrbitType, outPositionAngleType);
    this.blendingFunction = blendingFunction;
}

which are set to 2, there will be only 2 data points around the interpolation data available for the interpolation.

Hello @jeeenga,

This is indeed an issue inside InterpolationData as it should use getNbInterpolationPoints() instead of the locally defined interpolationPoints to get a neighborList of the adequate size for all sub-interpolators, I’m opening an issue.

Thank you for noticing this !

UPDATE:

Sorry forgot to update this thread, an issue has been opened on the forge :

Cheers,
Vincent

Hello @jeeenga,

This message to let you know, and everyone, else that the fix has been merged in the future 13.1.3 patch branch.

This led me to find another issue : Fix missing overriding function to get sub-interpolators on some interpolators (#1878) · Issues · Orekit / Orekit · GitLab

Thanks again for pointing it out !

Cheers,
Vincent

2 Likes

Hello @Vincent
Nice, thank you for fixing this and including it in the new patch. Can you estimate when the patch will be released?

And another thing: I currently trying to reproduce the results from your paper. Is there a code base that was published along with the paper?

Best regards

Hello @jeeenga,

Thank you for spotting this issue ! I need to finish some MR on my hand and i guess that @Serrof has a better estimate of when the patch will be released. I would say January or February.

There is a code base which but i would rather suggest you to look into the associated Orekit tests which are based on the paper cases: src/test/java/org/orekit/propagation/covariance/StateCovarianceBlenderTest.java · develop · Orekit / Orekit · GitLab

Cheers,
Vincent