CCSDS OEM
What it is
The Orbit Ephemeris Message is a CCSDS standard for exchanging trajectories as tabulated state vectors. It is the format to use when handing a trajectory to another organization.
What makes it the interchange format is not the numbers, it is the metadata: an OEM declares its reference frame, time system, and span in the file, so the recipient can reproduce your trajectory rather than approximate it.
A complete satellite block
CCSDS_OEM_VERS = 3.0
ORIGINATOR = ORBITFORGE
META_START
OBJECT_NAME = fmt-s0-p00-sat00
OBJECT_ID = fmt-s0-p00-sat00
CENTER_NAME = EARTH
REF_FRAME = EME2000
TIME_SYSTEM = UTC
START_TIME = 2026-01-01T00:00:00Z
STOP_TIME = 2026-01-01T01:00:00Z
META_STOP
2026-01-01T00:00:00Z 6928.137000000 0.000000000 0.000000000 0.000000000 4.564820232 6.057721051
2026-01-01T00:10:00Z 5486.340609294 2546.122041970 3378.818071009 -4.631912846 3.614847486 4.797064637
2026-01-01T00:20:00Z 1761.048355655 4032.510545065 5351.322236958 -7.335955263 1.160321911 1.539799184Real output, elided after three records.
The metadata block
| Parameter | Type | Unit | Default | Required | Description |
|---|---|---|---|---|---|
CCSDS_OEM_VERS | string | n/a | — | No | Format version. 3.0 here. |
ORIGINATOR | string | n/a | — | No | Who produced the file. |
OBJECT_NAME | string | n/a | — | No | Human-readable object name. |
OBJECT_ID | string | n/a | — | No | Object identifier. |
CENTER_NAME | string | n/a | — | No | Central body. `EARTH` here. |
REF_FRAME | string | n/a | — | No | Reference frame. `EME2000` here, an inertial frame aligned to the J2000 mean equator and equinox. |
TIME_SYSTEM | string | n/a | — | No | Time scale for every epoch in the block. `UTC` here. |
START_TIME | string | RFC 3339 UTC | — | No | First record epoch. |
STOP_TIME | string | RFC 3339 UTC | — | No | Last record epoch. |
REF_FRAME and TIME_SYSTEM are the reason to use this format. A trajectory
without them is ambiguous by kilometers and seconds, and the recipient has no
way to detect the ambiguity.
Read them before consuming an OEM from anyone else. An EME2000 file
interpreted as ECEF, or a TAI file interpreted as UTC, produces a
confidently wrong answer.
Data records
Each record is one line, whitespace-separated:
EPOCH X Y Z VX VY VZ| Field | Unit |
|---|---|
| Epoch | The declared TIME_SYSTEM, ISO 8601 |
| X, Y, Z | km |
| VX, VY, VZ | km/s |
Positions are in kilometers, unlike CZML, which
uses meters. The same first state reads 6928.137 here and 6928137.0 there.
Multiple objects in one file
A constellation export writes one META_START to META_STOP block per
satellite, each followed by its own records:
META_START
OBJECT_NAME = fmt-s0-p00-sat00
...
META_STOP
<records>
META_START
OBJECT_NAME = fmt-s0-p00-sat01
...
META_STOP
<records>A parser that reads only the first metadata block and then consumes every remaining line as data will silently concatenate all satellites into one trajectory, producing a path that teleports between them.
Each block’s metadata applies only until the next META_START. In principle
different blocks can declare different frames or spans, so the metadata must be
re-read per block rather than assumed constant.
Producing and consuming OEM
orbitforge simulate \
--constellation fmt.json \
--duration-hours 1 --step-seconds 600 \
--oem fmt.oemWrote OEM -> fmt.oemOver HTTP:
curl -s http://127.0.0.1:8080/scenarios/scenario-demo/oem > demo.oemReading one back creates a constellation propagated by table interpolation:
orbitforge import-ephem --oem fmt.oem --name imported --output imported.jsonImported satellites must then be propagated with --model ephemeris, and only
within the span the table covers. There is no dynamics in the file to
extrapolate with.
Interpolation
An OEM is a table, so a state between records must be interpolated. The standard allows a file to declare its intended interpolation method and degree, and honoring that declaration is what makes reproduction faithful rather than approximate.
See also
- CZML, which uses meters rather than kilometers.
import-ephemto read an OEM back.
main (pre-release)