Skip to main content

Enabling 5G NTN for satellite deployments

Overview

This tutorial demonstrates how to configure and run a 5G NR SA Non-Terrestrial Network (NTN) using OCUDU and an Amarisoft UE. NTN is a network deployment where communication between the gNB and UE is relayed via non-terrestrial components, such as satellites.

Deploying NTN introduces unique challenges due to the different link dynamics and characteristics compared to traditional terrestrial networks. To address these challenges, 3GPP introduced several enhancements and features in the 5G NR specifications (Release 17). Key features and enhancements include:

  • Frequency bands and spectrum allocation: new frequency bands suitable for satellite communication have been standardized to ensure high-capacity links.
  • Timing adjustments and delay management: mechanisms have been introduced to handle the long and variable propagation delays associated with satellite communication.
  • Doppler shift compensation: the relative movement of satellites, which can reach speeds of up to 27,000 km/h, introduces non-negligible Doppler shifts that must be compensated for to maintain reliable communication links.

In 3GPP NTN, the UE is responsible for managing long propagation delays and compensating for Doppler frequency shifts. To facilitate this, the gNB broadcasts a new SIB19 block containing NTN-related information, including the current position of the satellite. The UE uses this information to compute the current delay and Doppler frequency and adjust its transmission accordingly.

For more information, you can read the following documents:

OCUDU supports GEO, MEO, and LEO NTN scenarios. This tutorial covers GEO and LEO.

Choosing a path

Both paths use the same Amarisoft UE and Open5GS core, and the steps are almost identical. They differ only in how the satellite channel is emulated: an external GNU Radio emulator, or the Amarisoft UE's built-in NTN channel emulator.

  • External GNU Radio emulator (GEO): use this for the simplest end-to-end GEO test. An external GNU Radio flowgraph applies a fixed link delay over ZMQ, with static ephemeris. GEO only.
  • Built-in emulator (GEO/LEO): use this for realistic GEO or LEO passes. The Amarisoft UE's built-in NTN emulator applies the link delay and Doppler internally from a real satellite TLE, and the gNB ephemeris is refreshed live during a LEO pass.
External GNU Radio emulator (GEO)Built-in emulator (GEO/LEO)
Best forSimplest GEO smoke testRealistic GEO and LEO passes
OrbitsGEOGEO and LEO
Channel effectsFixed delayVariable delay and Doppler
Ephemeris sourceStatic, hand-writtenGenerated from a real TLE
Live SIB19 updatesNot usedYes (needed for LEO)
Extra toolingGNU Radio CompanionAmarisoft licence for the built-in emulator; Python 3 for the optional helper scripts
How to read this tutorial

Most of this tutorial is common to both paths. Wherever the paths differ, the section has an External GNU Radio emulator and a Built-in emulator tab. Picking a tab applies your choice across the whole page, so you only choose once.

Key concepts

The following parameters appear in the gNB NTN configuration. Each one is documented in full in the Configuration Reference.

  • Ephemeris: the satellite position and velocity. OCUDU can broadcast the ephemeris either as an ECEF state vector (ephemeris_info_ecef) or as orbital parameters (ephemeris_orbital).
  • Epoch time: the reference time to which the ephemeris and timing parameters apply.
  • Cell-specific k-offset: a scheduling offset (cell_specific_koffset) that accounts for the round-trip time of the NTN link.
  • Timing advance (TA): NTN separates the common TA (the delay to a reference point) from the UE-specific TA. The TA scheduler is tuned so that a new TA command is not issued before the previous one has been applied by the UE.
  • Feeder link and service link: the service link connects the UE to the satellite, while the feeder link connects the satellite to the ground gateway. When the gNB is on the ground rather than on the satellite, feeder link Doppler compensation applies.
  • GEO compared with LEO: a GEO link behaves as a large, effectively constant delay. A LEO satellite moves quickly across the sky, so its delay and Doppler change continuously during a pass and the ephemeris broadcast in SIB19 has to be refreshed while the UE is connected.

Step 1: Prerequisites and installation

Hardware and software

For this tutorial, the following hardware and software are used:

The Amarisoft UE simulator (AmariUE) is a commercial solution for functional and performance testing of 5G networks; as a compliant LTE, NB-IOT, and NR UE it can simulate multiple UEs concurrently.

Open5GS is an open source 5G Core. This tutorial runs it in Docker using the Compose file in the OCUDU source tree at ocudu/docker (from the clone in the build step below). The image is already configured for OCUDU, and its subscriber database is pre-populated with the Amarisoft UE test SIM, so it needs no manual setup. It exposes the AMF at 10.53.1.2, which is the address the gNB connects to in its cu_cp.amf section.

Install ZeroMQ

On Ubuntu, the ZeroMQ development libraries can be installed with:

