Formats¶
What each format expresses, what it cannot, and how it maps into the canonical
representation. Reading routes a format into its canonical category type; everything the
canonical form has no slot for is preserved on the source_native
fidelity model rather than dropped.
Support at a glance¶
| Format | Id | Read | Write | Canonical form |
|---|---|---|---|---|
| TLE / 3LE | tle |
✓ | ✓ | mean-element set |
| CCSDS OEM (KVN + XML) | ccsds-oem |
✓ | ✓ | ephemeris |
| CCSDS OMM (KVN + XML) | ccsds-omm |
✓ | ✓ | mean-element set |
| OMM JSON (Celestrak / Space-Track) | omm-json |
✓ | ✓ | mean-element set |
| OMM CSV (Celestrak / Space-Track) | omm-csv |
✓ | ✓ | mean-element set |
| CCSDS OPM (KVN + XML) | ccsds-opm |
✓ | ✓ | state vector |
| CCSDS OCM (KVN + XML) | ccsds-ocm |
✓ | ✓ | ephemeris |
| CCSDS AEM (KVN + XML) | ccsds-aem |
✓ | ✓ | attitude |
| CCSDS APM (KVN + XML) | ccsds-apm |
✓ | ✓ | attitude |
| CCSDS CDM (KVN + XML) | ccsds-cdm |
✓ | ✓ | conjunction |
| CCSDS TDM (KVN + XML) | ccsds-tdm |
✓ | ✓ | tracking |
| CCSDS combined NDM (KVN + XML) | ccsds-ndm |
✓ | ✓ | aggregate of NDM messages |
| GMAT report | gmat-report |
✓ | — | ephemeris / state |
| STK ephemeris | stk-ephemeris |
✓ | ✓ | ephemeris |
| STK attitude | stk-attitude |
✓ | ✓ | attitude |
| SP3 (SP3-c / SP3-d) | sp3 |
✓ | ✓ | ephemeris |
| RINEX navigation (3.x) | rinex-nav |
✓ | — | mean-element set / state |
SPK ([spk] extra) |
spk |
✓ | ✓ | ephemeris |
TLE and OMM share the mean-element set canonical form, so they convert into each other: read a TLE and write an OMM, or read an OMM and write a TLE. The Celestrak / Space-Track OMM JSON and CSV encodings are the same form again — flat serialisations of the OMM that round-trip into the CCSDS OMM, a TLE, and each other. A RINEX-navigation mean set is also in the mean-element form, but it carries GNSS broadcast elements rather than SGP4 elements, so it does not convert to a TLE or OMM — see RINEX navigation below.
Beyond the orbit-state forms, three CCSDS messages introduce non-orbit canonical
categories: AEM and APM read into an attitude (Attitude), the CDM into a conjunction
(Conjunction), and the TDM into a tracking set (Tracking). Each is its own form — what
they hold is described in the canonical representation, and what
converts to what is in the conversion matrix.
Vendor and extended formats
Alongside the open standards, orbit-formats reads and writes the vendor and alternative
encodings operators actually exchange — STK attitude (.a), the Celestrak / Space-Track flat
OMM (omm-json, omm-csv), and the name-annotated 3LE / catalogue / alpha-5 TLE variants —
each mapping onto a canonical form orbit-formats already models, not a new one. The supported
set is documented, open, text formats only. Proprietary or undocumented binary formats —
GMAT Code-500, JPL navigation databases, vendor OEM extensions — stay out of scope: a faithful
round trip needs a published format, and orbit-formats records what a format states.
CCSDS notation — KVN and XML. Every CCSDS message — OEM, OMM, OPM, OCM, AEM, APM, CDM, TDM,
and the combined NDM — reads and writes in both CCSDS notations under a single format id. The
two notations are held at parity: KVN and XML parse into the same fidelity model, so a
message carries identical content whichever it arrived in, and a KVN → XML → KVN round trip
reproduces it. On write, the destination extension selects the notation (the message's own
extension → KVN, .xml → XML); since .xml names no single NDM message, writing one needs an
explicit format= (e.g. write(eph, "sat.xml", format="ccsds-oem")).
TLE / 3LE — tle¶
A two-line (optionally name-prefixed three-line) element set reads into a MeanElementSet.
The elements are derived from the lines with sgp4 and stay mean elements in the
TEME frame on the UTC scale, geocentric; the NORAD id is tagged on
metadata.object_id. format="3le" is accepted as a synonym for tle — the name-annotated
form is the same format, not a separate one.
- Expresses: mean motion (rev/day), eccentricity, inclination, RAAN, argument of
periapsis, mean anomaly, and the SGP4 drag terms (
bstar, mean-motion derivatives). - Does not express: an osculating state. Turning a TLE into a state at any time other
than the element-set epoch is a propagation, not a format conversion — out of scope.
The single SGP4 state at the epoch is available via the fidelity model
(
result.source_native.epoch_state()). - Alpha-5 designators. The extended NORAD scheme — a leading letter that lifts the catalog
number past five digits (
E8493is148493, withIandOomitted so they cannot be read as1/0) — is decoded, sometadata.object_idis numeric even for an extended id. - A catalogue. Many element sets in one file (the Celestrak / Space-Track convention).
readreturns the first set'sMeanElementSet; the whole catalogue rides onsource_native(aTleCatalog), andresult.source_native.to_canonical()materialises every set in file order, each carrying its ownTleRecord. A lone set keeps aTleRecordonsource_nativedirectly. - Fidelity: the raw 69-character lines (and the optional name) are kept verbatim on
source_native. - Writing: a TLE read back out is echoed verbatim — every set, for a catalogue. A
MeanElementSetfrom another source (an OMM, say) is reconstructed into two element lines with fresh checksums — element-level lossless (a re-read reproduces the same elements to the TLE's representable precision), warning for each TLE identifier the source could not supply. - Two-line vs three-line on write: the leading name line is emitted whenever the source
carries a name. A
.3ledestination requests the name line; a source with no name to supply warns rather than fabricating one. - Detection: the
1/2line structure with valid mod-10 checksums and agreeing satellite numbers — name-annotated, alpha-5, and multi-set files all match — or the.tle/.3leextension. A bad checksum or disagreeing satellite numbers raiseMalformedSourceError.
CCSDS OEM (KVN + XML) — ccsds-oem¶
An Orbit Ephemeris Message reads into an Ephemeris. Both notations of the message — KVN
(key-value notation) and XML — are read and written; they share one ccsds-oem id and one
fidelity model, so an OEM is the same canonical object whichever notation it arrived in.
- Expresses: a Cartesian state-vector time series, with the frame, central body, time system, object name, and object id from the segment META.
- Multi-segment files are concatenated into one canonical ephemeris. The segments must
agree on reference frame, central body, and time system — the reader does not silently rotate
or rescale one segment to match another, so a disagreement raises
MalformedSourceErrorrather than producing a wrong series. (Rotating a whole ephemeris into another frame is a separate, explicit step —convert(..., frame=...).) Per-segment META is preserved onsource_native. - Preserved on
source_native, not in the canonical form: acceleration columns, covariance blocks, comments, non-standard META keywords, and the full per-segment header. An OEM whoseTIME_SYSTEMis one the canonical spine does not carry (e.g.TCB) leavesmetadata.time_scaleunset but keeps the raw value on the fidelity model. - Writing picks one of three paths automatically: a byte-identical re-emit (when the
read opted into
retain_source=True), a content-lossless re-serialisation of the fidelity model, or — for a synthesised or cross-format ephemeris with no OEMsource_native— a fresh OEM built from the canonical fields, warning for each OEM-required field the canonical form cannot supply. See Lossy conversions. - KVN vs XML on write: the destination extension selects the notation —
.oemwrites KVN,.xmlwrites XML — otherwise the source's own notation is re-emitted. Since.xmlnames no single NDM message, writing one needs an explicit format, e.g.write(eph, "sat.xml", format="ccsds-oem"). - Detection: the
CCSDS_OEM_VERS =KVN header, or an<oem>XML root carrying the same marker (theurn:ccsds:namespace is not required), or the.oemextension.
CCSDS OMM (KVN + XML) — ccsds-omm¶
An Orbit Mean-elements Message reads into a MeanElementSet. Both notations — KVN and XML —
are read and written under one ccsds-omm id and one fidelity model. An OMM is the CCSDS
sibling of a TLE: both carry SGP4 mean elements, so the two convert into each other losslessly
(TLE → OMM enriches the message with the TLE's identifiers; OMM → TLE reconstructs the
lines).
- Expresses: the six mean Keplerian elements plus the SGP4 mean motion, the mean-element
theory, the frame / central body / time system, and the TLE bookkeeping (catalog number,
classification, element-set and revolution numbers,
BSTARand the mean-motion derivatives). - Preserved on
source_native, not in the canonical form: the spacecraft-parameters and covariance blocks, user-defined parameters, comments, and the full header. A Keplerian OMM that statesSEMI_MAJOR_AXISrather thanMEAN_MOTIONhas its mean motion derived from the semi-major axis andGM. - Writing mirrors the OEM writer: byte-identical (with
retain_source=True), content-lossless, or synthesised from the canonical fields with a warning for each OMM-required field the source cannot supply. The destination extension selects the notation (.omm→ KVN,.xml→ XML). - Detection: the
CCSDS_OMM_VERS =KVN header, or an<omm>XML root carrying the same marker, or the.ommextension.
OMM JSON and CSV — omm-json, omm-csv¶
The flat JSON and CSV encodings of the OMM — the forms Celestrak's GP query and Space-Track's
OMM class serve, and the forms most operators actually consume. They are not a new format:
each record parses into the same OmmFile fidelity model and the same MeanElementSet as the
CCSDS OMM, so they convert into the CCSDS OMM, a TLE, and each other through the shared
mean-element form. The keys are the CCSDS OMM keywords (OBJECT_NAME, EPOCH, MEAN_MOTION,
ECCENTRICITY, INCLINATION, RA_OF_ASC_NODE, ARG_OF_PERICENTER, MEAN_ANOMALY, the
NORAD_CAT_ID / CLASSIFICATION_TYPE / ELEMENT_SET_NO / REV_AT_EPOCH / EPHEMERIS_TYPE
bookkeeping, and BSTAR / MEAN_MOTION_DOT / MEAN_MOTION_DDOT).
- A catalogue. A JSON object or array, and a CSV header row plus one or more data rows.
readreturns the first record'sMeanElementSet; the whole catalogue rides onsource_native(anOmmCatalog), andresult.source_native.to_canonical()materialises every record'sMeanElementSetin file order. - Implied metadata. The encoding records an SGP4 / TEME mean set, so
REF_FRAME(TEME),TIME_SYSTEM(UTC),MEAN_ELEMENT_THEORY(SGP4),CENTER_NAME(EARTH), andCCSDS_OMM_VERS(2.0) are implied — honoured when a file states them, defaulted when it does not. Columns the OMM does not define (a Space-Track GP record's extra catalogue fields) are ignored. - Writing emits the flat operational field set in one of the two notations, with the same
byte-identical (
retain_source=True) / content-lossless / synthesised tiers as the CCSDS OMM writer; a TLE source is enriched with its identifiers (theTLE → OMMmap). Any field the flat columns cannot hold — a header, comments, covariance, spacecraft parameters, user-defined keys, or a non-TEME/UTC/SGP4 set — is named in a warning rather than dropped. - Detection: the OMM key set in a JSON object/array (
omm-json) or a CSV header row (omm-csv). The.json/.csvextensions are ambiguous, so detection is signature-first and an explicitformat=always wins.
CCSDS OPM (KVN + XML) — ccsds-opm¶
An Orbit Parameter Message reads into a StateVector. Both notations — KVN and XML — are
read and written under one ccsds-opm id and one fidelity model. An OPM carries a single
Cartesian state at one epoch, optionally accompanied by an osculating Keplerian restatement,
spacecraft parameters, a covariance, and any number of planned maneuvers.
- Expresses: the Cartesian position and velocity at the state epoch, tagged with the frame, central body, time system, object name, and object id from the metadata.
- Osculating Keplerian block: when the OPM states one with a
TRUE_ANOMALYit populates the canonicalkeplerian— a redundant restatement of the same Cartesian state. A block stated withMEAN_ANOMALYinstead leaves the canonical view unset (the canonical form holds a true-anomaly representation), but the full block survives onsource_native. - Preserved on
source_native, not in the canonical form: the covariance, the maneuver blocks (ignition epoch, duration, delta-mass, frame, and the three delta-v components), the spacecraft-parameters block, the full Keplerian block, user-defined parameters, comments, and the header. An OPM whoseTIME_SYSTEMis one the canonical spine does not carry leavesmetadata.time_scaleunset with the raw value on the fidelity model. - Writing mirrors the OEM and OMM writers: byte-identical (with
retain_source=True), content-lossless, or synthesised from the canonical state with a warning for each OPM-required metadata field the source cannot supply. The destination extension selects the notation (.opm→ KVN,.xml→ XML). - Detection: the
CCSDS_OPM_VERS =KVN header, or an<opm>XML root carrying the same marker, or the.opmextension.
CCSDS OCM (KVN + XML) — ccsds-ocm¶
An Orbit Comprehensive Message reads into an Ephemeris. Both notations — KVN and XML — are
read and written under one ccsds-ocm id and one fidelity model. The OCM is the richest NDM
orbit message: alongside a state-vector trajectory it can carry covariance histories, planned
manoeuvres, physical properties, perturbation and orbit-determination metadata, and a
user-defined block. orbit-formats canonicalises the Cartesian trajectory into the
ephemeris; everything else is preserved on source_native.
- Expresses: the Cartesian state-vector time series from the OCM's trajectory block, tagged with the reference frame, central body, and time system from the metadata.
- Preserved on
source_native, not in the canonical form: any non-Cartesian trajectory block, the covariance and orbit-determination histories, the manoeuvre specifications, the physical-properties and perturbations blocks, the user-defined block, comments, and the full per-block metadata. - Writing mirrors the OEM writer: byte-identical (with
retain_source=True), content-lossless, or — for a synthesised or cross-format ephemeris with no OCMsource_native— a fresh OCM with a single Cartesian trajectory block built from the canonical fields, warning for each OCM-required field (object name, time system, the trajectory's start / stop time and reference frame) the canonical form cannot supply. KVN dimensioned values carry their units; the destination extension selects the notation (.ocm→ KVN,.xml→ XML). - Detection: the
CCSDS_OCM_VERS =KVN header, or an<ocm>XML root carrying the same marker, or the.ocmextension.
GMAT report — gmat-report¶
A GMAT ReportFile table reads into an Ephemeris (multiple rows) or a StateVector (a
single row). Columns are whitespace-aligned; a run of two-or-more spaces separates them, so a
single space inside a value (a Gregorian epoch) never splits a column. Headers re-emitted at
mission-sequence boundaries are skipped.
- Expresses: the first Cartesian state group it finds (
<resource>.<frame>.<component>), tagged with the frame from the coordinate-system segment and the time scale from the epoch column's suffix. - Tagged only where the column names declare it. A component named without a coordinate
system (GMAT's undeclared default frame) leaves
reference_frameunset; GMAT'sA1scale, which the canonical spine does not carry, leavestime_scaleunset with the raw column name on the fidelity model. A report does not declare a central body, socentral_bodystays unset — never inferred. - Missing components (a position-only report — common from GMAT) are filled with NaN, not
a fabricated value, and a
MissingFieldWarningnames exactly which components were absent. - Preserved on
source_native: every column the canonical form cannot place — a second spacecraft's state, Keplerian elements, mass, and any other parameter. - Detection: the GMAT report has no content signature. It is recognised by the
.reportextension or named with an explicitformat="gmat-report".
STK ephemeris — stk-ephemeris¶
An AGI / STK text ephemeris (.e) reads into an Ephemeris; GMAT's STK-TimePosVel writer
emits the same format. A stk.v.X.Y banner and optional # … comments precede a
BEGIN Ephemeris block of whitespace-separated KEY VALUE metadata, then an
EphemerisTimePosVel (or EphemerisTimePosVelAcc) data section of records — an
offset-from-epoch in seconds plus the position / velocity (and optional acceleration)
triplet — closed by END Ephemeris.
- Expresses: a Cartesian state-vector time series, tagged with the frame
(
CoordinateSystem) and central body (CentralBody) from the meta block. Each record's offset is made absolute againstScenarioEpoch. - Time scale: a
.edeclares none, so the canonical scale is tagged UTC — GMAT's default for the STK writer, and the only sensible default. The rawScenarioEpochtext is kept onsource_nativeso a consumer whose mission pinned another scale can re-interpret it.ScenarioEpochis read either as a GregorianDD Mon YYYY HH:MM:SS.fffvalue or as a numeric GMAT Modified Julian Date. - Preserved on
source_native, not in the canonical form: acceleration columns (from the…Accdata section — the canonicalEphemerisholds position and velocity only), the version banner, the header comments, and every meta keyword verbatim (includingNumberOfEphemerisPoints,DistanceUnit, and any the canonical form does not interpret). - Writing picks one of three paths automatically, mirroring the OEM writer: a
byte-identical re-emit (with
retain_source=True), a content-lossless re-serialisation of the fidelity model, or — for a synthesised or cross-format ephemeris with no STKsource_native— a fresh.ebuilt from the canonical fields, warning for each.e-required field (CentralBody,CoordinateSystem,ScenarioEpoch) the canonical form cannot supply. See Lossy conversions. - Detection: the
stk.v.X.Ybanner on the first non-comment line, or the.e/.ephemextension. Only the banner,BEGIN Ephemeris,ScenarioEpoch, and a recognised data section are mandatory; other data-section variants (e.g.EphemerisTimePos) raiseMalformedSourceError.
STK attitude — stk-attitude¶
An AGI / STK text attitude (.a) reads into an Attitude — the attitude analogue of the STK
ephemeris .e, sharing its file shape: a stk.v.X.Y banner and optional # … comments, then a
BEGIN Attitude block of whitespace-separated KEY VALUE metadata (ScenarioEpoch,
CentralBody, CoordinateAxes, Sequence, …), then an AttitudeTime… data section whose
records are an offset-from-epoch in seconds plus the attitude components.
- Expresses: a quaternion or Euler-angle attitude history.
AttitudeTimeQuaternions(scalar-last) andAttitudeTimeQuatScalarFirst(scalar-first, reordered to the canonical scalar-lastQ1 Q2 Q3 QC) read into a quaternion history;AttitudeTimeEulerAngles(with itsSequence) into an Euler-angle history. It is tagged with the reference axes (CoordinateAxes→frame_a; STK leaves the body frame implicit, soframe_bis unset), the central body, and — like the.e— the UTC default scale (a.adeclares none). Each record's offset is made absolute againstScenarioEpoch. - Does not express: STK's YPR, DCM, angular-velocity / rate, direction-vector, and spin
attitude sections have no faithful canonical representation here, so the reader rejects them
with
MalformedSourceErrorrather than guessing — the same discipline the AEM reader applies. The object name / id and the named body frame an AEM / APM carries have no slot in a.a. - Optional
END Attitude. AGI documents the terminator as required, but real STK output routinely omits it (the data section runs to end-of-file), so it is treated as optional: present, it closes the block and rejects trailing content; absent, EOF ends the data. - Preserved on
source_native, not in the canonical form: the version banner, the header comments, the data-section header, whether the source carriedEND Attitude, and every meta keyword verbatim (including any the canonical form does not interpret). - Writing picks one of three paths automatically, mirroring the OEM writer: a byte-identical
re-emit (with
retain_source=True), a content-lossless re-serialisation of the fidelity model (a scalar-first source is re-emitted scalar-first under its original section), or — for a synthesised or cross-format attitude with no STKsource_native— a fresh.abuilt from the canonical fields, warning for each.a-required field (ScenarioEpoch,CentralBody,CoordinateAxes, andSequencefor an Euler history) the canonical form cannot supply and for each canonical field a.acannot hold (the object name / id, the named body frame). A spin attitude has no STK section here and raisesUnsupportedConversionError. - Detection: the
stk.v.X.Ybanner with aBEGIN Attitudeblock — the block keyword is what distinguishes it from the ephemeris.e(which carriesBEGIN Ephemeris) — or the.aextension.
SP3 — sp3¶
An IGS precise GNSS ephemeris (.sp3, SP3-c / SP3-d) reads into an Ephemeris and writes back
out. SP3 is a multi-satellite product: a header declares the version, a position-only (P) or
position-and-velocity (V) mode, the satellite list with a per-satellite accuracy code, and
the time system; the body is a sequence of epochs, each carrying one position record per
satellite (and, in V mode, a velocity record).
- Expresses: a Cartesian state-vector time series per satellite, tagged ITRF (SP3 is Earth-centred, Earth-fixed) with Earth as the central body and the SP3 time system as the time scale. Positions are in km; SP3 velocities (decimetres·s⁻¹) are converted to km·s⁻¹.
- Multi-satellite → a per-satellite ephemeris set.
readreturns the first listed satellite as the canonicalEphemeris, its id onmetadata.object_name; the whole set isresult.source_native.ephemerides()— adictof satellite id →Ephemeris, each tagged identically. Every satellite's series rides onsource_native, so no satellite is dropped. - Time scale: the SP3 time system is tagged when the canonical spine carries it (
GPS/UTC/TAI/TT/UT1); a GNSS system time it does not model (GLO/GAL/QZS/BDT/IRN) leavestime_scaleunset, with the raw value kept on the fidelity model. - Position-only files (
P-mode) fill the canonical velocities with NaN — never a fabricated value — and aMissingFieldWarningnames them. - Preserved on
source_native, not in the canonical form: the satellite clock offsets (and rates), the per-satellite accuracy codes, the specific frame realisation (IGS20,IGb14), the agency / orbit type / GPS week / interval, and the header comments. - Writes the fixed-column SP3 layout in three tiers. An SP3 read back to SP3 from its
retained source is byte-identical; without retained bytes the whole fidelity model —
every satellite, the clock series, the accuracy codes, and the header — re-serialises
content-lossless. Any other
Ephemerissynthesises a single-satellite SP3-d: the GPS-week / MJD time header is derived from the epochs, but the clock columns SP3 requires have no canonical slot, so they are written as the SP3 missing-value sentinel and aLossyConversionWarningnames them.object_namebecomes the system+PRN satellite id when it already is one, else a placeholder is written (and named); a coordinate that overflows SP3's fixedF14.6field is truncated with aPrecisionLossWarning. - Detection: the
#+ version-letter (#c/#d) content signature on the first line, or the.sp3extension. The reader parses SP3-c and SP3-d; another version, a malformed header, a record with too few columns or a non-numeric value, or a satellite whose record count disagrees with the epoch count raiseMalformedSourceError.
RINEX navigation (3.x) — rinex-nav¶
A RINEX navigation file (the GNSS broadcast ephemeris) reads into the canonical form. It
is a fixed-layout text message: a header closed by END OF HEADER, then a sequence of
per-satellite records — an epoch line (satellite id, the time of clock Toc, and the SV-clock
polynomial terms) followed by the constellation's broadcast-orbit lines. RINEX navigation is
read-only — there is no writer, so a write to .rnx raises UnsupportedFormatError.
- Two canonical categories, by constellation. The Keplerian constellations — GPS, Galileo,
BeiDou, QZSS, and NavIC — carry quasi-Keplerian parameters and read into a
MeanElementSet: the headline mean elements, with the mean motion derived fromsqrt(A)andDelta nthrough the constellation's gravitational parameter, converted to rev/day. The Cartesian constellations — GLONASS and SBAS — carry an Earth-fixed position / velocity / acceleration and read into aStateVector(position and velocity; the acceleration rides onsource_native). - Frame and time. Tagged ITRF (RINEX navigation is Earth-centred, Earth-fixed; the
specific datum — WGS-84, PZ-90, GTRF, CGCS2000 — follows from the satellite id and stays on
the fidelity model) with Earth as the central body. The time scale is the constellation's
epoch time system when the canonical spine carries it — GPS →
GPS, GLONASS →UTC; Galileo / BeiDou / QZSS / NavIC system time the spine does not model leavestime_scaleunset, the same conservative rule SP3 follows. - Broadcast, not SGP4. A RINEX mean set is tagged with the broadcast mean-element
theory. Broadcast elements are referenced to the time of ephemeris in an Earth-fixed datum
and evaluated by the constellation's user algorithm — they are not SGP4 / TEME elements.
Converting one to a TLE or OMM is therefore refused with
IncompatibleMeanElementTheoryError(a subclass ofUnsupportedConversionError): a faithful conversion would need to propagate the broadcast model and refit SGP4 elements — a propagation plus an orbit fit, out of scope — not relabel the numbers. See Conversion matrix. - Multi-record → a record set.
readreturns the first record as its canonical object; the whole file isresult.source_native, andresult.source_native.to_canonical()returns every record's canonical object in file order. No record is dropped. - Preserved on
source_native, not in the canonical form: the SV-clock polynomial, the harmonic corrections (Cuc…Cis),Toeand the broadcast week, the satellite health, the group delays, and every other broadcast-orbit field — kept verbatim on each record, with named access viarecord.field(...)for the orbit-determining fields. - Detection: the
RINEX VERSION / TYPEheader label, or the.rnx/.nav/.NNn(version-2 year-and-system) extension. The reader parses RINEX 3.x; RINEX 2.x or 4.x, a missing or malformed header, an unknown constellation, a truncated record, or a non-numeric field raiseMalformedSourceError.
SPK ([spk] extra) — spk¶
A SPICE SPK binary kernel (.bsp / .spk) reads into an Ephemeris. SPK support pulls in
spiceypy and is kept behind the optional [spk] extra (pip install orbit-formats[spk]) so
the heavy SPICE kernel path stays out of the base install; without it, reading or writing SPK
raises MissingOptionalDependencyError naming the extra.
orbit-formats parses the sampled-state segment types — type 9 (Lagrange) and type 13
(Hermite) — whose stored data is exactly the state nodes the segment was built from. The nodes
are read straight from the DAF (no interpolation, no kernel pool, no furnsh), so reading
recovers them losslessly.
- Expresses: a Cartesian state-vector time series per segment, tagged TDB (SPK ephemeris
time is TDB by definition), with the segment's SPICE frame name (
J2000, …) as the reference frame and the centre body's SPICE name as the central body — a NAIF id rendered as a string when SPICE has no name for it. Positions and velocities are km and km·s⁻¹. - Multi-segment → a per-segment ephemeris set.
readreturns the first segment as the canonicalEphemeris; the whole set isresult.source_native.segment_ephemerides()— every segment as its ownEphemeris, each tagged with its frame, centre, and TDB. No segment is dropped. - Preserved on
source_native, not in the canonical form: each segment's descriptor — the NAIF body / centre / frame ids, the segment type, the interpolation degree, and the DAF array name — and every segment's full node set. - Writing picks one of three paths automatically, mirroring the OEM writer: a byte-identical
re-emit (with
retain_source=True), a content-lossless re-serialisation of every stored segment viaspiceypy, or — for a synthesised or cross-format ephemeris with no SPKsource_native— a fresh single type-9 segment built from the canonical fields, warning for each SPK-required field it cannot resolve: the target / centre NAIF ids (placeholders-999and Earth399), a SPICE-representable frame (J2000;EME2000/ICRF/GCRFalias to it), and the time scale. A single state cannot be written as SPK — a segment is an interpolatable trajectory of at least two states — so a one-sample ephemeris raisesUnsupportedConversionError. - Detection: the
DAF/SPKorNAIF/DAFbinary magic, or the.bsp/.spkextension. A file that is not a readable DAF/SPK, or a segment whose type is not 9 or 13, raisesMalformedSourceError.
CCSDS AEM (KVN + XML) — ccsds-aem¶
An Attitude Ephemeris Message reads into an Attitude — a time series of attitude records. Both
notations — KVN and XML — are read and written under one ccsds-aem id and one fidelity model.
- Expresses: an attitude history — the
attitude_type(quaternion, Euler angle, or spin), one record per epoch, and the two reference frames the rotation maps between (frame_a→frame_b), plus the rotation sequence for the Euler representation. Quaternions are stored scalar-last (Q1 Q2 Q3 QC) regardless of the source'sQUATERNION_TYPE FIRST/LAST. - Multi-segment files are concatenated into one history; the segments must agree on the
frames, time system, and attitude type, or the reader raises
MalformedSourceErrorrather than splicing mismatched segments. - Preserved on
source_native, not in the canonical form: the per-segment META the canonical form has no slot for — theATTITUDE_DIRandQUATERNION_TYPEnotation tags, the interpolation block (method and degree), the usable time windows — the comments, and the full header. - Writing mirrors the OEM writer: byte-identical (with
retain_source=True), content-lossless, or a synthesised AEM built from the canonical attitude, warning for each AEM-required META field (object name and id, the two frames, time system) the canonical form cannot supply; synthesised quaternions are written scalar-last. The destination extension selects the notation (.aem→ KVN,.xml→ XML). - Detection: the
CCSDS_AEM_VERS =KVN header, or an<aem>XML root carrying the same marker, or the.aemextension.
CCSDS APM (KVN + XML) — ccsds-apm¶
An Attitude Parameter Message reads into an Attitude holding a single attitude record at
one epoch. Both notations — KVN and XML — are read and written under one ccsds-apm id and one
fidelity model. AEM and APM share the attitude canonical form, so they convert into each
other: an APM embeds as a one-record AEM (lossless), and an AEM history collapses to its first
record for an APM (warning, naming the dropped records) — see
Conversion matrix.
- Expresses: a single quaternion attitude — the quaternion (stored scalar-last) and the two
reference frames it maps between (
frame_a→frame_b). - Preserved on
source_native, not in the canonical form: the quaternion-rate block (Q1_DOT …), theQ_DIRdirection tag, the message id, comments, and the full header. - Writing mirrors the OEM writer: byte-identical (with
retain_source=True), content-lossless, or a synthesised single-quaternion APM, warning for each APM-required field (object name and id, the frames, time system) the canonical form cannot supply. A multi-record attitude history written to APM keeps the first record and warns. A non-quaternion attitude (Euler, spin) cannot be written as an APM — representing it as a quaternion would be a representation conversion, out of scope — and raisesUnsupportedConversionError. - Detection: the
CCSDS_APM_VERS =KVN header, or an<apm>XML root carrying the same marker, or the.apmextension.
CCSDS CDM (KVN + XML) — ccsds-cdm¶
A Conjunction Data Message reads into a Conjunction — a close-approach record between exactly
two objects. Both notations — KVN and XML — are read and written under one ccsds-cdm id and
one fidelity model.
- Expresses: the time of closest approach (
tca), the miss distance, and — when the CDM carries the relative-state block — the relative position, velocity, and speed in the RTN frame; and, per object (OBJECT1/OBJECT2), its designator, reference frame, the Cartesian state at TCA (km, km·s⁻¹), and the 6×6 RTN position/velocity covariance. The metadata spine tags the primary object and the originator; the time scale is UTC — the CDM has noTIME_SYSTEMkeyword and is UTC by convention. - Exactly two objects. A CDM that does not relate two objects raises
MalformedSourceError. - Preserved on
source_native, not in the canonical form: the screen-period and screen-volume block, the collision-probability block, the per-object orbit-determination and additional parameters (area, mass, ballistic and SRP ratios), the extended covariance cross-terms (drag / SRP / thrust), and comments. - KVN shape. Unlike the other CCSDS messages, the CDM KVN has no
META_START/META_STOPmarkers — its sections are delimited by keyword membership and theOBJECT = OBJECT1/OBJECT2markers — and dimensioned values carry bracketed units (e.g.MISS_DISTANCE = 715.0 [m]). - Writing mirrors the OEM writer: byte-identical (with
retain_source=True), content-lossless, or a synthesised CDM, warning for each required object or relative-state field the canonical form cannot supply. The destination extension selects the notation (.cdm→ KVN,.xml→ XML). - Not an orbit. A conjunction has no orbit-state canonical form, so it round-trips to itself
and nothing else —
convertto any other format raises (see Conversion matrix). - Detection: the
CCSDS_CDM_VERS =KVN header, or a<cdm>XML root carrying the same marker, or the.cdmextension.
CCSDS TDM (KVN + XML) — ccsds-tdm¶
A Tracking Data Message reads into a Tracking — the tracking participants and a flat sequence
of timed observations. Both notations — KVN and XML — are read and written under one ccsds-tdm
id and one fidelity model.
- Expresses: the ordered tracking
participants(PARTICIPANT_1…PARTICIPANT_5— the ground stations and the tracked spacecraft) and the full sequence of(observation_type, epoch, value)triples, in file order, concatenated across every segment. The metadata spine carries the originator and the time scale. - Preserved on
source_native, not in the canonical form: the full per-segment META — the mode, signal path, frequency bands, integration interval, range units, delays, corrections, ephemeris names, and the rest — the per-segment comments, and the segment structure. The units a value is read in (range units, the angle type) live on the segment metadata, not on each observation. - Closed vocabularies. The observation and metadata keywords are fixed CCSDS sets; an
unrecognised keyword raises
MalformedSourceErrorrather than being silently kept. - Writing mirrors the OEM writer: byte-identical (with
retain_source=True), content-lossless, or a synthesised TDM, warning for each required META field (time system,PARTICIPANT_1) the canonical form cannot supply. The destination extension selects the notation (.tdm→ KVN,.xml→ XML). - Not a state. A tracking-data set has no orbit-state canonical form, so it round-trips to itself and nothing else (see Conversion matrix).
- Detection: the
CCSDS_TDM_VERS =KVN header, or a<tdm>XML root carrying the same marker, or the.tdmextension.
CCSDS combined NDM (KVN + XML) — ccsds-ndm¶
A combined (aggregate) NDM holds several individual NDM messages — an OPM and a CDM, several
OEMs, any mix — in one file. read returns a Combined: an ordered tuple of the member
canonical objects on Combined.messages, plus the wrapper's message_id and comments. Each
member is exactly the object reading that message on its own would yield — its full identity and
source_native intact — so the members of read("bundle.ndm") are an Ephemeris, a
Conjunction, a StateVector, and so on, ready to use individually.
- Two notations. XML is the standardised
<ndm>wrapper. KVN has no standardised wrapper, so the aggregate is the member KVN messages concatenated, each keeping itsCCSDS_<TYPE>_VERS =header. On write the destination extension selects the notation (.ndm/.kvn→ KVN,.xml→ XML); since.xmlnames no single message, writing one needs an explicitformat="ccsds-ndm". - Members group by type. The XML
<ndm>stores its children in one list per message type, so both notations emit the members grouped by type (and in their original order within a type). The two are held at parity: a combined NDM read from either carries the same members, and a KVN → XML → KVN round trip reproduces it. - The member format follows
source_native. Each member is written back as the NDM message it was read as — anEphemeriswhose native is accsds-oemwrites as an<oem>— so the members of aCombinedyou assemble yourself are objects read from (or otherwise tagged with) an NDM message. - The wrapper
MESSAGE_ID. XML carries it; KVN has nowhere to put it, so a KVN write reports it as a loss through the lossy-conversion framework. The wrapper comments carry in both notations. - Detection: the
<ndm>root element (XML), or two or moreCCSDS_<TYPE>_VERS =headers in one file (KVN) — either outranks the individual members, so a concatenation of an OEM and an OMM reads as one combined NDM. A member type this version has no reader for (anacmorrdmchild) raisesUnsupportedFormatErrorrather than being dropped; a single-member KVN "bundle" raisesMalformedSourceError. - Not a conversion target. An aggregate carries no single canonical form — it composes
messages rather than mapping between forms — so
convertto or fromccsds-ndmraisesUnsupportedConversionError.