Skip to content

Orbit Ingest

The ingest stage converts raw satellite ephemerides into a uniformly sampled, body-fixed orbit catalogue that downstream simulation and estimation stages consume. The implementation lives in src/orbit_processing.py and relies on SPICE frame transformations exposed through spiceypy, furnished by the kernels referenced in the scenario file.

Processing flow

Running poetry run acons ingest … executes the following steps for every satellite entry listed under orbits:

  1. Furnish SPICE kernelssrc/spice_support.py:furnish_kernels loads the kernel list from spice.kernels. A leapseconds kernel (LSK), a frame kernel (FK) for the inertial frame, and a binary/polynomial frame kernel (PCK/CK/BC) for the body-fixed frame are the minimum set.
  2. Resolve the ingest timelineget_time_config accepts absolute UTC/JD values or offsets in seconds from the first sample in the ephemerides (via time.start_seconds / time.end_seconds). The helper build_time_grid creates an inclusive Julian Date grid with the configured cadence.
  3. Load and normalise ephemeridesload_orbit_csv expects comma-separated files with at least jd, x_m, y_m, z_m, vx_mps, vy_mps, vz_mps. Columns are interpreted in the frame named by frames.input (typically J2000). An optional epoch_s column is recomputed if missing.
  4. Interpolation onto the gridresample_states_leapfrog applies a constant-acceleration leapfrog interpolator so every satellite has state vectors aligned to the ingest grid.
  5. Frame conversiontransform_states calls spice.sxform via spiceypy to obtain the 6×6 state transformation from frames.input to frames.body_fixed at each epoch. Julian Dates are first converted to ephemeris time using spice.unitim.
  6. Export artefacts – a parquet file per satellite (<sat_id>_orbit.parquet) plus an aggregate orbits_manifest.parquet are written to the ingest run directory. Each record contains epoch-relative seconds, Julian Date, ephemeris time, and body-fixed position/velocity. Quick-look plots are produced from both the input-frame states (plots/input_frame/) and the converted body-fixed orbits (plots/output_frame/) when reporting.enable_plots is true so you can inspect the transformation results.

If the ingest window extends outside the supplied ephemeris coverage, the interpolator raises an error with the offending timestamps, prompting you to widen the source data or tighten the ingest interval.

Required inputs

  • SPICE kernels: At minimum furnish
  • an LSK (e.g. naif0012.tls) for TDB↔UTC conversions,
  • an FK describing the inertial frame used by the ephemerides (e.g. moon_080317.tf for the Moon PA frame definitions),
  • a body orientation kernel (binary PCK or CK). For Moon and Mars these are typically binary PCKs (*.bpc), whereas Earth commonly uses high-accuracy CK/ITRF solutions. The exact mix depends on the frames you transform between; consult NAIF documentation if you need high-fidelity orientation or tidal models.
  • Ephemeris files: One CSV per satellite holding inertial states. The filename stem becomes the satellite identifier unless overridden by orbits[].id. Keep epochs monotonically increasing; gaps larger than the ingest cadence lead to constant-acceleration interpolation across the gap.
  • Scenario file: Defines frames.input, frames.body_fixed, ingest cadence (time.step_seconds), and optional relative start/end offsets. The receiver block provides body radius for plotting but does not influence the state conversion.

Adapting to other bodies

Only the scenario configuration and SPICE kernel list need to change to ingest orbits for a different central body.

  • Mars: Set frames.body_fixed: "IAU_MARS" (or the appropriate Mars-fixed frame) and furnish: naif0012.tls, the NAIF Mars frame kernel pck00011.tpc (used by ACONS for the Mars IAU transformations), and a binary orientation kernel such as mar097.bsp/mar097.bpc that carries the body-fixed rotation. Provide Mars-centric inertial ephemerides (e.g. in J2000). Update receiver geometry with Mars’ mean radius if you are plotting surface references.
  • Earth: Choose a body-fixed frame compatible with your SPICE set—ITRF93, IAU_EARTH, or EARTH_FIXED. Furnish an Earth FK (e.g. earth_latest_high_prec.tf) plus the appropriate high-precision Earth orientation kernels (earth_latest_high_prec.bpc or EOP CKs). Ensure the inertial ephemerides align with the same inertial frame (usually J2000). Because Earth orientation files can be time-limited, verify the ingest timeline remains within the kernel span.

For any new body the workflow is:

frames:
  input: "J2000"
  body_fixed: "IAU_MARS"   # or the target body's fixed frame

spice:
  kernels:
    - data/SPICE/naif0012.tls
    - data/SPICE/pck00011.tpc      # Mars frame definitions

orbits:
  - path: ephemeris/MARS_SAT1.csv
  - path: ephemeris/MARS_SAT2.csv

After updating the scenario file and placing the kernels in data/SPICE/, rerun poetry run acons ingest pointing to the modified configuration. The ingest stage reuses the same Python code regardless of the target body; all differences are encapsulated by the supplied SPICE assets and ephemerides.