Compare commits

...

9 Commits

Author SHA1 Message Date
Bartosz Podrygajlo
6103a6fe5d Fix network namespace usage in the up traffic step 2025-11-18 21:48:19 +01:00
Bartosz Podrygajlo
b98b0c4d32 Tutorials - continuation 2025-11-18 21:26:18 +01:00
Bartosz Podrygajlo
1d659aaf9c Map ENABLE_TAPS_CLIENT=ON fix to workshop branch 2025-11-18 21:16:12 +01:00
Merkebu Girmay
58a26fd8b4 FlatBuffers package name mismatch resolved 2025-11-18 21:12:10 +01:00
Merkebu Girmay
15f1b77077 Edit channel_modelling_external_channel.md 2025-11-16 07:16:09 +00:00
Merkebu Girmay
54c5590eee Docs: add external channel modeling tutorial for VRTSIM workshop 2025-11-10 00:51:57 -08:00
Bartosz Podrygajlo
cf9b1b12dc Tutorial for vrtsim 2025-11-07 17:22:47 +01:00
Bartosz Podrygajlo
fea52dc3d0 vrtsim: Optimize channel modelling
Optimization pass for channel modelling on transmission in vrtsim. This
comes from a requirement of O-RU to perform channel modelling with minimum
latency.

- Reduced MAX_CHANNEL_LENGTH to 200 and introduced SAVED_SAMPLES_LEN
- Refactored channel modelling actor allocation to parallelize work better
- Improved batching and task creation for channel modelling
- Replaced static global saved_samples with local static buffer in vrtsim_write_with_chanmod
2025-11-07 14:49:51 +01:00
Bartosz Podrygajlo
48c10bee5c Fix tracy git tag 2025-11-07 14:49:40 +01:00
12 changed files with 630 additions and 89 deletions

View File

@@ -282,7 +282,7 @@ add_boolean_option(TRACY_ENABLE OFF "Enable tracy instrumentation" ON)
if (TRACY_ENABLE)
# the tracy version here should match the tracy server version
# below is latest release as of this commit
CPMAddPackage("gh:wolfpld/tracy#0.12.2")
CPMAddPackage("gh:wolfpld/tracy#v0.12.2")
endif()
set (OCP_ITTI ${OPENAIR_DIR}/common/utils/ocp_itti)

View File

@@ -0,0 +1,100 @@
# About
In this step usage of channel modelling with `vrtsim` will be explained
# Configure
Modify the gNB config file at `targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf`. Add the following at the end:
```
channelmod = {
max_chan=10;
modellist="modellist_rfsimu_1";
modellist_rfsimu_1 = (
{
model_name = "server_tx_channel_model"
type = "AWGN";
ploss_dB = 0;
noise_power_dB = 0;
forgetfact = 0;
offset = 0;
ds_tdl = 0;
}
);
};
```
# (Optional) Run UE with scope to visualize the impact
```
cmake ../../ -DENABLE_IMSCOPE=ON
```
```
cmake --build . --target imscope
```
Add `--imscope` to UE command line
# Run
```
sudo ./nr-softmodem -O ../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --gNBs.[0].min_rxtxtime 6 --device.name vrtsim --vrtsim.role server --vrtsim.chanmod 1
```
```
sudo ./nr-uesoftmodem -C 3619200000 -r 106 --numerology 1 --ssb 516 --band 78 --device.name vrtsim
```
# Modifying the channel model
Try the following settings:
```
modellist_rfsimu_1 = (
{
model_name = "server_tx_channel_model"
type = "Rayleigh8";
ploss_dB = 0;
noise_power_dB = 0;
forgetfact = 0;
offset = 0;
ds_tdl = 0;
}
);
```
```
modellist_rfsimu_1 = (
{
model_name = "server_tx_channel_model"
type = "AWGN";
ploss_dB = -5;
noise_power_dB = 0;
forgetfact = 0;
offset = 0;
ds_tdl = 0;
}
);
```
```
modellist_rfsimu_1 = (
{
model_name = "server_tx_channel_model"
type = "AWGN";
ploss_dB = -10;
noise_power_dB = 0;
forgetfact = 0;
offset = 0;
ds_tdl = 0;
}
);
```
Add noise:
```
channelmod = {
max_chan=10;
modellist="modellist_rfsimu_1";
noise_power_dBFS = -42;
```

View File

