Tutorial 08 - OEM Files and Covariance¶
In version 0.9.0, ANISE introduces the ability to read CCSDS OEM (Orbit Ephemeris Message) files and interpolate them, including covariance data. This tutorial demonstrates:
- Reading an OEM File: Loading an OEM file into an
Ephemerisobject. - Interpolation: Querying state and covariance at arbitrary times.
- Covariance Frames: Accessing covariance in different frames (RIC, Inertial, etc.).
- Event Integration: Combining OEM data with event finding to query covariance at specific event times.
from pathlib import Path
from anise import Almanac
from anise.astro import Ephemeris, LocalFrame, DataType, Orbit, Frame
from anise.constants import Frames
from anise.time import Epoch, Unit
from anise.analysis import Event, StateSpec, FrameSpec
# Load a base Almanac (for frame definitions)
almanac = Almanac("../../data/pck08.pca")
almanac.describe()
=== PLANETARY DATA #0: `../../data/pck08.pca` === ┌───────┬─────────┬──────────────────────────┬─────────────────┬─────────────────┬─────────────────┬───────────────────────┬─────────────────────┬────────────────────────────────────────────────────────┐ │ Name │ ID │ Gravity param (km^3/s^2) │ Major axis (km) │ Minor axis (km) │ Polar axis (km) │ Pole right asc. │ Pole declination │ Prime meridian │ ├───────┼─────────┼───────────────────��──────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 1 │ 22031.78000000002 │ 2439.7 │ 2439.7 │ 2439.7 │ 281.01 + -0.033 t │ 61.45 + -0.005 t │ 329.548 + 6.1385025 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 2 │ 324858.59200000006 │ 6051.8 │ 6051.8 │ 6051.8 │ 272.76 + 0 t │ 67.16 + 0 t │ 160.2 + -1.4813688 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼───���────────────────────────────────────────────────────┤ │ Unset │ 3 │ 403503.2355022598 │ Unset │ Unset │ Unset │ Unset │ Unset │ Unset │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 4 │ 42828.37521400002 │ Unset │ Unset │ Unset │ Unset │ Unset │ Unset │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 5 │ 126712764.8000002 │ Unset │ Unset │ Unset │ Unset │ Unset │ Unset │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 6 │ 37940585.2 │ Unset │ Unset │ Unset │ Unset │ Unset │ Unset │ ├───────┼─────────┼──────────────────���───────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 7 │ 5794548.600000008 │ Unset │ Unset │ Unset │ Unset │ Unset │ Unset │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼──────────��──────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 8 │ 6836527.100580024 │ Unset │ Unset │ Unset │ Unset │ Unset │ Unset │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 10 │ 132712440041.93938 │ 696000 │ 696000 │ 696000 │ 286.13 + 0 t │ 63.87 + 0 t │ 84.1 + 14.1844 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 301 │ 4902.800066163796 │ 1737.4 │ 1737.4 │ 1737.4 │ 269.9949 + 0.0031 t │ 66.5392 + 0.013 t │ 38.3213 + 13.17635815 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 399 │ 398600.435436096 │ 6378.14 │ 6378.14 │ 6356.75 │ 0 + -0.641 t │ 90 + -0.557 t │ 190.147 + 360.9856235 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 401 │ 0.0007087546066894452 │ 13.4 │ 11.2 │ 9.2 │ 317.68 + -0.108 t │ 52.9 + -0.061 t │ 35.06 + 1128.844585 t + 0.000000006644300993056522 t^2 │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 402 │ 0.00009615569648120313 │ 7.5 │ 6.1 │ 5.2 │ 316.65 + -0.108 t │ 53.52 + -0.061 t │ 79.41 + 285.161897 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────���───────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 499 │ 42828.37362069909 │ 3396.19 │ 3396.19 │ 3376.2 │ 317.68143 + -0.1061 t │ 52.8865 + -0.0609 t │ 176.63 + 350.89198226 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼��───────────────────────────────────────────────────────┤ │ Unset │ 501 │ 5959.916033410404 │ 1829.4 │ 1819.3 │ 1815.7 │ 268.05 + -0.009 t │ 64.5 + 0.003 t │ 200.39 + 203.4889538 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 502 │ 3202.738774922892 │ 1564.13 │ 1561.23 │ 1560.93 │ 268.08 + -0.009 t │ 64.51 + 0.003 t │ 36.022 + 101.3747235 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 503 │ 9887.834453334144 │ 2632.4 │ 2632.29 │ 2632.35 │ 268.2 + -0.009 t │ 64.57 + 0.003 t ��� 44.064 + 50.3176081 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 504 │ 7179.28936139727 │ 2409.4 │ 2409.2 │ 2409.3 │ 268.72 + -0.009 t │ 64.83 + 0.003 t │ 259.51 + 21.5710715 t │ ├───────┼─────────┼───────────────��──────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 505 │ 0.1378480571202615 │ 125 │ 73 │ 64 │ 268.05 + -0.009 t │ 64.49 + 0.003 t │ 231.67 + 722.631456 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 599 │ 126686534.9218008 │ 71492 │ 71492 │ 66854 │ 268.05 + -0.009 t │ 64.49 + 0.003 t │ 284.95 + 870.536642 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────���────────────────────────────────────────────────────────┤ │ Unset │ 601 │ 2.503522884661795 │ 209.1 │ 196.2 │ 191.4 │ 40.66 + -0.036 t │ 83.52 + -0.004 t │ 337.46 + 381.994555 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼──────────────────────────────────────────────────────��─┤ │ Unset │ 602 │ 7.211292085479989 │ 256.3 │ 247.3 │ 244.6 │ 40.66 + -0.036 t │ 83.52 + -0.004 t │ 2.82 + 262.7318996 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 603 │ 41.21117207701302 │ 535.6 │ 528.2 │ 525.8 │ 40.66 + -0.036 t │ 83.52 + -0.004 t │ 10.45 + 190.6979085 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 604 │ 73.11635322923193 │ 560 │ 560 │ 560 │ 40.66 + -0.036 t │ 83.52 + -0.004 t │ 357 + 131.5349316 t │ ├───────┼─────────┼──────────────���───────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 605 │ 153.9422045545342 │ 764 │ 764 │ 764 │ 40.38 + -0.036 t │ 83.55 + -0.004 t │ 235.16 + 79.6900478 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼──────��──────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 606 │ 8978.138845307376 │ 2575 │ 2575 │ 2575 │ 36.41 + -0.036 t │ 83.94 + -0.004 t │ 189.64 + 22.5769768 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 607 │ 0.3718791714191668 │ 164 │ 130 │ 107 │ Unset │ Unset │ Unset │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼─────────────────────────────────────────────────────���──┤ │ Unset │ 608 │ 120.5134781724041 │ 718 │ 718 │ 718 │ 318.16 + -3.949 t │ 75.03 + -1.143 t │ 350.2 + 4.5379572 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 609 │ 0.5531110414633374 │ 115 │ 110 │ 105 │ 355 + 0 t │ 68.7 + 0 t │ 304.7 + 930.833872 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 610 │ 0.1266231296945636 │ 97 │ 95 │ 77 │ 40.58 + -0.036 t │ 83.52 + -0.004 t │ 58.83 + 518.2359876 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────────────────┼───────────────────────┼─────────────────────┼────────────────────────────────────────────────────────┤ │ Unset │ 611 │ 0.03513977490568457 │ 69 │ 55 │ 55 │ 40.58 + -0.036 t │ 83.52 + -0.004 t │ 293.87 + 518.4907239 t │ ├───────┼─────────┼──────────────────────────┼─────────────────┼─────────────────┼─────�
1. Reading an OEM File¶
We can load an OEM file directly into an Ephemeris object. This object holds the interpolated data.
oem_path = "../../data/tests/ccsds/oem/LRO_Nyx.oem"
print(f"Loading OEM from {oem_path}")
ephem = Ephemeris.from_ccsds_oem_file(oem_path)
print("Ephemeris loaded:")
print(ephem)
(start, end) = ephem.domain()
print(f"Domain: {start} to {end}")
Loading OEM from ../../data/tests/ccsds/oem/LRO_Nyx.oem Ephemeris loaded: 2010-LRO ephem from 2024-01-01T00:00:00 UTC to 2024-01-01T00:03:00 UTC (4 states, spans 3 min) Domain: 2024-01-01T00:00:00 UTC to 2024-01-01T00:03:00 UTC
2. Interpolation and Covariance¶
We can query the covariance at any time within the domain. ANISE supports transforming the covariance into various local frames:
- RIC (Radial, In-track, Cross-track): Also known as RTN.
- Inertial: The frame in which the data is defined (usually J2000).
- VNC (Velocity, Normal, Co-normal): Useful for maneuver planning.
- RCN: Radial, Cross-track, Normal.
query_time = start + (end - start) * 0.5
print(f"Querying covariance at {query_time}")
# Covariance in RIC frame
covar_ric = ephem.covar_at(query_time, LocalFrame.RIC, almanac)
print("\nCovariance (RIC):")
print(covar_ric)
# Covariance in Inertial frame
covar_inertial = ephem.covar_at(query_time, LocalFrame.Inertial, almanac)
print("\nCovariance (Inertial):")
print(covar_inertial)
Querying covariance at 2024-01-01T00:01:30 UTC Covariance (RIC): Covariance in RIC ┌ ┐ │ 0.962697 0.417577 -0.432062 0.004468 0.002043 -0.001881 │ │ 0.417577 0.672621 0.372849 0.002017 0.003435 0.001994 │ │ -0.432062 0.372849 0.832859 -0.001914 0.001990 0.004048 │ │ 0.004468 0.002017 -0.001914 0.000059 0.000024 -0.000022 │ │ 0.002043 0.003435 0.001990 0.000024 0.000036 0.000020 │ │ -0.001881 0.001994 0.004048 -0.000022 0.000020 0.000044 │ └ ┘ Covariance (Inertial): Covariance in Inertial ┌ ┐ │ 0.221927 0.425854 0.264891 0.001022 0.001972 0.001206 │ │ 0.425854 1.115708 0.013385 0.001966 0.005345 -0.000217 │ │ 0.264891 0.013385 1.138789 0.001213 -0.000234 0.005647 │ │ 0.001022 0.001966 0.001213 0.000011 0.000022 0.000013 │ │ 0.001972 0.005345 -0.000234 0.000022 0.000062 0.000004 │ │ 0.001206 -0.000217 0.005647 0.000013 0.000004 0.000067 │ └ ┘
3. Combining with Event Finding¶
A powerful workflow is to find events using the Almanac and then inspect the covariance at those specific times.
First, we load the OEM into an Almanac. We must provide a NAIF ID for the object in the OEM file (e.g., LRO is -85).
lro_id = -85
# Load OEM into a new Almanac, assigning it the LRO ID
almanac_oem = Almanac.from_ccsds_oem_file(oem_path, lro_id)
# Load PCK for frame definitions (needed for event finding involving other bodies or frames)
almanac_oem = almanac_oem.load("../../data/pck08.pca")
print("Almanac created from OEM:")
almanac_oem.describe(spk=True)
ephemeris contains covariance, which is NOT copied to the SPICE BSP file
Almanac created from OEM: === SPK #0: `2025-12-29T21:07:33.292829705 UTC` === ┌─────────────────────────────────────────┬────────────────┬────────────┬───────────────────────────────────┬───────────────────────────────────┬──────────┬──────────────────────┐ │ Name │ Target │ Center │ Start epoch │ End epoch │ Duration │ Interpolation kind │ ├─────────────────────────────────────────┼────────────────┼───────────���┼───────────────────────────────────┼───────────────────────────────────┼──────────┼──────────────────────┤ │ 2010-LRO (converted by Nyx Space ANISE) │ body -85 J2000 │ Moon J2000 │ 2024-01-01T00:01:09.183898601 TDB │ 2024-01-01T00:04:09.183898727 TDB │ 3 min │ Hermite Unequal Step │ └─────────────────────────────────────────┴────────────────┴────────────┴───────────────────────────────────┴───────────────────────────────────┴──────────┴──────────────────────┘
Now we define an event, for example, finding apoapsis events... of which there are none because there is only 3 min of data in this ephem
lro_frame = Frame(lro_id, 1) # Assuming J2000 orientation
moon_frame = Frames.MOON_J2000
lro_state_spec = StateSpec(
target_frame=FrameSpec.Loaded(lro_frame),
observer_frame=FrameSpec.Loaded(moon_frame),
ab_corr=None,
)
apolune = Event.apoapsis()
print(f"Searching for apoapsis events...")
apo_events = almanac_oem.report_events(lro_state_spec, apolune, start, end)
print(f"Found {len(apo_events)} apoapsis events.")
Searching for apoapsis events... Found 0 apoapsis events.
Finally, we iterate through the found events and query the covariance from the original Ephemeris object at each event time.
print("Querying covariance at event times:")
for i, event in enumerate(apo_events):
event_time = event.orbit.epoch
# Query covariance in RIC frame
cov = ephem.covar_at(event_time, LocalFrame.RIC, almanac_oem)
print(f"\nEvent {i+1} at {event_time}:")
print(cov)
Querying covariance at event times: