Orbit Determination from Linked Observations¶
Problem¶
You have linked detections and need fitted orbits with quantitative quality metrics and outlier-aware membership outputs.
What You Get Back¶
The orbit-determination APIs return two synchronized tables:
FittedOrbits: one row per solved candidate with quality metrics (orbit_id,arc_length,num_obs,chi2,reduced_chi2, convergence/status fields, and best-fit Cartesian state).FittedOrbitMembers: one row per observation assignment withorbit_id+obs_idplus per-observation residuals and outlier flags.
You use them together to rank candidates, inspect residual structure, remove poor fits, and feed validated solutions downstream.
Implementation Options and Tradeoffs¶
initial_orbit_determinationonly: Fast triage and coarse fits for many candidates.initial_orbit_determination+fit_least_squares: Higher-quality solutions and covariance updates, more compute and tuning.
Runnable Example¶
import pyarrow.compute as pc
from adam_assist import ASSISTPropagator
from adam_core.orbit_determination import (
FittedOrbitMembers,
FittedOrbits,
OrbitDeterminationObservations,
evaluate_orbits,
fit_least_squares,
initial_orbit_determination,
)
observations: OrbitDeterminationObservations
linkage_members: FittedOrbitMembers
# These are typically produced by your detection association pipeline.
propagator_cls: type[ASSISTPropagator] = ASSISTPropagator
iod_orbits: FittedOrbits
iod_members: FittedOrbitMembers
iod_orbits, iod_members = initial_orbit_determination(
observations=observations,
linkage_members=linkage_members,
propagator=propagator_cls,
min_obs=6,
min_arc_length=1.0,
chunk_size=1,
max_processes=4,
)
propagator = ASSISTPropagator()
# Inspect top candidates by quality metric.
ranked_orbits = iod_orbits.sort_by([("reduced_chi2", "ascending")])
# Refine one candidate orbit with differential correction.
# (Converts one fitted row to Orbits for the least-squares fitter.)
fitted_orbit, fitted_members = fit_least_squares(
orbit=ranked_orbits.take([0]).to_orbits(),
observations=observations,
propagator=propagator,
)
# Evaluate an orbit set against the same observation bundle.
evaluated_orbits, evaluated_members = evaluate_orbits(
orbits=iod_orbits.to_orbits(),
observations=observations,
propagator=propagator,
)
# Example: count non-outlier members by orbit_id.
non_outlier = evaluated_members.apply_mask(pc.invert(evaluated_members.outlier))
print(non_outlier.group_by("orbit_id").aggregate([("obs_id", "count")]))
When to Use This Pattern¶
Use this for candidate confirmation, orbit quality scoring, and iterative cleanup of observation-to-orbit assignments.