@@ -0,0 +1,59 @@
# About
Precomputed 3GPP 38.901 TDL profiles (A to E) with statistical MIMO channels, plus a Python emitter that publishes taps to VRTSIM over a nanomsg PUB socket using FlatBuffers. Supports multiple antenna shapes (up to 64x64), speed presets (walking about 1.5 m/s, car about 30 m/s), spatial correlation, mutual coupling, LOS steering for D and E, and time-varying lognormal shadowing.
---
## 1) Setup
python3 -m pip install --user flatbuffers nanomsg numpy pyyaml
cd ~/raytracing-channel-emulator/server/api
flatc --python -o . taps.fbs # generates ./Phy/Taps.py
export PYTHONPATH="$(pwd):$PYTHONPATH"
# switch to external_taps for the tools below
cd ~/raytracing-channel-emulator/server/external_taps
---
## 2) Generate the CIR file
Default profiles, delay spreads, antenna shapes, and speed presets are embedded.
Shadowing is enabled by default, lognormal per link, time varying across snapshots via AR(1).
This command writes:
- binary taps file: ./cir_db.bin
- YAML sidecar with per-entry metadata: ./cir_db.yaml (used by the emitter to resolve selections and offsets)
python3 CIR_generator.py --out ./cir_db.bin
To change shadowing, pass --shadow-sigma-db and optionally --shadow-tau-c-s for the correlation time. Set sigma to 0 to disable.
---
## 3) Run the emitter
Sequential replay, one snapshot every 0.5 s:
python3 emit_from_db.py --bind tcp://127.0.0.1:5555 --db ./cir_db.bin --model TDL-A --ds-ns 30 --nrx 1 --ntx 1 --interval 0.5
List what is in the database:
python3 emit_from_db.py --db ./cir_db.bin --describe-db
Optional, print the selected entry before streaming:
python3 emit_from_db.py --db ./cir_db.bin --print-selected
---
## 4) Run OAI with VRTSIM
gNB (server role):
sudo ./nr-softmodem -O ../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --device.name vrtsim --vrtsim.role server --vrtsim.taps-socket tcp://127.0.0.1:5555 --gNBs.[0].min_rxtxtime 3
UE (client role):
sudo ./nr-uesoftmodem -C 3619200000 -r 106 --numerology 1 --ssb 516 --band 78 --device.name vrtsim --vrtsim.role client

View File

@@ -0,0 +1,145 @@
# About
In this step the basics of compiling and running `vrtsim` will be explained.
# About vrtsim
vrtsim is a realtime/fixed timescale split8 device emulator. The main difference between
rfsim and vrtsim is the timing constraints vrtsim forces on the applications that use it.
# Compiling
Start by making a new directory under `cmake_targets`
```bash
mkdir -p cmake_targets/build/
```
Compile vrtsim + RAN elements
```bash
cd /cmake_targets/build
cmake ../../ -GNinja
cmake --build . --target vrtsim nr-softmodem nr-uesoftmodem ldpc params_libconfig params_yaml
```
# Running
Run a basic testcase to verify connectivity, no core network present
```bash
sudo ./nr-softmodem -O ../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --gNBs.[0].min_rxtxtime 6 --device.name vrtsim --vrtsim.role server
```
```bash
sudo ./nr-uesoftmodem -C 3619200000 -r 106 --numerology 1 --ssb 516 --band 78 --device.name vrtsim
```
# Verification
Goal is to have the UE connect for now (i.e. enter RRC Connected mode). The success depends on your
CPU speed.
## Example NR UE output when UE is connected
```
[PHY] Initial sync: pbch decoded sucessfully, ssb index 0
[PHY] pbch rx ok. rsrp:51 dB/RE, adjust_rxgain:-1 dB
[NR_PHY] Cell Detected with GSCN: 0, SSB SC offset: 516, SSB Ref: 0.000000, PSS Corr peak: 99 dB, PSS Corr Average: 61
[PHY] [UE0] In synch, rx_offset 444704 samples
[PHY] [UE 0] Measured Carrier Frequency offset 6 Hz
[PHY] Initial sync successful, PCI: 0
[PHY] HW: Configuring channel 0 (rf_chain 0): setting tx_freq 3619200006 Hz, rx_freq 3619200006 Hz, tune_offset 0
[PHY] Got synch: hw_slot_offset 29, carrier off 6 Hz, rxgain 110.000000 (DL 3619200006.000000 Hz, UL 3619200006.000000 Hz)
[PHY] UE synchronized! decoded_frame_rx=404 UE->init_sync_frame=0 trashed_frames=14
[PHY] Resynchronizing RX by 444704 samples
[HW] received write reorder clear context
[NR_RRC] SIB1 decoded
[NR_MAC] TDD period index = 6, based on the sum of dl_UL_TransmissionPeriodicity from Pattern1 (5.000000 ms) and Pattern2 (0.000000 ms): Total = 5.000000 ms
[NR_MAC] Set TDD configuration period to: 8 DL slots, 3 UL slots, 10 slots per period (NR_TDD_UL_DL_Pattern is 7 DL slots, 2 UL slots, 6 DL symbols, 4 UL symbols)
[NR_MAC] Configured 1 TDD patterns (total slots: pattern1 = 10, pattern2 = 0)
[PHY] N_TA_offset changed from 0 to 800
[MAC] Initialization of 4-Step CBRA procedure
[NR_MAC] PRACH scheduler: Selected RO Frame 421, Slot 19, Symbol 0, Fdm 0
[PHY] PRACH [UE 0] in frame.slot 421.19, placing PRACH in position 2828, Msg1/MsgA-Preamble frequency start 0 (k1 0), preamble_offset 6, first_nonzero_root_idx 0, preambleIndex = 27
[PHY] [UE 0] RAR-Msg2 decoded
[NR_MAC] [UE 0][RAPROC][RA-RNTI 010b] Got BI RAR subPDU 5 ms
[NR_MAC] [UE 0][RAPROC][RA-RNTI 010b] Got RAPID RAR subPDU
[NR_MAC] [UE 0][RAPROC][422.10] Found RAR with the intended RAPID 27
[MAC] received TA command 31
[NR_MAC] [RAPROC][422.19] RA-Msg3 transmitted
[MAC] [UE 0][423.10][RAPROC] 4-Step RA procedure succeeded. CBRA: Contention Resolution is successful.
[NR_RRC] [UE0][RAPROC] Logical Channel DL-CCCH (SRB0), Received NR_RRCSetup
[RLC] Added srb 1 to UE 0
[NR_RRC] State = NR_RRC_CONNECTED
```
## Example gNB output when connected
```
[NR_PHY] [RAPROC] 421.19 Initiating RA procedure with preamble 27, energy 31.7 dB (I0 0, thres 120), delay 0 start symbol 0 freq index 0
[NR_MAC] 421.19 UE RA-RNTI 010b TC-RNTI 2c32: initiating RA procedure
[NR_MAC] UE 2c32: Msg3 scheduled at 422.19 (422.10 TDA 0) start 0 RBs 8
[NR_MAC] UE 2c32: 422.10 Generating RA-Msg2 DCI, RA RNTI 0x10b, state 1, preamble_index(RAPID) 27, timing_offset = 0 (estimated distance 0.0 [m])
[NR_MAC] 422.10 Send RAR to RA-RNTI 010b
[NR_MAC] 422.19 PUSCH with TC_RNTI 0x2c32 received correctly
[MAC] [RAPROC] Received SDU for CCCH length 6 for UE 2c32
[RLC] Activated srb0 for UE 11314
[RLC] Added srb 1 to UE 11314
[NR_MAC] Activating scheduling Msg4 for TC_RNTI 0x2c32 (state WAIT_Msg3)
[NR_RRC] Decoding CCCH: RNTI 2c32, payload_size 6
[NR_RRC] [--] (cellID 0, UE ID 1 RNTI 2c32) Create UE context: CU UE ID 1 DU UE ID 11314 (rnti: 2c32, random ue id 1c14de2d3f000000)
[RRC] activate SRB 1 of UE 1
[NR_RRC] [DL] (cellID bc614e, UE ID 1 RNTI 2c32) Send RRC Setup
[NR_MAC] UE 2c32 Generate Msg4: feedback at 423.17, payload 225 bytes, next state nrRA_WAIT_Msg4_MsgB_ACK
[NR_MAC] 423.17 UE 2c32: Received Ack of Msg4. CBRA procedure succeeded (UE Connected)
[NR_MAC] Adding new UE context with RNTI 0x2c32
[NR_RRC] [UL] (cellID bc614e, UE ID 1 RNTI 2c32) Received RRCSetupComplete (RRC_CONNECTED reached)
```
## Troubleshooting:
In case the UE does not connect:
Interrupt the process using `CTRL + C` and analyze `vrtsim` stdout at the end. You should see the histogram
print from `vrtsim`
Example from a working configuration:
```
[HW] VRTSIM: Realtime issues: TX 0.00%, RX 0.00%
[HW] VRTSIM: Read/write too early (suspected radio implementaton error) TX: 0, RX: 0
[HW] VRTSIM: Average TX budget 913.111 uS (more is better)
[HW] VRTSIM: TX budget histogram: 6468 samples
[HW] Bin 0 [0.0 - 100.0uS]: 0
[HW] Bin 1 [100.0 - 200.0uS]: 0
[HW] Bin 2 [200.0 - 300.0uS]: 0
[HW] Bin 3 [300.0 - 400.0uS]: 0
[HW] Bin 4 [400.0 - 500.0uS]: 1
[HW] Bin 5 [500.0 - 600.0uS]: 0
[HW] Bin 6 [600.0 - 700.0uS]: 0
[HW] Bin 7 [700.0 - 800.0uS]: 1
[HW] Bin 8 [800.0 - 900.0uS]: 125
[HW] Bin 9 [900.0 - 1000.0uS]: 6242
[HW] Bin 10 [1000.0 - 1100.0uS]: 0
[HW] Bin 11 [1100.0 - 1200.0uS]: 0
```
The histogram above indicates if the application encountered any timing related issues. If the average TX budget
is low (near ~0) or bin 0 is being filled that could mean that your CPU is too slow.
Possible fixes:
- Try disabling idle states
```bash
sudo cpupower idle-set -D 0
```
- Change cpu frequency scaling governor to performance
```bash
sudo cpupower frequency-set --governor performance
```
- Modify this line in the code of the UE and rebuild:
```diff
-#define NR_UE_CAPABILITY_SLOT_RX_TO_TX (3)
+#define NR_UE_CAPABILITY_SLOT_RX_TO_TX (6)
```
If that doesnt work, adjust `--vrtsim.timescale <timescale>` argument on `nr-softmodem`.
Start lowering the timescale (e.g. to 0.2) to slow down time until the UE connects.

View File

@@ -0,0 +1,95 @@
# About
In this step using `iperf` to test the modems performance is explained.
# Running
## Option 1: --noS1 mode
Select this option on slower machines. This doesn't require core network.
1. Run gNB
```bash
sudo ./nr-softmodem -O ../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --gNBs.[0].min_rxtxtime 6 --device.name vrtsim --vrtsim.role server --noS1 --do-ra
```
2. Create UE namespace
```bash
sudo ip netns add ue_ns
```
2. Run UE in the new namespace
```bash
sudo ip netns exec ue_ns bash
sudo ./nr-uesoftmodem -C 3619200000 -r 106 --numerology 1 --ssb 516 --band 78 --device.name vrtsim --noS1 --do-ra
```
3. Run iperf server in the UE namespace
```bash
sudo ip netns exec ue_ns bash
iperf -s -B 10.0.1.2
```
4. Run iperf client in host namespace
```bash
iperf -c 10.0.1.2 -B 10.0.1.1
```
## Option 2: with core network
1. Start `cn` in `doc/tutorial_resources/oai-cn5g` with `docker compose up`
2. Run gNB
```bash
sudo ./nr-softmodem -O ../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --gNBs.[0].min_rxtxtime 6 --device.name vrtsim --vrtsim.role server
```
3. Verify connection to core network in gNB stdout
```
[NGAP] Send NGSetupRequest to AMF
[NGAP] 3584 -> 0000e000
[NGAP] Served GUAMIs for AMF OAI-AMF (assoc_id=3):
[NGAP] GUAMI:
[NGAP] PLMN: MCC=001, MNC=01
[NGAP] AMF Region ID: 1
[NGAP] AMF Set ID: 1
[NGAP] AMF Pointer: 1
[NGAP] Supported PLMN 0: MCC=001 MNC=01
[NGAP] Supported slice (PLMN 0): SST=0x01 SD=000
[NGAP] Received NGSetupResponse from AMF
```
4. Connect the UE.
```bash
sudo ./nr-uesoftmodem -C 3619200000 -r 106 --numerology 1 --ssb 516 --band 78 --device.name vrtsim --uicc0.imsi 001010000000001
```
5. Verify interface is created
```
[OIP] Interface oaitun_ue1 successfully configured, IPv4 10.0.0.2, IPv6 (null)
```
```bash
ifconfig | grep tun
```
6. Run iperf in oai-ext-dn container
```bash
docker exec -it oai-ext-dn bash
iperf -c 10.0.0.2 -B 192.168.70.135
```
## Troubleshooting
Use the same steps as from `first_steps.md`. This test adds additional requirements
on the CPU which might cause the UE to fail.

View File

@@ -0,0 +1,17 @@
# About
Just a demonstration of what we need vrtsim for
# Running
```
sudo -E LD_LIBRARY_PATH=/usr/local/lib/x86_64-linux-gnu/:. -E ASAN_OPTIONS=detect_odr_violation=0 ./oainr_ru -O ~/ru.band77.106prb.fhi72.2x2.conf --vrtsim.role server
```
```
sudo -E LD_LIBRARY_PATH=/usr/local/lib/x86_64-linux-gnu/:. -E ASAN_OPTIONS=detect_odr_violation=0 ./nr-softmodem -O ~/gnb.2x2.conf --gNBs.[0].min_rxtxtime 6
```
```
sudo -E LD_LIBRARY_PATH=. ./nr-uesoftmodem -C 4049760000 -r 106 --numerology 1 --ssb 516 --band 77 --device.name vrtsim
```

View File

@@ -0,0 +1,6 @@
1. Clone https://gitlab.eurecom.fr/oai/raytracing-channel-emulator
2. Run: sudo apt install git-lfs
3. In the cloned repository, run: git lfs fetch and git lfs checkout
4. Install the required Python packages listed here
5. sudo apt install -y llvm-dev libnanomsg-dev flatbuffers-compiler
6. Godot 4.4 for the test platform (optional) https://godotengine.org/download/archive/4.4-stable/

View File

@@ -0,0 +1,30 @@
# About
This tutorial will showcase the usage fo channel emulation server to provide realistic ray-traced channel to the softmodems
# Compiling
Reuse the previous step binaries
```
cmake ../../ -DOAI_VRTSIM_TAPS_CLIENT=ON
```
# Running
```
sudo ./nr-softmodem -O ../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --gNBs.[0].min_rxtxtime 6 --device.name vrtsim --vrtsim.role server --vrtsim.taps-socket ipc:///tmp/ru_socket_0
```
```
source .venv/bin/activate
python main.py example_config.yaml
```
```
sudo ./nr-uesoftmodem -C 3619200000 -r 106 --numerology 1 --ssb 516 --device.name vrtsim
```
```
./move_ue.sh
```

View File

