LEO mega-constellations from TLEs or orbital elements, with contact-graph routing across inter-satellite links
Toolkit · Install · Examples · Docs
Everything above this module needs to know where the satellites are, and the answer has to be the same answer at every layer. ntn-constellation generates a shell from two-line elements or from orbital elements, propagates it, and hands one consistent ephemeris to the radio, the handover logic, the routing and the visualization.
On top of the geometry sits the network view: a contact graph over inter-satellite links with limb-clearance so a link that would cut through the atmosphere is not offered, scheduling across contact windows, and shortest-path routing with a BFS cross-check so a route the scheduler likes can be compared against a route nobody optimized.
The free-space link budget is calibrated against the TR 38.821 corpus rather than against itself, which is a distinction with a history: the calibration test used to compare the reference corpus against a synthetic offset of itself and never touched the toolkit at all.
Inside the toolkit, where the module is already present and built:
./ns3 run ntn-constellation-demo
./ns3 run "ntn-constellation-walker --shell=starlink-550"Standalone, into an existing ns-3.43 tree:
git clone -b ntn-constellation-v2 https://github.com/Muhammaduazir69/ntn-constellation.git contrib/ntn-constellation
./ns3 configure --enable-modules='' --enable-examples --enable-tests
./ns3 buildINSTALL.md in this directory carries the full dependency list. Most examples in
this module build on ntn-traffic, the toolkit's real-stack spine, so the
toolkit tree is the path of least resistance.
ntn-constellation provides the orbital-mechanics foundation for the toolkit: it
generates LEO constellations, propagates them with high fidelity inside an ns-3
simulation, and turns the resulting time-varying geometry into the link-up/link-down
events that the rest of the data plane consumes. Everything lives in the
ns3::ntncon namespace.
- Walker-Delta / Walker-Star generator —
WalkerConstellation::BuildDelta()/BuildStar()build a full constellation from aWalkerConfig(planes, satellites per plane, altitude, inclination), emitting classical orbital elements ready for the mobility model. - Orbital propagation —
Sgp4MobilityModelis an ns-3MobilityModelthat propagates a satellite from aTleRecord(orKeplerianElements) using an analytic Kepler propagator with secular J2 corrections (RAAN and argument-of-perigee) and an SGP4-compatible TLE interface, so position queries duringSimulator::Run()follow the orbit. ECEF/ECI/geodetic surfaces and a ground-station elevation query are built in. Full Vallado SGP4 (with atmospheric drag / B*) is planned for Q4 2026; the TLE drag (B*) field is parsed but not yet used by this model. - Contact-graph scheduling —
ContactGraphSchedulerevaluates GSL (ground↔sat) and ISL (sat↔sat) visibility over the simulation timeline and raisesContactEvents as links come up and go down. - Contact-graph path computation —
ContactGraphRouteris a path-computation helper (inheritsObject): it computes paths across the time-varying topology and returns node-ID sequences — direct contacts, BFS shortest path, edge-weighted Dijkstra, and a regenerative-vs-bent-pipe mode (SetRegenMode) that steers the computed path around bent-pipe transit nodes. It installs no ns-3 forwarding table; the routed examples feed the computed path to ns-3 static/global routing themselves. - Calibration corpus —
tr38821-corpus(Tr38821CorpusReader,CalibrationHarness) ships 3GPP TR 38.821 reference scenarios/link budgets plus a Starlink-EU latency/station corpus to validate toolkit predictions against published references.
This module also ships a pip-installable Python companion (ntn_constellation) for
the tool side — see Python package.
Two propagators, two fidelity levels. The in-simulation C++ model
(Sgp4MobilityModel) is a Kepler + J2 secular propagator with a
TLE-compatible interface — it is not a full SGP4 implementation yet; full
Vallado SGP4 (atmospheric drag / B*) is planned for Q4 2026, and the B* field
is parsed but unused until then. The
tool-side Python package (ntn_constellation) is different: it uses the real
sgp4 library and Skyfield for canonical SGP4/SDP4 propagation when it generates
TLEs, ephemerides, and export files offline. So "SGP4" claims below apply to the
Python side; the C++ side is Kepler+J2 for now.
See CHANGELOG.md for this module's changelog.
- Measured radio in the access-link examples.
ntn-constellation-walker-trafficandntn-constellation-sgp4-mobility-trafficnow drive a real mmwave NR NTN cell throughNtnRealStackHelper(from thentn-trafficmodule): SpectrumPhy + MAC + HARQ + RLC/PDCP + RRC + EPC, with SINR/TBLER/throughput measured off the mmwave PHY traces — no closed-form SINR, no P2P star. Ground UEs use TR 38.811 mobility classes (NtnTr38811MobilityHelper, fromntn-cho). - Measured application KPIs in the routed examples. The
ntn-constellation-isl-routed-trafficandntn-constellation-real-routedexamples carry traffic withNtnOranApplication/NtnOranSink(fromntn-traffic): every packet carries a 24-byte in-bandNtnOranPayloadHeader(5QI, S-NSSAI, QFI, sequence, TX timestamp), and one-way delay, RFC 3550 jitter, and loss are measured at the sink from those header primitives.OnOffApplicationtraffic is gone toolkit-wide. - Real orbital dynamics in the routed examples. Satellites in the routed
examples are SGP4/Walker neighbours projected into a local ENU frame
(
NtnEnuProjectionMobilityModel, fromntn-cho), so the satA-sets / satB-rises reroute emerges from genuine orbital motion.
Derived from model/*.h:
| Header | Key types | Role |
|---|---|---|
walker-constellation.h |
WalkerConfig, WalkerConstellation (BuildDelta, BuildStar) |
Walker-Delta / Walker-Star constellation generation (planes, sats/plane, altitude, inclination). |
sgp4-mobility-model.h |
Sgp4MobilityModel |
ns-3 MobilityModel that propagates a satellite during the simulation via an analytic Kepler + secular-J2 propagator with an SGP4-compatible TLE interface (full Vallado SGP4 with drag/B* planned Q4 2026; B* parsed but unused). ECEF/ECI/geodetic accessors and GetElevationDeg(). |
orbital-elements.h |
TleRecord, KeplerianElements |
TLE / Keplerian element records consumed by the mobility model. |
contact-graph-scheduler.h |
ContactGraphScheduler, ContactEvent |
Computes GSL/ISL visibility and emits link up/down events over time; up/down event counters per link class. |
contact-graph-router.h |
ContactGraphRouter |
Path-computation helper over the time-varying contact graph (returns node-ID vectors; installs no forwarding table): BFS shortest path, weighted Dijkstra, regenerative-vs-bent-pipe constrained path selection. |
tr38821-corpus.h |
Tr38821CorpusReader, Tr38821Scenario, Tr38821LinkBudget, StarlinkLatencySample, StarlinkStation, CalibrationResidual |
TR 38.821 + Starlink calibration corpus and harness. |
Built binaries land in build/contrib/ntn-constellation/examples/ as
ns3.43-<NAME>-default. Each can be launched through ./ns3 run (from the repo
root) or invoked directly. The two access-link examples (walker-traffic,
sgp4-mobility-traffic) require the toolkit's mmwave module; the two routed
examples need only core ns-3 plus ntn-traffic/ntn-cho.
A Walker-Delta constellation provides the ephemeris and ISL/GSL contact-graph
context (ContactGraphScheduler), while ONE serving satellite carries a real
mmwave NR NTN cell (NtnRealStackHelper) to TR 38.811 ground UEs placed at its
sub-point. Radio KPIs (SINR/TBLER/throughput) are measured off the mmwave PHY
trace; constellation-scale connectivity is reported from the contact graph.
# via ns3 (from repo root)
./ns3 run "ntn-constellation-walker-traffic --simSeconds=20 --numPlanes=4 --satsPerPlane=11 --altKm=550 --inclinationDeg=53 --outputDir=results/walker"Outputs: sim_health.csv (measured-KPI fidelity gates) in --outputDir, plus
a summary block printed to stdout:
# === ntn-constellation-walker-traffic summary ===
# Walker: planes=<P> sats/plane=<S> total=<N> altKm=<A> inc=<I> deg
# serving cell on sat 0 (sub-point lat <..> lon <..>)
# measured SINR=<..> dB measured throughput=<..> Mbps
# GSL up=<N> down=<N> ISL up=<N> down=<N>
Key args: --simSeconds, --numPlanes, --satsPerPlane, --altKm,
--inclinationDeg, --islRangeCapKm, --numUes, --satEirpDbm, --outputDir.
A single LEO satellite from a TLE drives a real mmwave NR NTN cell
(NtnRealStackHelper) toward TR 38.811 ground UEs, while the
ContactGraphScheduler tracks GSL up/down events from the live orbital geometry.
If --gsLat/--gsLon are not supplied, the ground station is auto-placed beneath
the satellite's t=0 sub-point so a real rise→zenith→set pass always occurs
regardless of TLE epoch.
# via ns3 (from repo root)
./ns3 run "ntn-constellation-sgp4-mobility-traffic --simSeconds=20 --tle=contrib/ntn-rrc/data/iss-zarya.tle --outputDir=results/sgp4"
# pin a fixed ground site
./ns3 run "ntn-constellation-sgp4-mobility-traffic --simSeconds=20 --gsLat=33.6844 --gsLon=73.0479 --minElev=10 --outputDir=results/sgp4"Outputs: sim_health.csv in --outputDir, plus a summary block printed to
stdout:
# === ntn-constellation-sgp4-mobility-traffic summary ===
# TLE: <path> GS(lat,lon)=(..) minElev=<..> deg
# measured SINR=<..> dB measured throughput=<..> Mbps GSL up=<N> down=<N>
Key args: --simSeconds, --tle (default: contrib/ntn-rrc/data/iss-zarya.tle),
--gsLat / --gsLon (default: satellite t=0 sub-point), --minElev, --numUes,
--satEirpDbm, --outputDir.
Real ISL-routed packet forwarding GS1 -> satA -> [ISL] -> satB -> GS2: real Ipv4
forwarding through the satellite nodes, per-hop propagation delay set to the real
slant/ISL range over c, and a binary geometry contact gate per hop (GSL above
minimum elevation, ISL within the range cap) — when a hop falls out of contact its
link drops and delivery recovers when contact resumes. Traffic is an
NtnOranApplication CBR flow; delivery/delay/jitter/loss are measured end-to-end
at the NtnOranSink from the in-band NtnOranPayloadHeader.
./ns3 run "ntn-constellation-isl-routed-traffic --duration=40"Outputs: sim_health.csv (throughput, mean e2e delay, jitter, loss, delivery
ratio, out-of-contact ticks — each tagged with its measurement provenance) in
--outputDir, plus a measured summary on stdout.
Key args: --duration, --altKm, --satSpeed, --minElev,
--islRangeCapKm, --outputDir.
Routing-pattern flagship: the geometry-driven routing decision actually INSTALLS
Ipv4 static routes, so real UDP packets are forwarded through the satellite nodes
and adaptively REROUTE as the constellation moves — gs1 -> satA -> gs2 while
satA is in contact, then gs1 -> satB -> gs2 once satA sets and satB rises (the
two satellites are real Kepler+J2-secular Walker neighbours — Vallado SGP4
available via SetUseVallado — projected into a local ENU frame).
Per-link delay is the real slant range over c; KPIs are measured at the
NtnOranSink.
./ns3 run "ntn-constellation-real-routed --duration=40"Outputs: sim_health.csv (throughput, delay, jitter, loss, route installs,
reroute count) in --outputDir, plus per-event ROUTE INSTALLED via satA/satB
lines and a measured summary on stdout.
Key args: --duration, --altKm, --satSpeed, --outputDir.
This module also ships a pip-installable Python companion, ntn_constellation —
a pure-Python, tool-side pipeline for fresh ephemerides, canonical SGP4/SDP4
propagation, and export shapes that drop into both the simulator (SNS3 scenario
layout) and the CesiumJS 3D viewer. It does not modify the C++ ns-3 build; it
produces inputs the simulator already understands.
- Built-in presets: Starlink (shells 1+2 + polar) · OneWeb · Kuiper · Telesat Lightspeed · Iridium NEXT.
- Walker generators (
walker_delta,walker_star) emitting valid SGP4-parseable TLEs. Satellite/ConstellationAPI over Skyfield + rawsgp4; geodetic subpoint, ECI state vector, ground-station elevation/azimuth/range.- ISL topology builders (
build_isl_topologyk-NN with range cap;grid_isl_topology_walkerclosed-form +grid for Walker layouts). - Live feeds: CelesTrak (no credentials) and Space-Track
(
SPACETRACK_USER/SPACETRACK_PASS), with a TTL-based on-disk TLE cache (default 6 h). - Exporters:
write_sns3_scenario(SNS3positions/{tles,isls,start_date,gw_positions,ut_positions}.txt) andwrite_czml(CesiumJS CZML). ntn-fetchCLI entry point for one-line scenario builds (preset or live).
Install and run:
git clone https://github.com/Muhammaduazir69/ntn-constellation.git contrib/ntn-constellation
cd contrib/ntn-constellation
python3 -m venv .venv
.venv/bin/pip install -e .[test]# Live: current Starlink → SNS3 + Cesium
.venv/bin/ntn-fetch starlink --out data/starlink-now \
--max-sats 200 --czml --czml-duration-min 120 --czml-step-sec 30 -v
# Preset (no internet): Kuiper Phase-1 Walker
.venv/bin/ntn-fetch kuiper --out data/kuiper --isl-walker --czmlfrom datetime import datetime, timedelta, timezone
from ntn_constellation import (
CelesTrakFeed, TleCache, Constellation,
build_isl_topology, write_sns3_scenario, write_czml,
)
feed = CelesTrakFeed(cache=TleCache("./.cache"))
tles = feed.fetch_group("oneweb")[:100]
c = Constellation.from_tles(tles)
when = datetime.now(tz=timezone.utc)
visible = c.visible_from(when, observer_lat_deg=33.6844,
observer_lon_deg=73.0479, min_elevation_deg=10)
isls = build_isl_topology(c, when, k_nearest=4, max_range_km=5000.0)
write_sns3_scenario(scenario_dir="data/oneweb-sample", tles=tles,
start_date=when, isls=isls)
write_czml(constellation=c, start=when, duration=timedelta(hours=2),
sample_step=timedelta(seconds=30),
out_path="data/oneweb-sample/oneweb.czml")The Python side ships 10 unit tests (TLE parsing, preset generation, SGP4 propagation, ISS visibility from Islamabad, ISL topology, SNS3 file layout) and is validated against an independent Skyfield reference (24 h / 66 sats / 1440 samples: 0 NaN, 0.4 s wallclock; STARLINK-1008 1800 s pass: max 23.5 µs error, drift 0.006 µs/s). See INSTALL.md for the full Python setup including CelesTrak/Space-Track environment variables.
From the repository root:
# Configure & build
./ns3 configure --enable-examples --enable-tests
./ns3 build
# Run an example
./ns3 run "ntn-constellation-real-routed --duration=40"
# Run this module's test suite
./test.py --suite=ntn-constellationThe ntn-constellation suite has 20 unit tests covering TLE parsing/checksums,
periodic-return and ECEF-altitude propagation checks, Walker-Delta geometry,
contact scheduling (LEO pass + same-plane ISL pair), contact-graph routing
(direct edges, BFS, weighted Dijkstra, regenerative-only routing — including
600 s Simulator::Run() cases), and the TR 38.821 + Starlink calibration
harness. The constellation mobility models are additionally cross-validated
against Kepler orbital theory, the Doppler envelope, and TR 38.821 geometry by
the toolkit's standards-validation campaign (in ntn-cho's test suite).
For prerequisites and per-module setup, see INSTALL.md. For the full toolkit build, see the toolkit repository.
3GPP TR 38.821 (NTN reference constellations, Set-1 and Set-2 parameters, free-space link budget), TR 38.811 (NTN geometry and elevation dependence). SGP4 and SDP4 orbital propagation per the standard Vallado formulation, CCSDS-style contact graph routing concepts.
LEO constellation, mega-constellation, Walker-Delta, Walker-Star, SGP4, two-line element, TLE, orbital propagation, ephemeris, inter-satellite link, ISL, contact graph routing, contact plan, satellite topology, Starlink, OneWeb, Iridium, CelesTrak, satellite visibility, elevation angle, slant range, non-terrestrial network, ns-3.
Muhammad Uzair, Independent Researcher ORCID 0009-0002-4104-2680
Part of the ns3-ntn-toolkit, a pre-integrated ns-3.43 platform for 6G non-terrestrial network research. Mirrored on GitLab.
GPL-2.0-only, matching ns-3.