Orbit determination
/od/tracking/od/bls/od/ekfPurpose
POST /od/tracking generates synthetic observations from a known truth orbit.
POST /od/bls fits one epoch state to a whole arc. POST /od/ekf processes the
same observations sequentially.
They form a workflow rather than three unrelated endpoints: the tracking simulator is what makes the estimators testable, because it starts from an answer you already know.
Observations travel inline
Unlike the CLI, which reads a tracking CSV from disk, these endpoints take measurements inline as JSON. That is what makes them usable from another host, and it means a real arc produces a large request body: 220 observations is roughly 27 kB.
The station list is also inline, and it must describe every station appearing in the measurements. Without it a measurement cannot be related to a state.
POST /od/bls
Request
| Parameter | Type | Unit | Default | Required | Description |
|---|---|---|---|---|---|
epoch | string | RFC 3339 UTC | — | Yes | Solution epoch. Observations must not precede it. |
measurements | array | n/a | — | Yes | Observations, each with epoch, station_id, kind, value, and sigma. |
stations | array | n/a | — | Yes | Ground stations. Must cover every station_id in the measurements. |
initial_orbit | object | n/a | — | Yes | Keplerian elements as the initial guess. Note: `initial_orbit`, where the CLI flag is `--initial`. |
force | string | n/a | j2 | No | Reference force model: `two_body`, `j2`, or `j4`. |
edit_sigma | number | sigma | 4 | No | Residual editing threshold. Zero disables editing. |
max_iterations | integer | count | 10 | No | Iteration cap. Reaching it without convergence is a failure, not an answer. |
Example response
Fitting 220 synthetic observations from two Deep Space Network stations:
{
"epoch": "2026-01-01T00:00:00Z",
"position_eci_km": [3209.861533717679, 5499.371867195568, 2711.997942122806],
"velocity_eci_km_s": [-5.533572605774019, 0.6885441582931939, 5.15319070740035],
"covariance": [[3.5789720154651683e-7, "..."]],
"position_sigma_km": ["..."],
"velocity_sigma_km_s": ["..."],
"rms_history": ["..."],
"iterations": 3,
"converged": true,
"measurements_used": 220,
"measurements_edited": 0,
"residuals": ["..."]
}Elided: covariance is a full 6-by-6 matrix and residuals carries one entry per
observation.
The response gives you more than the CLI
| Field | Why it matters |
|---|---|
position_eci_km, velocity_eci_km_s | The estimated state itself, which the CLI summary does not print |
covariance | The full 6-by-6 matrix, not just the diagonal sigmas |
rms_history | RMS at each iteration, which shows whether convergence was clean or struggled |
residuals | Per-observation residuals, for spotting a bad station or an epoch tagged wrongly |
converged | Explicit. Check it before reading anything else |
converged: false with iterations at the cap means the solver did not find a
solution. The state and covariance are still populated, and they are the last
iterate rather than an answer.
Always check converged first. Nothing else in the response indicates failure.
Covariance is formal, not truth
The reported sigmas are what the estimator believes given its own model and the stated measurement noise. They are optimistic whenever the force model is incomplete, because unmodeled acceleration is absorbed as signal.
An RMS near 1.0 is the target: residuals are weighted by each observation’s sigma, so an RMS of 1 means the fit disagrees with the data by about as much as the stated noise. Much above 1 means the model cannot explain the data; much below means the sigmas are pessimistic.
POST /od/ekf
Processes observations sequentially, maintaining a running state and covariance. It takes the same measurement and station arrays plus process-noise and initial uncertainty parameters.
The filter’s reported uncertainty is typically one to two orders of magnitude
larger than batch on the same data, and that is correct: different epochs, time
since the last observation, and deliberate process noise all contribute. See the
od ekf page for the comparison in detail.
POST /od/tracking
Generates synthetic observations from a truth orbit, which is the only way to validate an estimator against an answer you already know.
Run many seeds, compare actual error against reported sigma, and confirm the errors fall within one sigma about 68 percent of the time. A filter that reports 0.03 km while actually erring by 0.3 km is worse than one that honestly reports 0.3 km, because downstream decisions trust the number.
See also
od bls,od ekf, andod simulate-trackingfor the workflow from a shell, including the tracking CSV format.
main (pre-release)