Why does getBSTAR() return different value than the one in TLE

I am doing orbit determination and then I am creating a TLE using TLEPropagatorBuilder but the value I see in the drag term is different than the bstar I get when I used the method .get_BSTAR(). where is it getting this BSTAR value?

what does the setting BSTAR as free parameter do?

If I remove the ‘BSTAR’ from the convert() it shows an error, why is that?

here is the code snippet for the bug.

from org.orekit.propagation.conversion import TLEPropagatorBuilder, FiniteDifferencePropagatorConverter

from org.orekit.propagation.analytical.tle import TLEPropagator

from org.orekit.propagation.analytical.tle.generation import LeastSquaresTleGenerationAlgorithm

threshold = 1.0 # “absolute threshold for optimization algorithm”, but no idea about its impact

tle_builder = TLEPropagatorBuilder(orekitTle, PositionAngleType.MEAN, 1.0,LeastSquaresTleGenerationAlgorithm())

fitter = FiniteDifferencePropagatorConverter(tle_builder, threshold, 1000)

fitter.convert(states_list, False,‘BSTAR’) # Setting BSTAR as free parameter

tle_propagator = TLEPropagator.cast_(fitter.getAdaptedPropagator())

tle_fitted = tle_propagator.getTLE()

print(tle_fitted)

print(orekitTle)

print(orekitTle.getBStar())

output cell
1 55069U 23001BN 24330.73825074 .00051058 00000-0 33919-2 0 9995
2 55069 97.4046 33.3284 0008944 323.3187 37.4765 15.39536492105535
1 55069U 23001BN 24330.73825074 .00051058 00000-0 12818-2 0 9990
2 55069 97.4045 33.3269 0008949 321.7983 38.2628 15.39797920105530
0.0033918884963623575

Heya!
Could you include how you generate states_list? Otherwise, my instinct is that the convergence tolerance is set loosely. Does changing “threshold” there change the result?

