3.4 KiB
yksa_orbital
Propagation for Django services: a backend registry, and the client to the Orekit sidecar.
from yksa_orbital import get_backend
state = get_backend().state_at(omm, at)
weather = get_backend("orekit").space_weather(start, stop)
Why it is its own app
ODMS and track.tmtc.yksa.space both propagate, both against the same sidecar.
The alternative to sharing this is two HTTP clients that drift apart on timeouts,
on 503 handling, and on what they put in a request — and since the sidecar's
whole purpose is that two services fly the same model, two clients that send
different things quietly defeat it.
Install
Add "yksa_orbital" to INSTALLED_APPS and set:
ORBITAL_PROPAGATOR_BACKEND=sgp4 # or "orekit"
OREKIT_SERVICE_URL=http://orekit:5000
It depends on odm and on httpx. Nothing else — in particular, nothing
from the host service.
Backends
| Name | What it can do |
|---|---|
sgp4 |
Pure Python. TEME plus a GMST Earth-fixed frame. Analytical theory only: no drag integration, so it refuses decay, drag fitting and space weather rather than returning a number nobody should trust. |
orekit |
HTTP client to the Orekit sidecar (tle/services/orekit). Rigorous frames, numerical and semi-analytical propagation, TLE fitting, drag fitting, decay forecasts, solar-activity ensembles, space weather. |
Name the backend when you need the sidecar
get_backend() returns the deployment's default, which is sgp4. Anything
needing physics sgp4 does not have must ask for "orekit" explicitly.
This is not hypothetical. A view that forgot to, and swallowed the resulting
PropagationError, rendered an empty space-weather chart for weeks with nothing
logging a complaint. If your call needs the sidecar, say so.
Capacity
The sidecar keeps a worker free for the interactive queries a page load waits on,
and turns heavy work away rather than queueing it. A 503 arrives here as
BackendBusy — a subclass of PropagationError, so existing handlers still
work, but a Celery task should catch it first and retry. Nothing about the
request needs to change for it to succeed later; recording it as a failed
forecast is wrong.
The model config
yksa_orbital.model_config reads the sidecar's GET /config — the force model,
propagator, decay altitude, drag-fit thresholds and weather sources it is
actually flying — with a cache and a vendored fallback.
Use it for values a page genuinely needs locally: the ensemble's display floor, the decay altitude in a caption. Do not use it to build a request. Omitting a parameter already gets the sidecar's value; echoing it back only adds a way for the two to disagree.
from yksa_orbital.model_config import model_config, setting
floor_km = setting("ensemble", "display_floor_km", 150.0)
setting() applies this deployment's DECAY_* override when there is one, so a
caption describes the run on screen rather than the model in general.
Layout
| File | What |
|---|---|
registry.py |
get_backend(), and register() for a service with its own propagator. |
backends/sgp4.py |
The pure-Python backend. |
backends/orekit.py |
The sidecar HTTP client. |
wire.py |
Stored OMM dict → the CCSDS message the sidecar consumes. The only place that conversion happens. |
model_config.py |
Cached access to the sidecar's model definition. |