Skip to Content
ReferenceCLIod simulate-tracking

orbitforge od simulate-tracking

Synopsis

orbitforge od simulate-tracking --orbit <PATH> [OPTIONS]

Description

Generates realistic tracking observations from a known truth orbit: propagate the orbit, work out when each station can see it, and emit noisy measurements at a fixed cadence.

Its purpose is testing. Orbit determination is hard to validate against real data because the true answer is unknown. Here the truth orbit is an input, so the solution can be compared against it directly, and the estimated uncertainty can be checked against the actual error.

The dotted line is the point of the whole exercise: the truth orbit is available for comparison in a way it never is operationally.

Options

ParameterTypeUnitDefaultRequiredDescription
--orbitpathn/a—YesKeplerian-elements JSON for the truth orbit. See the schema below.
--stationspathn/a—NoTracking-stations JSON, with per-station noise specifications.
--stationstringn/a—NoCatalog station shorthand, repeatable, for example `--station dsn:goldstone`. Uses default range and range-rate noise.
--startstringRFC 3339 UTC2026-01-01T00:00:00ZNoWindow start epoch.
--duration-hoursfloath24NoWindow length.
--cadence-secondsfloats60NoObservation interval while a station has visibility.
--seedintegern/a7NoNoise seed. The same seed reproduces the same observations exactly.
--forceenumn/aj2NoTruth force model: `two-body`, `j2`, or `j4`.
--light-timeflagn/a—NoApply the one-way light-time correction.
--csvpathn/a—NoWrite observations as tracking CSV, the input format for `od bls` and `od ekf`.
--tdmpathn/a—NoWrite observations as a CCSDS TDM (KVN) file.
--satellite-idstringn/asat-1NoSatellite identifier stamped into the TDM.

Truth orbit schema

{ "semi_major_axis_km": 6928.0, "eccentricity": 0.001, "inclination_deg": 51.6, "raan_deg": 40.0, "argument_of_perigee_deg": 30.0, "true_anomaly_deg": 0.0 }

Every field is required. A missing field is reported by name:

Error: failed to parse orbit file `orbit.json` Caused by: missing field `argument_of_perigee_deg` at line 8 column 1

Worked example

Two Deep Space Network stations tracking a station-like orbit for a day:

orbitforge od simulate-tracking \ --orbit orbit.json \ --station dsn:goldstone --station dsn:madrid \ --duration-hours 24 --cadence-seconds 60 \ --csv obs.csv
Simulated 220 observations from 2 stations over 24.0 h (seed 7). Wrote tracking CSV -> obs.csv

The observation file

epoch,station_id,kind,value,sigma 2026-01-01T00:06:00Z,dsn:madrid,range,1775.655885312,0.010000000 2026-01-01T00:06:00Z,dsn:madrid,range_rate,-5.887454298,0.000010000
ColumnMeaning
epochObservation time, RFC 3339 UTC
station_idWhich station produced it
kindrange in km, range_rate in km/s, azimuth or elevation in degrees
valueThe noisy measurement
sigmaOne-sigma uncertainty, in the measurement’s own units

Each visible epoch produces one row per measurement kind, so 110 epochs each carrying a range and a range-rate measurement give 220 observations.

220 observations over 24 hours at a 60-second cadence is sparse, and correctly so. Two stations at fixed sites see a low Earth orbit only during passes, typically a few minutes several times a day. Most of the window has no visibility from either site, which is exactly the condition that makes orbit determination interesting.

Stations file

The --station shorthand uses catalog defaults. For explicit control over noise, supply a stations file:

[ { "station": { "id": "dsn:goldstone", "name": "NASA DSN Goldstone", "latitude_deg": 35.4267, "longitude_deg": -116.89, "altitude_km": 1.0, "min_elevation_deg": 6.0 }, "range": { "sigma": 0.01 }, "range_rate": { "sigma": 0.00001 } } ]

A measurement kind is produced only if it is present. Omitting range_rate yields range-only tracking, which is a materially harder estimation problem. NoiseSpec also accepts a bias term, defaulting to zero, for modeling systematic station errors.

The same stations file must be supplied to od bls and od ekf. The solvers need each station’s position to relate a measurement to a state, and its sigma to weight the residual. Passing a different file than the one used to simulate makes the solution inconsistent with the data in a way that shows up as inflated residuals rather than as an error.

Reproducibility

The noise is seeded. Re-running with the same --seed reproduces the same observations exactly, which is what makes a regression test possible. Change the seed to test the estimator against a different noise realization, and vary it across many runs to check that the estimated covariance is statistically consistent with the actual error.

See also

  • od bls to fit an epoch state to these observations.
  • od ekf to process them sequentially.
  • stations list for catalog identifiers.
Question? Give us feedbackDocuments Varaha Constellation Designer main (pre-release)
Last updated on