Copyright (c) 2026 Anubhab Banerjee (AnubhabBanerjee/kernel-critic) All rights reserved. No part of this repository may be used, redistributed, or modified in any form or by any means without the prior written permission of the author.
GPU-accelerated ray-traced RF simulation with Sionna RT—place cooperative gNodeBs in a Munich scene, solve planar radio maps, export KPIs and coverage PNGs, optionally tune antenna azimuth with finite-difference + Adam, and ship a Word baseline-vs-optimized comparison for reviews and demos.
This repo is a compact network digital twin slice: it pairs NVIDIA’s Sionna ray-tracing stack with a practical experiment driver and reporting path—useful for storytelling around O-RAN / AI-RAN, coverage optimization, and simulation-first R&D workflows.
The pipeline is a linear experiment graph with an optional optimization loop—no separate services; everything runs from one Python entry point:
- Scene — Load the bundled Munich scene and attach two gNodeBs with positions, power, and aim from
config.ini. - Radio map (baseline) — Build a shared
PlanarArray, configureRadioMapSolveron a planar grid, and produce a baselinePlanarRadioMap(GPU-backed Sionna RT solve). - KPIs & figures — Derive SINR / throughput / outage-style metrics to CSV (and optional JSON), and render coverage PNGs for quick visual diffing.
- Optimization (optional) — Either a legacy stub sweep or an NN-style path: Adam on azimuth (α) offsets using central finite-difference gradients on a scalar loss (e.g. −P10 SINR), then re-export KPIs and maps.
- Report — Merge
data/baseline/anddata/optimized/KPI CSVs into a DOCX comparison suitable for write-ups and stakeholder decks.
- Sionna RT — Ray-traced propagation and
RadioMapSolveron the Munich scene (see Sionna / NVIDIA ecosystem alignment). - Mitsuba 3 + Dr.Jit — Physically based rendering stack pulled in by Sionna’s RT path.
- PyTorch — Tensor plumbing for the optional optimization loop (CUDA wheels recommended for parity with the reference
requirements.txtpins).
The experiment is configuration-driven: tune grids, seeds, and KPI toggles without touching Python for many baseline-only studies.
- Python 3.12+ (matches the pinned reference environment).
- NVIDIA GPU recommended for interactive runs with CUDA PyTorch and responsive Sionna RT solves (CPU is possible but slower; adjust
torchinstall—see below). - Enough disk for scene assets,
data/KPI bundles, andimages/PNGs (generated paths are gitignored by default).
From the repository root (so import src.* resolves):
python3.12 -m venv ai_ran_env
source ai_ran_env/bin/activate # Windows: ai_ran_env\Scripts\activate
pip install --upgrade pip
pip install -r requirements.txtCPU-only PyTorch (skip CUDA index):
pip install torch==2.5.1 --index-url https://download.pytorch.org/whl/cpu
pip install -r requirements.txt --no-deps
pip install drjit lxml matplotlib mitsuba numpy python-docx sionna pytest(Adjust so torch is not overwritten by the CUDA extra index if you need CPU wheels.)
After installing dependencies, smoke-check PyTorch, CUDA, and Sionna RT (including loading the bundled Munich scene):
python verify_setup.pyverify_setup() (in verify_setup.py) prints PyTorch version, whether CUDA is available and the active GPU name when present, then tries sionna.rt.load_scene on scene.munich so you catch missing mitsuba / wrong Python / broken installs before run_experiment.py.
| Section | Role |
|---|---|
[nodeb_0], [nodeb_1] |
gNodeB positions (m) and power_dbm. |
[look_at] |
Shared aim point when sites are created. |
[planar_array] |
PlanarArray — num_rows, num_cols, spacing, pattern, polarization. |
[radio_map_baseline] |
RadioMapSolver grid: center_*, orientation_*, size_*, cell_size_*, max_depth, samples_per_tx, seed. |
[kpi] |
save_* toggles, sinr_outage_threshold_db, bandwidth_mhz. |
[optimization] |
Stub loop: num_iterations, fixed α deltas (0 = skip). |
[nn_optimization] |
use_nn_optimizer, num_epochs, learning_rate, finite_diff_epsilon_rad, optional torch_seed. |
Defaults keep runs baseline-only (num_iterations = 0, use_nn_optimizer = false). Turn on use_nn_optimizer and set num_epochs for the NN-style loop.
End-to-end experiment:
python run_experiment.pyAfter data/baseline/ and data/optimized/ contain KPI CSVs, generate the Word report:
python -c "from src.report_generator import generate_kpi_comparison_docx; print(generate_kpi_comparison_docx())"Smoke tests:
pytest$ source ai_ran_env/bin/activate
$ python run_experiment.py
# Baseline radio map → data/baseline/baseline_kpis.csv, images/initial_radio_map.png
# If optimization enabled → data/optimized/optimized_kpis.csv, images/optimized_radio_map.png
| Artifact | Path |
|---|---|
| Baseline KPI CSV | data/baseline/baseline_kpis.csv |
| Optimized KPI CSV | data/optimized/optimized_kpis.csv |
| Baseline coverage PNG | images/initial_radio_map.png |
| Optimized coverage PNG | images/optimized_radio_map.png |
| KPI comparison DOCX | data/kpi_comparison_report.docx |
sionna-ndt/
├── verify_setup.py # PyTorch/CUDA + Sionna RT Munich load smoke test
├── run_experiment.py # Entry: baseline map → KPIs → PNGs → optional optimization
├── config.ini # Scene, arrays, radio map, KPI, optimization toggles
├── requirements.txt # Pinned deps (CUDA PyTorch via extra index)
├── pyproject.toml
├── data/ # Generated KPI bundles & reports (mostly gitignored)
│ ├── baseline/
│ └── optimized/
├── images/ # Coverage PNGs (gitignored)
└── src/
├── scene_builder.py # Munich + gNodeBs from INI
├── radiomap_builder.py # PlanarRadioMap + RadioMapSolver
├── kpi_creator.py # KPI CSV/JSON from PlanarRadioMap
├── image_creator.py # PNG export
├── radio_optimization.py # Stub sweep or NN optimizer dispatch
├── nn_optimizer.py # Finite-difference Adam on α offsets
└── report_generator.py # Baseline vs optimized DOCX
Active and planned hardening—this prototype is intentionally honest about where the stack can grow next:
- Full autodiff through Sionna RT — Today’s loop uses finite-difference gradients on a scalar KPI, not end-to-end AD through
RadioMapSolver/ Mitsuba; exploring evaluated derivatives and tighter coupling where the stack allows. - Train elevation & polarization DoF —
β/γ(and related orientation axes) locked in the current NN path; extend the optimizer to joint antenna pose search beyond α-only offsets. - Association-aware KPIs — Move from max-over-transmitter aggregate maps toward scheduler / association-style metrics where project goals require 3GPP-closer semantics.
- CI & regression — Expand pytest coverage beyond CSV/DOCX smoke tests; optional headless baseline runs in CI with tight timeouts.
Built with Sionna (Sionna RT), Mitsuba 3, Dr.Jit, and the broader NVIDIA GPU computing ecosystem. Scene and solver behavior follow upstream library semantics—see project docs for license and attribution details.