Skip to content

Tags: DeepMIMO/DeepMIMO

Tags

v4.0.2

Toggle v4.0.2's commit message
DeepMIMO v4.0.2

v4.0.1

Toggle v4.0.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
add Sionna 2.0 support (#98)

* Drop Sionna 0.19/1.x support: bump deps to sionna-rt>=2.0.1

- pyproject.toml [sionna] + [all]: replace sionna-rt==1.0.2 with
  sionna-rt>=2.0.1, add explicit mitsuba==3.8.0 and drjit==1.3.1 pins,
  remove dead Python 3.10 bpy pin and legacy numpy<2.0 pin
- consts.py: RAYTRACER_VERSION_SIONNA 0.19.2 → 2.0.1, drop
  SUPPORTED_SIONNA_VERSIONS list (version gate removed in follow-up)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Remove is_sionna_v1() and all legacy 0.19/1.x branching from pipeline

sionna_utils.py:
- Delete is_sionna_v1(); keep get_sionna_version() for version recording
- set_materials(): always use "backscattering" string, drop BackscatteringPattern
- create_base_scene(): always pass merge_shapes=False to load_scene()

sionna_raytracer.py:
- Delete IS_LEGACY_VERSION, TF import block, TF_CPP_MIN_LOG_LEVEL env var
- Always import and use PathSolver (Sionna 2.0 API)
- Collapse all if IS_LEGACY_VERSION branches to the 1.x/2.0 code path
- Remove tf.Variable power_dbm wrapper; always pass velocity kwarg directly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Port exporter and converter to Sionna 2.0 single code path

sionna_exporter.py:
- Remove SUPPORTED_SIONNA_VERSIONS version gate
- Remove is_sionna_v1() import and all branches; always use 1.x/2.0 shapes
- export_paths(): always use 'interactions' key; a always as (real,imag) pair;
  targets/sources always transposed
- export_scene_rt_params(): single default-params block for 2.0 API;
  keep num_samples/reflection/scattering aliases for the converter reader
- export_scene_buildings(): always transpose vertex array (Sionna 1.x/2.0 shape)
- Fix import error message to reference [sionna] extra

sionna_paths.py:
- Delete _is_sionna_v1(), _get_sionna_interaction_types() (0.x-only)
- Remove duplicate SIONNA_TYPE_* constant block
- Drop sionna_version parameter from read_paths() and _process_paths_batch()
- _process_paths_batch(): collapse to 2.0 shapes (no batch dim); always use
  'interactions' key and _transform_interaction_types()

sionna_converter.py:
- Drop sionna_version arg from read_paths() call
- Fix broken __main__ block (missing txrx_dict arg)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Update docs and blender mitsuba pin for Sionna 2.0

docs/installation.md: replace [sionna1]/[sionna019] references with [sionna];
  drop Python 3.10 row; add Sionna RT 2.0 requirements section including
  native Linux GPU note

blender_utils.py: mitsuba==3.5.0 -> mitsuba==3.8.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Rewrite Sionna tests for 2.0: remove version mocks, update shapes

test_sionna_exporter.py:
- Remove all is_sionna_v1 patches; test assumes 2.0 API throughout
- mock_paths: a is (real,imag) tuple; uses 'interactions' not 'types'
- mock_scene: rx/tx array.positions() is a callable (2.0 API)
- Verify 'interactions' key present, 'types' absent, a is complex

test_sionna_paths.py:
- Replace 0.x-shaped mock data with 2.0 shapes (no batch dim)
- Add unit tests for _transform_interaction_types: LoS, reflections, mixed
- Remove sionna_version="0.19.1" argument from read_paths call
- Document correct single-antenna shapes (no antenna dims in vertices/interactions)

test_sionna_converter.py:
- Remove _get_sionna_interaction_types import (function deleted)
- Remove test_get_sionna_interaction_types and test_edge_cases (0.x only)
- Update mock version to "2.0.1"; split into two focused tests

All 302 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Port Sionna integration to 2.0 API: interaction remapping, mi_mesh, PathSolver

- sionna_paths: add _SIONNA_TO_DEEPMIMO remapping (SPECULAR=1→1, DIFFUSE=2→3,
  REFRACTION=4→4, DIFFRACTION=8→2); update _transform_interaction_types to
  remap before digit-concatenating; drop SIONNA_TYPE_LOS alias
- sionna_exporter: obj._mi_shape → obj.mi_mesh (now public in 2.0);
  normalise path_list to list before subscript check to fix single-Paths case
- sionna_raytracer: remove paths.normalize_delays=False (property removed in 2.0)
- sionna_utils: use BackscatteringPattern() object for existing-material
  scattering_pattern assignment (string assignment fails in 2.0); remove
  scene.synthetic_array=True (moved to PathSolver arg in 2.0)
- pyproject.toml: update sionna extra deps; add torch>=2.9.0 to sionna/all extras
- tests: add 2.0 remapping test; fix interaction/vertices shapes for single-ant case

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix ruff violations: remove unused import/noqa, add SLF001 suppressions in tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add Sionna 2.0 downstream and upstream application notebooks

Downstream (2_sionna_rt_downstream.py): Sionna RT 2.0 ray tracing on the
Munich scene → sionna_exporter → dm.convert → dm.load with channel
generation and per-UE path count / power table.

Upstream (3_sionna_upstream.py): Load DeepMIMO scenario → SionnaAdapter
→ OFDM channel matrix (einsum over paths) → spectral efficiency CDF and
SNR sweep plot.

Also fixes a SionnaAdapter bug where num_paths from the dataset could
exceed the channels array path dimension, causing a broadcast ValueError.
Added regression test for the fix. Both notebooks are added to mkdocs nav
and execute_ignore (require sionna / network access).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Sionna 2.0: comments, tests, and bug fixes from simplify review

- Add inline WHY comments throughout sionna_paths, sionna_exporter,
  sionna_utils, sionna_raytracer (named constants replace magic numbers)
- Rename _transform_interaction_types → public to eliminate SLF001 noqa
- Fix UnboundLocalError: initialise tx_ant_idx before inner loop in read_paths
- Fix test data: use distinct TX/RX positions to avoid false BS-BS detection
- Fix sys.modules contamination: test_sionna_exporter no longer overwrites
  real sionna when it is installed, preventing integration test fixture breakage
- Add test_sionna_exporter_integration.py: 24 Sionna 2.0 integration tests
  (skipped automatically when sionna-rt is not installed)
- Fix RUF001/RUF003 ambiguous × character in upstream notebook comment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add 5G NR PUSCH BLER notebook (DeepMIMO -> Sionna upstream)

Replaces the earlier spectral-efficiency notebook with a full link-level
BLER simulation using Sionna's PHY stack:
- CIRDataset wraps a DeepMIMO generator; UL channel built via DL reciprocity
- PUSCHTransmitter/Receiver provide 5G NR LDPC + OFDM + LS/LMMSE chain
- sim_ber sweeps Eb/N0 and stops after 100 block errors per point
- Side-by-side BLER/BER plots compare DeepMIMO vs Rayleigh fading baseline
- sionna-no-rt>=2.0.1 added to pyproject.toml [sionna] and [all] extras
  (Python >=3.12 marker avoids conflict with the InSite numpy<2 pin)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add no-Blender OSM pipeline and notebook

deepmimo/pipelines/osm_to_mitsuba.py: new module that downloads
building footprints from OpenStreetMap via the Overpass API, extrudes
them into 3D PLY meshes, and writes a Mitsuba 2.1 scene.xml directly —
no Blender or blosm addon required.

docs/applications/4_osm_pipeline.py: end-to-end notebook covering
GPS bbox -> OSM -> Mitsuba scene -> Sionna RT -> sionna_exporter ->
dm.convert -> dm.load -> power map visualisation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Apply ruff format to all Sionna-related files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix integration test skip when sionna.rt is mocked in sys.modules

pytest.importorskip finds the MagicMock injected by test_sionna_exporter.py
and does not skip the module in CI (no sionna-rt installed). Replace with
an explicit __file__ type check: real modules always have a str __file__,
MagicMocks produce None or a Mock object.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Pin project to Python 3.14

All dependencies (sionna-rt, sionna-no-rt, torch, mitsuba, drjit) install
cleanly on 3.14 and the full test suite (344 tests) passes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Update versioning, AODT support, and remove Blender from Sionna extra

consts.py:
- Add AODT to SUPPORTED_RAYTRACERS (converter already exists in deepmimo/converters/aodt/)
- Add SUPPORTED_SIONNA_VERSIONS = ["2.0.x", "2.1.x"] matching InSite pattern
- Set SUPPORTED_AODT_VERSIONS = ["1.x"]

pyproject.toml:
- [sionna] extra: remove bpy, lxml, ipykernel — Blender no longer needed
  for the Sionna pipeline thanks to osm_to_mitsuba.py
- [sionna] extra: add <3.0.0 upper bound to sionna-rt and sionna-no-rt
- [all] extra: consolidate Blender deps under InSite section with TODO note
- ruff target-version: py311 -> py314 (matches .python-version)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Remove .python-version from tracking, add to .gitignore

Local Python version pin is a developer environment preference,
not a project constraint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add python-via-uv skill to project .claude/skills/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Remove .python-version from .gitignore

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix all ruff lint errors across codebase

- UP037: remove unnecessary string quotes from type annotations (now on 3.14)
- UP045: use X | None instead of Optional[X]
- TC001/TC002/TC003: move type-only imports into TYPE_CHECKING blocks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add from __future__ import annotations to fix Python 3.11 CI failures

The ruff UP037/TC0xx fixes in f2b7cff removed string quotes from
annotations and moved imports under TYPE_CHECKING. Python 3.14 evaluates
annotations lazily (PEP 649) so this works there, but Python 3.11 evaluates
them eagerly causing NameError on self-referential and TYPE_CHECKING-guarded
names like DotDict. Adding from __future__ import annotations makes
annotations lazy on 3.11 too.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add notebook pre-rendering for docs (execute: false)

- Convert all .py tutorials and Sionna applications to .ipynb stubs
  using jupytext; commit alongside .py sources as code-only starting points
- Add docs/applications/4_osm_pipeline.ipynb to mkdocs.yml nav
- Switch mkdocs-jupyter from execute:true to execute:false — docs build
  now uses stored .ipynb outputs instead of re-executing at build time
- Add scripts/pre_render_notebooks.py: convert + execute notebooks
  grouped by --tutorials / --sionna flags; run before committing doc changes
- Update docs/resources/workflow.md with full pre-render workflow
- Add jupytext>=1.16 to [dev] deps; exclude docs/**/*.ipynb from ruff

To generate full outputs: uv run python scripts/pre_render_notebooks.py --sionna

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Remove .ipynb files from tracking; gitignore docs/**/*.ipynb

Pre-rendered notebooks are local-only build artifacts — run
scripts/pre_render_notebooks.py to generate them before mkdocs build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix docs build: pin pygments<2.20 and update .py links to .ipynb

pygments 2.20 broke mkdocstrings: pymdownx passes filename=None for
untitled block code, which html.escape() can't handle. Pin pygments<2.20
until pymdownx or pygments ships a fix.

Also update internal links in index/capability pages from .py to .ipynb
now that tutorials and apps are served as pre-rendered notebooks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add conditional docs build to pre-commit; configure coverage exclusions

- pre-commit: run mkdocs build --strict only when docs/ or mkdocs.yml
  is among staged files (~13s overhead only on doc commits)
- coverage: exclude deepmimo/pipelines/* (require Sionna/Blender/InSite)
  and TYPE_CHECKING/NotImplementedError blocks; real coverage is 75%
  not the misleading 59% that included uncoverable pipeline code

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Expand test coverage from 76% to 83% across six core modules

Adds ~270 new tests targeting the lowest-coverage modules: stats.py
(59%→99%), load.py (78%→99%), channel.py (82%→99%), visualization.py
(73%→93%), scene.py (64%→85%), and dataset.py (61%→71%). Also fixes a
jupytext cell-marker bug in tutorial 8 that dropped the `import deepmimo`
line, and corrects the mkdocs nav/link for the channel prediction notebook.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Push dataset.py coverage from 71% to 85%

Adds 59 new tests covering previously untested branches: orientation
properties (tx_ori, rx_ori, bs_ori, ue_ori), compute_channels with
num_timestamps, ue_look_at early-return and per-user position paths,
rotated-angle random-range sampling, path hash/id computation, grid index
resolution, DynamicDataset speed propagation, MacroDataset shared-param
and single-access-method dispatch, and merge_datasets padding branches.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Eliminate in-function imports and reach 100% channel.py coverage

- Fix circular import (dataset.py → summary.py) by moving plot_summary
  import inside Dataset.plot_summary method; allows stats.py and
  summary.py to import load/dataset at module level instead of inside
  functions — reduces PLC0415 noqa tags from ~35 to 3
- Update test patch targets from deepmimo.datasets.load.load →
  deepmimo.datasets.stats.load to match new module-level binding
- Move all in-function test imports to file top level across five test
  files (test_dataset.py, test_summary.py, test_generate.py,
  test_channel.py, test_sionna_paths.py)
- Add two coverage tests for channel.py: zero-path user skipped (576)
  and missing OFDM keys early return (233) → channel.py now at 100%

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add data generation pipeline docs and update workflow guide

- New page: docs/resources/data_generation.md — 3-phase ray tracing
  pipeline (scene generation → channel emulation → downstream sim)
  with code examples, parameter tables, and tracer comparison
- Rewrote docs/resources/workflow.md with prerequisites per notebook
  group, precise timing tables, and clearer two-step workflow
- Wired data_generation.md into mkdocs.yml nav under Resources

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Replace ASCII pipeline diagram with SVG; fix British English

- Add docs/assets/images/data_generation_pipeline.svg: three-phase
  color-coded pipeline diagram (blue / green / amber phases with
  labeled step boxes and connecting arrows)
- Replace ASCII art block in data_generation.md with SVG reference
- Remove "Supported Ray Tracers" table section
- Fix British spellings: centre→center, normalises→normalizes (×2)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix Sionna RT scene decomposition and notebook rendering

- sionna_scene.py: replace Python union-find with scipy connected_components
  to correctly split merged city meshes (e.g. Munich no-name-4) into
  individual building components; O(F) searchsorted replaces O(N_obj x F) filter
- sionna_paths.py: store tx_pos as (1,3) so dataset.plot_rays works correctly
- sionna_exporter.py: save face connectivity (sionna_faces.pkl) for mesh splitting
- 2_sionna_rt_downstream.py: complete rewrite for Sionna 2.0 API (scene.render
  returns Figure, paths.a shape is (rx,tx,rx_ant,tx_ant,max_paths)), with
  timing, coverage scatter, delay profiles, and DeepMIMO ray visualization
- Update tests for 3-tuple export_scene_buildings and FileNotFoundError mock

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix ground plane, trim notebook to 4 UEs with valid paths

- sionna_scene.py: add 'ground' to terrain keywords so Munich's ground
  mesh is classified as terrain instead of inheriting building rainbow colors
- scene.py: skip terrain in 3D plot to avoid matplotlib depth-sort artifacts
  (large flat ground polygons render on top regardless of z_order)
- 2_sionna_rt_downstream.py: reduce to 4 RX positions that have confirmed
  paths; set display_radius=8m on receivers for legible Sionna renders;
  remove coverage scatter and standalone scene plot; show all 4 UE ray
  visualizations in a single subplot figure

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add OSM pipeline visualizations and write pipeline API docs

Notebook (4_osm_pipeline.py):
- Switch BBOX from Midtown Manhattan (Overpass timeout) to Munich city
  centre, which reliably returns ~265 buildings
- Add 2D building footprint map rendered from PLY bottom-ring vertices
  (no extra API call; note about Google satellite view via fetch_satellite_view)
- Add Sionna RT scene renders (top-down + perspective) after TX/RX placement
- Set display_radius=5m on receivers for legible renders
- Add DeepMIMO reconstructed scene plot (dataset.scene.plot) after conversion
- Simplify coverage map to use dataset.power directly instead of compute_channels
- Import Camera from sionna.rt

docs/api/pipelines.md:
- Replace 'Coming Soon' placeholder with full pipeline documentation:
  explanation of what pipelines are, OSM-to-Mitsuba workflow diagram,
  height-tag priority table, coordinate system overview, satellite imagery
  usage, and mkdocstrings API refs for all public functions

txrx_placement.py: fix malformed docstring that was failing mkdocs strict build

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Enable diffuse reflection, shrink device radii, add PDP grids

- RT_PARAMS: diffuse_reflection True — adds surface scattering paths,
  enriching delay profiles without significant cost at 4 UEs
- Transmitter display_radius 5m, Receiver display_radius 4m (was 8m)
- PDP subplots: add ax.grid(visible=True, alpha=0.3) for readability

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Consolidate 4 redundant pipeline runner scripts into one

Deleted pipeline_runner_{static,dynamic,osm_static,osm_dynamic}.py — all
four followed the same scene→raytrace→convert pattern with minimal
variation; osm_static had a debug `break`, osm_dynamic was abandoned
(InSite + pickle, no conversion step).

New pipeline_runner.py reads a CSV, skips already-converted scenarios,
and calls generate_scene → gen_tx_pos/gen_rx_grid → raytrace_sionna →
dm.convert — the same chain demonstrated in the OSM notebook.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix Sionna camera orientation and remove redundant scene.plot()

Camera offset slightly south (-5 m in y) so Sionna's Z-up rendering
convention produces East-right/North-up images that match the 2D OSM
footprint plot. Oblique camera moved to south-facing position for the
same reason.

Removed the explicit dataset.scene.plot() cell — the scene is already
rendered automatically during dm.convert().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add edge diffraction and per-step timing to Sionna RT notebook

Enabled diffraction=True (UTD) and raised max_depth to 3 so building-corner
diffraction paths appear in both the PDP and ray visualization.

Added time.perf_counter() instrumentation around each pipeline stage
(scene load, ray trace, export, convert, dataset load) and a summary
table printed at the end showing seconds per step and total wall time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix Overpass API 406 errors; add notebook rendering guide to contributing docs

osm_to_mitsuba: add User-Agent + Accept headers and 3-attempt exponential
backoff (5s, 10s, 20s) to query_osm_buildings. The Overpass API rejects
requests without a User-Agent with 406 Not Acceptable.

contributing.md: add 'Pre-rendering Notebooks' section documenting the
pre_render_notebooks.py workflow, usage examples, and an approximate
runtime table for each notebook group (tutorials + Sionna apps).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Try all Overpass API mirrors on query failure

Replaced single-URL retry loop with mirror rotation: overpass-api.de →
overpass.kumi.systems → overpass.openstreetmap.ru. Any non-200 response
or connection error moves to the next mirror instead of backing off on
the same server. Also raised timeout to 90 s and added maxsize hint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Cache OSM scene to disk; use persistent work dir in notebook

generate_scene: skip Overpass query and mesh generation if scene.xml +
osm_gps_origin.txt already exist in the output folder. This makes
repeated renders (or CI re-runs) free after the first successful download.

4_osm_pipeline.py: replace tempfile.mkdtemp() with a persistent
~/.cache/deepmimo/osm_pipeline_munich directory so the generated scene
survives between runs and the cache check can trigger.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add OSM main API fallback when all Overpass mirrors are unavailable

When overpass-api.de, kumi.systems, and openstreetmap.ru all return
errors, query_osm_buildings now falls back to api.openstreetmap.org/0.6/map
and parses the XML response via a new _parse_osm_xml helper. The existing
Overpass JSON path is extracted into _parse_overpass_json.

The OSM main API has a separate backend from the Overpass infrastructure,
so it stays available during Overpass outages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Pre-render OSM pipeline notebook with full outputs

Generated via: python scripts/pre_render_notebooks.py docs/applications/4_osm_pipeline.py

OSM data fetched via OSM main API fallback (Overpass was unavailable during
generation); scene cached at ~/.cache/deepmimo/osm_pipeline_munich so future
re-renders skip the network download entirely.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Document git add -f requirement for pre-rendered ipynb files

.ipynb files are gitignored to prevent accidental large commits; add a note
and example showing the force-add step needed after pre_render_notebooks.py.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix scrollbar multiplots, revert OSM oblique camera, update contributing setup

- 2_sionna_rt_downstream.py: switch PDP and ray-viz plots from 1×N to 2×2
  grid (≤10" wide) so docs page never gets a horizontal scrollbar
- 4_osm_pipeline.py: revert oblique camera to [-300,-300,300] (pre-alignment)
- contributing.md: replace mamba+pip setup with gh repo fork --clone + uv sync
- Pre-render 2_sionna_rt_downstream.ipynb with updated layouts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add channel prediction notebook to pre-render pipeline

- Remove 1_channel_prediction.py from SKIP (scenario data is available)
- Add APPS group (non-Sionna application notebooks) + --apps CLI flag
- Include 1_channel_prediction in default render run and timing table
- Update contributing.md skipped-notebooks note (manual.py only now)
- Pre-render 1_channel_prediction.ipynb (4.4 MB)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Re-render OSM pipeline notebook with reverted oblique camera

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add Dynamic Ray Tracing notebook (application #5)

- New docs/applications/5_dynamic_rt.py: drone TX moving through
  simple_street_canyon_with_cars across 4 snapshots, each exported
  and converted to DeepMIMO, then assembled as DynamicDataset
- Prominent upfront warning pointing to Tutorial 5 for the common case
- Summary table: dynamic RT vs static+Doppler vs batch pipeline
- Wire into mkdocs.yml nav and .py exclude list, applications/index.md,
  pre_render_notebooks.py SIONNA_APPS, contributing.md timing table
- Pre-rendered 5_dynamic_rt.ipynb (1.9 MB)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Polish notebooks, docs, and SVG for Sionna branch

- 2_sionna_rt_downstream: add note about multi-material building display artifact
- 4_osm_pipeline, 5_dynamic_rt: American English (centre→center, visualise→visualize, kerbs→curbs)
- 5_dynamic_rt: fix camera angle, remove noqa from markdown table, fix broken batch_pipeline link, hoist MIN_POWER_DBW constant
- data_generation_pipeline.svg: transparent background for dark-mode compatibility
- contributing.md: replace stale Testing section with actual pytest instructions
- pipeline_params.py: remove deprecated sionna019 extra and sionna_version config references

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add building deduplication to Sionna scene converter

Sionna's default merge_shapes=True fuses all shapes with the same
material into one mesh, so a building with N materials produces N
overlapping convex hulls in the DeepMIMO scene view.

Fix: three-phase read_scene in sionna_scene.py —
  1. Split material meshes into connected components (unchanged)
  2. Cluster overlapping building components via AABB containment
     (new _cluster_by_aabb with union-find, deduplicate=True default)
  3. Emit one DeepMIMO object per cluster with merged vertices

deduplicate=True is the default; pass deduplicate=False or tune
overlap_threshold to disable/adjust the heuristic for any scene.
18 new tests cover _cluster_by_aabb and read_scene end-to-end.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Re-render sionna_rt_downstream notebook with deduplication note

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Bump version to 4.0.1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

v4.0.0

Toggle v4.0.0's commit message
DeepMIMO v4.0.0 - Stable Release

DeepMIMO v4.0.0 is the first stable release of the new-generation DeepMIMO toolbox for AI-native wireless research.

Highlights:
- aligned NumPy-based dataset format for faster slicing, filtering, batching, and analysis
- flatter and cleaner structure than v3, with easier top-level access to metadata and dataset fields
- explicit 3-step workflow: load, modify/sample/filter, then compute channels
- migration support for legacy v3 row/column behavior with dm.load(..., compat_v3=True)
- dm.stats() for scenario and dataset statistics
- explicit MacroDataset merge support for combining receiver-grid datasets
- expanded tutorials, migration guidance, and documentation polish for the stable 4.0 release

Merged since v4.0.0-beta:
- #88 Release DeepMIMO 4.0
- #87 Add compat_v3 load mode for v3 migration indexing
- #86 Add explicit MacroDataset merge support
- #85 Docs polish, quieter notebook execution
- #80 Improve docs readability and notebook execution
- #75 Add dm.stats()
- #72 Update capabilities comparison between V3 and V4
- #69 Add raytracer comparison docs draft
- #68 Add dynamic example
- #67 Add multipath lifetime maps and channel prediction notebook
- #66 Add feature tables and fix warnings
- #61 Add comprehensive testing, code quality improvements, and refactoring
- #59 Migrate documentation to MkDocs
- #51 Unify trim()/get_idxs() and improve FoV integration
- #49 Add subcarrier index validation
- #42 Update TX/RX set indexing for web export
- #41 Flatten nested download unzip folders
- #38 Add dataset binary exporter
- #37 Add RT source download option
- #22 Proper Doppler and start of path interpolation

Contributors since beta include João Morais, Jeong Seungmin, Soham Daga, Namhyun Kim, Sadjad Alikhani, Liu Zongxi, StrasserFlorian, ZhangZc_HUST, guavamin, and dependabot.

v4.0.0-beta

Toggle v4.0.0-beta's commit message
add numpy version constraint (pinned by scipy)

v3.2.9

Toggle v3.2.9's commit message
DeepMIMOv3

v2.0

Toggle v2.0's commit message
DeepMIMOv2

v4.0.0-alpha.3

Toggle v4.0.0-alpha.3's commit message
both docs themes working

v4.0.0-alpha.2

Toggle v4.0.0-alpha.2's commit message
bump version to 4.0.0a1

v4.0.0-alpha.1

Toggle v4.0.0-alpha.1's commit message
inherit and propagate new Channel Params DotDict

v4.0.0-alpha

Toggle v4.0.0-alpha's commit message
fix bug on channel generation path const