Skip to content

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.

GEO NTN testbed system architecture. Three columns: the OAI nrUE with NAS, RRC including SIB19 decode, MAC with NTN timing advance configuration, PHY with NTN timing advance and Doppler application, and the rfsimulator device as a client to port 4043 with a propagation delay of 119.37 ms. The centre column is the OCUDU gNB with CU-CP carrying NGAP over N2, CU-UP carrying GTP-U over N3, a DU-high containing the DU manager, RRC, RLC and MAC, and an NTN configuration manager holding satellites, cells, epoch timestamp, ephemeris in ECEF and orbital compute. Below are the DU-low upper PHY, the RU SDR type and the rfsimulator radio session with real-time pacing and the vendored rfsimulator in server role. The third column is the 5G core, either OAI CN5G with its network functions on the 192.168.70 subnet or SD-Core with AMF, slice SST 1 and DNN internet. The footer lists interfaces: Uu over TCP port 4043 carrying IQ blocks, N2 NGAP over SCTP, N3 GTP-U over UDP, NTN control, and the TUN interface oaitun_ue1.
Figure 1: GEO NTN testbed system architecture. The rfsimulator carries IQ samples over a TCP socket and applies the 119.37 ms propagation delay itself.

What this is

Three components run side by side on a single host:

  • OCUDU gNB (TOSSI-Foundation/OCUDU-RAN, branch ntn) with the OAI rfsimulator radio driver
  • OAI nrUE (TOSSI-Foundation/OAI-RAN, branch rfsim_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.

PropertyValue
OrbitGeostationary, 35 786 km altitude, ECEF state vector (42 164 140, 0, 0) m
Reference location / UE positionSub-satellite point, latitude 0, longitude 0
One-way propagation delay119.36926 ms, applied by the rfsimulator on both ends
Round-trip delay~239 ms air interface, ~480 ms for an ICMP echo
PayloadTransparent (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

ParameterValueWhere
Bandn256 (NTN S-band)cell_cfg.band
DL carrier2185 MHz (dl_arfcn 437000)cell_cfg.dl_arfcn, UE -C 2185000000
UL offset-190 MHzUE --CO -190000000
Bandwidth10 MHz, 52 PRB, 15 kHz SCSchannel_bandwidth_MHz, UE -r 52 --numerology 0
SSB position62 subcarriers from Point AUE --ssb 62
Cell-specific K_offset240 slotsntn.cell_specific_koffset
UL sync validity240 sntn.ntn_ul_sync_validity_dur
HARQDL feedback disabled, UL HARQ mode B, no retransmissionspdsch, pusch
SIB19Scheduled every 16 radio frames, state-vector ephemerissib.si_sched_info, ntn.use_state_vector

Prerequisites

  • Ubuntu 22.04 or 24.04, x86-64, 8+ cores recommended
  • sudo rights (the UE creates the oaitun_ue1 TUN 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:

ItemShipped valueConfig key
AMF address192.168.70.132cu_cp.amf.addr
gNB N2 bind address192.168.70.129cu_cp.amf.bind_addr
gNB N3 bind address192.168.70.129cu_up.ngu.socket[0].bind_addr
PLMN / TAC00101 / 1cell_cfg.plmn, cell_cfg.tac
SliceSST 1, no SDtai_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

FilePurpose
configs/ntn/geo_rfsim_gnb.ymlGEO cell: band n256, K_offset 240, GEO ephemeris, core addresses
configs/ntn/sdcore.ymlSD-Core overlay (AMF, bind addresses, slice)
scripts/run_geo_rfsim.shOne-command bring-up: epoch, gNB, UE, PDU session, ping
OAI_RAN/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.ntn.geo.rfsim.confUE identity and GNSS position

References

DocumentRelevance
3GPP TS 38.300, section 16.14Non-Terrestrial Networks
3GPP TS 38.331SIB19 (SIB19-r17, NTN-Config-r17)
3GPP TS 38.213, section 4.2UE timing advance pre-compensation for NTN
3GPP TR 38.821Solutions for NR to support non-terrestrial networks

Source repositories

RepositoryBranchContents
OCUDU-RANntngNB: rfsimulator NTN channel emulation, configs, run scripts
OAI-RANrfsim_ocudunrUE: SIB19 decoding, NTN UE configurations

See also the OAI rfsimulator documentation and the LEO NTN rfsimulator testbed.