You need to tell the finite difference solver which parameter to vary to perform the fit when you use the “convert” method (see https://www.orekit.org/site-orekit-12.2/apidocs/org/orekit/propagation/conversion/AbstractPropagatorConverter.html#convert(java.util.List,boolean,java.lang.String…) ), so without “BSTAR” it has nothing to vary and hence will throw an exception. With just “BSTAR” it will vary that value alone in order to best fit the TLE to the list of states in states_list

1 Like

thanks for the answer. I am confused even more now. so I am trying to do Orbit determination using the PVT data from GPS. aI want to create a TLE that I can use from past data with high accuracy.
why should I set BSTAR as free parameter. to fit the orbit shouldn’t I set some orbital parameters as free like eccentricity or some other ones?

shouldn’t the Bstar param be a constant?

here is where I am adding spacecraft states,

from java.util import ArrayList
states_list = ArrayList()

temp_prop_list=

temp_observed_list =
for d in timestamps:
spacecraftState = ephemeris.propagate(datetime_to_absolutedate(d))
states_list.add(spacecraftState)
temp_prop= ephemeris.propagate(datetime_to_absolutedate(d)).getPosition()
matching_rows = df[df.index == d]
list_pos= matching_rows[[‘x’, ‘y’, ‘z’]].to_numpy().tolist()
temp_observed = Vector3D(list_pos[0])

temp_prop_list.append(temp_prop)
temp_observed_list.append(temp_observed)

dist = [pos.distance(pos_ref) for pos, pos_ref in zip(temp_prop_list, temp_observed_list)]

Ah, right, I see what you’re trying to do. BSTAR will change, while it’s defined as the cross sectional area times the coefficient of drag over the mass (plus a reference density), these values can change as the object orientation changes. Allowing BSTAR to vary also allows us to better fit a varying atmosphere.

A trivial example of the sort of thing you’re trying to do is below. It generates some measurements (using a propagation of the TLE and adding some noise), then sets up the estimator, sets all the parameters as drivers for the estimation, performs the estimation, and reports the result.

You can see that the TLE will vary slightly as we’ve added some noise and prevented it from doing a really good fit.

import orekit_jpype as orekit

vm = orekit.initVM()
from orekit_jpype.pyhelpers import (
    setup_orekit_curdir,
)
from pathlib import Path

setup_orekit_curdir(str(Path.cwd() / "orekit-data"))
from org.orekit.propagation.analytical.tle import TLE, TLEPropagator
from org.orekit.orbits import (
    PositionAngleType,
)
from org.orekit.propagation.conversion import TLEPropagatorBuilder
from org.orekit.propagation.analytical.tle.generation import (
    LeastSquaresTleGenerationAlgorithm,
)
from org.hipparchus.linear import QRDecomposer
from org.hipparchus.optim.nonlinear.vector.leastsquares import (
    GaussNewtonOptimizer,
)
from org.orekit.estimation.leastsquares import BatchLSEstimator
from org.orekit.estimation.measurements import PV, ObservableSatellite
from org.hipparchus.geometry.euclidean.threed import Vector3D

import numpy as np

rng = np.random.default_rng(seed=42)
rnorm = rng.normal

# Using ISS for purpose of demonstration
line1 = "1 25544U 98067A   24346.58085661  .00019796  00000+0  34772-3 0  9995"
line2 = "2 25544  51.6389 156.5072 0007053 328.6631  66.3051 15.50486876486069"
tle = TLE(line1, line2)
print("Starting TLE:")
print(tle.toString())
propagator = TLEPropagator.selectExtrapolator(tle)
epoch = tle.getDate()
end_date = epoch.shiftedBy(86400.0)
step = 100.0
cur_date = epoch
# Generate a set of input PV data
pvcoordinates = []
dates = []
while cur_date < end_date:
    pvcoordinates.append(propagator.getPVCoordinates(cur_date))
    dates.append(cur_date)
    cur_date = cur_date.shiftedBy(step)

measurement_error = 100.0
convergence_threshold = 1e-3
max_iterations = 100
max_evaluations = 10
tle_builder = TLEPropagatorBuilder(
    tle,
    PositionAngleType.MEAN,
    measurement_error,
    LeastSquaresTleGenerationAlgorithm(),
)

# Set estimation to use all the parameters (PV + BSTAR)
print("Input values")
for element in tle_builder.getOrbitalParametersDrivers().getDrivers():
    print(element)
    element.setSelected(True)
for element in tle_builder.getPropagationParametersDrivers().getDrivers():
    print(element)
    element.setSelected(True)
    if "BSTAR" in element.toString():
        # BSTAR < 0 is impossible
        element.setMinValue(0.0)

matrixDecomposer = QRDecomposer(1e-11)
optimizer = GaussNewtonOptimizer(matrixDecomposer, False)
estimator = BatchLSEstimator(optimizer, tle_builder)
estimator.setParametersConvergenceThreshold(convergence_threshold)
estimator.setMaxIterations(max_iterations)
estimator.setMaxEvaluations(max_evaluations)

observableSatellite = ObservableSatellite(0)  # Propagator index = 0

for date, pv in zip(dates, pvcoordinates):
    orekit_position = PV(
        date,
        # Add noise to the measurement
        pv.getPosition().add(
            Vector3D(*rnorm(scale=measurement_error, size=3))
        ),
        pv.getVelocity().add(
            Vector3D(*rnorm(scale=measurement_error / 10, size=3))
        ),
        measurement_error,
        measurement_error / 10,  # Assume velocity error 10% of position error
        1.0,  # Base weight
        observableSatellite,
    )
    estimator.addMeasurement(orekit_position)

propagator = estimator.estimate()[0]
print("Estimated values")
for element in estimator.getOrbitalParametersDrivers(True).getDrivers():
    print(element)
for element in estimator.getPropagatorParametersDrivers(True).getDrivers():
    print(element)
new_tle = propagator.getTLE().toString()

print("New TLE:")
print(new_tle)

Based upon Orbit determination example

1 Like

look I get it now. I am trying to run your code but it doesn’t work. I am guessing you are using the Orekit from pip install. but I fail to understand why you don’t need statelist to generate a TLE. if I try the same in my Orekit form conda like

propagator.getTLE() it says it doesn’t have any method named getTLE() why is that?

Tweaked it a bit such that it works for both the older Python wrapper and orekit_jpype, see below.
The measurements added to the estimator are used instead of a list of SpacecraftStates. FiniteDifferencePropagatorConverter is designed to convert one propagator to another and doesn’t consider the errors on each measurement. So while it will work to fit a set of PVT data to a TLE, I don’t think it’s the best method.

try:
    import orekit_jpype as orekit
    vm = orekit.initVM()
    from orekit_jpype.pyhelpers import (
        setup_orekit_curdir,
        absolutedate_to_datetime
    )
except ModuleNotFoundError:
    import orekit
    vm = orekit.initVM()
    from orekit.pyhelpers import (
        setup_orekit_curdir,
        absolutedate_to_datetime
    )



from pathlib import Path

setup_orekit_curdir(str(Path.cwd() / "orekit-data"))
from org.orekit.propagation.analytical.tle import TLE, TLEPropagator
from org.orekit.orbits import (
    PositionAngleType,
)
from org.orekit.propagation.conversion import TLEPropagatorBuilder
from org.orekit.propagation.analytical.tle.generation import (
    LeastSquaresTleGenerationAlgorithm,
    TleGenerationUtil,
)
from org.hipparchus.linear import QRDecomposer
from org.hipparchus.optim.nonlinear.vector.leastsquares import (
    GaussNewtonOptimizer,
)
from org.orekit.estimation.leastsquares import BatchLSEstimator
from org.orekit.estimation.measurements import PV, ObservableSatellite
from org.hipparchus.geometry.euclidean.threed import Vector3D
from org.orekit.orbits import KeplerianOrbit
from org.orekit.time import UTCScale
from org.orekit.utils import (
    Constants,
)

import numpy as np

rng = np.random.default_rng(seed=42)
rnorm = rng.normal

# Using ISS for purpose of demonstration
line1 = "1 25544U 98067A   24346.58085661  .00019796  00000+0  34772-3 0  9995"
line2 = "2 25544  51.6389 156.5072 0007053 328.6631  66.3051 15.50486876486069"
tle = TLE(line1, line2)
print("Starting TLE:")
print(tle.toString())
propagator = TLEPropagator.selectExtrapolator(tle)
epoch = tle.getDate()
end_date = absolutedate_to_datetime(epoch.shiftedBy(86400.0))
step = 100.0
cur_date = epoch
# Generate a set of input PV data
pvcoordinates = []
dates = []
while absolutedate_to_datetime(cur_date) < end_date:
    pvcoordinates.append(propagator.getPVCoordinates(cur_date))
    dates.append(cur_date)
    cur_date = cur_date.shiftedBy(step)

measurement_error = 100.0
convergence_threshold = 1e-3
max_iterations = 100
max_evaluations = 10
tle_builder = TLEPropagatorBuilder(
    tle,
    PositionAngleType.MEAN,
    measurement_error,
    LeastSquaresTleGenerationAlgorithm(),
)

# Set estimation to use all the parameters (PV + BSTAR)
print("Input values")
for element in tle_builder.getOrbitalParametersDrivers().getDrivers():
    print(element)
    element.setSelected(True)
for element in tle_builder.getPropagationParametersDrivers().getDrivers():
    print(element)
    element.setSelected(True)
    if "BSTAR" in element.toString():
        # BSTAR < 0 is impossible
        element.setMinValue(0.0)

matrixDecomposer = QRDecomposer(1e-11)
optimizer = GaussNewtonOptimizer(matrixDecomposer, False)
estimator = BatchLSEstimator(optimizer, tle_builder)
estimator.setParametersConvergenceThreshold(convergence_threshold)
estimator.setMaxIterations(max_iterations)
estimator.setMaxEvaluations(max_evaluations)

observableSatellite = ObservableSatellite(0)  # Propagator index = 0

for date, pv in zip(dates, pvcoordinates):
    pos_err = rnorm(scale=measurement_error, size=3)
    vel_err = rnorm(scale=measurement_error / 10, size=3)
    orekit_position = PV(
        date,
        # Add noise to the measurement
        pv.getPosition().add(
            Vector3D(*[float(x) for x in pos_err])
        ),
        pv.getVelocity().add(
            Vector3D(*[float(x) for x in vel_err])
        ),
        measurement_error,
        measurement_error / 10,  # Assume velocity error 10% of position error
        1.0,  # Base weight
        observableSatellite,
    )
    estimator.addMeasurement(orekit_position)

propagator = estimator.estimate()[0]
print("Estimated values")
for element in estimator.getOrbitalParametersDrivers(True).getDrivers():
    print(element)
for element in estimator.getPropagatorParametersDrivers(True).getDrivers():
    print(element)
try:
    new_tle = propagator.getTLE().toString()
except AttributeError:
    # Older version of Orekit
    new_tle = TLEPropagator.cast_(propagator).getTLE().toString()

print("New TLE:")
print(new_tle)

1 Like

okay I managed to your code. In your code you are fitting the measurement to a TLE But I want to use the measurements and propagate with a force model to get the estimate of future TLE of satellite.
I have measurements from T0 to T1 and I want to make a TLE for T1 to T2. T1 to T2 is about a 24hours.

in this case wouldn’t the better approach be to propagate and get the states and then make a TLE?

also, when I try the same cast method to get TLE from propagator I get an error. I suspect is that cause I used a numerical propagator.

cov_mat=estimator.getPhysicalCovariances(1.0e-10)
print(type(estimated_propagator))
estimated_propagator = estimated_propagator_array[0]
new_tle=TLEPropagator.cast_(estimated_propagator).getTLE().toString()
generator = estimated_propagator.getEphemerisGenerator()

index = timestamp_full.index(timestamps[14])

FIRST_DATE= datetime_to_absolutedate(timestamp_full[index])
LAST_DATE=datetime_to_absolutedate(timestamp_full[900
])
print(index)
timestamps = timestamp_full[index:900]
print(len(timestamps))
estimated_propagator.propagate(FIRST_DATE, LAST_DATE)
#new_tle = TLEPropagator.cast_(estimated_propagator).getTLE().toString()
print(new_tle)
ephemeris = generator.getGeneratedEphemeris()

<class ‘org.orekit.propagation.Propagator’>

--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[90], line 4 2 print(type(estimated_propagator)) 3 estimated_propagator = estimated_propagator_array[0] ----> 4 new_tle=TLEPropagator.cast_(estimated_propagator).getTLE().toString() 5 generator = estimated_propagator.getEphemerisGenerator() 7 index = timestamp_full.index(timestamps[14]) TypeError: org.orekit.propagation.numerical.NumericalPropagator@743f58c3

Yes, this is just an example to show how to fit a TLE to measurements. If you have GPS data you would insert them at the “estimator.addMeasurement” line. If you want to generate a better orbit model to propagate forwards in time, replace tle_builder with a NumericalPropagatorBuilder, following Orbit determination example .

Then once you’ve done that, feed the completed propagator into FiniteDifferencePropagatorConverter.convert (you don’t need to create a set of States) Class AbstractPropagatorConverter. That will then give you a TLEPropagator instance with which you can call getTLE.

1 Like

hello, I tried several ways to make it work but I can’t. can you write a example?

here my work
from org.orekit.propagation.conversion import TLEPropagatorBuilder, AbstractPropagatorConverter,FiniteDifferencePropagatorConverter

from org.orekit.propagation.analytical.tle import TLEPropagator

from org.orekit.propagation.analytical.tle.generation import LeastSquaresTleGenerationAlgorithm

threshold = 1.0 # “absolute threshold for optimization algorithm”, but no idea about its impact

#print()

orb=estimated_propagator.propagate(FIRST_DATE, LAST_DATE).getOrbit()

tle_builder = NumericalPropagatorBuilder(orb, integratorBuilder, PositionAngleType.MEAN, ESTIMATOR_POSITION_SCALE)

fitter = FiniteDifferencePropagatorConverter(tle_builder, threshold, 1000)

print(fitter)

fitter.convert(tle_builder,50,26,‘BSTAR’) # Setting BSTAR as free parameter

tle_propagator = TLEPropagator.cast_(fitter.getAdaptedPropagator())

tle_fitted = tle_propagator.getTLE()

#tle_conv = TLE(tle_fitted)

print(tle_fitted.toString())

print(type(orekitTle))

print(orekitTle.getBStar())

different attempt
if I do smth like this

orb=estimated_propagator.propagate(FIRST_DATE, LAST_DATE).getOrbit()

tle_builder = NumericalPropagatorBuilder(orb, integratorBuilder, PositionAngleType.MEAN, ESTIMATOR_POSITION_SCALE)

fitter = FiniteDifferencePropagatorConverter.convert(tle_builder)

it gives me
TypeError: descriptor ‘convert’ for ‘AbstractPropagatorConverter’ objects doesn’t apply to a ‘NumericalPropagatorBuilder’ object

See below. Note that in the old Python wrapper there’s something stopping me calling getPVCoordinates on the new TLEPropagator at the end, but that only affects the printing of the PV so doesn’t affect the rest of the functionality. I’ve also changed the satellite to a GPS satellite so atmospheric drag isn’t involved.

Edit: added a .propagate() call that I missed

The output should be:

Initial TLE Epoch:
2024-12-11T18:33:12.231072Z
Starting TLE:
1 24876U 97035A   24346.77305823  .00000035  00000+0  00000+0 0  9991
2 24876  55.7332 120.1869 0086157  54.9246 305.8513  2.00561920200673
Input values from TLE in the ECI Frame
Px = -1.315473354461232E7
Py = 2.292137467376963E7
Pz = 31062.321250132172
Vx = -1879.722804250604
Vy = -1115.6288201491861
Vz = 3221.9184921375195
Estimated values based upon the Numerical Propagator in the ECI Frame
Px = -1.3282248886262149E7
Py = 2.2847572940558236E7
Pz = 216.22092157859151
Vx = -1881.2306313275792
Vy = -1126.2502392826345
Vz = 3217.3494285220254
Epoch (this is the Epoch of the input TLE!):
2024-12-11T18:33:12.231072Z
New TLE:
1 24876U 97035A   24346.77305823  .00000035  00000-0  00000-0 0  9993
2 24876  55.6132 120.5525 0086153  54.8501 305.8441  2.00564010200675
PVT of the TLE at the final time point
{2024-12-13T18:33:12.231072, P(-1.4142619061821254E7, 2.225304832353743E7, 1583440.2617032689), V(-1736.7012930178475, -1363.8053685657765, 3209.0587988536736), A(0.3058772009740569, -0.4812899163947692, -0.03424671193421054)}
PVT of the numerical propagator at the final time point
{2024-12-13T18:33:12.231072, P(-1.4140121819620019E7, 2.2255010028368253E7, 1577001.1469659884), V(-1737.449970286972, -1363.0427786061248, 3208.9899113618135), A(0.3058534479627173, -0.4813808599033754, -0.034117217119593236)}
try:
    import orekit_jpype as orekit

    vm = orekit.initVM()
    from orekit_jpype.pyhelpers import (
        setup_orekit_curdir,
        absolutedate_to_datetime,
    )
except ModuleNotFoundError:
    import orekit

    vm = orekit.initVM()
    from orekit.pyhelpers import setup_orekit_curdir, absolutedate_to_datetime


from pathlib import Path

setup_orekit_curdir(str(Path.cwd() / "orekit-data"))
from org.orekit.propagation.analytical.tle import TLE, TLEPropagator

try:
    from org.orekit.orbits import (
        PositionAngle,
    )
except ImportError:
    from org.orekit.orbits import PositionAngleType
from org.orekit.propagation.conversion import (
    TLEPropagatorBuilder,
    FiniteDifferencePropagatorConverter,
)
from org.orekit.propagation.analytical.tle.generation import (
    LeastSquaresTleGenerationAlgorithm,
)
from org.hipparchus.linear import QRDecomposer
from org.hipparchus.optim.nonlinear.vector.leastsquares import (
    GaussNewtonOptimizer,
)
from org.orekit.estimation.leastsquares import BatchLSEstimator
from org.orekit.estimation.measurements import PV, ObservableSatellite
from org.hipparchus.geometry.euclidean.threed import Vector3D
from org.orekit.frames import FramesFactory
from org.orekit.utils import IERSConventions
from org.orekit.orbits import CartesianOrbit
from org.orekit.propagation.conversion import DormandPrince853IntegratorBuilder
from org.orekit.propagation.conversion import NumericalPropagatorBuilder
from org.orekit.models.earth import ReferenceEllipsoid
from org.orekit.forces.gravity.potential import GravityFieldFactory
from org.orekit.forces.gravity import HolmesFeatherstoneAttractionModel
from org.orekit.propagation import SpacecraftState

import numpy as np

rng = np.random.default_rng(seed=42)
rnorm = rng.normal

# Using GPS BIIR-2  (PRN 13) for purpose of demonstration
line1 = "1 24876U 97035A   24346.77305823  .00000035  00000+0  00000+0 0  9991"
line2 = "2 24876  55.7332 120.1869 0086157  54.9246 305.8513  2.00561920200673"
tle = TLE(line1, line2)
print("Initial TLE Epoch:")
print(tle.getDate())
print("Starting TLE:")
print(tle.toString())
# Getting some input data (Processing of laser data/GPS data would go here) ---
propagator = TLEPropagator.selectExtrapolator(tle)
epoch = tle.getDate()
end_date = absolutedate_to_datetime(epoch.shiftedBy(86400.0))

step = 100.0
cur_date = epoch
# Generate a set of input PV data
pvcoordinates = []
dates = []
while absolutedate_to_datetime(cur_date) < end_date:
    pvcoordinates.append(propagator.getPVCoordinates(cur_date))
    dates.append(cur_date)
    cur_date = cur_date.shiftedBy(step)
# Now we have some data, set up the numerical propagator builder --------------

gcrf = FramesFactory.getGCRF()
itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, False)
# Selecting frames to use for OD
eci = gcrf
ecef = itrf
tleInitialState = propagator.getInitialState()
tleEpoch = tleInitialState.getDate()
tleOrbit_TEME = tleInitialState.getOrbit()
tlePV_ECI = tleOrbit_TEME.getPVCoordinates(eci)