sudo apt-get install libzmq3-dev

Build OCUDU

Compile OCUDU with ZeroMQ enabled (assuming the other dependencies are already installed). ZeroMQ is activated by the -DENABLE_EXPORT=ON -DENABLE_ZEROMQ=ON flags on the cmake command:

git clone https://gitlab.com/ocudu/ocudu.git
cd ocudu
mkdir build
cd build
cmake ../ -DENABLE_EXPORT=ON -DENABLE_ZEROMQ=ON
make -j`nproc`

Pay attention to the cmake console output. Make sure you see the following line:

...
-- FINDING ZEROMQ.
-- Checking for module 'ZeroMQ'
-- No package 'ZeroMQ' found
-- Found libZEROMQ: /usr/local/include, /usr/local/lib/libzmq.so
...
info

If you built OCUDU before installing ZMQ, you will have to re-build it so the ZMQ drivers are recognized correctly.

Install the Amarisoft UE and the ZeroMQ TRX driver

Download and install the Amarisoft UE (this tutorial uses version 2023-12-15 or later).

Interfacing the Amarisoft UE with OCUDU requires a custom TRX driver implemented by SRS, found in the OCUDU source at ocudu/utils/trx_ocudu. The Amarisoft UE release folder (amarisoft.2026-03-13.tar.gz) contains a trx_uhd-2026-03-13.tar.gz file; uncompress both before proceeding.

Compile the driver from ocudu/build:

cmake ../ -DENABLE_EXPORT=TRUE -DENABLE_ZEROMQ=TRUE -DENABLE_TRX_DRIVER=TRUE -DTRX_DRIVER_DIR=<PATH TO trx_uhd-2026-03-13>
make trx_ocudu_test
ctest -R trx_ocudu_test

Make sure CMake finds trx_driver.h in the specified folder:

-- Found trx_driver.h in TRX_DRIVER_DIR=/home/user/amarisoft/2026-03-13/trx_uhd-2026-03-13/trx_driver.h

Then create a symbolic link so the UE application can load the driver. From the Amarisoft UE build folder:

ln -s ocudu/build/utils/trx_ocudu/libtrx_ocudu.so trx_ocudu.so

Install the path-specific tooling

Install GNU Radio Companion, which runs the GEO NTN channel emulator:

sudo apt-get install gnuradio

Step 2: Configuration

The tutorial ships prepared configuration files so you can avoid errors while editing configs manually. The description of any parameter not covered here is available in the Configuration Reference. Details of the ZMQ-based setup are explained in the Amarisoft UE tutorial. The Amarisoft UE also requires the ue-ifup script that ships with it, located in the config folder of the UE application.

Download the prepared files for your path from the links in the sections below. Each config passed to the gNB with -c is read from the current working directory, so keep the files there or pass a full path (for example, -c ~/configs/ocudu_gnb.yml). Put the Amarisoft UE config in the Amarisoft UE directory, alongside the ue-ifup script.

gNB RF driver

The gNB uses the ZMQ-based RF driver to exchange samples over virtual radios. The endpoints differ between the two paths.

The gNB exchanges samples with the GNU Radio emulator:

ru_sdr:
device_driver: zmq
device_args: tx_port=tcp://127.0.0.1:2000,rx_port=tcp://127.0.0.1:2001
srate: 5.76

gNB NTN configuration

Enabling NTN features in the gNB requires the following:

  • using one of the available bands (here band: 256) and ARFCN (DL and SSB)
  • disabling Msg3 HARQ retransmissions (max_msg3_harq_retx: 0)
  • using Preamble Format 1 to improve timing robustness (here prach_config_index: 31)
  • adapting periods and timers to match the NTN link RTT
  • enabling transmission of SIB19
  • adding an ntn config section with the parameters used to configure the gNB in NTN mode and to fill SIB19

The following diagram shows the components in this setup:

image

The cell_cfg section for the GEO scenario is as follows:

cell_cfg:
dl_arfcn: 437000 # ARFCN of the downlink carrier (center frequency).
band: 256 # Use NTN band.
channel_bandwidth_MHz: 5 # Bandwidth in MHz. Number of PRBs will be automatically derived.
common_scs: 15 # Subcarrier spacing in kHz used for data.
plmn: "00101" # PLMN broadcasted by the gNB.
tac: 7 # Tracking area code (needs to match the core configuration).
pdsch:
nof_harqs: 16 # Sets the number of Downlink HARQ processes.
max_nof_harq_retxs: 0 # Disable HARQ retransmissions.
prach:
prach_config_index: 31 # Use Preamble Format 1 to improve the timing robustness.
max_msg3_harq_retx: 0 # Disable Msg3 HARQ retransmissions.
sib:
t300: 2000 # Extend the RRC Connection Establishment timer in ms.
t301: 2000 # Extend the RRC Connection Re-establishment timer in ms.
t311: 3000 # Extend the RRC Connection Re-establishment procedure timer in ms.
t319: 2000 # Extend the RRC Connection Resume timer in ms.
si_window_length: 40 # Set SI Window Length.
si_sched_info:
- si_period: 16 # Set SIB2 period.
sib_mapping: 2 # Enable SIB2.
- si_period: 16 # Set SIB19 period.
sib_mapping: 19 # Enable SIB19.
si_window_position: 2 # Set SIB19 position.
pucch:
sr_period_ms: 80 # Set Scheduling Request period.
csi:
csi_rs_period: 80 # Set CSI-RS report period.

