UE: implement TRS processing in PHY (#199)
This PR implements PHY layer processing for CSI-RS tracking signal that
estimates the CFO and sends a frequency correction command to the radio
when CFO goes above a threshold of 500Hz.
A CI test is added with a GNU radio script between OCUDU gNB and the UE
that simulates a continuous frequency offset. The test passes if the UE
sends a frequency correction command.
Reviewed-by: Robert Schmidt <robert.schmidt@openairinterface.org>
Reviewed-by: Bartosz Podrygajlo <bartosz.podrygajlo@openairinterface.org>
Reviewed-by: Francesco Mani <email@francescomani.it>
TRS resources if configured by gnb, is present in two consequtive slots
and two symbols per slot. LS estimates from the first symbol is saved
and in second symbol frequency offset and time offset is estimated. The
estimated FO is saved in UE global structure which is used in the last
TRS slot. If the FO is above a threshold, the radio's center frequency
is adjusted.
Time offset is estimated but not used because time is already tracked
using PBCH DMRS.
Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
Implementation of the E3 Agent for dApps and E3AP (no service models) (#204)
These changes introduce an E3 Agent for dApps in the OAI codebase. dApps
are real-time microservices designed to operate within the O-RAN
ecosystem, enabling sub-10 ms Artificial Intelligence (AI) routines in
the Radio Access Network (RAN).
The E3 Agent enables spectrum sensing, frequency-domain signal logging,
and dynamic PRB (Physical Resource Block) policies through IPC/ZMQ
communication with dApps or xApps.
The dApps are designed for co-location with the CU/DU, where it can
interact directly with user-plane data to enable different network
management scenarios such as optimizing network slicing, scheduling, and
resource management. A python library for the creation of the dApps is
available here [1].
Additional information about dApps:
- Paper on the dApp architecture [2]
- dApp framework presentation [3]
- Tutorial on dApp deployment on OAI [4]
As agreed in the original MR [5], this PR includes only the agent lifecycle,
configuration parsing, build plumbing, and the nr-softmodem init/destroy
hook.
It registers zero service models, so it builds and runs as an idle
agent. Concrete service models (e.g. spectrum sensing) and the PHY/MAC
hooks that drive them follow in later PRs.
Opt-in and dependencies
- Gated behind the E3_AGENT CMake option (OFF by default) / the
--build-e3 build flag. The default build is unaffected — e3ap is only
compiled and linked into nr-softmodem when E3_AGENT=ON.
- When enabled, requires the external libe3 library [6] (vendor-neutral
E3AP C++ lib), discovered via pkg_check_modules(CLIBE3 REQUIRED
libe3). It is not vendored.
Install libe3 (Debian/Ubuntu):
git clone https://github.com/wineslab/libe3 && cd libe3
./build_libe3 -I # installs deps: build-essential cmake pkg-config libzmq3-dev asn1c nlohmann-json3-dev libsctp-dev ...
./build_libe3 --install # release build + installation
Build & test
Tested in RFsim: the gNB initializes the E3 agent, opens its setup
socket (/tmp/dapps/setup), registers zero service models, and runs
without crashing. Configuration
The agent reads an optional E3Configuration section from the gNB config
file (parsed only when E3_AGENT=ON). If absent, it falls back to
built-in defaults (posix/ipc).
E3Configuration : {
link = "zmq"; # posix | zmq
transport = "ipc"; # tcp | sctp | ipc
};
The same parameters can be overridden on the command line (no
config-file edit required):
sudo ./nr-softmodem -O <gnb.conf> ... --E3Configuration.link zmq --E3Configuration.transport ipc
Validated link/transport combinations: (zmq,ipc) (zmq,tcp) (posix,tcp)
(posix,sctp) (posix,ipc).
Notes
- I have added a new log component E3AP specific for the ops performed
by the E3 Agent.
- This PR ships no gNB config file; the E3Configuration block / CLI
override above is the documented way to enable the agent. Example
configs follow in the next PRs.
[1] https://pypi.org/project/dapps/
[2] https://arxiv.org/pdf/2501.16502
[3] https://openrangym.com/o-ran-frameworks/dapps
[4] https://openrangym.com/tutorials/dapps-oai
[5] https://gitlab.eurecom.fr/oai/openairinterface5g/-/merge_requests/3361
[6] https://github.com/wineslab/libe3
Reviewed-by: Teodora Vladić <teodora.vladic@openairinterface.org>
Reviewed-by: Sagar Arora <sagar.arora@openairinterface.org>
Reviewed-by: Robert Schmidt <robert.schmidt@openairinterface.org>
Add the E3 agent lifecycle on top of libe3: configuration mapping,
agent creation/init/start, dApp report and status-change handlers,
and xApp control and subscription-query helpers. Wire e3_init() and
e3_destroy() into nr-softmodem under the E3_AGENT guard.
The agent registers no concrete service models: service models (such
as spectrum sensing) live in their own modules and register
themselves, keeping the framework decoupled from any specific use
case.
Signed-off-by: Andrea Lacava <thecave003@gmail.com>
After having removed eth_params_t from all L2/L3 files, we can reduce
the scope of common_lib.h, and remove the include from many files.
Signed-off-by: Robert Schmidt <robert.schmidt@openairinterface.org>
Add NR O-RU (#211)
This is a PR that will add a functional vrtsim-based nr-oru to the build
system. This is only slightly different SW to the one being presented at
the OAI summer 2026 workshop.
Reviewed-by: Robert Schmidt <robert.schmidt@openairinterface.org>
Reviewed-By: Merkebu Girmay <merkebu.girmay@openairinterface.org>
Instead of guessing what is the absolute timestamp of each symbol returned
from fronthaul, add absolute hyper frame from GPS Epoch to the O-RU. The
O-RU can calculate the absolute sample index from hyper frame reliably
regardless of the frame/slot/symbol ordering.
Add config file for 1x1 O-DU that matches the edited O-RU config.
Signed-off-by: Bartosz Podrygajlo <bartosz.podrygajlo@openairinterface.org>
Added oru_south_read_thread that reads samples from vrtsim.
No UL FH processing is done as of this commit.
Signed-off-by: Bartosz Podrygajlo <bartosz.podrygajlo@openairinterface.org>
Start O-RU fronthaul library inside the O-RU application and start
reading DL IQ data.
Added configuration elements to the ORUs section to support configuring
the library.
Signed-off-by: Bartosz Podrygajlo <bartosz.podrygajlo@openairinterface.org>
Added initialization of frame params according to configuration added
in the new ORUs section. Only one ORU is supported right now.
Added example config that allows starting the ORU and verifying manually
that the config is read.
Signed-off-by: Bartosz Podrygajlo <bartosz.podrygajlo@openairinterface.org>
fh_if4p5_south_in and fh_if4p5_south_out are called in NR for 7.2 split but never actually executed
they are overwritten at runtime in ru_thread
Signed-off-by: Francesco Mani <email@francescomani.it>
wrong usage of extern declaration in C files, and header cleanup
wrong usage of extern declaration in C files, instead of headers, and
fix hidden bugs by this wrong extern declaration duplication.
this fixes pure bugs because we cast variables to the wrong types, even
if the bug has no consequence
it also separates 4G/5G include files, as the error is also in the
headers mixup. Clean up header includes in F1AP.
Further remove some "CU/DUuniqinstances".
Reviewed-by: Bartosz Podrygajlo <bartosz.podrygajlo@openairinterface.org>
1. Beam index:
So far rxdataF and txdataF had beam number as first index to separate freq
domain samples of antenna ports when mulitple beams are served in a slot.
This works fine when the beam is applied to entire symbol / slot but not
suitable for digital beamforming. This commit removes the beam number index
from the data buffers and the buffers hold all the antenna ports in the first
dimension. The antenna port index to be used for each UE in a MU-MIMO or
concurrent analog beam scenario is signalled by L2 via dedicated fields in
the FAPI PDU.
2. Beam ID array changes:
- The gNB and RU struct has a 2D array to hold beam IDs for all symbols in a
frame and all antenna ports. The order is now changes to first: symbol index
and second: antenna port because the RU access all ports' beam IDs for each
symbol / slot at a time. This ordering is optimal for maximizing cache hits.
- The type is now changed from int to uint16_t. So far the L1 had to deduce
the beam number index (done in beam_index_allocation()) from the beam ID sent
by L2 and this is done by initializing the beam_id array to -1 which denoted
no beam id set. Now since L2 explicitely passes the port indices, there is no
need for denoting if a beam id is assigned or not to a slot in L1. And
uint16_t matches with the type used by FAPI to carry beam ID. Since the type
is uin16_t, beam_id array is initialized to 0 and the check for -1 when
passing beam ID 0 to xran is also removed.
3. Number of antenna ports:
The removal of beam index from rxdataF and txdataF buffers resulted in all
antenna ports to be in a single vector. The number of logical ports passed to
L1 is not N1*N2*XP*number of beams per period. The buffer initialization
function is updated to reflect this change. DAS reference config file is
updated in accordance with these changes.
4. oaioran.c:
Remove the check of beam ID = -1 for setting nPrbElm = 0. This is a hack for
LiteON to supposedely improve performance according to Mario. If it's true
then a proper fix would be to pass allocation information from L1 and use it
instead of beam ID.
Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
Preparatory changes for LDPC CUDA integration
This changeset is preparatory work to merge LDPC CUDA offload in !4097.
Notably, it includes changes for cleaning up some defines, updates to
the LDPC interface, and CI specific changes to prepare for the other MR.
The goal is to merge changes in a first step such that, in a second
step, only the actual LDPC CUDA implementation and ancillary changes
(CUDA memory allocations, CI files, ...) need to be merged.
Reviewed-By: Bartosz Podrygajlo <bartosz.podrygajlo@openairinterface.org>
Provide the memory buffer size for storing LLRs across HARQ rounds. then
we don't need to check for this in the API users.
Signed-off-by: Robert Schmidt <robert.schmidt@openairinterface.org>
even if 2 codewords are currently not supported and not tested, the way UE handled the possibility of having 2 codewords was messy, in between support and non-support
the intention of this MR is to cleanup the code more than extend the support
Signed-off-by: Francesco Mani <email@francescomani.it>
We already check for number of received samples above after receiving.
When aligned to the slot boundary for synchronization, this length
of the samples is no longer samples_per_slot.
Signed-off-by: Rakesh Mundlamuri <rakesh.mundlamuri@openairinterface.org>
Make sure the radio libs are stopped before `end()` call. This allows
for a cleaner exit under most circumstances. Some libraries like zmq_radio
don't exit cleanly without it.
L1 RX: use queues instead of arrays and linear search for PUCCH, PUSCH, SRS, PRACH
This MR is an attempt to reduce the time L1 RX searches in array for the
next job to process, and instead use a queue. This queue is a FIFO,
because the various jobs (FAPI messages) to process come in order, and
need to be processed in order. The MR (hopefully, to be measured)
reduces the amount of time spent searching for the next UE (because the
next job is always at the beginning of the queue), and should scale
better for many UEs.
It does the following:
- introduce two helper libraries for (1) Frame.Slot calculation (sfn_t),
already introduced in !3521 (merged) commit 3102068e, and (2) a ring
buffer with fixed size
- use sfn_t and ring buffer (gNB->pucch_queue) to remove the linear
array for PUCCH (gNB->pucch)
- use sfn_t and ring buffer (gNB->pusch_queue) for some PUSCH lookups.
Because we need to still store PUSCH contexts, gNB->pusch is still
there
- use sfn_t and ring buffer (gNB->srs_queue) to remove the linear array
for SRS (gNB->srs)
- use sfn_t and ring buffers (gNB->prach_ru_queue and
gNB->prach_l1rx_queue) to remove the linear array for PRACH
(gNB->prach_list)
- some minor cleanups, e.g., additional loops over the PUSCH array,
using const, using pointers instead of indices, etc
Use two queues for PRACH processing:
- prach_ru_queue: pass jobs from TX thread (scheduler) to RU thread. For
split 8, the RU thread itself handles PRACH processing; for split 7.2,
it is the library that is responsible for handling PRACH messages (see
oran_fh_if4p5_south_in())
- prach_l1rx_queue: after jobs have been handled in RU thread, use this
queue to pass jobs to the RX thread. There, preamble detection is
performed, and RACH.indication FAPI messages are filled if a preamble
has been detected.
Together, these queues replace a linear search in a global array that
has been modified by three threads at the same time. The design ensures
that access now is thread-safe, and with less overhead.
Signed-off-by: Robert Schmidt <robert.schmidt@openairinterface.org>
Thread-pool support for TX symbol processing.
This MR adds thread-pool support for TX symbol processing. It allows modulation
/mapping/layer-precoding to run in parallel and offers a speedup of around 3
compared to single-thread execution. This is particularly important for large
bandwidths and 4 or more TX antenna ports where the precoding operation is quite
computationally-intensive.
Please see the description of !3489 for the performance comparison results and
the nr_dlsim timing measurements.
* Add option `--L1s.L1_num_tx_sym_per_thread` for the softmodems and `-Y` for `nr_dlsim`
to provide the number of symbols processed per thread.
It defaults to 0 which makes that every symbols are processed in one thread.
* The last symbol processing task is processed in the L1 TX thread.
Further unused arguments cleanup
More fixes for unused function arguments (see #1057),
add_compile_options(-Wunused-parameter) added in folders:
- nfapi
- openair2
- openair3
- USRP
- rfsimulator
* Global timers were started and stopped
in the TX symbol processing tasks
which is not thread safe
* gNBs nrL1_stats.log now shows
PDSCH generation time rather than
layer mapping and precoding times
Cleanup common_lib.h
This change reduces the number of dependecies of common_lib.h and simplifies
the task of implementing an external OAI radio library.