wgs84Ellipsoid = ReferenceEllipsoid.getWgs84(ecef)
tleOrbit_ECI = CartesianOrbit(tlePV_ECI, eci, wgs84Ellipsoid.getGM())


# Propagator position error for adaptive step sizing
prop_position_error = 1e-3
# Propagator step size limits
prop_min_step = 0.1
prop_max_step = 600.0
# Getting an integrator builder
integratorBuilder = DormandPrince853IntegratorBuilder(
    prop_min_step, prop_max_step, prop_position_error
)

# Getting a propagator builder
measurement_error = 100.0
propagatorBuilder = NumericalPropagatorBuilder(
    tleOrbit_ECI, integratorBuilder, PositionAngleType.MEAN, measurement_error
)
propagatorBuilder.setMass(419725.0)  # ISS Mass

# Adding a gravity model (more perturbations should be used)

gravityProvider = GravityFieldFactory.getConstantNormalizedProvider(
    64, 64, tleEpoch
)
gravityAttractionModel = HolmesFeatherstoneAttractionModel(
    ecef, gravityProvider
)
propagatorBuilder.addForceModel(gravityAttractionModel)

# Set estimation to use all the parameters (PV)
print("Input values from TLE in the ECI Frame")
for element in propagatorBuilder.getOrbitalParametersDrivers().getDrivers():
    print(element)
    element.setSelected(True)