The ntn section holds the static satellite ephemeris:

cell_cfg:
ntn:
cell_specific_koffset: 240 # Cell-specific k-offset.
ta_common: 0 # TA common offset.
ephemeris_info_ecef: # Satellite ephemeris in position and velocity state vector format.
pos_x: -28105880
pos_y: 31509747
pos_z: -1691895
vel_x: 34
vel_y: 9
vel_z: -385

Finally, the Timing Advance (TA) scheduler must account for the large propagation delays in GEO NTN. In particular, avoid measuring and issuing new TA commands before the previous command has been applied by the UE:

cell_cfg:
ta:
ta_cmd_offset_threshold: 1 # Threshold above which a Timing Advance Command is triggered.
ta_measurement_slot_period: 40 # Periodicity, in slots, over which the new TA command is computed.
ta_measurement_slot_prohibit_period: 250 # Delay, in slots, between issuing a TA_CMD and restarting measurements.
ta_target: 0 # Timing advance target in units of TA.

The gnb_zmq.yml file contains the basic (generic) gNB config, while the NTN-related parameters are defined in a separate geo_ntn.yml file.

Amarisoft UE configuration

Enabling NTN in the UE requires the following (the exact keys differ between the two paths):

  • matching the gNB band and ARFCN (here band: 256, dl_nr_arfcn: 437000)
  • enabling NTN operation, and for the built-in path the channel simulator
  • setting the UE ground position, used to compute the link delay and Doppler
  • pointing the ZMQ rf_driver at the gNB

The UE connects to the GNU Radio channel emulator over ZMQ, so its rf_driver section is:

rf_driver: {
/* OCUDU zmq RF device */
name: "ocudu",
log_level: "info",
tx_port0: "tcp://*:2101",
rx_port0: "tcp://localhost:2100",
},

The cell_groups section is as follows:

