title: ntn-digital-twin - live LEO constellation mirror with handover prediction API | ns3-ntn-toolkit description: ns-3 NTN digital twin: pulls live CelesTrak TLEs, propagates with SGP4, and serves a FastAPI handover-prediction REST API for any satellite ground location.
W10 - ntn-digital-twin¶
ntn-digital-twin is the ns3-ntn-toolkit module that mirrors a real LEO constellation in near-real time: a refresher loop pulls live CelesTrak TLEs, propagates them with SGP4, emits CesiumJS CZML and InfluxDB telemetry, and a FastAPI service answers handover-prediction queries for any UE location. It reuses the toolkit's SGP4 propagator and metric schema so the live twin shares dashboards with simulated runs.
Why it matters. Validating NTN handover logic and coverage models against the constellation as it actually flies (not a synthetic shell) closes the loop between simulation and reality. Researchers and operators need a service that tracks today's Starlink (or any CelesTrak group), predicts the next handovers for a ground terminal, and feeds the same Grafana dashboards and Cesium viewer used for ns-3 runs. This module is that always-on twin.
What it simulates¶
- Refresher loop (
twin_loop.py, CLIntn-twin-loop): on a cron / systemd timer it fetches CelesTrak TLEs (6-hour on-disk cache), propagates with thentn-constellationSGP4-direct path, writes CesiumJS CZML, and emits InfluxDB line protocol. It is crash-tolerant: exceptions are logged and the loop continues on schedule. - Handover-prediction REST API (
api/server.py, CLIntn-twin-api, FastAPI / Uvicorn): closed-form ECEF→ENU elevation on the hot path (no Skyfield), with a constellation cache refreshed from CZML file mtime.GET /health- uptime, loaded constellation size, last refresh timestamp.GET /constellation/state?at=<ISO>- per-satellite NORAD id, geodetic lat/lon/alt, and ECI velocity at a given epoch.POST /predict/handover- givenue_lat_deg,ue_lon_deg, optionalue_alt_m,horizon_min,step_sec, andmin_elevation_deg, returns the ordered handover events (incoming / outgoing satellite, elevations, time) over the horizon plus serverelapsed_ms.
- InfluxDB telemetry (
ntn_sat_posmeasurement:sat_x_m,sat_y_m,sat_z_m, taggedsat_norad/run_id): interoperates with the canonicalntn-observabilityschema, so the existing Grafana dashboards consume the live twin directly. - CesiumJS Live viewer: a viewer patch adds a Live toggle so the Cesium globe shows current satellite positions.
- systemd units (
ntn-twin.service,ntn-twin-api.service): production deployment of the loop and API with restart-on-failure and state directories.
Gallery¶
Standards & references¶
- CelesTrak (Dr. T. S. Kelso): live TLE feed driving the twin.
- SGP4: orbital propagation via the
sgp4library, reused fromntn-constellation. - WGS-84: geodetic and ECEF/ECI reference frames for satellite and UE positions.
- InfluxDB line protocol: shared telemetry format with
ntn-observability.
Use cases¶
- Live handover rehearsal: query
/predict/handoverfor a ground station to anticipate the next serving-satellite changes minutes ahead. - Constellation tracking dashboards: stream
ntn_sat_posinto the existing Grafana stack to monitor the real fleet alongside simulated runs. - Coverage and visibility studies: call
/constellation/stateto snapshot which satellites are overhead a location at any epoch. - CI-friendly validation: run a bounded loop (
--max-iterations) to verify propagation fidelity against the SGP4-direct reference. - Always-on deployment: install the systemd units for a continuously refreshing twin tied to a chosen CelesTrak group.
Run it¶
This runs three loop iterations against the live Starlink TLE feed, writing CesiumJS CZML and InfluxDB line protocol. Then start the API with ntn-twin-api --host 0.0.0.0 --port 8090 and query it:
curl http://localhost:8090/predict/handover \
-H 'content-type: application/json' \
-d '{"ue_lat_deg":33.6844,"ue_lon_deg":73.0479,"horizon_min":10}'
Scope¶
Cron pulls TLEs, propagator regenerates state, CesiumJS shows current positions, REST API answers /predict/handover for a UE over the next N minutes.
| Component | What it does |
|---|---|
twin_loop.py |
Cron entry; refresh TLE + push to InfluxDB + emit CZML |
api/server.py |
FastAPI: /health, /constellation/state, /predict/handover |
systemd/ntn-twin.service |
systemd unit for the loop |
viewer-patches/index.html.patch |
Adds Live toggle to the CesiumJS viewer |
Validation gates¶
- 6/6 tests green
- 24-h continuous loop without crash; 144-iter loop, 0 errors
- API answers
/predict/handoverp99 = 29.9 ms over 100 calls (gate 500 ms) - CesiumJS "Live" toggle works against running loop
Quickstart¶
pip install -e contrib/ntn-digital-twin
# One-shot loop iteration
ntn-twin-loop
# Long-running API
ntn-twin-api &
curl http://localhost:8090/health
curl http://localhost:8090/predict/handover \
-H 'content-type: application/json' \
-d '{"ue_lat_deg":33.6844,"ue_lon_deg":73.0479,"horizon_min":10}'