# Setting up the estimator ----------------------------------------------------
convergence_threshold = 1e-3
max_iterations = 100
max_evaluations = 10
matrixDecomposer = QRDecomposer(1e-11)
optimizer = GaussNewtonOptimizer(matrixDecomposer, False)
estimator = BatchLSEstimator(optimizer, propagatorBuilder)
estimator.setParametersConvergenceThreshold(convergence_threshold)
estimator.setMaxIterations(max_iterations)
estimator.setMaxEvaluations(max_evaluations)

# Adding measurements to the estimator ----------------------------------------
observableSatellite = ObservableSatellite(0)  # Propagator index = 0

for date, pv in zip(dates, pvcoordinates):
    pos_err = rnorm(scale=measurement_error, size=3)
    vel_err = rnorm(scale=measurement_error / 10, size=3)
    orekit_position = PV(
        date,
        # Add noise to the measurement
        pv.getPosition().add(Vector3D(*[float(x) for x in pos_err])),
        pv.getVelocity().add(Vector3D(*[float(x) for x in vel_err])),
        measurement_error,
        measurement_error / 10,  # Assume velocity error 10% of position error
        1.0,  # Base weight
        observableSatellite,
    )
    estimator.addMeasurement(orekit_position)
# Now performing the estimation -----------------------------------------------

