ntn-sagin
June 27, 2026 · View on GitHub
Space-Air-Ground Integrated Network for ns-3.43 — LEO space layer, an air layer of aircraft / HAPS / UAV swarms, and a ground layer of maritime, high-speed-train and ADS-B terminals, stitched together by a multi-layer / slice-aware router and carried over a real mmwave NR NTN cell. Part of ns3-ntn-toolkit — toolkit / INSTALL.
Overview
Most ns-3 NTN work stops at "satellite + ground". A realistic 6G access network spans three
layers — space (LEO/MEO/GEO), air (HAPS, UAVs, commercial flights) and ground — and a
single session frequently traverses two or three of them. ntn-sagin models all three:
ground UE ──► UAV-relay ──► HAPS (20 km) ──► LEO (550 km)
▲ TR 36.777 A2G channel ▲ ▲ SGP4 pass + measured NR radio
- Space. LEO passes driven by SGP4 (
Sgp4MobilityModelfromntn-constellation, Walker geometry) and, for routed scenarios, contact-graph shortest-path ISL routing. - Air. HAPS station-keeping (figure-8 lemniscate + waypoint trajectory), three UAV mobility patterns (waypoint / patrol / search-lawnmower), and constant-altitude aeronautical cruise.
- Ground / mobile terminals. Maritime AIS vessels, OpenSky ADS-B aircraft, and high-speed-train mobility, each with replayable trace feeds.
- Channel. 3GPP TR 36.777 v15.0.0 air-to-ground path loss and LOS probability for the
UMa-AV / RMa-AV / UMi-AV reference scenarios — available both as the
A2gChannelTr36777calculator and as a realPropagationLossModel(SaginA2gPropagationLossModel) that attenuates actual packets on a real mmwave NR spectrum channel. - Path / layer selection. A greedy max-elevation
MultiLayerRouter(Ground → UAV → HAPS → LEO) and a QFI → S-NSSAI slice-awareSaginSliceRouterthat biases the layer choice by latency budget. Both are path-computation helpers (inheritObject, returnSaginHopvectors); they install no ns-3 forwarding table — examples carry the chosen path over static/global routing or per-leg delay. - Measured KPIs. Radio examples ride a real mmwave NR NTN cell (
NtnRealStackHelper: SpectrumPhy + MAC + HARQ + RLC/PDCP + RRC + EPC), so SINR / TBLER / throughput are measured off the PHY trace. Data-plane examples carryNtnOranApplicationtraffic whose in-bandNtnOranPayloadHeaderlets theNtnOranSinkmeasure one-way delay, jitter, loss and goodput per flow — no closed-form KPI formulas, noOnOffApplication.
What's new (June 2026)
See the CHANGELOG for the full history.
- New flagship example
ntn-sagin-remote-coverage— a multi-MNO shared LEO cell for remote/rural coverage. Two MNOs serve four village households; with--sharing=1MNO-B's UEs ride MNO-A's real cell on their own S-NSSAI, and the per-MNO delivered volume — measured in-band by the KPM monitor — yields the cost-sharing split. With--sharing=0MNO-B's households simply have no service. - Measured radio everywhere. The radio examples (HAPS relay, UAV swarm, aeronautical,
flight-E2, maritime, HST, ADS-B) now build a real mmwave NR NTN cell via
NtnRealStackHelper; SINR / TBLER / throughput come off the PHY trace, not closed-form link budgets. The TR 36.777 A2G channel was re-homed asSaginA2gPropagationLossModelso it attenuates real packets (seesagin-a2g-real-stack). NtnOranApplicationtraffic suite. The data-plane examples (multihop, slice, SGP4-routed) replacedOnOffApplicationwithNtnOranApplicationsources andNtnOranSinksinks: every packet carries an in-band payload header (flow identity, 5QI, S-NSSAI, timestamps), so per-slice one-way delay / jitter / loss are measured from the packets themselves — e.g. the mMTC slice steered onto the GEO leg measures ≈119 ms one-way delay, exactly the 35 786 km physical propagation time.
Models, helpers & key classes
Derived from model/*.h and helper/*.h.
| Class | Header | Role |
|---|---|---|
HapsMobilityModel | haps-mobility-model.h | Lemniscate-of-Bernoulli (figure-8) station-keeping with tanh-clamped ±50 m vertical envelope |
HapsTrajectoryMobilityModel | haps-trajectory-mobility-model.h | Waypoint/segment-driven HAPS trajectory playback |
| (trace) | haps-trajectory-trace.h | Loads / replays HAPS trajectory traces |
UavWaypointMobilityModel | uav-mobility-models.h | RNG-driven random-waypoint UAV |
UavPatrolMobilityModel | uav-mobility-models.h | Linear A↔B patrol at constant speed |
UavSearchPatternMobilityModel | uav-mobility-models.h | Lawnmower search scan with configurable lane spacing |
AeronauticalMobilityModel | aeronautical-scenario.h | Constant-altitude / constant-ground-speed cruise |
AisMobilityModel | ais-mobility-model.h | Maritime vessel mobility (AIS-style) |
| (trace) | ais-maritime-trace.h | AIS message trace feed for vessel terminals |
OpenSkyMobilityModel | opensky-mobility-model.h | ADS-B aircraft mobility from OpenSky-style feeds |
| (trace) | opensky-adsb-trace.h | OpenSky ADS-B trace loader |
HstMobilityModel | hst-mobility-model.h | High-speed-train mobility along a track |
| (trace) | hst-trace.h | HST position/speed trace feed |
A2gChannelTr36777 | a2g-channel-tr36777.h | TR 36.777 v15.0.0 path loss (LOS + NLOS floor) and LOS probability for UMa-AV / RMa-AV / UMi-AV |
SaginA2gPropagationLossModel | sagin-a2g-propagation-loss-model.h | The TR 36.777 A2G model as a real ns-3 PropagationLossModel; chained onto a real mmwave NR spectrum channel it attenuates actual packets (returns the excess over free space to avoid double-counting) |
MultiLayerRouter | multi-layer-router.h | Greedy max-elevation Ground→UAV→HAPS→LEO path computation (returns a SaginHop vector; installs no forwarding table); pluggable SaginScoreCallback for RL/external scoring |
SaginSliceRouter | sagin-slice-router.h | 5G QFI → S-NSSAI → SliceProfile mapping; computes a layer/hop choice (returns a SaginHop vector; installs no forwarding table) biased by latency budget + GEO allowance |
SaginHelper | sagin-helper.h | Factory façade: builds a ready-to-route 4-layer scene in one call |
Examples
Twelve example programs ship under examples/. Build any of them with ./ns3 build <NAME>; the
binary lands at build/contrib/ntn-sagin/examples/ns3.43-<NAME>-default.
They fall into two families:
- Real-cell examples (
ntn-sagin-remote-coverage,sagin-haps-leo-relay,sagin-uav-swarm,sagin-a2g-real-stack,sagin-aeronautical,sagin-flight-leo-e2,sagin-maritime-leo-traffic,sagin-hst-leo-traffic,sagin-adsb-flight-leo-traffic) build a real mmwave NR NTN cell withNtnRealStackHelper; measured SINR / TBLER / throughput are printed to the console and an honestsim_health.csvis written to--outputDir. - Data-plane examples (
sagin-multihop-traffic,sagin-slice-traffic,sagin-sgp4-routed-traffic) build a point-to-point IP data plane with geometry-driven error models and carryNtnOranApplicationtraffic; theNtnOranSinkprints measured in-band KPIs (one-way delay, jitter, loss, goodput) to the console.
ntn-sagin-remote-coverage (flagship)
Remote/rural coverage with multi-MNO infrastructure sharing on a real LEO cell. A remote
village has four households: two subscribe to MNO-A, two to MNO-B; only MNO-A has a satellite
overhead (SGP4 Walker LEO at 550 km). With --sharing=1 the cell is shared — MNO-B's UEs ride
MNO-A's real cell on their own S-NSSAI (SST 1 / SD 0xB) — and the per-MNO delivered volume,
measured in-band, yields the cost-sharing split. With --sharing=0 MNO-B's households have no
service. Run both and compare.
./ns3 run "ntn-sagin-remote-coverage --sharing=0"
./ns3 run "ntn-sagin-remote-coverage --sharing=1"
Outputs: console report — per-MNO households served, delivered Mbps, measured cost-sharing
split, village coverage and cell SINR / throughput / one-way delay; sim_health.csv and
kpm_series.csv in --outputDir.
Key args: --simSeconds, --sharing, --outputDir.
sagin-haps-leo-relay
Ground-UE → UAV-relay → HAPS → LEO multi-layer route. The MultiLayerRouter selects the layered
path every second and logs per-hop elevation/range, while the access hop (ground UE ↔ UAV relay)
is a real mmwave NR cell carrying the TR 36.777 A2G channel — access SINR/TBLER/throughput are
measured off the PHY trace.
./ns3 run "sagin-haps-leo-relay --simTime=30 --csv=sagin.csv"
Outputs: <outputDir>/<csv> with columns
time_s,n_hops,uav_el_deg,uav_range_km,haps_el_deg,haps_range_km,leo_el_deg,leo_range_km;
sim_health.csv in --outputDir.
Key args: --simTime, --numUes, --uavAlt, --gnbTxDbm, --csv, --outputDir.
sagin-uav-swarm
8-UAV swarm (2 random-waypoint, 4 patrol, 2 search-pattern) served by a ground gNB over a real mmwave NR cell carrying the TR 36.777 RMa-AV A2G channel. Each UAV is a UE; per-UAV measured SINR is printed each second as the swarm manoeuvres.
./ns3 run "sagin-uav-swarm --simTime=30 --fcGHz=2.0"
Outputs: per-UAV measured-SINR table on the console; sim_health.csv in --outputDir.
Key args: --simTime, --fcGHz, --gnbTxDbm, --outputDir.
sagin-a2g-real-stack
Channel-plugin recipe: the TR 36.777 A2G model re-homed as SaginA2gPropagationLossModel and
chained onto a real mmwave NR air interface. A UAV/HAPS aerial platform is the gNB, ground nodes
are UEs; the LOS-vs-NLOS branch shows up as a real measured SINR / throughput gap.
./ns3 run "sagin-a2g-real-stack --duration=12 --link=NLOS --scenario=UMa_AV"
Outputs: measured SINR/throughput summary on the console; sim_health.csv in --outputDir.
Key args: --duration, --numUes, --uavAlt, --gnbTxDbm, --freqGhz,
--link (LOS | NLOS), --scenario (UMa_AV | RMa_AV | UMi_AV), --outputDir.
sagin-aeronautical
Passenger broadband on a commercial flight: a great-circle cruise leg at 11 km / 250 m/s served by
a passing LEO over a real mmwave NR NTN cell. The MultiLayerRouter logs the per-hop geometry;
the radio KPIs are measured off the PHY trace.
./ns3 run "sagin-aeronautical --simTime=30 --cruise=11000 --speed=250"
Outputs: <outputDir>/<csv> with columns
time_s,ac_x_m,ac_alt_m,leo_x_m,leo_z_m,leo_el_deg,slant_km; sim_health.csv in --outputDir.
Key args: --simTime, --numUes, --cruise, --speed, --leoAltKm, --satEirpDbm,
--csv, --outputDir.
sagin-flight-leo-e2
Commercial long-haul flight served by a passing LEO over a real mmwave NR NTN cell, with OAI-style O-RAN E2-KPM indications emitted from the satellite gNB to a Near-RT RIC. Each reporting period the KPM report carries the measured DL SINR / TBLER / throughput plus real elevation / Doppler / delay geometry; a mid-pass elevation descent drops the measured SINR below the in-service threshold so the handover CSV shows a real RELEASE event.
./ns3 run "sagin-flight-leo-e2 --simSeconds=30 --reportMs=500"
Outputs: sagin-flight-leo-kpm.csv (KPM indications), sagin-flight-leo-handover.csv
(ACQUIRE/RELEASE events) and sim_health.csv, all in --outputDir.
Key args: --simSeconds, --reportMs, --minElevDeg, --cruiseAltM, --cruiseSpeed,
--satAltM, --satSpeed, --satEirpDbm, --outputDir.
sagin-multihop-traffic
Real end-to-end multi-hop forwarding Ground→UAV→HAPS→LEO: three point-to-point hops joined by an
IPv4 stack with global routing, each hop with its own geometry-driven error model (TR 36.777 A2G,
free space, free space + min-elevation gate). An NtnOranApplication UDP flow is forwarded
hop-by-hop; the end-to-end PDR / delay / jitter / goodput are measured at the NtnOranSink from
the in-band payload header and track the live geometry.
./ns3 run "sagin-multihop-traffic --simSeconds=60 --dataRateMbps=20 --eirpDbm=43"
Outputs: per-second hop/path-loss/goodput table and a measured end-to-end summary
(txPackets, rxPackets, PDR, mean delay, jitter, goodput) on the console.
Key args: --simSeconds, --freqGHz, --dataRateMbps, --packetBytes, --uavAltM,
--hapsAltKm, --leoAltKm, --satSpeed, --linkCapacityMbps, --eirpDbm.
sagin-slice-traffic
Cross-layer network-slice steering via SaginSliceRouter with real per-slice traffic. Three
concurrent flows (URLLC QFI 1 / 5QI 82, eMBB QFI 7 / 5QI 2, mMTC QFI 50 / 5QI 9) are steered onto
HAPS / LEO / GEO legs by latency budget; each leg's channel delay is the physical one-way
propagation time for that layer's altitude. Per-slice delay / jitter / loss are measured by
NtnOranSink from the in-band header — the mMTC slice on the GEO leg measures ≈119 ms one-way
delay (35 786 km / c), while the tight-URLLC slice is forced down to the HAPS layer.
./ns3 run "sagin-slice-traffic --simSeconds=60 --dataRateMbps=10"
Outputs: slice→layer decision table plus per-slice measured results (rx bytes, one-way delay,
jitter, loss, goodput) on the console.
Key args: --simSeconds, --dataRateMbps, --packetBytes, --hapsAltKm, --leoAltKm,
--geoAltKm.
sagin-maritime-leo-traffic
Maritime AIS vessel terminal (AisMobilityModel) served by a passing LEO over a real mmwave NR
NTN cell. DL SINR/TBLER/throughput are measured off the PHY trace as the vessel sails and the
satellite crosses overhead.
./ns3 run "sagin-maritime-leo-traffic --simSeconds=30 --vesselSpeedKn=20"
Outputs: per-second link probe and measured summary on the console; sim_health.csv in
--outputDir.
Key args: --simSeconds, --leoAltKm, --satSpeed, --freqGHz, --satEirpDbm,
--vesselSpeedKn, --outputDir.
sagin-hst-leo-traffic
High-speed-train terminal (HstMobilityModel, TR 38.901-style track) served by a passing LEO over
a real mmwave NR NTN cell, with measured DL KPIs as the train races along the track.
./ns3 run "sagin-hst-leo-traffic --simSeconds=30 --trainSpeedKmh=500"
Outputs: per-second link probe and measured summary on the console; sim_health.csv in
--outputDir.
Key args: --simSeconds, --leoAltKm, --satSpeed, --freqGHz, --satEirpDbm,
--trainSpeedKmh, --outputDir.
sagin-adsb-flight-leo-traffic
In-flight-connectivity terminal aboard a commercial aircraft replayed from an ADS-B trace
(OpenSkyMobilityModel), served by a passing LEO over a real mmwave NR NTN cell with measured DL
KPIs.
./ns3 run "sagin-adsb-flight-leo-traffic --simSeconds=30 --cruiseAltM=11000"
Outputs: per-second link probe and measured summary on the console; sim_health.csv in
--outputDir.
Key args: --simSeconds, --leoAltKm, --satSpeed, --freqGHz, --satEirpDbm,
--cruiseAltM, --cruiseSpeedMps, --outputDir.
sagin-sgp4-routed-traffic
SGP4-driven SAGIN with graph shortest-path ISL routing. Composes ntn-constellation
(Sgp4MobilityModel + ContactGraphScheduler + ContactGraphRouter) with a real ns-3 IP data
plane whose space links follow the live contact graph: contacts bring IPv4 interfaces up/down,
channel delays follow the real slant range, and global routing re-routes the live
NtnOranApplication flow as satellites hand over. The measured in-band goodput / one-way delay
tracks the actual end-to-end connectivity, cross-checked each second against the router's Dijkstra
path.
./ns3 run "sagin-sgp4-routed-traffic --simSeconds=120 --altKm=550 --inclDeg=53 --minElevDeg=10"
Outputs: per-second contact-graph/path/goodput trace and a measured summary (GSL/ISL
transitions, delivered packets, in-band one-way delay / jitter / loss) on the console.
Key args: --simSeconds, --altKm, --inclDeg, --leadSeconds, --minElevDeg,
--dataRateMbps, --packetBytes, --spaceCapMbps, --eirpDbm, --minSnrDb.
Build, run & test
# Configure (from the ns-3-dev root) and build the module + its examples.
./ns3 configure --enable-examples --enable-tests
./ns3 build
# Build / run a single example.
./ns3 build ntn-sagin-remote-coverage
./ns3 run "ntn-sagin-remote-coverage --sharing=1"
# Run the unit-test suite for this module (32 test cases).
./test.py -s ntn-sagin
For module setup (dependencies, enabling modules, environment), see INSTALL.md. For the full toolkit, see ns3-ntn-toolkit.
License & author
GPL-2.0-only — see LICENSE.
Muhammad Uzair, Independent Researcher.
@misc{uzair2026ntnsagin,
author = {Uzair, Muhammad},
title = {ntn-sagin: Space-Air-Ground Integrated Network for 6G NTN Simulation},
year = {2026},
url = {https://github.com/Muhammaduazir69/ntn-sagin}
}
Acknowledgements
3GPP RAN1 (TR 36.777 work item) · ns-3 mobility module · OpenSky Network ADS-B · NIST NetSimulyzer for downstream visualisation.