State vector differences between poliastro.twobody.Orbit and spg4
See original GitHub issueI am trying to compare various poliastro orbit propagation methods vs the spg4 propagator. However, the resulting state vectors are significantly different between both.
🐞 Problem
Essentially, we generate a poliastro.twobody.Orbit and use it to initialise the spg4 orbit. However, when converting back from spg4 to Orbit (for the same epoch, without actual propagation), the state vector is off by several kilometres.
Sample code here:
#!/usr/local/bin/python3
from astropy import coordinates as coord, units as u
from astropy.time import Time
from astropy.coordinates import TEME
from poliastro.twobody import Orbit
from poliastro.bodies import Earth
from poliastro.twobody import angles
from poliastro.examples import iss
from sgp4.api import Satrec, SGP4_ERRORS, WGS84
if __name__ == "__main__":
# Display some initial data
print(f" Orbit: {iss}")
print(" State vector [poliastro]")
print(f" r = {iss.r}")
print(f" v = {iss.v}")
print()
# Generate the equivalent using spg4
epochTime = Time(iss.epoch, format='datetime', scale='utc')
eccAnomaly = angles.nu_to_E(iss.nu, iss.ecc)
meanAnomaly = angles.E_to_M(eccAnomaly, iss.ecc)
sat = Satrec()
sat.sgp4init(WGS84, 'i', 0, epochTime.jd - 2433281.5, 0.0, 0.0, 0.0,
iss.ecc, iss.argp.value, iss.inc.value, meanAnomaly.value,
iss.n.to(u.rad/u.minute).value, iss.raan.value,
)
# Compute state vector from sgp4
errorCode, rTEME, vTEME = sat.sgp4(epochTime.jd1, epochTime.jd2)
if errorCode != 0:
raise RuntimeError(SGP4_ERRORS[errorCode])
pTEME = coord.CartesianRepresentation(rTEME*u.km)
vTEME = coord.CartesianDifferential(vTEME*u.km/u.s)
svTEME = TEME(pTEME.with_differentials(vTEME), obstime=iss.epoch)
svITRS = svTEME.transform_to(coord.ITRS(obstime=iss.epoch))
sv = Orbit.from_coords(Earth, svITRS)
print("State vector [spg4]")
print(f" r = {sv.r}")
print(f" v = {sv.v}")
print()
print("State vector differences [poliastro - spg4]")
print(f" r = {iss.r - sv.r}")
print(f" v = {iss.v - sv.v}")
print()
🖥 Results:
State vector [poliastro]
r = [ 859.07256 -4137.20368 5295.56871] km
v = [7.37289205 2.08223573 0.43999979] km / s
State vector [spg4]
r = [ 852.72472797 -4137.51683084 5287.30166418] km
v = [7.38429906 2.06186541 0.430843 ] km / s
State vector differences [poliastro - spg4]
r = [6.34783203 0.31315084 8.26704582] km
v = [-0.01140701 0.02037032 0.0091568 ] km / s
💡 Possible solutions
This involves a combination of poliastro, astropy and spg4 and transformation between different frames, so it is not clear where the problem is.
Any advise is much appreciated.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:2
- Comments:8 (5 by maintainers)
Top Results From Across the Web
poliastro.twobody.orbit.scalar
Position and velocity of a body with respect to an attractor at a given time (epoch). Regardless of how the Orbit is created,...
Read more >poliastro.twobody.states
State defined by its position and velocity vectors. ModifiedEquinoctialState. State defined by modified equinoctial elements representation. class ...
Read more >Quickstart — poliastro 0.17.0 documentation
The core of poliastro are the Orbit objects inside the poliastro.twobody module. ... The position and velocity vectors or the orbital elements.
Read more >poliastro.twobody.orbit
Orbit. Position and velocity of a body with respect to an attractor. Previous Next. © Copyright 2013, Juan Luis Cano Rodríguez and the...
Read more >API reference — poliastro 0.17.0 documentation
class poliastro.twobody.Orbit(state, epoch). Position and velocity of a body with respect to an attractor at a given time (epoch). Regardless of how the ......
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found

After giving this a closer inspection, I can conclude that this is “not a bug”, but a very common confusion arising with TLEs. Let me explain without getting into much detail.
This line:
creates a TLE using osculating orbital elements, which are the ones that
Orbitobjects in poliastro handle. As poliastro is mostly concerned with the purely Keplerian two body problem, this is everything we need.However, as you know better than me1, the real world is way more complex, and orbits deviate from its purely Keplerian motion all the time. As a result, osculating elements only have value on a given instant in time, but they slowly evolve with time (with the exception, of course, of anomalies, that change rapidly anyway).
And here comes the common mistake: TLEs do not use osculating elements, but Brouwer mean elements. They are mean elements because they use some averaging technique over a period of time, and this technique is due to Dirk Brouwer (Brouwer, Dirk “Solution of the Problem of Artificial Satellite Theory without Drag”, 1959) as opposed to, say, Kozai mean elements (Kozai, Yoshihide “The Motion of a Close Earth Satellite”, 1959).
In summary, when creating a TLE directly from osculating elements, this leads to a systematic error, and therefore one cannot expect the propagation to be accurate (they will be precise, but not accurate, i.e. close to the true value).
This is a surprisingly common misconception that is not clearly addressed in the famous TLE FAQ by Dr. T. S. Kelso. I have pointed out this mistake in other places, for example in https://github.com/aerospaceresearch/orbitdeterminator/issues/195.
There are several ways to do this properly:
And there are several actions we could take on the poliastro side:
poliastro.twobody.Orbitto/from TLE (or any other GP data format, like OMM) so there is a clear API that does _the right thing_™ and reduces confusion.Please @jtegedor let me know if all of this makes sense.
Please forgive this “mansplaining” line - it’s not for you @jtegedor, but for future readers!
Merged! 🚀 I’m closing this support issue in favor of https://github.com/poliastro/poliastro/issues/1215, which I think it’s the first step towards providing a proper API.