propagator = estimator.estimate()[0]
print("Estimated values based upon the Numerical Propagator in the ECI Frame")
for element in estimator.getOrbitalParametersDrivers(True).getDrivers():
    print(element)
for element in estimator.getPropagatorParametersDrivers(True).getDrivers():
    print(element)

# So we've fitted to the first day's worth of data, now we want to go to
# one day later, then fit a TLE to that.
final_date = epoch.shiftedBy(86400.0 * 2)
propagator.propagate(final_date)  # Added this line to put the propagator where we want to be

# Now we have a propagator, we want to fit a TLE to the estimated propagator
# Final end date is the final point at which we want the TLE fitted to
tle_builder = TLEPropagatorBuilder(
    tle,
    PositionAngleType.MEAN,
    measurement_error,
    LeastSquaresTleGenerationAlgorithm(),
)
fitter = FiniteDifferencePropagatorConverter(
    tle_builder, convergence_threshold, max_iterations
)

# Fitting a TLE to the numerical propagator -----------------------------------
# The span is set to a small number to make this quick - to get a good fit
# a larger number should be used.
fitted = fitter.convert(propagator, convergence_threshold, 60, "BSTAR")

try:
    new_tle = fitted.getTLE()
except AttributeError:
    # Older version of Orekit
    new_tle = TLEPropagator.cast_(fitted).getTLE()

print("Epoch (this is the Epoch of the input TLE!):")
print(new_tle.getDate())
print("New TLE:")
print(new_tle.toString())

new_tle_propagator = TLEPropagator.selectExtrapolator(new_tle)
print("PVT of the TLE at the final time point")
# In the old orekit wrapper, this line bugs out
pv_tle = new_tle_propagator.getPVCoordinates(
    final_date, propagator.getFrame()
)
print(pv_tle)
print("PVT of the numerical propagator at the final time point")
pv = propagator.getPVCoordinates(
    final_date, propagator.getFrame()
)
print(pv)

1 Like

that the solution to my question, but you are not using the final_date to propagate the orbit forwards in time. you are fitting the propagator and making the TLE and that’s why when I run my code both the TLE are very same.

to determine the orbit in future shouldn’t you use the propagator.propagate(T1,T2)?

Whoops, good spot. I’d taken out a propagate() call and forgotten to put it back in again! I’ve edited my previous response. The TLEs before and after will be very similar but not completely the same - the addition of errors should cause the results to be different.