Conversion of TLE

Hi All,

I am trying to convert from TLE to Cartesian and viceversa, but I am not fully sure that I am following the correct procedure.

Below you can find the code:

public class TLEConversionNumericalModel {

public static void main(String[] args) throws OrekitException {

    String orekitDataPath = args[0];

    DataProvidersManager.getInstance().addProvider(new DirectoryCrawler(new File(orekitDataPath)));      

    TLE inputTle = new TLE("1 31135U 07013A   11003.00000000  .00000816  00000+0  47577-4 0    11",
            "2 31135   2.4656 183.9084 0021119 236.4164  60.4567 15.10546832    15");

    // Retrieve the correct propagator that was used to generate the TLE (SGP4 or SDP4)
    Propagator tlePropagator = TLEPropagator.selectExtrapolator(inputTle);

    // Initial reference Orbit for the builder
    Orbit referenceOrbit = tlePropagator.getInitialState().getOrbit();

     * Numerical Propagator to fit the samples generated by the TLE propagator
    // Adaptive stepsize
    double minStep = 1e-3;
    double maxStep = 600;
    double dP = 1e-3;
    DormandPrince853IntegratorBuilder dormandBuilder = new DormandPrince853IntegratorBuilder(minStep, maxStep, dP);

    NumericalPropagatorBuilder numericalPropBuilder = new NumericalPropagatorBuilder(referenceOrbit, dormandBuilder, PositionAngle.TRUE, 1.0);


    FiniteDifferencePropagatorConverter numericalFitter = new FiniteDifferencePropagatorConverter(numericalPropBuilder, 1.0e-3, 1000);

    double duration = 86400.0;
    double stepSize = 300.0;
    Double points = duration / stepSize;

    numericalFitter.convert(tlePropagator, duration, points.intValue());

    NumericalPropagator numericalPropagator = (NumericalPropagator) numericalFitter.getAdaptedPropagator();

     * Convert Back to TLE
    Orbit orbit = numericalPropagator.getInitialState().getOrbit();

    // Convert to keplerian orbit to get missing elements for the TLEtemplate
    KeplerianOrbit keplerianOrbit = (KeplerianOrbit) OrbitType.KEPLERIAN.convertType(orbit);

    TLE tleTempalte = new TLE(inputTle.getSatelliteNumber(),

    TLEPropagatorBuilder builder = new TLEPropagatorBuilder(tleTempalte, PositionAngle.TRUE, 1.0);

    FiniteDifferencePropagatorConverter tleFitter = new FiniteDifferencePropagatorConverter(builder, 1e-3, 1000);

    System.out.println("START TLE PROPAGATOR FITTING");
    tleFitter.convert(numericalPropagator, duration, points.intValue(), TLEPropagatorBuilder.B_STAR);
    System.out.println("END TLE PROPAGATORFITTING");

    TLEPropagator propTLE = (TLEPropagator) tleFitter.getAdaptedPropagator();

    TLE outputTLE = propTLE.getTLE();

    System.out.println("INPUT TLE");
    System.out.println("OUTPUT TLE");


private static void setUpPropagatorBuilderForceModels(NumericalPropagatorBuilder propagatorBuilder) throws OrekitException {

     * Add the forces to the Numerical Builder

    // Create Earth
    OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING,
            FramesFactory.getITRF(IERSConventions.IERS_2010, false));

    // Earth Geopotential
    NormalizedSphericalHarmonicsProvider provider = GravityFieldFactory.getNormalizedProvider(4, 0);
    HolmesFeatherstoneAttractionModel geopotentialForce = new HolmesFeatherstoneAttractionModel(earth.getBodyFrame(), provider);

    // Solar Radiation Pressure
    CelestialBody sun = CelestialBodyFactory.getSun();
    double solarRadiationPressureCoefficient = 1.4;
    double solarRadiationPressureArea = 10;
    RadiationSensitive radiationSensitive = new IsotropicRadiationSingleCoefficient(solarRadiationPressureArea, solarRadiationPressureCoefficient);
    SolarRadiationPressure srp = new SolarRadiationPressure(sun, earth.getEquatorialRadius(), radiationSensitive);

    // Third Bodies
    ThirdBodyAttraction thirdbodyMoon = new ThirdBodyAttraction(CelestialBodyFactory.getMoon());
    ThirdBodyAttraction thirdbodySun = new ThirdBodyAttraction(sun);

    // Drag
    HarrisPriester atmosphere = new HarrisPriester(sun, earth);
    double cd = 1.2;
    double area = 5;
    IsotropicDrag spacecraft = new IsotropicDrag(area, cd);
    DragForce drag = new DragForce(atmosphere, spacecraft);

     * Add force models


What I am doing is:

  1. Building the corresponding TLEPropagator from a TLE
  2. Create and set up a NumericalPropagatorBuilder to be given in input to the FiniteDifferencePropagatorConverter
  3. Get the NumericalPropagator as a result of the fitting procedure on the internal generated samples

at this point I query for the PVCoordinates of the initial state of the spacecraft from the NumericalPropagator to use it for regenerate a set of TLE, by repeating the procedure above. Inverting the roles of the two propagators.
Is this the right approach?

The input and output TLE are the following:

  • Input TLE:
    1 31135U 07013A 11003.00000000 .00000816 00000+0 47577-4 0 11
    2 31135 2.4656 183.9084 0021119 236.4164 60.4567 15.10546832 15
  • Output TLE:
    1 31135U 07013A 11003.00000000 .00000000 00000-0 14638-3 0 18
    2 31135 2.4656 183.9084 0021118 236.4174 60.4567 15.10545148 03

I believe that the small differences in the mean elements are due to the different force models used by the TLEPropagator and NumericalPropagator.
But what I don’t understand is why the Bstar coefficients are so different. Should they not be the same ? Or am I missing something?

Thank you really much for your reply and for this forum, it is really useful!



Your procedure is totally correct to do what you want to do.

About the B*, the SGP4 specific ballistic coefficient, the ratio from 1 to 3 (input vs output) is not so bad. Theoretically, as related to drag, it depends on Cd, A, m and also from the atmospheric model in your case, when converting from TLEPropagator to NumericalPropagator and then back to TLE. When building the forces, you set the Cd and the drag area and the HarrisPriester as the atmospheric model, the mass is set by default to 1000 kg by Orekit. All these parameters affect the double fitting process and changing any of them will conduct to a different B*. Recovering the drag often conducts to indetermination.

Setting for example the mass to 3000 kg:


gives to the following results:

1 31135U 07013A 11003.00000000 .00000816 00000+0 47577-4 0 11
2 31135 2.4656 183.9084 0021119 236.4164 60.4567 15.10546832 15
1 31135U 07013A 11003.00000000 .00000000 00000-0 48942-4 0 14
2 31135 2.4656 183.9084 0021119 236.4164 60.4567 15.10546809 08

The output B* is now closer from the input and the orbital elements are also better.

At last, you set a duration of one day, 86400 s, for fitting that is more than 15 orbital periods and is a bit long in this case, try with 2 orbital periods as a duration, it will greatly reduce the processing time with comparable results.

Hi Pascal,

thank you really much for your reply and for the hint on the time span.
How did you find the value of 3000 Kg? Is it just a guess or there is a general procedure to find it?

In addition how can I set the correct mass of the spacecraft in the TLEPropagatorBuilder?


Hi @leonardo,
You have about a factor 3 between your output TLE and your input TLE for the Bstar (Bout ~= 3 Bin).
B* is inversely related with mass. So, if you multiply the mass by 3, you will reduce the B* by 3.
In Orekit, the default value for the mass is 1000 kg. That is why Pascal choose 1000 kg * 3 = 3000 kg to obtain a value of B* close to your input TLE.

I hope that I answer your question and that my explanations are clear.


Hi @leonardo,

To go a bit further with Bryan’s answer, as the B* is related to all the stuff associated to drag, you would get same results by dividing the Cd or the area by 3, I just mentioned mass to underline this hidden parameter, by the way the setMass() method is for the NumericalPropagatorBuilder, not the TLEPropagatorBuilder.


thank you really much to both of you, for your answers. Now I get how this value is set.

I still don´t understand why when building the TLEPropagatorBuilder it is not possible to set the mass of the spacecraft, should we not set the correct mass value of the Spacecraft for the fitting?
Does it not create problems the fact that the TLEPropagatorBuilder assumes the default mass of the spacecraft (1000Kg) during the fitting?


Hi @leonardo,

In practice, the mass is not used by the TLEPropagator, so it doesn’t have any effect when fitting an already configured NumericalPropagator to get a TLE. But on the other side, when fitting a TLE to get a NumericalPropagator, then the mass modulates the drag force added to the NumericalPropagatorBuilder, thus it affects this part of the fitting.

In your case, as all the parameters of the forces added to the NumericalPropagatorBuilder are fixed, the fitting is constrained. You may try to free the force parameters to get a “better” fitting, something like:

    numericalFitter.convert(tlePropagator, duration, points.intValue(), DragSensitive.DRAG_COEFFICIENT);

Doing this, the conversion will also try to fit the drag coefficient in order to better fit the orbit. Make some tries with different values of the fitting duration, with others atmosphere models (as the Harris-Priester is not very accurate) and you will see the results vary. There is no right answer here, only tweaking.

Hi @pascal.parraud,

thank you really much for your reply and sorry for the late response,
I tried to play a bit with the propagator and this solved my problem.

Thank you again