I am attempting to create a TLE from a set of GPS data. I have code with which I generate an Ephemeris using the base from which I edited but my output is roughly the same. I also have a program that accepts data in Earth Centered Earth Fixed (GTOD) and converts is to the Earth Centered Inertia (GCRF) used in the program. It is clear that creating the Ephemeris is simple. However, I am new to Orekit and am unfamiliar with how to create a fit TLE from this data. Note: The base code is in Orekit version 10.2 and mine is updated to 11.2.
Hi @separnell
Welcome to the Orekit forum!
In Orekit, you have two possibilities to generate a TLE:
- Generate the exact TLE of a single orbit. It can be done calling the method
TLE.stateToTLE(SpacecraftState, TLE)
- Generate a TLE that represents and fits an interval of data.
For the second point, which is I think what you want to do, you try something like below. If
your have access to the List<SpacecraftState>
used to initialize the Ephemeris
object, let sample
be the List<SpacecraftState>
.
builder = TLEPropagatorBuilder(tleTemplate, PositionAngle.TRUE, 1.0);
fitter = FiniteDifferencePropagatorConverter(builder, 0.001, 1000);
fitter.convert(sample, false);
prop = TLEPropagator.cast_(fitter.getAdaptedPropagator())
fitted_tle = prop.getTLE()
With tleTemplate
is a TLE
object used to initialize some values like the NORAD ID, the epoch of the TLE, etc. In other words, the keplerian elements of the tleTemplate
can be equal to 0.0.
Best regards,
Bryan
Thanks @bcazabonne for your advice,
Iāve been trying to follow your recommendation have had problems creating the tleTemplate.
(Ran out of embedded media objects)
And Iām getting this error. I presumed there was something incorrect with my date formatting, so I did it differently and got a not implemented error .
Traceback (most recent call last):
File āC:\Users\separ\Desktop\New_Orekit_Orbit_Determination.pyā, line 245, in
tleTemplate = TLE(11111, āUā, 2020, 222, āAā, 0, 333, AbsoluteDate(2020, 1, 1, TimeScale(utc)), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
NotImplementedError: (āinstantiating java classā, <class āorg.orekit.time.TimeScaleā>)
(Ran out of links⦠please bear with me as I try to become a level 1 userā¦)
What formatting should I be using for the date/ is there some other way to create the tleTemplate?
The problem is the conversion from integer to double. You should initialize the tleTemplate like that:
tleTemplate = TLE(11111, "U", 2020, 222, "A", 0, 333, ref_date, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0)
Bryan
That resolved my problem with creating the tleTemplate, I however then encountered the error message that the Jacobian matrix is singular. I have encountered this several times throughout working on this, but it usually fixes itself by just messing with values which doesnāt seem to be working here. What does this mean (from a code issue perspective, I know what a singular or degenerate matrix is mathematically), and how is it actually supposed to be fixed?
I see. Let āephemerisā be your Ephemeris object, could you try initializing the tleTemplate like that.
tleTemplate = TLE.stateToTLE(ephemeris.propagate(date_start), tleTemplate)
Bryan
I think thatās because for TLE fitting the keplerian elements of the tleTemplate canāt be equal to 0 (while for the stateToTLE they can). So, thatās why I propose to use the stateToTLE method to initialize the template
Sorry for the wrong information in my first messageā¦
I initialized it and end up getting what I think is an error code, though itās hard to tell as itās longer than the terminal⦠here is a clip of it
I have figured out that it happens here in this line:
I used my estimated propagator (creating a spacecraft state alike to that which is required for stateToTLE) in my ephemeris code, could it have changed the nature of it?
I may also have the wrong list of spacecraft states. The one used is generated in the last code block above.
Quick update to anyone who may read and respond to this, I have realized that I did indeed have my spacecraft states incorrect and they are now the list of absolute pv coordinates that it should be, I also seem to need some list of āfree parametersā and have otherwise been unable to figure out what this means. I am getting the IllegalArgumentException which makes sense as I am not listing any free parameters.
If itās possible for you, Iāll need a sample of code in order to run you application and see whatās wrong. Because itās hard to understand.
By default, all orbital parameters are fitted. freeParameters
are additional parameters that you want to fit. For TLE fitting, it can be the B* parameter.
Bryan
I forgot I could do this now that Iām no longer a level 0 userā¦
New_Orekit_Orbit_Determination.py (22.2 KB)
And this accepts the Earth Centered Earth Fixed Frame, so here is a data set that can be run with it.
SimulatedObservationsOK.csv (8.1 KB)
The TLE fitting is at the bottom, but it needs all the code to run.
I just found this post:
Generation of TLE - Orekit development - Orekit
And it looks like the approach you are using used an Orbit object for the spacecraft states. The only difficulty is I donāt have an orbit as a spacecraft state, but rather an AbsolutePV coordinate. Is there a different approach that would be better to use, or is there some way to turn my PV coordinates into an orbit rather that I am just not seeing?
Hi,
I solved the argument error. The TLESpacecraftStates needs to be converted to a Java list. You can solve the issue like that:
# Convert to a list
states_list = ArrayList()
for state in TLESpacecraftStates:
states_list.add(state)
tleTemplate = TLE(11111, "U", 2020, 222, "A", 0, 333, date_start, 0.0, -138.8546595251871, 0.0, 0.00029131750532795117, 98.24086439196059, 66.12659133154932, -55.56899656065682, 0.0, 0, 0.0)
tleTemplate = stateToTLE(estimatedPropagator.propagate(date_start), tleTemplate)
builder = TLEPropagatorBuilder(tleTemplate, PositionAngle.TRUE, 1.0)
fitter = FiniteDifferencePropagatorConverter(builder, 0.001, 1000)
fitter.convert(states_list, False, 'BSTAR')
I added the BSTAR parameter as free parameter. Indeed, I think it is interesting to fit it.
The convert method is now used but another exception is raised: MathIllegalStateException for the Q.R decomposition. This must be investigated.
Bryan
Ok, I solved the second issue.
Because GCRF is an inertial frame, you can use orbits instead of absolute coordinates. Indeed, absolute coordinates were implemented to create spacecraft states defined in non inertial states and to perform the computation in non inertial frame (e.g. trajectory around Lagragian points) Therefore, you can change your lines
pv = TimeStampedPVCoordinates(date, vector_gtod, velocity_gtod)
pv_gcrf = gtod.getTransformTo(gcrf, date).transformPVCoordinates(pv)
absolute_pv_gcrf = AbsolutePVCoordinates(gcrf, pv_gcrf)
TLESpacecraftStates.append(SpacecraftState(absolute_pv_gcrf))
by
from org.orekit.utils import Constants
from org.orekit.orbits import CartesianOrbit
pv = TimeStampedPVCoordinates(date, vector_gtod, velocity_gtod)
pv_gcrf = gtod.getTransformTo(gcrf, date).transformPVCoordinates(pv)
TLESpacecraftStates.append(SpacecraftState(CartesianOrbit(pv_gcrf, gcrf, date, Constants.WGS84_EARTH_MU)))
Best regards,
Bryan
Now I have an open question.
Because your initial need is to generate a TLE that fits your GPS data. Maybe you could perform a SGP4 (i.e., TLE-based) orbit determination?
It means that instead of using a numerical model during the orbit determination you can use the SGP4 model. At the end, you will obtain an estimated TLE fitted using the observations.
Also, I saw that your numerical model doesnāt consider any perturbation. Therefore, the accuracy will be very poor⦠And your fitted TLE will be very inaccurate.
Maybe you can try to replace your propagatorBuilder initialization by
tleTemplate = TLE(11111, "U", 2020, 222, "A", 0, 333, orbit_first_guess.getDate(), 0.0, -138.8546595251871, 0.0, 0.00029131750532795117, 98.24086439196059, 66.12659133154932, -55.56899656065682, 0.0, 0, 0.0)
tleInitialGuess = stateToTLE(SpacecraftState(orbit_first_guess), tleTemplate)
propagatorBuilder = TLEPropagatorBuilder(tleInitialGuess, PositionAngle.TRUE, estimator_position_scale)
And obtain the estimated (fitted) TLE by using
print(TLEPropagator.cast_(estimatedPropagator).getTLE())
and not the FiniteDifferencePropagatorConverter
!
Just be careful that the outputs will be in TEME frame.
I didnāt try in your application because my Orekit Python version is 10.3 and this functionality was introduced in 11.0. But I think it can be very useful for your need. However, itās only an advice, your free to try or not
If you want to know more about SGP4 orbit determination you can look at this reference:
Bryan
Thank you for your advice!
In response to your open question, I didnāt do that simply because I didnāt know I could. So, I will investigate that. You mentioned that my numerical propagator doesnāt consider any perturbation⦠is that specifically in reference to the way I was trying to generate my TLE, or will that effect the accuracy of my Ephemeris as well as it uses a numerical propagator?
I was unable to get this line working:
print(TLEPropagator.cast_(estimatedPropagator).getTLE())
But in comparison with another programs output (FreeFlyer) which we are seeking an alternative to, changing the first three lines made a difference of about 10 meters in comparison which is about 50% closer. So, I think everything is now working. Thanks for all your help!