GEO NTN Testbed: OCUDU gNB with OAI nrUE over the rfsimulator
A complete 5G Standalone network in which the radio link between the UE and the gNB behaves like a geostationary satellite link: roughly 120 ms of propagation delay in each direction, a Release 17 NTN air interface, and a real core network behind it. Everything runs on one Linux host, with no radio hardware.
What this is
Three components run side by side on a single host:
- OCUDU gNB (
TOSSI-Foundation/OCUDU-RAN, branchntn) with the OAI rfsimulator radio driver - OAI nrUE (
TOSSI-Foundation/OAI-RAN, branchrfsim_ocudu) connected over the same rfsimulator - A 5G core: SD-Core or OAI CN5G
This replaces the earlier ZMQ and Python relay GEO testbed. The rfsimulator carries IQ samples over a TCP socket and applies the propagation delay itself, so no relay process is needed.
Link model
| Property | Value |
|---|---|
| Orbit | Geostationary, 35 786 km altitude, ECEF state vector (42 164 140, 0, 0) m |
| Reference location / UE position | Sub-satellite point, latitude 0, longitude 0 |
| One-way propagation delay | 119.36926 ms, applied by the rfsimulator on both ends |
| Round-trip delay | ~239 ms air interface, ~480 ms for an ICMP echo |
| Payload | Transparent (bent pipe), gNB on the ground |
A GEO satellite is fixed relative to the ground, so the delay is constant and the rfsimulator's own prop_delay models it exactly. No channel model is enabled on either side.
Air interface
| Parameter | Value | Where |
|---|---|---|
| Band | n256 (NTN S-band) | cell_cfg.band |
| DL carrier | 2185 MHz (dl_arfcn 437000) | cell_cfg.dl_arfcn, UE -C 2185000000 |
| UL offset | -190 MHz | UE --CO -190000000 |
| Bandwidth | 10 MHz, 52 PRB, 15 kHz SCS | channel_bandwidth_MHz, UE -r 52 --numerology 0 |
| SSB position | 62 subcarriers from Point A | UE --ssb 62 |
| Cell-specific K_offset | 240 slots | ntn.cell_specific_koffset |
| UL sync validity | 240 s | ntn.ntn_ul_sync_validity_dur |
| HARQ | DL feedback disabled, UL HARQ mode B, no retransmissions | pdsch, pusch |
| SIB19 | Scheduled every 16 radio frames, state-vector ephemeris | sib.si_sched_info, ntn.use_state_vector |
Prerequisites
- Ubuntu 22.04 or 24.04, x86-64, 8+ cores recommended
sudorights (the UE creates theoaitun_ue1TUN interface; the gNB writes its logs as root)- A running 5G core reachable from the host
- About 15 GB of free disk space for both builds
Create one workspace. The run scripts expect OCUDU-RAN and OAI_RAN to sit side by side:
mkdir -p ~/ntn && cd ~/ntn
1. Get the sources
cd ~/ntn
git clone -b ntn https://github.com/TOSSI-Foundation/OCUDU-RAN.git
git clone -b rfsim_ocudu https://github.com/TOSSI-Foundation/OAI-RAN.git OAI_RAN
2. Build the OCUDU gNB
Dependencies:
sudo apt-get update
sudo apt-get install -y cmake make gcc g++ pkg-config git \
libfftw3-dev libmbedtls-dev libsctp-dev libyaml-cpp-dev libgtest-dev \
libzmq3-dev libboost-program-options-dev
Configure with the rfsimulator radio enabled and build the gnb target. The run scripts look for the binary in build_ntn:
cd ~/ntn/OCUDU-RAN
cmake -S . -B build_ntn -DCMAKE_BUILD_TYPE=Release -DENABLE_RFSIM=ON
make -C build_ntn -j"$(nproc)" gnb
ls -l build_ntn/apps/gnb/gnb
3. Build the OAI nrUE
cd ~/ntn/OAI_RAN/cmake_targets
./build_oai -I # external dependencies, first time only
./build_oai --nrUE -w SIMU # nr-uesoftmodem + rfsimulator
ls -l ran_build/build/nr-uesoftmodem ran_build/build/librfsimulator.so
The UE configuration used here is targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.ntn.geo.rfsim.conf:
uicc0 = {
imsi = "001010000000002";
key = "fec86ba6eb707ed08905757b1bb44b8f";
opc = "C42449363BBAD02B66D16BC975D77CC1";
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
}
position0 = { x = 6378137.0; y = 0.0; z = 0.0; }
position0 is mandatory for an NTN UE: it is the UE's own GNSS position, combined with the SIB19 ephemeris to pre-compensate the timing advance. Without it random access fails.
Core network
This testbed has been tested against both SD-Core and OAI CN5G. Both work for GEO attach and user-plane traffic. OAI CN5G does not support the NGAP Path Switch procedure, so the handover scenarios in the LEO testbed use SD-Core only.
configs/ntn/geo_rfsim_gnb.yml ships with these core-facing settings; change them to match your core:
| Item | Shipped value | Config key |
|---|---|---|
| AMF address | 192.168.70.132 | cu_cp.amf.addr |
| gNB N2 bind address | 192.168.70.129 | cu_cp.amf.bind_addr |
| gNB N3 bind address | 192.168.70.129 | cu_up.ngu.socket[0].bind_addr |
| PLMN / TAC | 00101 / 1 | cell_cfg.plmn, cell_cfg.tac |
| Slice | SST 1, no SD | tai_slice_support_list, cell_cfg.slicing |
A default OAI CN5G has no slice differentiator, so the gNB slice and the UE NSSAI carry SST 1 only. Offering an SD the AMF does not list makes NG setup and registration fail.
The subscriber (IMSI, key, OPc, DNN, slice) must be provisioned in the core and match the uicc0 block of the UE configuration, or be overridden on the UE command line with --uicc0.imsi, --uicc0.key, --uicc0.opc, --uicc0.nssai_sst, --uicc0.nssai_sd and --uicc0.pdu_sessions.[0].dnn.
To point the GEO cell at SD-Core, layer configs/ntn/sdcore.yml on top of the GEO config (edit its addresses first) and pass the SD-Core subscriber on the UE command line, exactly as in the LEO testbed.
4. Run
Option A: one command
cd ~/ntn/OCUDU-RAN
PING_TARGET=8.8.8.8 ./scripts/run_geo_rfsim.sh
The script kills any stale gnb or nr-uesoftmodem, refreshes the SIB19 epoch, starts the gNB, waits for NG setup, starts the UE, waits for the PDU session and pings. Ctrl-C stops both. Every path is overridable from the environment, for example OAI=/path/to/OAI_RAN.
Option B: step by step
Before every run:
sudo pkill -9 -f nr-uesoftmodem; sudo pkill -9 -f 'build_ntn/apps/gnb/gnb'
sudo rm -f /tmp/gnb_geo.log
The gNB log is created by root; a stale one from a previous run makes the next gNB unable to open it.
Refresh the epoch. The gNB reads epoch_timestamp once at start-up and broadcasts ephemeris relative to it, so it must be close to the current UTC time:
cd ~/ntn/OCUDU-RAN
sed -i "s/epoch_timestamp: '[^']*'/epoch_timestamp: '$(date -u '+%Y-%m-%dT%H:%M:%S')'/" configs/ntn/geo_rfsim_gnb.yml
grep epoch_timestamp configs/ntn/geo_rfsim_gnb.yml
Terminal 1, gNB (rfsimulator server)
cd ~/ntn/OCUDU-RAN
sudo ./build_ntn/apps/gnb/gnb -c configs/ntn/geo_rfsim_gnb.yml
Wait for NG setup to complete in the gNB log:
sudo grep -a 'NG Setup Procedure' /tmp/gnb_geo.log
Terminal 2, UE (rfsimulator client)
sudo ~/ntn/OAI_RAN/cmake_targets/ran_build/build/nr-uesoftmodem \
-O ~/ntn/OAI_RAN/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.ntn.geo.rfsim.conf \
--band 256 -C 2185000000 --CO -190000000 -r 52 --numerology 0 --ssb 62 \
--rfsim --rfsimulator.[0].serveraddr 127.0.0.1 \
--rfsimulator.[0].prop_delay 119.36926
Terminal 3, traffic
ip -4 addr show oaitun_ue1
ping -I oaitun_ue1 8.8.8.8
5. Verify
gNB log (/tmp/gnb_geo.log), in order:
[NGAP ] [I] "NG Setup Procedure" finished successfully
[RRC ] [I] ue=0 c-rnti=0x4601: DCCH UL rrcSetupComplete
[NGAP ] [I] ue=0 ran_ue=0 amf_ue=10: "PDU Session Resource Setup Procedure" started...
UE console:
[NR_MAC] [UE 0] ... 4-Step RA procedure succeeded. CBRA: Contention Resolution is successful.
[NAS] Received Registration Accept with result 3GPP
[OIP] TUN Interface oaitun_ue1 successfully configured, IPv4 ...
Measured on this testbed: the attach completes about 6 s after NG setup, and pings to 8.8.8.8 over the GEO link take 276 to 555 ms (average 456 ms), two passes of the 239 ms air-interface round trip plus scheduling latency and the internet path.
For deeper inspection, enable the NGAP and MAC PCAPs in configs/ntn/geo_rfsim_gnb.yml (pcap.ngap_enable, pcap.mac_enable) and raise log.all_level to debug.
Files
| File | Purpose |
|---|---|
configs/ntn/geo_rfsim_gnb.yml | GEO cell: band n256, K_offset 240, GEO ephemeris, core addresses |
configs/ntn/sdcore.yml | SD-Core overlay (AMF, bind addresses, slice) |
scripts/run_geo_rfsim.sh | One-command bring-up: epoch, gNB, UE, PDU session, ping |
OAI_RAN/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.ntn.geo.rfsim.conf | UE identity and GNSS position |
References
| Document | Relevance |
|---|---|
| 3GPP TS 38.300, section 16.14 | Non-Terrestrial Networks |
| 3GPP TS 38.331 | SIB19 (SIB19-r17, NTN-Config-r17) |
| 3GPP TS 38.213, section 4.2 | UE timing advance pre-compensation for NTN |
| 3GPP TR 38.821 | Solutions for NR to support non-terrestrial networks |
Source repositories
| Repository | Branch | Contents |
|---|---|---|
| OCUDU-RAN | ntn | gNB: rfsimulator NTN channel emulation, configs, run scripts |
| OAI-RAN | rfsim_ocudu | nrUE: SIB19 decoding, NTN UE configurations |
See also the OAI rfsimulator documentation and the LEO NTN rfsimulator testbed.