cell_groups: [{
group_type: "nr",
multi_ue: false,
cells: [{
rf_port: 0,
bandwidth: 5,
sample_rate: 5.76,
band: 256,
dl_nr_arfcn: 437000,
ssb_nr_arfcn: 437090,
ssb_subcarrier_spacing: 15,
subcarrier_spacing: 15,
n_antenna_dl: 1,
n_antenna_ul: 1,
ntn: true,
ntn_ground_position: {
latitude: -2.2970186,
longitude: 131.7327201,
altitude: 1
},
}],

The complete file is provided as ue-nr-ntn-geo.cfg.

Channel emulator

GNU Radio Companion runs the channel emulator, which delays signal samples between the gNB and UE over ZMQ. Download it as a flow-graph or a Python script:

image

The upper graph handles downlink samples and the lower graph handles uplink samples: each signal is received from the gNB (UE) over a ZMQ socket, delayed by the NTN link delay, and forwarded to the UE (gNB). It introduces only the link delay, which is sufficient to demonstrate NTN operation. Doppler shift, delay variation, and path loss are not modelled: in the GEO scenario the Doppler shift is negligible, the slow delay variation is handled by the gNB using TA commands, and path loss does not affect the NTN protocol.


Step 3: Run the network

Start the components in the order shown for your path, each in its own terminal.

1. Start the Open5GS core (--build is only needed the first time):

cd ./ocudu/docker
docker compose up --build 5gc

2. Start the GEO NTN channel emulator using the pre-generated script:

python3 ./geo_ntn_channel_emulator.py --channel-delay-us=119720

The delay value of 119720 us matches the link delay between the GEO satellite (position in ephemeris_info_ecef) and the UE (coordinates in ntn_ground_position).

3. Start the gNB from the OCUDU source root, with the config files in the working directory:

sudo ./build/apps/gnb/gnb -c gnb_zmq.yml -c geo_ntn.yml cell_cfg ntn --epoch_timestamp $(date -u +"%Y-%m-%dT%H:%M:%S.%3N")

4. Start the Amarisoft UE:

sudo ./lteue ue-nr-ntn-geo.cfg

Verifying the connection

Once the gNB starts, its console shows the cell parameters and an AMF connection attempt:

--== OCUDU gNB (commit d9a4b15) ==--

Connecting to AMF on 10.53.1.2:38412
Available radio types: zmq.
Cell pci=1, bw=5 MHz, 1T1R, dl_arfcn=437000 (n256), dl_freq=2185.0 MHz, dl_ssb_arfcn=437090, ul_freq=1995.0 MHz

==== gNodeB started ===
Type <t> to view trace

The Connecting to AMF message indicates the gNB initiated a connection to the core. On success, the Open5GS console logs a matching gNB-N2 accepted entry.

The ue-ifup script must be in the same directory as the UE and executable (chmod +x ./ue-ifup) so the simulator can create the UE network namespace. Once samples flow, the UE detects the cell (Cell 0: SIB found) and starts the attach procedure. Verify the connection with the ue command:

(ue) ue
# UE_ID CL RNTI RRC_STATE EMM_STATE #ERAB IP_ADDR
NR 0 1 0 4601 running registered 1 10.45.1.2

The connection has succeeded once the UE has an IP (here: 10.45.1.2).


Step 4: Test the network

Routing configuration

Before you can ping the UE, add a route to the UE on the host machine (the one running the Open5GS docker container):

sudo ip ro add 10.45.0.0/16 via 10.53.1.2

Check the host routing table with route -n. It should contain entries similar to the following (the Iface names might differ):

Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
10.45.0.0 10.53.1.2 255.255.0.0 UG 0 0 0 br-dfa5521eb807
10.53.1.0 0.0.0.0 255.255.255.0 U 0 0 0 br-dfa5521eb807

Ping

Test the connection in the uplink direction:

sudo ip netns exec ue1 ping 10.45.1.1

Or the downlink direction (take the UE IP from the UE console, as it can change on reconnect):

ping 10.45.1.2

Example ping output:

# sudo ip netns exec ue1 ping 10.45.1.1 -c4
PING 10.45.1.1 (10.45.1.1) 56(84) bytes of data.
64 bytes from 10.45.1.1: icmp_seq=1 ttl=64 time=762 ms
64 bytes from 10.45.1.1: icmp_seq=2 ttl=64 time=723 ms

--- 10.45.1.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss
rtt min/avg/max/mdev = 723.0/742.5/762.0/19.5 ms
note

The round-trip latency depends on the orbit. A GEO link shows a large, roughly constant delay (several hundred milliseconds), whereas a LEO link shows a lower delay that varies through the pass as the satellite rises, culminates, and sets.

Iperf

Test throughput in the uplink direction:

sudo ip netns exec ue1 iperf -c 10.45.1.1 -i 1 -t 100 -u -b25M

Or the downlink direction:

iperf -c 10.45.1.2 -i 1 -t 1000 -u -b 25M

Example gNB console trace when running iperf:

         |--------------------DL---------------------|-------------------------UL----------------------------------
pci rnti | cqi ri mcs brate ok nok (%) dl_bs | pusch rsrp ri mcs brate ok nok (%) bsr ta phr
1 4601 | 15 1.0 27 21M 988 0 0% 3.15M | 51.9 -8.9 1 27 20.1M 988 0 0% 700k -151n 23
1 4601 | 15 1.0 27 21M 988 0 0% 3.83M | 51.9 -8.9 1 27 20.1M 988 0 0% 700k -152n 23

Troubleshooting

Running gNB and Amarisoft UE on separate machines

When running the gNB and the Amarisoft UE on two separate host machines (for example, using an Amarisoft CallBox), you need to adapt the IP addresses used as the TX and RX endpoints in the ZMQ-based RF drivers.

If the NTN channel emulator runs on the same PC as the gNB:

  1. The ru_sdr section in the gNB config stays unchanged (tx_port=tcp://127.0.0.1:2000,rx_port=tcp://127.0.0.1:2001).
  2. In the GNU Radio channel emulator, change the DL transmit endpoint from tcp://127.0.0.1:2100 to tcp://0.0.0.0:2100, and the UL receive endpoint from tcp://127.0.0.1:2101 to tcp://$UE_IP:2101.
  3. In the Amarisoft UE rf_driver, set tx_port0: "tcp://*:2101" and rx_port0: "tcp://$GNB_IP:2100".

Limitations

  • ZeroMQ-based setup only: the channel emulator uses ZMQ sockets to transfer signal samples. Running over the air would require a real RF NTN channel emulator.
  • GEO scenario only: the emulator introduces only a fixed delay. LEO requires an emulator that also simulates delay variation and Doppler; use the Amarisoft path for that.
  • Satellite-based gNB placement: this scenario assumes the gNB is on the satellite, so there is no feeder link.
  • Disabled HARQ retransmissions: HARQ retransmissions are disabled. This is a valid option as specified in the NTN standards.

Next steps