Skip to Content
GuidesOperatingOrbit determination

Orbit determination

What you will accomplish

An orbit fitted to tracking observations, with a covariance you understand well enough to quote.

The two estimators here report position uncertainties that differ by an order of magnitude on identical data. Neither is wrong. This guide is mostly about why.

Prerequisites

  • A station catalog.
  • An initial orbit estimate.

Steps

Build a tracking-station file

stations list --json writes a catalog, which is not the same document an OD run consumes. The OD tools need each station wrapped with the measurement kinds it produces and their noise:

[ { "station": { "id": "dsn:goldstone", "name": "NASA DSN Goldstone (Mojave, USA)", "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.001 } } ]

Passing the catalog directly fails with missing field 'station' at line 11 column 3, which names the field but not the document type it expected.

Simulate observations

orbitforge od simulate-tracking \ --orbit orbit.json \ --stations tracking-stations.json \ --duration-hours 24 --cadence-seconds 30 \ --csv obs.csv
Simulated 614 observations from 3 stations over 24.0 h (seed 7).

Fit

orbitforge od bls \ --obs obs.csv --stations tracking-stations.json \ --initial orbit.json --epoch 2026-01-01T00:00:00Z \ --json bls.json
BLS converged in 2 iterations: RMS 1.027, 614 used / 0 edited. Position sigma [0.0016, 0.0011, 0.0014] km; velocity sigma [1.06e-6, 1.69e-6, 1.67e-6] km/s.

Read the RMS first

An RMS near 1.0 means the residuals match the sigmas you declared for the measurements. It is the fastest indication that the fit is consistent with its own noise model.

Much above 1 means the model does not explain the data, or the sigmas are optimistic. Much below 1 means the sigmas are pessimistic and the solution is fitting noise you claimed was larger than it is.

Arc length decides whether it converges at all

The same true orbit, the same estimator, and the initial guess set to the exact truth in every case:

SetupObservationsResult
1 station, 6 hours38Fails
1 station, 24 hours174Converges, 3 iterations
3 stations, 24 hours614Converges, 2 iterations

The 6-hour case reports:

invalid orbit-determination input: only 0 usable measurements; at least 6 are required

That message describes a symptom, not the cause. The observations parsed fine and 38 of them were used on the first iteration.

The solution then diverged, and on the next pass the residual editor rejected everything, leaving zero. A short single-station arc gives a nearly singular normal matrix, so tiny residuals produce enormous corrections.

This happened starting from the true orbit, so it is not a bad initial guess. The geometry simply does not determine six states.

If OD fails this way, lengthen the arc before improving the guess. Six hours is under four revolutions seen from one point on a rotating Earth; 24 hours gives the station a spread of viewing geometries.

Station diversity buys precision, not convergence

SetupPosition sigma R, I, C
1 station, 24 hours[9.4, 4.3, 4.7] m
3 stations, 24 hours[1.6, 1.1, 1.4] m

Both converge. Three stations improve the radial component by about a factor of six, because widely separated sites see the satellite along different lines of sight and break correlations a single site cannot.

Arc length fixes convergence. Station geometry fixes precision. They are separate problems and the fix for one does not fix the other.

The EKF’s number answers a different question

Running an EKF over the identical 614 observations:

orbitforge od ekf \ --obs obs.csv --stations tracking-stations.json \ --initial orbit.json --epoch 2026-01-01T00:00:00Z
EKF processed 307 epochs: 614 accepted / 0 rejected. Final position sigma [0.0198, 0.1085, 0.0379] km at 2026-01-02T00:00:00Z.

Compared with the batch solution’s [1.6, 1.1, 1.4] m, the EKF looks roughly 12 to 100 times worse. Concluding that batch estimation is better would be wrong.

The two numbers are at different epochs and carry different assumptions.

Batch least squares reports covariance at the solution epoch, having used every observation in the arc, before and after. The EKF reports covariance at the last epoch, using only observations up to that moment, and inflated by process noise between updates.

The process noise is the whole difference. Sweeping --snc, the acceleration PSD in km^2/s^3:

--sncFinal position sigma R, I, C
0[2.0, 1.1, 1.0] m
1e-12 (default)[19.8, 108.5, 37.9] m
1e-9[16.8, 7.3, 5.5] km

With process noise switched off the EKF reports [2.0, 1.1, 1.0] m against the batch solution’s [1.6, 1.1, 1.4] m. They agree.

The apparent order-of-magnitude gap was a modeling choice, not an estimator quality difference. The default 1e-12 is an assumption about unmodeled acceleration, and like the covariance in conjunction screening, it is supplied rather than measured.

Choosing between them

Use batch least squares whenUse the EKF when
The arc is complete and in handObservations arrive continuously
You want the best fit over the whole arcYou want the current best estimate
Reprocessing is acceptableYou cannot reprocess history
Dynamics are well modeledUnmodeled accelerations are present

The in-track component being worst in the EKF result, 108.5 m against 19.8 m radial, is the usual pattern. Along-track position is the least observable direction from range and range-rate, and it is also where process noise accumulates fastest.

Checklist

  1. Is the RMS near 1.0?
  2. Is the arc long enough to converge, before you blame the initial guess?
  3. Are you comparing covariances at the same epoch?
  4. Is the EKF’s process noise stated alongside its covariance?
  5. Are the measurement sigmas realistic for the actual sensors?
  6. Does the station file have the wrapped tracking-station schema?

Next steps

Question? Give us feedbackDocuments Varaha Constellation Designer main (pre-release)
Last updated on