Osculating to Mean elements conversion with DSST

Hello community!

I would like to convert a cartesian state into mean equinoctial elements using the DSST theory (I have not looked into the subject before, so please excuse in advance any incorrect statement).

To my knowledge, I found two ways to do so in Orekit:

  • use DSSTPropagator.computeMeanState static method (requiring the osculating SpacecraftState and a list of DSST force models)
  • use the OsculatingToMeanElementsConverter class, that requires a DSSTPropagator instance

I wrote a simple script that compares the results by the two converters, and the two state’s PV coordinates are not matching. I was wondering then what is the best way to do this conversion.

Thank you!

        Frame inertialFrame = FramesFactory.getEME2000();
        Frame earthFrame = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
        FrameAlignedProvider attitudeProvider = new FrameAlignedProvider(inertialFrame);

        DormandPrince853Integrator integrator =
                new DormandPrince853Integrator(0.001, 100.0, 1.0e-12, 1.0e-12);

        DSSTPropagator propagator =
                new DSSTPropagator(integrator, PropagationType.MEAN, attitudeProvider);

        List<DSSTForceModel> forces = new ArrayList<>();

        UnnormalizedSphericalHarmonicsProvider gravityProvider =
                GravityFieldFactory.getUnnormalizedProvider(10, 10);

        forces.add(new DSSTZonal(earthFrame, gravityProvider));
        forces.add(new DSSTTesseral(earthFrame, Constants.WGS84_EARTH_ANGULAR_VELOCITY, gravityProvider));

        OneAxisEllipsoid earthShape = new OneAxisEllipsoid(
                Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
                Constants.WGS84_EARTH_FLATTENING,
                earthFrame
        );

        CelestialBody sun = CelestialBodyFactory.getSun();
        CelestialBody moon = CelestialBodyFactory.getMoon();

        forces.add(new DSSTThirdBody(sun, Constants.WGS84_EARTH_MU));
        forces.add(new DSSTThirdBody(moon, Constants.WGS84_EARTH_MU));

        HarrisPriester atmosphere = new HarrisPriester(sun, earthShape, 6.0);
        DragForce dragForce = new DragForce(atmosphere, new IsotropicDrag(1.0, 2.2));
        forces.add(new DSSTAtmosphericDrag(dragForce, Constants.WGS84_EARTH_MU));

        IsotropicRadiationSingleCoefficient srpCoeff = new IsotropicRadiationSingleCoefficient(1.0, 1.8);
        forces.add(new DSSTSolarRadiationPressure(sun, earthShape, srpCoeff, Constants.WGS84_EARTH_MU));

        for (DSSTForceModel force : forces) {
            propagator.addForceModel(force);
        }

        PVCoordinates coord = new PVCoordinates(
                new Vector3D(7_100_000, 0, 1_300_000),
                new Vector3D(0, 7_350, 1_000)
        );

        AbsoluteDate date = new AbsoluteDate("2025-03-24T12:34:00.445Z", TimeScalesFactory.getUTC());
        CartesianOrbit cartOrbit = new CartesianOrbit(coord, inertialFrame, date, Constants.WGS84_EARTH_MU);
        EquinoctialOrbit eqOrbit = new EquinoctialOrbit(cartOrbit);
        SpacecraftState state = new SpacecraftState(eqOrbit).withMass(1000.0);

        SpacecraftState mean1 = DSSTPropagator.computeMeanState(state, null, propagator.getAllForceModels());

        OsculatingToMeanElementsConverter converter =
                new OsculatingToMeanElementsConverter(state, 1, propagator, 1000.0);
        SpacecraftState mean2 = converter.convert();

Ciao Paolo,

I think that the difference between the two approaches is the following:

The DSST theory provides explicit expressions to compute the short periodic terms, and thus to convert a mean state to an osculating one. The opposite is not true, and the computation of a mean state given an osculating one requires some kind of iterative algorithm, like fix point iterations or LS.

The static method DSSTPropagator.computeMeanState does exactly this. Given an osculating state, it computes a mean state at the same epoch such that, when the short periodic terms are added to the latter, the result is (approximately) the initial osculating state.

This is akin to what TLE.stateToTle does. Like DSST, SGP4 can compute an osculating (Cartesian) state given a TLE (i.e. a mean state), but the opposite require solving a fix point or LS problem.

Instead, OsculatingToMeanElementsConverter finds the Keplerian orbit (in the sense that it follows Keplerian motion, not necessarily that is expressed in Keplerian elements) that minimizes the RMS error w.r.t. the DSST propagator over a number of revolutions input to the class constructor.

Under the hood it does this:

  1. using the input DSST propagator, it samples a number of osculating states distributed over the input number of revolutions. To compute these states, DSST is initialized with a mean orbit that is computed using the static method above
  2. using a Keplerian propagator, it performs a LS optimization to minimize the RMS error between the sample states computed with DSST (the target values), and the predicted states computed with the Keplerian propagator (the free variables)
  3. the mean state that is returned is the initial state of the Keplerian propagator at convergence

Hope this helps!

Cheers,

Alberto

2 Likes

Thank you Alberto, super useful! This clarifies how the two methods work and why I get different results.

I was wondering then what would be the criteria to chose one method over the other.

In Orekit’s source code, I found that computeMeanState is used extensively, while OsculatingToMeanElementsConverter is only used in its own test.

I would think that it depends on the application.

  1. computeMeanState if you need an “instantaneous” mean state that represents the same physical state as the osculating one. You need this for example to propagate an osculating state with DSST
  2. OsculatingToMeanElementsConverter if you need the “average” R2BP orbit that is closest to the osculating trajectory computed with DSST over a given time span

I think that the usage in Orekit reflects the fact that (1) is used as an intermediate operation, as the output state is intended to be input to other routines.

Instead, (2) is more a “final” operation, I would use it only for visualization purposes for example.

1 Like

Hello,

Just to add some context, OsculatingToMeanElementsConverter is an old class (2012) that is seldom used (as far as I know).
@pascal.parraud recently added (v13.0) an interface OsculatingToMeanConverter that is much more powerful (you can choose the conversion method: least-square or fixed-point, the mean theory: DSST, BL, EH, TLE).

1 Like

Shall be depreciate OsculatingToMeanElementsConverter?

I realize I wrote my comment a bit too fast.
To rephrase what @afvy said, OsculatingToMeanConverter will provide an instantaneous state (1) while OsculatingToMeanElementsConverter an average of a trajectory (2).
It wraps a FiniteDifferencePropagatorConverter so I think it could be deprecated yes, since it is just a specific use case of a finite differences propagator converter.
And I find it confusing.

Thank you @MaximeJ

Indeed, OsculatingToMeanConverter is what computeMeanState uses internally.

I also agree with deprecating OsculatingToMeanElementsConverter.

Hi all,

I believe the FixedPointConverter and LeastSquaresConverter cover both cases indeed.
Rather than deprecating OsculatingToMeanElementsConverter, we could even remove then since the next version is a major one.

Cheers,
Romain.

1 Like