Documentation Map
Hardware Setup
See backend and frontend hardware requirements, node connections, and interface requirements.
Jump to Hardware SetupSoftware Installation
See supported environments, dependency installation, build steps, and performance tuning notes.
Jump to Software InstallationTypical Usage Example
See typical BS, UE, frontend visualization, and web-console execution examples.
Jump to Typical Usage ExampleParameter Reference
Read the OFDM modulator and demodulator parameter tables together with their YAML meanings.
Jump to Parameter ReferenceHardware Setup
Backend (C++)
To set up the complete system, you will need the following hardware:
- USRP Devices: 2 units (e.g., USRP X310, B210, etc.)
- Computers: 2 units (High performance recommended for signal processing)
- Antennas: 3
- OCXO/GPSDO: 2 units (Required for both USRPs)
Connection Setup
The system consists of two main nodes:
-
BS Node
- Hardware: 1x Computer, 1x USRP.
- Antennas: Connect 2 antennas to this USRP (1 for TX, 1 for RX).
- Clock: Connect an OCXO or GPSDO to the REFIN port of the USRP.
- Function: Transmits the OFDM signal and receives the radar echo.
-
UE Node
- Hardware: 1x Computer, 1x USRP.
- Antennas: Connect 1 antenna to the RX port of this USRP.
- Clock: Connect an OCXO or GPSDO to the REFIN port of the USRP.
- High-precision DAC (Optional): Use a high-precision DAC to enable finetuning the OCXO.
- Function: Receives the OFDM signal for communication and bistatic sensing.
Interface Requirements
To support high bandwidth and sample rates, ensure the connection between the Computers and USRPs uses:
- >= 10 Gigabit Ethernet (10GbE) (For X-series)
- USB 3.0 (For B-series)
Frontend (Python)
- Computer: 1x Computer (Windows or Linux).
- Can be one of the backend computers or a separate machine.
- CPU: High performance CPU (i7 10700 or better) if no GPU is available.
- GPU: An Nvidia GPU is recommended for acceleration.
Software Installation
Backend (C++)
Operating System
- Ubuntu 24.04 LTS
- Download: http://www.ubuntu.com/download/desktop
- macOS (Apple Silicon, local development / demo only)
- Guide: Separate macOS build guide
Dependencies & Installation
1. UHD (USRP Hardware Driver)
Install the UHD toolchain by following the official Ettus guide (Please follow the tutorial for Ubuntu 24.04):
Note: This code has been tested on UHD v4.9.0.1. You can checkout this version using
git checkout v4.9.0.1.
2. Install Aff3ct
This project uses the Aff3ct library for Forward Error Correction (FEC). Install it from source:
sudo apt-get install nlohmann-json3-dev
git clone https://github.com/aff3ct/aff3ct.git
cd aff3ct
git submodule update --init --recursive
mkdir build
cd build
cmake .. -G"Unix Makefiles" -DCMAKE_CXX_COMPILER="g++" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_CXX_FLAGS="-funroll-loops -march=native" -DAFF3CT_COMPILE_EXE="OFF" -DAFF3CT_COMPILE_SHARED_LIB="ON" -DSPU_STACKTRACE="OFF" -DSPU_STACKTRACE_SEGFAULT="OFF" -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -faligned-new"
make -j$(nproc)
sudo make install
3. Clone Repository
Clone the OpenISAC repository:
cd ~
git clone https://github.com/zhouzhiwen2000/OpenISAC.git
4. Build OpenISAC
Build the project using CMake:
sudo apt-get install libyaml-cpp-dev
cd OpenISAC
mkdir build
cd build
cmake ..
make -j$(nproc)
5. System Performance Tuning
Run the provided script to optimize your system settings for real-time processing:
cd ~/OpenISAC
chmod +x scripts/set_performance.bash
./scripts/set_performance.bash
Note:
secure_bootneeds to be turned off in your BIOS settings to enableRT_RUNTIME_SHAREfunctionality.
When UHD spawns a new thread, it may try to boost the thread's scheduling priority. If setting the new priority fails, the UHD software prints a warning to the console, as shown below.
[WARNING] [UHD] Failed to set desired affinity for thread
To address this issue, non-privileged (non-root) users need to be given special permission to change the scheduling priority. This can be enabled by creating a group usrp, adding your user to it, and then appending the line @usrp - rtprio 99 to the file /etc/security/limits.conf.
sudo groupadd usrp
sudo usermod -aG usrp $USER
Then add the line below to end of the file /etc/security/limits.conf:
@usrp - rtprio 99
You must log out and log back into the account for the settings to take effect. In most Linux distributions, a list of groups and group members can be found in the /etc/group file.
6. CPU Isolation and Execution
To ensure stable real-time performance, use scripts/isolate_cpus.bash to constrain system services (system.slice, user.slice, init.scope) to selected CPUs and reserve other CPUs for your workload.
All commands require root privileges (sudo):
cd ~/OpenISAC
chmod +x scripts/isolate_cpus.bash
sudo ./scripts/isolate_cpus.bash --help
Default isolation policy
sudo ./scripts/isolate_cpus.bash
- Default reserved cores for application: first 8 cores (
0-7). - System services are restricted to the remaining cores.
- If total CPU cores are
<= 8, isolation cannot be applied effectively and both app/system use all cores.
Custom application CPU set
sudo ./scripts/isolate_cpus.bash 4 # App uses 0-3
sudo ./scripts/isolate_cpus.bash 8-15 # App uses 8-15
sudo ./scripts/isolate_cpus.bash 0,2,4,6 # App uses explicit core list
The selected app CPU set is saved to /tmp/isolate_cpus_app.conf.
CPU binding priority when cores are limited
- Reserve one dedicated core for the main thread first.
- Then prioritize the TX/RX real-time threads.
- Finally allocate cores to modulation/demodulation and sensing/signal-processing threads, because these compute-heavy stages typically have larger buffers and can absorb moderate scheduling jitter.
In the web CPU-binding editor, this usually means prioritizing main thread affinity first, then _tx_proc / rx_proc and per-channel RX loops, and only after that the modulation/demodulation and sensing-processing workers.
Run application on reserved cores
cd build
sudo ../scripts/isolate_cpus.bash run ./OFDMModulator
runreads saved app CPUs from/tmp/isolate_cpus_app.conf.- If no saved config exists,
runfalls back to the default app CPU set.
Note: Always use
sudo ../scripts/isolate_cpus.bash run ...to launch applications after isolation is set. Direct execution or manualtasksetmay fail due to slice affinity constraints.
Reset configuration (optional)
sudo ./scripts/isolate_cpus.bash reset
This removes the isolation settings and restores system slices to all CPUs.
7. Configuration
The system uses YAML files for runtime configuration.
- Config filenames:
OFDMModulatorreadsModulator.yaml, andOFDMDemodulatorreadsDemodulator.yamlfrom the working directory. - First run:
Template YAML files live in
config/. Copyconfig/Modulator_X310.yaml/config/Modulator_B210.yamlorconfig/Demodulator_X310.yaml/config/Demodulator_B210.yamltoModulator.yaml/Demodulator.yaml, then edit them in place.
Frontend (Python)
It is recommended to use a conda or venv environment with Python 3.13.
Miniconda Installation Guide:
- Windows: Miniconda Installation for Windows
- Linux: Miniconda Installation for Linux
Create a new conda environment:
conda create -n OpenISAC python=3.13
conda activate OpenISAC
Install Dependencies
pip install -r requirements.txt
Note: ffmpeg is required for video streaming demonstrations.
- Ubuntu:
sudo apt install ffmpeg - Windows: Download from ffmpeg.org and add to PATH, or place executable in the working directory.
Enable GPU Acceleration (Optional)
If an Nvidia GPU is available, install cupy-cuda12x to enable GPU acceleration:
Note: Please ensure that the CUDA Toolkit is installed before installing CuPy.
pip install cupy-cuda12x
Enable Intel Integrated GPU Acceleration (Optional)
If your device has an Intel integrated GPU (e.g., Intel UHD Graphics, Intel Iris Xe, etc.), you can enable GPU acceleration via dpctl and dpnp. This is especially useful for laptops and desktops without a dedicated Nvidia GPU.
1. Install Intel GPU Official Driver
First, ensure your system has the latest Intel GPU driver installed:
- Windows: Download and install the latest driver from Intel Download Center: https://www.intel.com/content/www/us/en/download-center/home.html
- Ubuntu: Install Intel compute-runtime:
sudo apt install intel-opencl-icd libze-intel-gpu1 libze1 intel-media-va-driver-non-free
2. Install Python Dependencies
pip install dpctl dpnp
3. Verify Installation
Run the following command to check if the Intel GPU is correctly recognized:
python -c "import dpctl; print(dpctl.get_devices())"
If the installation is successful, you should see output similar to:
[<dpctl.SyclDevice [backend_type.level_zero, device_type.gpu, Intel(R) UHD Graphics] at 0x...>]
4. Usage Notes
The OpenISAC frontend automatically detects available GPU backends. The priority order is:
- Nvidia GPU (CUDA)
- Intel iGPU (dpnp)
- CPU (fallback)
No code modifications are required; the system will automatically select the best available backend.
Typical Usage Example
1. Startup of the BS
sudo -s
cd build
# For X310:
cp ../config/Modulator_X310.yaml Modulator.yaml
sudo ../scripts/isolate_cpus.bash
sudo ../scripts/isolate_cpus.bash run ./OFDMModulator
# For B210:
cp ../config/Modulator_B210.yaml Modulator.yaml
sudo ../scripts/isolate_cpus.bash
sudo ../scripts/isolate_cpus.bash run ./OFDMModulator
If you are using a separate frontend computer, set default_ip in Modulator.yaml to that frontend IP.
2. Startup of the UE
sudo -s
cd build
# For X310:
cp ../config/Demodulator_X310.yaml Demodulator.yaml
sudo ../scripts/isolate_cpus.bash
sudo ../scripts/isolate_cpus.bash run ./OFDMDemodulator
# For B210:
cp ../config/Demodulator_B210.yaml Demodulator.yaml
sudo ../scripts/isolate_cpus.bash
sudo ../scripts/isolate_cpus.bash run ./OFDMDemodulator
If you are using a separate frontend computer, set default_ip in Demodulator.yaml to that frontend IP.
3. Stream video to the BS
ffmpeg -re -stream_loop -1 -fflags +genpts -i video.mp4 -an -c:v libx264 -x264-params keyint=5:min-keyint=1 -b:v 3000k -minrate 3000k -maxrate 3000k -bufsize 1M -f rtp -sdp_file video.sdp "rtp://<your IP of the BS>:50000"
If you are streaming locally, your IP of the BS can be set to 127.0.0.1.
If you want to stream audio together with the video, use RTP MPEG-TS instead:
ffmpeg -re -stream_loop -1 -fflags +genpts -i video.mp4 -c:v libx264 -x264-params keyint=5:min-keyint=1 -b:v 30000k -minrate 30000k -maxrate 30000k -bufsize 1M -c:a aac -b:a 128k -ar 48000 -ac 2 -f rtp_mpegts "rtp://<your IP of the BS>:50000"
4. Play video from the UE
Copy video.sdp to the video receiver, modify m=video 50000 RTP/AVP 96 to m=video 50001 RTP/AVP 96.
ffplay -protocol_whitelist file,rtp,udp -i video1.sdp
Note that this command should be run on the frontend.
For the RTP MPEG-TS stream with audio, you can play it directly without an SDP file:
ffplay rtp://0.0.0.0:50001
5. Run monostatic frontend
python3 ./scripts/plot_sensing_fast.py
This maintained viewer auto-selects CUDA, MLX, Intel GPU, or CPU backends.
6. Run bistatic frontend
python3 ./scripts/plot_bi_sensing_fast.py
This maintained viewer auto-selects CUDA, MLX, Intel GPU, or CPU backends.
7. Web Config Console
For remote-friendly configuration editing and process control, run:
python3 scripts/config_web_editor.py --host 0.0.0.0 --port 8765
Then open http://<your-host>:8765 in a browser.
What it does:
- Provides separate Modulator / Demodulator tabs, plus a
Resource Plannertab fordata_resource_blocksand aSensing Resource Maptab forsensing_mask_blocks. - Edits
build/Modulator.yamlandbuild/Demodulator.yamlas parameter/value forms instead of a raw YAML text area. - Provides a dedicated CPU-binding editor for
cpu_cores, with thread names, generated comments, and per-thread CPU selection. - Saves the current form back to YAML and starts/stops modulator and demodulator processes from the
build/directory. - Includes launch options such as enabling/disabling CPU isolation and overriding the isolate CPU list.
- Includes CPU/CUDA command presets and a custom command field for each tab.
- Lets you draw payload / sensing-pilot rectangles for
data_resource_blocks, or compact sensing rectangles forsensing_mask_blocks, snap the block boundaries to integer RE grid points, and apply the result independently to the transmitter or receiver YAML. - Includes a
Guard Band Gridpreset that followsscripts/plot_const.py, i.e. it keeps only subcarriers1..489and535..N-1before the normal sync/pilot stripping rules are applied.
Notes:
- Default commands are
./OFDMModulatorand./OFDMDemodulator; switch to the CUDA preset if needed. - The editor currently targets the runtime YAML files in
build/, because the binaries readModulator.yaml/Demodulator.yamlfrom their working directory. Resource Plannereditsdata_resource_blocks: it decides which RE carry payload and which RE are reserved assensing_pilot.Sensing Resource Mapeditssensing_mask_blocks: it decides which RE are exported on the compact sensing path whensensing_output_mode=compact_mask.- Both planners can be applied to either side. During experiments TX and RX may differ temporarily, but normal operation still expects matching
data_resource_blockson both sides. - If CPU cores are limited, reserve a dedicated core for
main thread affinityfirst, then prioritize TX/RX threads, and finally modulation/demodulation plus sensing/signal-processing threads; these compute-heavy stages typically have larger buffers and tolerate transient jitter better. - If
Enable runtime CPU isolationis on, the console uses the currentcpu_coreslist to derive the default isolated CPU set and callsscripts/isolate_cpus.bashbefore launch. - If
Override CPU isolation listis enabled, the runtime isolation text box is seeded from the default isolate list and you may edit it manually for this launch. - If
Enable runtime CPU isolationis off, the console still launches the selected command through the privileged runtime path, but it does not callscripts/isolate_cpus.bash. - The runtime panel also provides an optional sudo-password field and a
Reset CPU isolationaction. - Because the console can launch arbitrary commands entered in the web UI, bind it only to trusted networks or keep the default
127.0.0.1.
Parameter Reference
OFDM Modulator
OFDMModulator is configured through Modulator.yaml.
Use config/Modulator_X310.yaml or config/Modulator_B210.yaml as a starting template.
Modulator.yaml parameter reference:
| Key | Type/Unit | Typical Value | Description |
|---|---|---|---|
fft_size |
int |
1024 |
OFDM FFT size. |
cp_length |
int |
128 |
Cyclic prefix length (samples). |
sync_pos |
int |
1 |
Sync symbol index in one frame. |
sample_rate |
float / Hz |
50000000 |
Baseband sample rate. |
bandwidth |
float / Hz |
50000000 |
Analog bandwidth, usually same as sample_rate. |
center_freq |
float / Hz |
2400000000 |
RF center frequency. |
tx_gain |
float / dB |
30 |
TX gain. |
tx_channel |
int |
0 |
TX channel index. |
zc_root |
int |
29 |
Zadoff-Chu root index. |
num_symbols |
int |
100 |
Number of OFDM symbols per frame. |
sensing_output_mode |
string |
dense |
Sensing UDP output mode. dense keeps the legacy STRD-based full-buffer output. compact_mask switches sensing to per-frame compact RE extraction. |
cuda_mod_pipeline_slots |
int |
2 |
Number of CUDA modulation pipeline slots. Values below 1 are clamped to 1. |
pilot_positions |
int[] |
[571,...,451] |
Pilot subcarrier indices. |
data_resource_blocks |
object[] |
omitted | Optional communication resource map. It answers: "which RE are allowed to carry payload?" Omit the key to keep the legacy behavior, where every non-sync, non-pilot RE carries payload. Set [] to disable payload RE entirely. Each block is a rectangle with symbol_start, symbol_count, subcarrier_start, subcarrier_count, and optional kind. kind: payload means those RE carry real payload. kind: sensing_pilot means those RE transmit a deterministic sensing-pilot reference sequence instead, so they stay predictable for sensing and are excluded from payload mapping. This sensing-pilot sequence is generated from an alternate Zadoff-Chu root that is different from the frame sync root, which avoids confusing sensing-pilot symbols with the dedicated sync symbol. Any remaining non-sync, non-pilot RE outside payload blocks transmit pre-generated QPSK. |
sensing_mask_blocks |
object[] |
omitted | Optional compact sensing resource map. It answers: "which RE should be exported on the sensing output path?" It is used only when sensing_output_mode=compact_mask; in dense mode it is ignored. Each block is a rectangle in absolute frame-symbol index and raw FFT-bin index. Sync / pilot RE are allowed here, overlapping blocks are merged automatically, and the exported order is fixed as symbol-major then subcarrier-major. If every selected symbol uses the same subcarrier set and the selected symbols are evenly spaced on the frame ring, runtime MTI and local Delay-Doppler processing can also be enabled. |
device_args |
string |
"" |
Shared USRP args fallback for TX/RX. |
tx_device_args |
string |
"" |
TX-specific USRP args. |
rx_device_args |
string |
"" |
Default sensing RX USRP args. |
clock_source |
string |
internal/external/gpsdo |
Global clock source. |
time_source |
string |
"" |
Global time/PPS source; empty means follow clock_source. |
tx_clock_source |
string |
"" |
TX clock source override. |
tx_time_source |
string |
"" |
TX time source override. |
rx_clock_source |
string |
"" |
Default sensing RX clock source override. |
rx_time_source |
string |
"" |
Default sensing RX time source override. |
wire_format_tx |
string |
sc16 |
TX wire format, typically sc16 or sc8. |
wire_format_rx |
string |
sc16 |
RX wire format, typically sc16 or sc8. |
udp_input_ip |
string / IPv4 |
0.0.0.0 |
Bind IP for incoming payload UDP packets. |
udp_input_port |
int |
50000 |
Bind port for incoming payload UDP packets. |
mono_sensing_ip |
string / IPv4 |
127.0.0.1 |
Destination IP for monostatic sensing output. |
mono_sensing_port |
int |
8888 |
Destination port for monostatic sensing output. |
sensing_rx_channel_count |
int |
1 |
Number of sensing RX channels (0 disables sensing RX). |
sensing_rx_channels |
object[] |
[] |
Per-channel sensing RX settings (see table below). |
default_ip |
string / IPv4 |
127.0.0.1 |
Default destination IP for outputs that are not explicitly set. |
control_port |
int |
9999 |
UDP port for control commands (heartbeat/MTI/etc.). |
measurement_enable |
bool |
false |
Enable CPU internal measurement mode. When enabled, OFDMModulator generates deterministic PRBS payloads instead of listening on udp_input_*, and OFDMDemodulator switches decoded measurement payloads into BER/BLER/EVM accounting. CUDA binaries ignore this mode. |
measurement_mode |
string |
internal_prbs |
Measurement mode selector. Only internal_prbs is supported. Unsupported values disable measurement mode during config normalization. |
measurement_run_id |
string |
"" |
Run identifier written into measurement CSV summaries. |
measurement_output_dir |
string |
"" |
Output directory used by the CPU measurement summaries. |
measurement_payload_bytes |
int |
1024 |
Bytes per internally generated measurement payload. Values below the internal header size are clamped up. |
measurement_prbs_seed |
int |
0x5A |
Base seed used to derive deterministic PRBS payload contents. |
measurement_packets_per_point |
int |
1 |
Number of measurement payloads sent for each online MRST epoch. Values below 1 are clamped to 1. |
profiling_modules |
string |
"" |
Profiling module list, comma-separated. Common values include modulation, latency, data_ingest, and sensing_proc; all enables every module. Modulator end-to-end latency profiling is enabled only when both modulation and latency are included. |
cpu_cores |
int[] |
[0,1,2,3,4,5] |
Allowed CPU core list. Size this list for the TX thread, modulation thread, data-ingest thread, each enabled sensing channel's RX/sensing threads, and the main thread. If cores are limited, keep one dedicated core for the main thread first, then prioritize the TX and sensing RX threads, and only after that the modulation/data-ingest/sensing-processing threads because the latter stages have deeper buffers. |
Quick mental model:
data_resource_blocksdecides where communication data goes.sensing_mask_blocksdecides which RE are exported for compact sensing.- The first affects payload mapping; the second affects sensing output only.
If data_resource_blocks is enabled, copy the same rectangles and kind values into Demodulator.yaml. If a block overlaps sync_pos or pilot_positions, the built-in sync / pilot RE still take precedence. Priority is always sync symbol > pilot > sensing_pilot > payload/random QPSK.
When sensing_output_mode=compact_mask, sensing sends one compact UDP packet per OFDM frame and includes only the RE selected by sensing_mask_blocks. In this mode STRD is ignored, because the mask itself defines the sampling pattern. If the mask is "regular" (same subcarrier set on every selected symbol, and selected symbols evenly spaced around the frame), runtime MTI and local Delay-Doppler processing can also be enabled: SKIP=1 keeps the raw compact RE output, while SKIP=0 switches back to dense Delay-Doppler output computed from that regular selection. Config normalization also expands range_fft_size and doppler_fft_size when needed so they cover the selected subcarriers and symbols. The compact sensing UDP payload begins with CompactSensingFrameHeader { magic/version, mask_hash, re_count, frame_start_symbol_index }, followed by re_count raw complex<float> values in fixed order. Existing plot_sensing*.py viewers cannot handle non-"regular" compact payloads yet.
sensing_rx_channels object fields:
| Key | Type | Typical Value | Description |
|---|---|---|---|
usrp_channel |
int |
0 |
USRP RX channel index. |
device_args |
string |
"" |
Per-channel USRP args. |
clock_source |
string |
"" |
Per-channel clock source override. |
time_source |
string |
"" |
Per-channel time source override. |
wire_format_rx |
string |
"" |
Per-channel RX wire format override. |
rx_gain |
float |
30 |
RX gain for this channel. |
alignment |
int |
63 |
Per-channel alignment offset (samples). |
rx_antenna |
string |
"" |
RX antenna name, e.g. TX/RX, RX1. |
enable_system_delay_estimation |
bool |
false |
If true, this channel performs a ZC-based system delay estimation at startup and then once every 434 frames, while keeping the sensing pipeline disabled and continuing to drain frames. |
Notes:
- If
sensing_rx_channelsis empty andsensing_rx_channel_count > 0, default channels0..N-1are generated automatically. - If the count and list size differ, the list is resized to match
sensing_rx_channel_count. - When
enable_system_delay_estimation=truefor a channel, that channel performs one system delay estimation near startup and then repeats it once every 434 frames while continuing to drain frames. Normal sensing processing and sensing UDP output remain disabled. - In practice, keep hardware-specific fields such as
device_args,wire_format_*, per-channel RX antenna selection, and output IPs aligned with the actual radio/deployment you are using; the sample YAMLs are starting points, not universal presets.
OFDM Demodulator
OFDMDemodulator is configured through Demodulator.yaml.
Use config/Demodulator_X310.yaml or config/Demodulator_B210.yaml as a starting template.
Demodulator.yaml parameter reference:
| Key | Type/Unit | Typical Value | Description |
|---|---|---|---|
fft_size |
int |
1024 |
OFDM FFT size. |
cp_length |
int |
128 |
Cyclic prefix length (samples). |
sync_pos |
int |
1 |
Sync symbol index in one frame. |
sample_rate |
float / Hz |
50000000 |
Baseband sample rate. |
bandwidth |
float / Hz |
50000000 |
Analog bandwidth, usually same as sample_rate. |
center_freq |
float / Hz |
2400000000 |
RF center frequency. |
rx_gain |
float / dB |
50 |
RX gain. |
rx_agc_enable |
bool |
false |
Enable hardware RX AGC. Tracking AGC uses the filtered delay_spectrum main peak to adjust USRP RX gain, applies stale-frame timestamp gating like alignment/frequency updates, and forces gain reduction when the sync symbol approaches ADC full scale. |
rx_agc_low_threshold_db |
float / dB |
11.0 |
Lower bound of the tracking AGC window. Gain is increased only when the filtered delay_spectrum main peak falls below this threshold. |
rx_agc_high_threshold_db |
float / dB |
13.0 |
Upper bound of the tracking AGC window. Gain is decreased only when the filtered delay_spectrum main peak rises above this threshold. |
rx_agc_max_step_db |
float / dB |
3.0 |
Maximum RX gain step applied by one AGC update. Saturation-triggered protection also uses this step size when forcing gain down. |
rx_agc_update_frames |
int |
4 |
Minimum processed-frame interval between tracking-stage AGC updates. Values below 1 are clamped to 1. |
rx_channel |
int |
0 |
RX channel index. |
zc_root |
int |
29 |
Zadoff-Chu root index. |
num_symbols |
int |
100 |
Number of OFDM symbols per frame. |
sensing_symbol_num |
int |
100 |
Number of symbols used for sensing processing. |
sensing_output_mode |
string |
dense |
Bistatic sensing UDP output mode. dense keeps the legacy STRD-based full-buffer output. compact_mask switches sensing to per-frame compact RE extraction. |
cuda_demod_pipeline_slots |
int |
3 |
Number of CUDA demodulation pipeline slots. Values below 1 are clamped to 1. |
frame_queue_size |
int |
8 |
Capacity of the demodulator RX frame queue. Values below 1 are clamped to 1. |
sync_queue_size |
int |
8 |
Capacity of the demodulator sync-search batch queue. Values below 1 are clamped to 1. |
reset_hold_s |
float / s |
0.5 |
How long invalid delay conditions must persist before the demodulator forces a hard reset back to sync search. Internally this is converted to a frame count from samples_per_frame / sample_rate. Values below 0 are clamped to 0.5. |
range_fft_size |
int |
1024 |
Range FFT size. |
doppler_fft_size |
int |
100 |
Doppler FFT size. |
pilot_positions |
int[] |
[571,...,451] |
Pilot subcarrier indices. |
data_resource_blocks |
object[] |
omitted | Receiver-side communication resource map. It answers: "which RE should be interpreted as payload?" Omit the key to keep the legacy behavior, where every non-sync, non-pilot RE is treated as payload. Set [] to extract no payload LLR at all. Use the same rectangles and kind values as the transmitter. Blocks with kind: payload produce payload LLR; blocks with kind: sensing_pilot are treated as known reference RE instead and are excluded from payload extraction. The known sensing-pilot reference uses the same alternate Zadoff-Chu root as the transmitter, distinct from the frame sync root. |
sensing_mask_blocks |
object[] |
omitted | Receiver-side compact sensing resource map. It answers: "which RE should be exported on the bistatic sensing path in compact_mask mode?" The coordinate system and behavior are the same as on the modulator side: absolute frame-symbol index, raw FFT-bin index, sync / pilot RE allowed, overlapping blocks merged automatically, and exported order fixed as symbol-major then subcarrier-major. If the mask is regular, runtime MTI and local Delay-Doppler processing can also be enabled. |
device_args |
string |
"" |
USRP device args. |
clock_source |
string |
internal/external/gpsdo |
Clock source. |
wire_format_rx |
string |
sc16 |
RX wire format, typically sc16 or sc8. |
software_sync |
bool |
true |
Enable software synchronization tracking. |
predictive_delay |
bool |
true |
Enable CFO-based predictive delay compensation during initial alignment and tracking delay correction. Use this only when the sample clock and carrier frequency are derived from the same reference, and there is no secondary frequency conversion outside the USRP. |
hardware_sync |
bool |
false |
Enable hardware synchronization. |
hardware_sync_tty |
string |
/dev/ttyUSB0 |
TTY device used by hardware sync controller. |
ocxo_pi_switch_abs_error_ppm |
float |
0.0002 |
Switch to slow-stage OCXO PI when absolute error_ppm stays below this threshold. |
akf_enable |
bool |
true |
Enable adaptive Kalman filtering (AKF) on hardware-sync error_ppm. |
akf_bootstrap_frames |
int |
64 |
Cold-start frame count before AKF starts normal KF updates. |
akf_innovation_window |
int |
64 |
Innovation history window used for ACF/LS adaptation. |
akf_max_lag |
int |
4 |
Maximum innovation autocorrelation lag used in LS fitting. |
akf_adapt_interval |
int |
64 |
Frame interval for adaptive Q/R least-squares updates. |
akf_gate_sigma |
float |
3.0 |
Innovation gating threshold (sigma). |
akf_tikhonov_lambda |
float |
1e-3 |
Tikhonov regularization weight for LS adaptation. |
akf_update_smooth |
float |
0.2 |
Exponential smoothing factor for updated Q/R. |
akf_q_wf_min |
float |
1e-10 |
Lower bound of white-frequency-noise coefficient. |
akf_q_wf_max |
float |
1e2 |
Upper bound of white-frequency-noise coefficient. |
akf_q_rw_min |
float |
1e-12 |
Lower bound of random-walk-frequency-noise coefficient. |
akf_q_rw_max |
float |
1e1 |
Upper bound of random-walk-frequency-noise coefficient. |
akf_r_min |
float |
1e-8 |
Lower bound of observation-noise variance R. |
akf_r_max |
float |
1e3 |
Upper bound of observation-noise variance R. |
ppm_adjust_factor |
float |
0.05 |
Frequency offset compensation factor. |
desired_peak_pos |
int |
20 |
Target delay-peak position used by alignment logic. |
enable_bi_sensing |
bool |
true |
Enable the bistatic sensing pipeline and UDP output. When set to false, both OFDMDemodulator and CUDAOFDMDemodulator skip bistatic sensing channel startup. |
bi_sensing_ip |
string / IPv4 |
127.0.0.1 |
Destination IP for bistatic sensing output. |
bi_sensing_port |
int |
8889 |
Destination port for bistatic sensing output. |
channel_ip |
string / IPv4 |
127.0.0.1 |
Destination IP for channel-estimation output. |
channel_port |
int |
12348 |
Destination port for channel-estimation output. |
pdf_ip |
string / IPv4 |
127.0.0.1 |
Destination IP for PDP/PDF output. |
pdf_port |
int |
12349 |
Destination port for PDP/PDF output. |
constellation_ip |
string / IPv4 |
127.0.0.1 |
Destination IP for constellation output. |
constellation_port |
int |
12346 |
Destination port for constellation output. |
vofa_debug_ip |
string / IPv4 |
127.0.0.1 |
Destination IP for VOFA+ debug output. |
vofa_debug_port |
int |
12347 |
Destination port for VOFA+ debug output. |
udp_output_ip |
string / IPv4 |
127.0.0.1 |
Destination IP for decoded payload output. |
udp_output_port |
int |
50001 |
Destination port for decoded payload output. |
default_ip |
string / IPv4 |
127.0.0.1 |
Default destination IP used when output IP fields are empty. |
control_port |
int |
9999 |
UDP port for control commands. |
measurement_enable |
bool |
false |
Enable CPU internal measurement mode. In this mode, decoded measurement payloads are consumed locally for BER/BLER/EVM statistics instead of being forwarded to udp_output_*. CUDA binaries ignore this mode. |
measurement_mode |
string |
internal_prbs |
Measurement mode selector. Only internal_prbs is supported. Unsupported values disable measurement mode during config normalization. |
measurement_run_id |
string |
"" |
Run identifier written into measurement CSV summaries. |
measurement_output_dir |
string |
"" |
Output directory used by the CPU measurement summaries. |
measurement_payload_bytes |
int |
1024 |
Expected bytes per measurement payload. Values below the internal header size are clamped up. |
measurement_prbs_seed |
int |
0x5A |
Base seed used to rebuild deterministic PRBS measurement payloads. |
measurement_packets_per_point |
int |
1 |
Expected measurement payload count for each online MRST epoch. Values below 1 are clamped to 1. |
profiling_modules |
string |
"" |
Profiling module list, comma-separated. Common values include demodulation, agc, align, and snr; all enables every module. agc gates AGC logs, align gates runtime ALGN: logs, and snr prints periodic _snr_db / _noise_var / _llr_scale updates from the active demodulator path. |
cpu_cores |
int[] |
[0,1,2,3,4,5] |
Allowed CPU core list. If cores are limited, keep one dedicated core for the main thread first, then prioritize rx_proc, and only after that process_proc, sensing_process_proc, and bit_processing_proc, because those later stages have larger buffers and can better tolerate short scheduling jitter. |
Receiver-side note:
data_resource_blocksshould normally match the transmitter exactly, includingkind.- If a resource block overlaps
sync_posorpilot_positions, the built-in sync / pilot RE still win. Priority issync symbol > pilot > sensing_pilot > payload/random QPSK. - In
compact_maskmode, bistatic sensing also sends one compact UDP packet per OFDM frame and includes only the RE selected bysensing_mask_blocks;STRDis ignored in this mode because the mask already defines the sampling pattern. - The compact payload format is the same as on the modulator side:
CompactSensingFrameHeaderfollowed by fixed-order rawcomplex<float>samples.
Notes:
- RX AGC has two phases. During
SYNC_SEARCH, the receiver resets gain to the configuredrx_gainand performs a coarse search sweep (+1 dB every 10 frames, wrapping from max gain back to min gain). After lock, tracking AGC uses the filtereddelay_spectrumpeak window defined byrx_agc_low_threshold_dbandrx_agc_high_threshold_db. - Sync-symbol time-domain samples are also checked for near/full-scale ADC usage. If too many I/Q components approach full scale, the demodulator forces gain reduction and temporarily blocks gain increases to avoid ping-pong behavior.
- A hard reset clears timing/frequency tracking state, flushes pending queues, resets the tracking AGC state, and returns the receiver to
SYNC_SEARCH.reset_hold_scontrols how long bad delay conditions must persist before this happens.