@@ -219,7 +219,7 @@ void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue,
int SNRtimes10 = dB_fixed_x10(signal_pwr) - dB_fixed_x10(ue->measurements.n0_power_avg);
ue->measurements.ssb_sinr_dB[ssb_index] = SNRtimes10 / 10.0;
LOG_D(PHY,
LOG_I(PHY,
"[UE %d] ssb %d SS-RSRP: %d dBm/RE (%f dB/RE), SS-SINR: %f dB\n",
ue->Mod_id,
ssb_index,

View File

@@ -8,6 +8,7 @@ target_link_libraries(vrtsim PRIVATE SIMU shm_td_iq_channel actor noise_device l
add_boolean_option(OAI_VRTSIM_TAPS_CLIENT OFF "Enable taps client" ON)
if (OAI_VRTSIM_TAPS_CLIENT)
target_link_libraries(vrtsim PRIVATE taps_client)
target_compile_definitions(vrtsim PRIVATE ENABLE_TAPS_CLIENT=ON)
file(DOWNLOAD
"https://gitlab.eurecom.fr/oai/raytracing-channel-emulator/-/raw/59589ad2a534881810b2aa7dd81e63066245bb8d/server/api/taps.fbs?inline=false"
${CMAKE_SOURCE_DIR}/taps.fbs
@@ -26,6 +27,14 @@ if (OAI_VRTSIM_TAPS_CLIENT)
add_library(taps_client taps_client.cpp ${TAPS_API_HEADER})
target_include_directories(taps_client PUBLIC .)
find_package(Flatbuffers REQUIRED)
#find_package(Flatbuffers REQUIRED)
find_package(FlatBuffers QUIET)
if(NOT FlatBuffers_FOUND)
# Fall back to lowercase (Ubuntu 22.04)
find_package(Flatbuffers REQUIRED)
set(FLATBUFFERS_TARGET flatbuffers)
else()
set(FLATBUFFERS_TARGET flatbuffers::flatbuffers)
endif()
target_link_libraries(taps_client PUBLIC flatbuffers taps_api SIMU nanomsg)
endif()

View File

@@ -20,6 +20,7 @@
*/
#include "PHY/TOOLS/tools_defs.h"
#include "notified_fifo.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
@@ -54,7 +55,10 @@
typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role;
#define MAX_NUM_ANTENNAS_TX 4
#define MAX_CHANNEL_LENGTH (1 << 20)
#define MAX_CHANNEL_LENGTH 200
#define SAVED_SAMPLES_LEN (MAX_CHANNEL_LENGTH - 1)
#define BATCH_SIZE 4096
#define FIRST_BATCH_SIZE (BATCH_SIZE / 2)
#define ROLE_CLIENT_STRING "client"
#define ROLE_SERVER_STRING "server"
@@ -112,6 +116,7 @@ typedef struct {
uint64_t rx_samples_late;
uint64_t rx_early;
uint64_t rx_samples_total;
int num_tx_timing;
tx_timing_t *tx_timing;
peer_info_t peer_info;
int chanmod;
@@ -120,14 +125,12 @@ typedef struct {
int tx_num_channels;
int rx_num_channels;
channel_desc_t *channel_desc;
int num_chanmod_actors;
Actor_t *channel_modelling_actors;
char *taps_socket;
int client_num_rx_antennas;
} vrtsim_state_t;
// Sample history for channel impulse response
static c16_t saved_samples[MAX_NUM_ANTENNAS_TX][MAX_CHANNEL_LENGTH] __attribute__((aligned(32))) = {0};
static void histogram_add(histogram_t *histogram, double diff)
{
histogram->num_samples++;
@@ -312,10 +315,11 @@ static int vrtsim_connect(openair0_device *device)
}
// Handle channel modelling after number of RX antennas are known
int num_tx_stats = 1;
vrtsim_state->num_tx_timing = 1;
if (vrtsim_state->chanmod || vrtsim_state->taps_socket) {
vrtsim_state->channel_modelling_actors = calloc_or_fail(vrtsim_state->peer_info.num_rx_antennas, sizeof(Actor_t));
for (int i = 0; i < vrtsim_state->peer_info.num_rx_antennas; i++) {
vrtsim_state->num_chanmod_actors = vrtsim_state->peer_info.num_rx_antennas * vrtsim_state->tx_num_channels;
vrtsim_state->channel_modelling_actors = calloc_or_fail(vrtsim_state->num_chanmod_actors, sizeof(Actor_t));
for (int i = 0; i < vrtsim_state->num_chanmod_actors; i++) {
init_actor(&vrtsim_state->channel_modelling_actors[i], "chanmod", -1);
}
if (vrtsim_state->taps_socket) {
@@ -327,10 +331,10 @@ static int vrtsim_connect(openair0_device *device)
} else {
load_channel_model(vrtsim_state);
}
num_tx_stats = vrtsim_state->peer_info.num_rx_antennas;
vrtsim_state->num_tx_timing = vrtsim_state->num_chanmod_actors;
}
vrtsim_state->tx_timing = calloc_or_fail(num_tx_stats, sizeof(tx_timing_t));
for (int i = 0; i < num_tx_stats; i++) {
vrtsim_state->tx_timing = calloc_or_fail(vrtsim_state->num_tx_timing, sizeof(tx_timing_t));
for (int i = 0; i < vrtsim_state->num_tx_timing; i++) {
vrtsim_state->tx_timing[i].tx_histogram.min_samples = 100;
// Set the histogram range to 3000uS. Anything above that is not interesting
vrtsim_state->tx_timing[i].tx_histogram.range = 3000.0;
@@ -371,25 +375,24 @@ typedef struct {
vrtsim_state_t *vrtsim_state;
openair0_timestamp timestamp;
c16_t *samples[MAX_NUM_ANTENNAS_TX];
c16_t *first_samples[MAX_NUM_ANTENNAS_TX];
int nsamps;
int nbAnt;
int flags;
int aarx;
int task_index;
int num_tasks;
int tx_timing_index;
c16_t samples_copy[1];
} channel_modelling_args_t;
static void perform_channel_modelling(void *arg)
{
channel_modelling_args_t *channel_modelling_args = arg;
vrtsim_state_t *vrtsim_state = channel_modelling_args->vrtsim_state;
int nsamps = channel_modelling_args->nsamps;
int aarx = channel_modelling_args->aarx;
int nb_tx_ant = channel_modelling_args->nbAnt;
c16_t **input_samples = (c16_t **)channel_modelling_args->samples;
int aligned_nsamps = ceil_mod(nsamps, (512 / 8) / sizeof(cf_t));
cf_t samples[aligned_nsamps] __attribute__((aligned(64)));
// Apply noise from global settings
get_noise_vector((float *)samples, nsamps * 2);
channel_modelling_args_t *args = arg;
vrtsim_state_t *vrtsim_state = args->vrtsim_state;
int nsamps = args->nsamps;
int aarx = args->aarx;
int nb_tx_ant = args->nbAnt;
channel_desc_t *channel_desc = vrtsim_state->channel_desc;
@@ -417,90 +420,149 @@ static void perform_channel_modelling(void *arg)
}
}
for (int aatx = 0; aatx < nb_tx_ant; aatx++) {
c16_t *previous_samples = saved_samples[aatx];
for (int i = 0; i < nsamps; i++) {
cf_t *impulse_response = channel_impulse_response_p[aatx];
for (int l = 0; l < channel_desc->channel_length; l++) {
int idx = i - l;
// TODO: Use AVX2 for this
c16_t tx_input = idx >= 0 ? input_samples[aatx][idx]
: previous_samples[(channel_modelling_args->timestamp + i + idx) % MAX_CHANNEL_LENGTH];
samples[i].r += tx_input.r * impulse_response[l].r - tx_input.i * impulse_response[l].i;
samples[i].i += tx_input.i * impulse_response[l].r + tx_input.r * impulse_response[l].i;
// Calculate number of batches to process per thread.
int num_batches_to_process = 0;
if (nsamps > args->task_index * FIRST_BATCH_SIZE) {
num_batches_to_process = 1;
int nsamps_after_first_batch = max(0, nsamps - args->num_tasks * FIRST_BATCH_SIZE);
int num_full_size_batches = nsamps_after_first_batch / (args->num_tasks * BATCH_SIZE);
int nsamps_left = nsamps_after_first_batch - (num_full_size_batches * BATCH_SIZE);
if (nsamps_left > args->task_index * BATCH_SIZE)
num_batches_to_process++;
num_batches_to_process += num_full_size_batches;
}
for (int batch_index = 0; batch_index < num_batches_to_process; batch_index++) {
int batch_start_offset;
int batch_size;
if (batch_index == 0) {
batch_start_offset = args->task_index * FIRST_BATCH_SIZE;
batch_size = FIRST_BATCH_SIZE;
} else {
batch_start_offset = args->num_tasks * (FIRST_BATCH_SIZE + (batch_index - 1) * BATCH_SIZE) + args->task_index * BATCH_SIZE;
batch_size = BATCH_SIZE;
}
int batch_nsamps = min(batch_size, nsamps - (batch_start_offset - args->timestamp));
int aligned_nsamps = ceil_mod(batch_nsamps, (512 / 8) / sizeof(cf_t));
cf_t samples[aligned_nsamps] __attribute__((aligned(64)));
get_noise_vector((float *)samples, batch_nsamps * 2);
c16_t **input_samples = batch_start_offset == 0 ? args->first_samples : (c16_t **)args->samples;
for (int aatx = 0; aatx < nb_tx_ant; aatx++) {
for (int i = 0; i < batch_nsamps; i++) {
cf_t *impulse_response = channel_impulse_response_p[aatx];
cf_t sample = {0, 0};
for (int l = 0; l < channel_desc->channel_length; l++) {
int idx = i - l;
// TODO: Use AVX2 for this
c16_t tx_input = input_samples[aatx][batch_start_offset + idx];
sample.r += tx_input.r * impulse_response[l].r - tx_input.i * impulse_response[l].i;
sample.i += tx_input.i * impulse_response[l].r + tx_input.r * impulse_response[l].i;
}
samples[i].r += sample.r;
samples[i].i += sample.i;
}
}
}
// Convert to c16_t
c16_t samples_out[aligned_nsamps] __attribute__((aligned(64)));
// Convert to c16_t
c16_t samples_out[aligned_nsamps] __attribute__((aligned(64)));
#if defined(__AVX512F__)
for (int i = 0; i < aligned_nsamps / 8; i++) {
simde__m512 *in = (simde__m512 *)&samples[i * 8];
simde__m256i *out = (simde__m256i *)&samples_out[i * 8];
*out = simde_mm512_cvtsepi32_epi16(simde_mm512_cvtps_epi32(*in));
}
for (int i = 0; i < aligned_nsamps / 8; i++) {
simde__m512 *in = (simde__m512 *)&samples[i * 8];
simde__m256i *out = (simde__m256i *)&samples_out[i * 8];
*out = simde_mm512_cvtsepi32_epi16(simde_mm512_cvtps_epi32(*in));
}
#elif defined(__AVX2__)
for (int i = 0; i < aligned_nsamps / 4; i++) {
simde__m256 *in = (simde__m256 *)&samples[i * 4];
simde__m128i *out = (simde__m128i *)&samples_out[i * 4];
*out = simde_mm256_cvtsepi32_epi16(simde_mm256_cvtps_epi32(*in));
}
for (int i = 0; i < aligned_nsamps / 4; i++) {
simde__m256 *in = (simde__m256 *)&samples[i * 4];
simde__m128i *out = (simde__m128i *)&samples_out[i * 4];
*out = simde_mm256_cvtsepi32_epi16(simde_mm256_cvtps_epi32(*in));
}
#else
for (int i = 0; i < nsamps; i++) {
samples_out[i].r = lroundf(samples[i].r);
samples_out[i].i = lroundf(samples[i].i);
}
for (int i = 0; i < nsamps; i++) {
samples_out[i].r = lroundf(samples[i].r);
samples_out[i].i = lroundf(samples[i].i);
}
#endif
vrtsim_write_internal(channel_modelling_args->vrtsim_state,
channel_modelling_args->timestamp,
samples_out,
channel_modelling_args->nsamps,
aarx,
channel_modelling_args->flags,
aarx);
vrtsim_write_internal(args->vrtsim_state,
args->timestamp + batch_start_offset,
samples_out,
batch_nsamps,
aarx,
args->flags,
args->tx_timing_index);
}
}
static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state,
openair0_timestamp timestamp,
void **samplesVoid,
c16_t **samplesVoid,
int nsamps,
int nbAnt,
int flags)
{
AssertFatal(nbAnt < MAX_NUM_ANTENNAS_TX, "Number of antennas %d exceeds maximum %d\n", nbAnt, MAX_NUM_ANTENNAS_TX);
AssertFatal(nbAnt <= MAX_NUM_ANTENNAS_TX, "Number of antennas %d exceeds maximum %d\n", nbAnt, MAX_NUM_ANTENNAS_TX);
static int actor = 0;
// Sample history for channel impulse response
static c16_t saved_samples[MAX_NUM_ANTENNAS_TX][SAVED_SAMPLES_LEN] __attribute__((aligned(32))) = {0};
static openair0_timestamp last_timestamp = 0;
for (int aarx = 0; aarx < vrtsim_state->peer_info.num_rx_antennas; aarx++) {
notifiedFIFO_elt_t *task = newNotifiedFIFO_elt(sizeof(channel_modelling_args_t), 0, NULL, perform_channel_modelling);
channel_modelling_args_t *args = (channel_modelling_args_t *)NotifiedFifoData(task);
args->vrtsim_state = vrtsim_state;
args->timestamp = timestamp;
args->nsamps = nsamps;
args->nbAnt = nbAnt;
args->flags = flags;
args->aarx = aarx;
for (int i = 0; i < nbAnt; i++) {
args->samples[i] = samplesVoid[i];
for (int task_index = 0; task_index < vrtsim_state->tx_num_channels; task_index++) {
// Allocate extra space at the end of the message to copy historical samples
size_t extra_size = sizeof(c16_t) * (BATCH_SIZE + SAVED_SAMPLES_LEN) * nbAnt;
notifiedFIFO_elt_t *task = newNotifiedFIFO_elt(sizeof(channel_modelling_args_t) + extra_size, 0, NULL, perform_channel_modelling);
channel_modelling_args_t *args = NotifiedFifoData(task);
if (task_index == 0) {
for (int aatx = 0; aatx < nbAnt; aatx++) {
c16_t *buffer = (c16_t *)(args + 1) + aatx * (FIRST_BATCH_SIZE + SAVED_SAMPLES_LEN);
size_t gap_samples = timestamp - last_timestamp;
if (gap_samples > 0) {
size_t gap_samples_needed = min(SAVED_SAMPLES_LEN, gap_samples);
memset(&buffer[SAVED_SAMPLES_LEN - gap_samples_needed], 0, sizeof(c16_t) * gap_samples_needed);
if (gap_samples < SAVED_SAMPLES_LEN) {
size_t samples_from_saved = SAVED_SAMPLES_LEN - gap_samples_needed;
memcpy(&buffer[0], &saved_samples[aatx][SAVED_SAMPLES_LEN - samples_from_saved], sizeof(c16_t) * samples_from_saved);
}
} else {
memcpy(buffer, saved_samples[aatx], sizeof(c16_t) * SAVED_SAMPLES_LEN);
}
memcpy(&buffer[SAVED_SAMPLES_LEN], &samplesVoid[aatx][0], sizeof(c16_t) * FIRST_BATCH_SIZE);
args->first_samples[aatx] = buffer + SAVED_SAMPLES_LEN;
}
}
for (int i = 0; i < nbAnt; i++) {
args->samples[i] = samplesVoid[i];
}
args->vrtsim_state = vrtsim_state;
args->timestamp = timestamp;
args->nsamps = nsamps;
args->nbAnt = nbAnt;
args->flags = flags;
args->aarx = aarx;
args->task_index = task_index;
args->num_tasks = vrtsim_state->tx_num_channels;
actor = (actor + 1) % vrtsim_state->num_chanmod_actors;
args->tx_timing_index = actor;
pushNotifiedFIFO(&vrtsim_state->channel_modelling_actors[actor].fifo, task);
}
pushNotifiedFIFO(&vrtsim_state->channel_modelling_actors[aarx].fifo, task);
}
int start_index = timestamp % MAX_CHANNEL_LENGTH;
int end_index = min(start_index + nsamps, MAX_CHANNEL_LENGTH);
int cp_nsamps = end_index - start_index;
for (int aatx = 0; aatx < nbAnt; aatx++) {
c16_t *samples = (c16_t *)samplesVoid[aatx];
memcpy(&saved_samples[aatx][start_index], &samples[0], sizeof(c16_t) * cp_nsamps);
}
if (end_index < start_index + nsamps) {
// wrap around condition, write at beginning of buffer
cp_nsamps = nsamps - cp_nsamps; // remaining samples
start_index = 0;
// Save samples for next round
if (nsamps < MAX_CHANNEL_LENGTH) {
for (int aatx = 0; aatx < nbAnt; aatx++) {
c16_t *samples = (c16_t *)samplesVoid[aatx];
memcpy(&saved_samples[aatx][start_index], &samples[0], sizeof(c16_t) * cp_nsamps);
memmove(&saved_samples[aatx][0], &saved_samples[aatx][nsamps], sizeof(c16_t) * (SAVED_SAMPLES_LEN - nsamps));
memcpy(&saved_samples[aatx][SAVED_SAMPLES_LEN - nsamps], &samplesVoid[aatx][0], sizeof(c16_t) * nsamps);
}
} else {
for (int aatx = 0; aatx < nbAnt; aatx++) {
memcpy(saved_samples[aatx], &samplesVoid[aatx][nsamps - SAVED_SAMPLES_LEN], sizeof(c16_t) * (SAVED_SAMPLES_LEN));
}
}
last_timestamp = timestamp + nsamps;
return nsamps;
}
@@ -515,7 +577,7 @@ static int vrtsim_write(openair0_device *device, openair0_timestamp timestamp, v
timestamp -= device->openair0_cfg->command_line_sample_advance;
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
bool channel_modelling = vrtsim_state->chanmod || vrtsim_state->taps_socket;
return channel_modelling ? vrtsim_write_with_chanmod(vrtsim_state, timestamp, samplesVoid, nsamps, nbAnt, flags)
return channel_modelling ? vrtsim_write_with_chanmod(vrtsim_state, timestamp, (c16_t **)samplesVoid, nsamps, nbAnt, flags)
: vrtsim_write_internal(vrtsim_state, timestamp, (c16_t *)samplesVoid[0], nsamps, 0, flags, 0);
}
@@ -569,18 +631,18 @@ static void vrtsim_end(openair0_device *device)
tx_timing_t *tx_timing = vrtsim_state->tx_timing;
if (vrtsim_state->chanmod || vrtsim_state->taps_socket) {
for (int i = 0; i < vrtsim_state->peer_info.num_rx_antennas; i++) {
for (int i = 0; i < vrtsim_state->num_chanmod_actors; i++) {
shutdown_actor(&vrtsim_state->channel_modelling_actors[i]);
}
free(vrtsim_state->channel_modelling_actors);
for (int i = 1; i < vrtsim_state->peer_info.num_rx_antennas; i++) {
for (int i = 1; i < vrtsim_state->num_tx_timing; i++) {
histogram_merge(&tx_timing->tx_histogram, &tx_timing[i].tx_histogram);
tx_timing->tx_early += tx_timing[i].tx_early;
tx_timing->tx_samples_late += tx_timing[i].tx_samples_late;
tx_timing->average_tx_budget += tx_timing[i].average_tx_budget;
tx_timing->tx_samples_total += tx_timing[i].tx_samples_total;
}
tx_timing->average_tx_budget /= vrtsim_state->peer_info.num_rx_antennas;
tx_timing->average_tx_budget /= vrtsim_state->num_tx_timing;
free_noise_device();
if (vrtsim_state->taps_socket) {
taps_client_stop();

View File

@@ -248,3 +248,21 @@ e2_agent = {
#sm_dir = "/path/where/the/SMs/are/located/"
sm_dir = "/usr/local/lib/flexric/"
};
channelmod = {
max_chan=10;
modellist="modellist_rfsimu_1";
modellist_rfsimu_1 = (
{
model_name = "server_tx_channel_model"
type = "AWGN";
ploss_dB = 0;
noise_power_dB = 0;
forgetfact = 0;
offset = 0;
ds_tdl = 0;
}
);
};