Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Osculating elements in OMM seem to change when creating an EarthSatellite object #1037

Open
scottshambaugh opened this issue Feb 11, 2025 · 2 comments

Comments

@scottshambaugh
Copy link

scottshambaugh commented Feb 11, 2025

I am comparing orbital elements before and after creation of an EarthSatellite from an OMM, and am getting slightly different values. I expect this is benign, but am not sure what's going on.

Here's a quick example script that shows what's happening:

from skyfield.api import EarthSatellite, load
from skyfield.elementslib import osculating_elements_of

ts = load.timescale()
omm_data = {
    'OBJECT_NAME': 'TEST SAT',
    'OBJECT_ID': '2024-001A',
    'NORAD_CAT_ID': '12345',
    'EPOCH': '2024-01-01T00:00:00.000000',
    'MEAN_MOTION': 15.5,      # rev/day
    'ECCENTRICITY': 0.01,     # unitless
    'INCLINATION': 51.6,      # degrees
    'RA_OF_ASC_NODE': 180.0,  # degrees
    'ARG_OF_PERICENTER': 0.0, # degrees
    'MEAN_ANOMALY': 0.0,      # degrees
    'BSTAR': 0.0,             # 1/earth radius
    'MEAN_MOTION_DOT': 0.0,   # rev/day^2
    'MEAN_MOTION_DDOT': 0.0,  # rev/day^3
    'CLASSIFICATION_TYPE': 'U',
    'EPHEMERIS_TYPE': '0',
    'ELEMENT_SET_NO': '999',
    'REV_AT_EPOCH': '0',
}
sat = EarthSatellite.from_omm(ts, omm_data)

pos = sat.at(sat.epoch)
osc_elements = osculating_elements_of(pos)  # ICRF frame

print(sat.epoch.utc)
print(osc_elements.eccentricity, omm_data['ECCENTRICITY'])
print(osc_elements.inclination.degrees, omm_data['INCLINATION'])
print(osc_elements.longitude_of_ascending_node.degrees, omm_data['RA_OF_ASC_NODE'])
print(osc_elements.argument_of_periapsis.degrees, omm_data['ARG_OF_PERICENTER'])
print(osc_elements.mean_anomaly.degrees, omm_data['MEAN_ANOMALY'])

# All values are at least somewhat different.
'''
CalendarTuple(year=2024, month=1, day=1, hour=0, minute=0, second=0.0)
0.010881909723842008 0.01
51.62267299309298 51.6
179.58708119720018 180.0
4.705040984693307 0.0
355.46545250154924 0.0
'''

I thought this might have to do with the frame conversion between TEME and ICRF, but when I try to check it the results are very roughly the same as before.

from skyfield.sgp4lib import TEME
osc_elements = osculating_elements_of(pos, reference_frame=TEME.rotation_at(sat.epoch))  # TEME frame

'''
CalendarTuple(year=2024, month=1, day=1, hour=0, minute=0, second=0.0)
0.010881909723847644 0.01
51.61995468574305 51.6
179.99991187961967 180.0
4.535383674828455 0.0
355.46545250155054 0.0
'''
@brandon-rhodes
Copy link
Member

The snag is that you are comparing an element set from one theory of orbital motion, the simple Kepler elliptical-orbit model, with elements from a different model, the SGP4 theory of perturbed Earth satellite motion. The elements don't mean quite the same thing and so don't ever match.

Is there somewhere in the documentation where, if it mentioned this more prominently, you would have been spared the confusion about the two element sets? If you let me know which document and section, I could try adding a paragraph!

@scottshambaugh
Copy link
Author

scottshambaugh commented Feb 11, 2025

Thank you for the quick response, and for the wonderful library! I'm finding it incredibly useful.

I was ultimately looking to generate expected OMM messages after propagation. It's possible to do that for the initial epoch with elements matching the input with sgp4lib:

from sgp4 import exporter
exporter.export_omm(sat.model, sat.name)

'''
'OBJECT_NAME' = 'TEST SAT'
'OBJECT_ID' = '2024-001A'
'CENTER_NAME' = 'EARTH'
'REF_FRAME' = 'TEME'
'TIME_SYSTEM' = 'UTC'
'MEAN_ELEMENT_THEORY' = 'SGP4'
'EPOCH' = '2024-01-01T00:00:00.000000'
'MEAN_MOTION' = 15.5
'ECCENTRICITY' = 0.01
'INCLINATION' = 51.6
'RA_OF_ASC_NODE' = 180.0
'ARG_OF_PERICENTER' = 0.0
'MEAN_ANOMALY' = 0.0
'EPHEMERIS_TYPE' = 0
'CLASSIFICATION_TYPE' = 'U'
'NORAD_CAT_ID' = 12345
'ELEMENT_SET_NO' = 999
'REV_AT_EPOCH' = 0
'BSTAR' = 0.0
'MEAN_MOTION_DOT' = 0.0
'MEAN_MOTION_DDOT' = 0.0
'''

But I'm still unclear how to generate TLEs/OMMs at future epochs based on the propagated state. #1021 is a similar ask. Understood that it's a bad idea to do that in real-life scenarios since these messages are by definition only valid at their initial epoch. But there are some legit uses:

  • It would be useful for making test data for other tools to ingest.
  • Being able to generate propagated orbital elements would be valuable for some use cases without the same pitfalls as generating TLEs/OMMs.
  • Being able to generate EarthSatellite objects from an epoch and position/velocity state vectors would be broadly useful

For the original ask, I think it's ultimately on me being confused that the TLE/OMM data was delivered with mean elements instead of osculating! But happy to provide some suggestions on improving the docs:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants