handoverlab 2.1.0__tar.gz → 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {handoverlab-2.1.0 → handoverlab-2.2.0}/CHANGELOG.md +33 -1
- {handoverlab-2.1.0 → handoverlab-2.2.0}/CITATION.cff +2 -2
- {handoverlab-2.1.0 → handoverlab-2.2.0}/PKG-INFO +2 -2
- {handoverlab-2.1.0 → handoverlab-2.2.0}/README.md +1 -1
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/calibration.md +18 -0
- handoverlab-2.2.0/docs/guides/fading.md +78 -0
- handoverlab-2.2.0/docs/guides/scheduler.md +65 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/cli.md +2 -2
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/highway-tr37885-30ghz.md +7 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/highway-tr37885-4ghz.md +7 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/standard-compliance.md +14 -1
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/user_guide.md +7 -2
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/verification.md +1 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/mkdocs.yml +2 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/pyproject.toml +1 -1
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/__init__.py +1 -1
- handoverlab-2.2.0/src/handoverlab/channel/fading.py +157 -0
- handoverlab-2.2.0/src/handoverlab/channel/l2s.py +51 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/channel/source.py +26 -3
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/config.py +36 -2
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/engine/batch.py +3 -1
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/engine/core.py +39 -10
- handoverlab-2.2.0/src/handoverlab/engine/scheduler.py +210 -0
- handoverlab-2.2.0/src/handoverlab/linklevel.py +145 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/scenarios/__init__.py +7 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/seeds.py +3 -1
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/__init__.py +6 -2
- handoverlab-2.2.0/src/handoverlab/verify/fading.py +61 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab.egg-info/PKG-INFO +2 -2
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab.egg-info/SOURCES.txt +9 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/data/public_api.json +7 -0
- handoverlab-2.2.0/tests/test_fading.py +127 -0
- handoverlab-2.2.0/tests/test_scheduler.py +136 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_verify.py +1 -1
- {handoverlab-2.1.0 → handoverlab-2.2.0}/.zenodo.json +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/CODE_OF_CONDUCT.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/CONTRIBUTING.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/LICENSE +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/MANIFEST.in +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/SECURITY.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/RELEASING.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/calibration-3gpp.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/guides/add-scenario.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/guides/beams-layers.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/guides/daps-ltm.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/guides/dashboard.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/guides/export-event-logs.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/guides/highway.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/guides/indoor-rural.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/guides/learning-rule.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/guides/many-cores.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/guides/mro.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/guides/ntn.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/guides/radio-maps.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/guides/reproduce.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/guides/upper-mid-band.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/images/calibration_38901.png +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/images/dashboard-charts.png +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/images/dashboard-compare.png +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/images/dashboard-where.png +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/images/dashboard.png +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/images/ntn-beams.png +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/images/radio-map.png +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/images/report-comparison.png +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/images/report-tuning.png +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/images/ssb-beams.png +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/index.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/migration-2.0.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/performance.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/api/config.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/api/engine.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/api/eventlog.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/api/gui.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/api/index.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/api/mapfile.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/api/ntn.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/api/rules.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/api/scenarios.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/api/simulate.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/api/stability.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/api/stats.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/api/studies.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/api/testing.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/api/verify.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference/metrics.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/reference-study.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/dense-urban-2layer.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/dense-urban-2layer.svg +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/fr3-urban-15ghz.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/fr3-urban-15ghz.svg +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/highway-tr37885-30ghz.svg +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/highway-tr37885-4ghz.svg +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/indoor-office-4ghz.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/indoor-office-4ghz.svg +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/ns3-urban-3.5ghz.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/ns3-urban-3.5ghz.svg +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/ntn-leo600-2ghz.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/ntn-leo600-2ghz.svg +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/open-area-10ghz.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/open-area-10ghz.svg +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/rural-700mhz.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/rural-700mhz.svg +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/smoke.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/smoke.svg +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/urban-grid-10ghz.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/urban-grid-10ghz.svg +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/urban-grid-28ghz-beams.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/scenarios/urban-grid-28ghz-beams.svg +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/stability.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/time-step.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/tutorials/first-run.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/tutorials/own-rule.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/tutorials/reading-the-report.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/docs/tutorials/tuning-study.md +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/examples/compare_a3_cho.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/examples/open_area.toml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/examples/radio_map.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/examples/smoke.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/examples/speed_rule.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/examples/street_grid.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/examples/study_reference.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/examples/study_reference_explore.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/examples/study_smoke.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/examples/traffic_models.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/setup.cfg +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/__main__.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/channel/__init__.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/channel/antenna.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/channel/extended.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/channel/ntn.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/channel/pathloss.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/channel/radiomap.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/cli.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/engine/__init__.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/engine/_kernels.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/engine/extended.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/engine/invariants.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/engine/metrics.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/engine/procedures.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/eventlog.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/gui/__init__.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/gui/app.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/gui/logic.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/io.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/layout.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/mapfile.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/measurement.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/mobility.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/py.typed +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/requirements.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/rules/__init__.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/rules/base.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/rules/builtin.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/rules/dqn.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/rules/mro.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/scenarios/cards/dense-urban-2layer.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/scenarios/cards/fr3-urban-15ghz.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/scenarios/cards/highway-tr37885-30ghz.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/scenarios/cards/highway-tr37885-4ghz.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/scenarios/cards/indoor-office-4ghz.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/scenarios/cards/ns3-urban-3.5ghz.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/scenarios/cards/ntn-leo600-2ghz.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/scenarios/cards/open-area-10ghz.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/scenarios/cards/rural-700mhz.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/scenarios/cards/smoke.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/scenarios/cards/urban-grid-10ghz.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/scenarios/cards/urban-grid-28ghz-beams.yaml +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/simulate.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/stability.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/standard.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/stats.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/studies/__init__.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/studies/config.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/studies/report.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/studies/runner.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/studies/status.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/studies/store.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/studies/study.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/studies/tuning.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/testing.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/traffic.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/calibration.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/data/golden.json +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/data/golden_1x.json +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/data/ns3_urban_a3.json +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/data/r1_165974.csv +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/engine_checks.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/extended.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/golden.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/highway.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/learning.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/ns3.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/ntn.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/radio.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/report.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/stored.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/verify/values.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab/world.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab.egg-info/dependency_links.txt +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab.egg-info/entry_points.txt +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab.egg-info/requires.txt +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/src/handoverlab.egg-info/top_level.txt +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/conftest.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/data/bh6_reference.json +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/data/bh6_wide.json +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/data/make_bh6_reference.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/data/make_bh6_wide.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/helpers.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_batch.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_beams_layers.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_calibration.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_channel_detail.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_cltm.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_config_cli.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_contract.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_determinism.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_dqn.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_engine_triggers.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_eventlog.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_gui.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_highway.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_highway_tr37885.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_indoor_rural.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_invariants.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_levels_status_extend.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_lm_model.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_mapfile.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_measurement.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_mro.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_ntn.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_pathloss.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_protocol_3gpp.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_readme_boundaries.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_regression_bh6.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_regression_bh6_wide.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_rrc_detail.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_rules_rc2.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_scenarios.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_signalling_energy.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_stability.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_stats.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_study.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_tools.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_traffic.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_tuning.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tests/test_v111.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tools/compare_fingerprints.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tools/make_beam_figure.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tools/make_calibration_figure.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tools/make_ntn_figure.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tools/make_radiomap_figure.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tools/make_readme_images.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tools/mkdocs_hooks.py +0 -0
- {handoverlab-2.1.0 → handoverlab-2.2.0}/tools/release_check.py +0 -0
|
@@ -7,6 +7,37 @@ All notable changes to this project are documented in this file. The format foll
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.2.0] - 2026-10-22
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Fast fading as an option (`radio.fast_fading`: `tdl-a` .. `tdl-e`, off by default): the tapped delay line
|
|
15
|
+
models of TR 38.901 V19.5.0 clause 7.7.2 with the delay scaling of Eq. 7.7-1 (`radio.delay_spread_ns`, 100 ns
|
|
16
|
+
by default) and the K-factor change of clause 7.7.6 (`radio.fading_k_db`); each user-cell link fades on its own
|
|
17
|
+
with 32 sinusoids per Rayleigh tap (Jakes spectrum, f_D from the user's speed) and the LOS tap of TDL-D / -E at
|
|
18
|
+
0.7 f_D. Link-to-system mapping (`handoverlab.channel.l2s`): radio-link monitoring compares the MIESM effective
|
|
19
|
+
SINR of QPSK over the 24 PRBs of the hypothetical PDCCH (TS 38.133 Tables 8.1.2.1-1/-2) with Qout / Qin, and
|
|
20
|
+
the rate uses the capacity-equivalent SINR over the carrier. Base engine only in this version. With the option
|
|
21
|
+
off every result is unchanged. Guide: `docs/guides/fading.md`; `verify` group `fading` (criteria fixed before
|
|
22
|
+
the model was written; 32 sinusoids instead of 16 after the Rayleigh test failed with 16).
|
|
23
|
+
- Slot scheduler as an option (`protocol.scheduler`: `rr` or `pf`, off by default): every slot of the interval is
|
|
24
|
+
played (slot length of TS 38.211 Table 4.3.2-1), the free PRBs of a cell go to its users with data, the MCS is
|
|
25
|
+
the highest of TS 38.214 Table 5.1.3.1-1 with a block-error probability of at most 10 % at the reported SINR,
|
|
26
|
+
the TBS follows TS 38.214 clause 5.1.3.2, and HARQ runs with 8 processes per user, chase combining and at most
|
|
27
|
+
`protocol.harq_max_tx` transmissions after `protocol.harq_rtt_slots`. The block-error probability is the normal
|
|
28
|
+
approximation of the finite-blocklength error probability on the BICM bit channel of the modulation
|
|
29
|
+
(`handoverlab.linklevel`), with an implementation loss `protocol.l2s_loss_db`. Base engine only; about 45
|
|
30
|
+
times slower than the rate model. Guide: `docs/guides/scheduler.md`.
|
|
31
|
+
- `benchmarks/ns3/run_benchmark.py --fading`: the ns-3 runs with ns-3's TR 38.901 fast fading.
|
|
32
|
+
|
|
33
|
+
### Documentation
|
|
34
|
+
|
|
35
|
+
- Fast fading against ns-3 runs with fading (96 runs, criterion fixed before the runs): `tdl-c` passes
|
|
36
|
+
(handover ratio 1.04, unnecessary-handover ratio 1.24, ranks 0.97 / 0.98); `docs/guides/fading.md`.
|
|
37
|
+
- Held-out check of the failure-model parts on 40 new ns-3 runs, limits fixed before the runs: execution time
|
|
38
|
+
passes; the load effect on link monitoring and the time without connection after a failure fail; execution
|
|
39
|
+
failures are not measurable (none in ns-3). Reported as is in `docs/calibration.md`.
|
|
40
|
+
|
|
10
41
|
## [2.1.0] - 2026-10-21
|
|
11
42
|
|
|
12
43
|
A clause-by-clause audit of the protocol engine against TS 38.331 V18.11.0, TS 38.133, TS 38.300 V18.11.0 and
|
|
@@ -903,7 +934,8 @@ First alpha release (stage 1: the core simulator).
|
|
|
903
934
|
- Documentation: README, user guide, contribution guide, citation file; CI on Linux, Windows and
|
|
904
935
|
macOS with Python 3.9-3.12.
|
|
905
936
|
|
|
906
|
-
[Unreleased]: https://github.com/mjs19971997/handoverlab/compare/v2.
|
|
937
|
+
[Unreleased]: https://github.com/mjs19971997/handoverlab/compare/v2.2.0...HEAD
|
|
938
|
+
[2.2.0]: https://github.com/mjs19971997/handoverlab/compare/v2.1.0...v2.2.0
|
|
907
939
|
[2.1.0]: https://github.com/mjs19971997/handoverlab/compare/v2.0.0...v2.1.0
|
|
908
940
|
[2.0.0]: https://github.com/mjs19971997/handoverlab/compare/v1.12.0...v2.0.0
|
|
909
941
|
[1.12.0]: https://github.com/mjs19971997/handoverlab/compare/v1.11.0...v1.12.0
|
|
@@ -11,7 +11,7 @@ abstract: >-
|
|
|
11
11
|
measurement chain, a radio-link failure model, an outcome label for every handover attempt,
|
|
12
12
|
a plug-in interface for handover rules, equal-budget tuning studies with paired statistics,
|
|
13
13
|
and verification against hand-computed values, golden event-log fingerprints and ns-3 / 5G-LENA.
|
|
14
|
-
version: "2.
|
|
14
|
+
version: "2.2.0"
|
|
15
15
|
doi: 10.5281/zenodo.23409131
|
|
16
16
|
identifiers:
|
|
17
17
|
- type: doi
|
|
@@ -23,7 +23,7 @@ identifiers:
|
|
|
23
23
|
- type: doi
|
|
24
24
|
value: 10.5281/zenodo.23409402
|
|
25
25
|
description: "Version 1.0.1 on Zenodo"
|
|
26
|
-
date-released: 2026-10-
|
|
26
|
+
date-released: 2026-10-22
|
|
27
27
|
license: MIT
|
|
28
28
|
repository-code: "https://github.com/mjs19971997/handoverlab"
|
|
29
29
|
url: "https://mjs19971997.github.io/handoverlab/"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: handoverlab
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: System-level handover simulator for 5G-Advanced and beyond-5G research
|
|
5
5
|
Author: Mostafa Jalili Sanjarani, Yasser Elmi Sola
|
|
6
6
|
License-Expression: MIT
|
|
@@ -190,7 +190,7 @@ the clause-by-clause detail is in [standard compliance](https://github.com/mjs19
|
|
|
190
190
|
| Part | Modelled | Abstracted | Not modelled |
|
|
191
191
|
|---|---|---|---|
|
|
192
192
|
| Layouts | `street_grid` (TR 37.885 urban grid), `open_area`, `highway` (TR 37.885 / TR 36.885, wrap-around), `indoor` (TR 38.901 office), `ntn` (one LEO satellite, TR 38.821); explicit site lists | sites on the pavement with small cells (urban cards) | the 500 m macro grid of the TR 37.885 urban scenario, several satellites |
|
|
193
|
-
| Channel | TR 38.901 path loss and LOS (UMi, UMa, RMa, InH), LOS from buildings, spatially consistent LOS and shadowing, penetration loss, radio maps from a file (clause 8), TR 38.811 for the satellite | received power per site and step
|
|
193
|
+
| Channel | TR 38.901 path loss and LOS (UMi, UMa, RMa, InH), LOS from buildings, spatially consistent LOS and shadowing, penetration loss, radio maps from a file (clause 8), TR 38.811 for the satellite | received power per site and step with a slow time-varying component; optional TDL fast fading with effective SINRs (clause 7.7.2, since 2.2.0) | CDL and the full fast-fading model of clause 7.5, MIMO |
|
|
194
194
|
| Beams and carriers | SSB beams per sector, cell quality from beams, beam failure detection and recovery, several carriers with gaps and Event A5 | the TR 38.901 antenna element and DFT beams; isotropic UE | UE-side beamforming, dual connectivity and PSCell change |
|
|
195
195
|
| Mobility | street-following vehicles (60 km/h, two lanes), highway lanes at 70/140 km/h, random waypoints, pedestrians | constant speed per user | handheld rotation and body blockage |
|
|
196
196
|
| Traffic and load | constant rates per 5QI, full buffer, periodic, FTP model 3; cell load drives interference | rate from SINR (Shannon-type mapping), no scheduler | slot scheduler, HARQ, RLC/PDCP, TCP and applications |
|
|
@@ -132,7 +132,7 @@ the clause-by-clause detail is in [standard compliance](https://github.com/mjs19
|
|
|
132
132
|
| Part | Modelled | Abstracted | Not modelled |
|
|
133
133
|
|---|---|---|---|
|
|
134
134
|
| Layouts | `street_grid` (TR 37.885 urban grid), `open_area`, `highway` (TR 37.885 / TR 36.885, wrap-around), `indoor` (TR 38.901 office), `ntn` (one LEO satellite, TR 38.821); explicit site lists | sites on the pavement with small cells (urban cards) | the 500 m macro grid of the TR 37.885 urban scenario, several satellites |
|
|
135
|
-
| Channel | TR 38.901 path loss and LOS (UMi, UMa, RMa, InH), LOS from buildings, spatially consistent LOS and shadowing, penetration loss, radio maps from a file (clause 8), TR 38.811 for the satellite | received power per site and step
|
|
135
|
+
| Channel | TR 38.901 path loss and LOS (UMi, UMa, RMa, InH), LOS from buildings, spatially consistent LOS and shadowing, penetration loss, radio maps from a file (clause 8), TR 38.811 for the satellite | received power per site and step with a slow time-varying component; optional TDL fast fading with effective SINRs (clause 7.7.2, since 2.2.0) | CDL and the full fast-fading model of clause 7.5, MIMO |
|
|
136
136
|
| Beams and carriers | SSB beams per sector, cell quality from beams, beam failure detection and recovery, several carriers with gaps and Event A5 | the TR 38.901 antenna element and DFT beams; isotropic UE | UE-side beamforming, dual connectivity and PSCell change |
|
|
137
137
|
| Mobility | street-following vehicles (60 km/h, two lanes), highway lanes at 70/140 km/h, random waypoints, pedestrians | constant speed per user | handheld rotation and body blockage |
|
|
138
138
|
| Traffic and load | constant rates per 5QI, full buffer, periodic, FTP model 3; cell load drives interference | rate from SINR (Shannon-type mapping), no scheduler | slot scheduler, HARQ, RLC/PDCP, TCP and applications |
|
|
@@ -10,6 +10,24 @@ rates agree (median ratios 0.93 and 0.95, ranks 0.97), and the failure level agr
|
|
|
10
10
|
0.84, limit 0.67-1.5), but the order of the failure rates does not (rank 0.68, limit 0.8). See
|
|
11
11
|
[standard compliance](standard-compliance.md#fresh-ns-3-hold-out-190).
|
|
12
12
|
|
|
13
|
+
**Held-out check of the failure-model parts (2.2.0).** 40 new ns-3 runs (seeds 201-210, urban,
|
|
14
|
+
20 users, A3 3 dB / 300 ms, ISD 200 and 400 m at 16 m/s, light traffic and 12 Mbit/s full traffic)
|
|
15
|
+
tested each part of the failure model against limits fixed before the runs, with the 2.0.0 engine as
|
|
16
|
+
registered (2.1.0 defaults gave the same verdicts):
|
|
17
|
+
|
|
18
|
+
| Part | ns-3 | HandoverLab | Limit | Result |
|
|
19
|
+
|---|---|---|---|---|
|
|
20
|
+
| Load: link-monitoring SINR, light to full traffic | -2.1 / -1.8 dB | -13.3 / -13.4 dB | within 2 dB | fails |
|
|
21
|
+
| Execution: command to completion | median 4.1 ms | `exec_s` 10 ms | within 10 ms | passes |
|
|
22
|
+
| Recovery: time without connection per failure | 0.09 s | 1.0 s (`reest_s`) | ratio 0.67-1.5 | fails |
|
|
23
|
+
| Execution failures | none in any cell | 0-5 % | needs 10 in ns-3 | not measurable |
|
|
24
|
+
|
|
25
|
+
The two failing parts explain much of the failure gap: HandoverLab's full-buffer load always fills
|
|
26
|
+
every cell, so interference is far higher than with ns-3's offered traffic (ns-3 has fewer failures
|
|
27
|
+
at full traffic, 90 to 34 and 13 to 3; HandoverLab many more, 18 to 521 and 4 to 175), and a
|
|
28
|
+
re-establishment takes a fixed second. A traffic-driven load and a recovery time from the standard
|
|
29
|
+
texts are the next steps; they need new ns-3 runs to be judged, as these runs have now been seen.
|
|
30
|
+
|
|
13
31
|
**Summary (1.5.0).** Handover and unnecessary-handover rates of HandoverLab agree with ns-3 /
|
|
14
32
|
5G-LENA. For failure rates, the order of settings and conditions agrees on part A and on both
|
|
15
33
|
hold-out sets when the in-car loss of ns-3 and the restart of link monitoring are switched on
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Fast fading and effective SINR
|
|
2
|
+
|
|
3
|
+
By default HandoverLab works on the received-power level: path loss, LOS state, shadowing and a
|
|
4
|
+
slow time-varying component, with radio-link monitoring on the wideband SINR. Since 2.2.0 the option
|
|
5
|
+
`radio.fast_fading` adds the fast fading of the tapped delay line (TDL) models of TR 38.901 and maps
|
|
6
|
+
the SINR at several frequencies to one effective SINR. It is off by default; with it off every
|
|
7
|
+
result of 2.1.0 is unchanged bit for bit.
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
scenario:
|
|
11
|
+
base: ns3-urban-3.5ghz
|
|
12
|
+
radio:
|
|
13
|
+
fast_fading: tdl-c # tdl-a, tdl-b, tdl-c (NLOS), tdl-d, tdl-e (LOS); null: off
|
|
14
|
+
delay_spread_ns: 100 # RMS delay spread (TR 38.901 Table 7.7.3-1: 10, 30, 100, 300, 1000 ns)
|
|
15
|
+
fading_k_db: null # tdl-d / tdl-e only: another K-factor (TR 38.901 clause 7.7.6)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## 1. The channel
|
|
19
|
+
|
|
20
|
+
| Item | TR 38.901 V19.5.0 | HandoverLab |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| Tap delays and powers | Tables 7.7.2-1 to 7.7.2-5 | the five tables, the powers normalised to a unit sum (mean link gain 1) |
|
|
23
|
+
| Delay scaling | Eq. 7.7-1: tau_scaled = tau_model x DS | `delay_spread_ns` |
|
|
24
|
+
| Doppler | clause 7.7.2: Jakes spectrum per tap, f_D = \|v\| / lambda_0 | 32 sinusoids per Rayleigh tap with random arrival angles and phases, f_D from the user's speed and the carrier |
|
|
25
|
+
| LOS tap of TDL-D / TDL-E | Rice, K1 = 13.3 dB / 22 dB, Doppler peak at f_S = 0.7 f_D | a specular component at 0.7 f_D next to the Rayleigh part of the first tap |
|
|
26
|
+
| Another K-factor | clause 7.7.6, Eq. 7.7.6-1 and 7.7.6-2, delays re-normalised | `fading_k_db` (the K of Eq. 7.7.6-2: the LOS power over all Rayleigh taps; about 9 dB for the table of TDL-D) |
|
|
27
|
+
|
|
28
|
+
Every user-cell link fades independently (the TDL models are single-link models; their MIMO
|
|
29
|
+
extensions of clause 7.7.5 are not used). The channel is evaluated at four points spread over the
|
|
30
|
+
24 PRBs of the hypothetical PDCCH (TS 38.133 Tables 8.1.2.1-1/-2) and at eight points spread over
|
|
31
|
+
the carrier (N_RB of TS 38.101-1/-2 Table 5.3.2-1). The received power of a cell (L1 samples, the
|
|
32
|
+
link budget of every check) takes the mean gain over the PDCCH band, close to the 20 PRBs of an SSB.
|
|
33
|
+
|
|
34
|
+
## 2. From SINR to one effective SINR
|
|
35
|
+
|
|
36
|
+
| Use | Mapping | Why |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| Radio-link monitoring (Qout, Qin) | MIESM for QPSK over the PDCCH band: the mean bit-wise mutual information of QPSK (binary input, Gaussian channel) mapped back to the SINR with the same mutual information on a flat channel | TS 38.133 8.1 defines Qout and Qin as the BLER of a hypothetical QPSK PDCCH; the thresholds `qout_db` / `qin_db` are flat-channel SINRs, so the faded channel is compared through its flat-channel equivalent |
|
|
39
|
+
| Delivered rate | capacity-equivalent SINR over the carrier: 2^(mean log2(1 + SINR)) - 1 | the rate model uses log2(1 + SINR) |
|
|
40
|
+
|
|
41
|
+
Both mappings return the SINR itself on a flat channel and never more than the mean SINR. Every
|
|
42
|
+
interfering link has its own fading. Above about 18 dB the mutual information of QPSK is 1 to
|
|
43
|
+
double precision; the MIESM result is capped there, far above Qout and Qin. No BLER table of
|
|
44
|
+
another simulator is used; a BLER per MCS (TS 38.214 tables) follows with the slot scheduler.
|
|
45
|
+
|
|
46
|
+
## 3. Cost and limits
|
|
47
|
+
|
|
48
|
+
- A single run is about twice as long (32 sinusoids per tap, every step; 10 users on the ns-3 card:
|
|
49
|
+
about 6 s instead of 3 s for 20 s simulated); many rules on one world take longer (24 rules: about
|
|
50
|
+
6 to 8 times), as the batched and compiled loops are not used with fading.
|
|
51
|
+
- This version needs the base engine: no beams, layers, NTN or TS 38.133 periods
|
|
52
|
+
(`meas_periods: sample`, `rlm_eval: fixed`); such a configuration is refused.
|
|
53
|
+
- The step stays 10 ms. At 30 m/s and 3.5 GHz the coherence time is about 1 ms, so successive
|
|
54
|
+
steps see nearly independent fading; the L1 sample of a measurement instant is one such snapshot.
|
|
55
|
+
|
|
56
|
+
## 4. Against ns-3 (exploratory)
|
|
57
|
+
|
|
58
|
+
On the ns-3 card (24 A3 settings, four conditions, one seed) against the stored ns-3 results, which were run
|
|
59
|
+
without fading: with `tdl-c` the median handover ratio is 1.01 and the unnecessary-handover ratio 1.18 (0.95 and
|
|
60
|
+
1.06 without fading), the rank correlations 0.98; the failure rate stays at about 0.01-0.02 per UE-minute
|
|
61
|
+
against 0.43 in ns-3. Fast fading therefore does not close the known gap in failures, which follows the 14 dB gap
|
|
62
|
+
in mean serving SINR (see [verification](../verification.md)).
|
|
63
|
+
|
|
64
|
+
Against ns-3 runs that use fading themselves (`benchmarks/ns3/run_benchmark.py --fading`, 96 runs, TR 38.901
|
|
65
|
+
fast fading in ns-3), with the criterion fixed before those runs existed (`tdl-c`, delay spread 100 ns, seed
|
|
66
|
+
500; median ratios in [0.8, 1.25], rank correlations at least 0.9): the handover ratio is 1.04 and the
|
|
67
|
+
unnecessary-handover ratio 1.24, close to its limit, and the rank correlations are 0.97 and 0.98, so the
|
|
68
|
+
criterion passes. As additional rows, `tdl-a` would miss the unnecessary-handover limit (1.27), `tdl-d` (1.00 /
|
|
69
|
+
1.16) and no fading (0.98 / 1.09) pass. ns-3 itself moves little with fading (mean failure rate 0.40 against
|
|
70
|
+
0.43 without, serving SINR 11.5 dB in both), and the failure gap stays as it was (HandoverLab 0.014 per
|
|
71
|
+
UE-minute with `tdl-c`).
|
|
72
|
+
|
|
73
|
+
## 5. Checks
|
|
74
|
+
|
|
75
|
+
`handoverlab verify --only fading` runs the criteria fixed before the model was written: Rayleigh
|
|
76
|
+
taps with unit power (KS test), the J0 time correlation, the K-factor of the first TDL-D tap, the
|
|
77
|
+
delay spread after scaling, and the two properties of the mappings. `tests/test_fading.py` also
|
|
78
|
+
checks that the option off changes no fingerprint and that a run with fading is reproducible.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Slot scheduler, MCS and HARQ
|
|
2
|
+
|
|
3
|
+
By default HandoverLab computes the delivered rate from the SINR with a capacity formula and shares
|
|
4
|
+
a cell's resources among its users in proportion to their demand. Since 2.2.0 the option
|
|
5
|
+
`protocol.scheduler` replaces this with a data plane that plays every slot: resource blocks per
|
|
6
|
+
user, an MCS of TS 38.214, transport blocks that fail with a block error probability, and HARQ
|
|
7
|
+
retransmissions. It is off by default; with it off every result of 2.1.0 is unchanged bit for bit.
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
scenario:
|
|
11
|
+
base: ns3-urban-3.5ghz
|
|
12
|
+
traffic: {model: full_buffer}
|
|
13
|
+
protocol:
|
|
14
|
+
scheduler: pf # rr (round robin) or pf (proportional fair); null: off
|
|
15
|
+
harq_max_tx: 4 # transmissions of a transport block (first + retransmissions)
|
|
16
|
+
harq_rtt_slots: 8 # HARQ round trip [slots]
|
|
17
|
+
l2s_loss_db: 1.0 # implementation loss of the block-error model [dB]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
It combines with fast fading (`radio.fast_fading`, see [fast fading](fading.md)): the scheduler
|
|
21
|
+
then uses the effective SINR over the carrier.
|
|
22
|
+
|
|
23
|
+
## 1. What a slot does
|
|
24
|
+
|
|
25
|
+
| Item | Source | HandoverLab |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| Slot length | TS 38.211 Table 4.3.2-1 (2^mu slots per 1 ms subframe) | 1 ms / 2^mu for the subcarrier spacing of the carrier |
|
|
28
|
+
| Resource blocks of a cell | TS 38.101-1/-2 Table 5.3.2-1 | N_RB of the carrier, less the share of the background load |
|
|
29
|
+
| Who gets them | gNB implementation (not specified) | `rr`: every connected user with data gets an equal share in every slot; `pf`: the whole band goes to the user with the largest instantaneous over average rate; a due retransmission comes first |
|
|
30
|
+
| MCS | TS 38.214 Table 5.1.3.1-1 (MCS table 1) | the highest MCS whose block-error probability at the SINR reported one measurement interval earlier is at most 10 % |
|
|
31
|
+
| Transport block size | TS 38.214 clause 5.1.3.2 | steps 1 to 4 with Table 5.1.3.2-1; 12 PDSCH symbols, 12 DMRS REs per PRB, no xOverhead |
|
|
32
|
+
| HARQ processes | TS 38.321 5.3.2; TS 38.331 PDSCH-ServingCellConfig | 8 per user (the number when nrofHARQ-ProcessesForPDSCH is absent); a new transport block needs a free process |
|
|
33
|
+
| Retransmission | TS 38.321 5.3.2.2 (combined with the earlier data) | after `harq_rtt_slots`, chase combining (the SINRs of the transmissions add), at most `harq_max_tx` transmissions (the number is the network's choice) |
|
|
34
|
+
|
|
35
|
+
## 2. The block-error probability
|
|
36
|
+
|
|
37
|
+
3GPP gives no curve of block errors against SINR; it is a property of the receiver. HandoverLab
|
|
38
|
+
uses the normal approximation of the error probability of a code of finite length (Polyanskiy,
|
|
39
|
+
Poor and Verdu, IEEE Trans. Inf. Theory 56(5), 2010) on the bit channel of the modulation: the
|
|
40
|
+
mutual information C and the dispersion V per coded bit of QPSK, 16QAM and 64QAM with Gray mapping
|
|
41
|
+
(computed by quadrature), and P_e = Q((n C - k + log2(n) / 2) / sqrt(n V)) for n coded bits and
|
|
42
|
+
k = TBS + 24 information bits, at the SINR less `l2s_loss_db` (the gap of a practical LDPC decoder,
|
|
43
|
+
an assumption). For 51 PRBs the 10 % points run from about -6 dB (MCS 0) to about 19 dB (MCS 28);
|
|
44
|
+
at each of them the spectral efficiency of the MCS lies below the Shannon capacity. No block-error
|
|
45
|
+
table of another simulator is used.
|
|
46
|
+
|
|
47
|
+
## 3. Cost and limits
|
|
48
|
+
|
|
49
|
+
- Every slot is played: about 45 times the time of the default rate model (10 users on the ns-3
|
|
50
|
+
card: about 90 s instead of 2 s for 20 s simulated). Use it for focused studies; a compiled loop
|
|
51
|
+
is planned.
|
|
52
|
+
- The channel is held for the 10 ms step; mobility decisions stay on the 10 ms grid.
|
|
53
|
+
- This version needs the base engine (no beams, layers, NTN or TS 38.133 periods).
|
|
54
|
+
- Data of a user stop during a handover interruption and wait in its buffer; forwarding between
|
|
55
|
+
cells, RLC and PDCP are the next item of the roadmap.
|
|
56
|
+
- The decoding draws come from the world's stream `harq`, one number per user and slot whatever the
|
|
57
|
+
decisions, so every rule compared on one seed sees the same draws.
|
|
58
|
+
|
|
59
|
+
## 4. Checks
|
|
60
|
+
|
|
61
|
+
`tests/test_scheduler.py` holds the criteria fixed before the code: the MCS and CQI tables against
|
|
62
|
+
the text, six transport block sizes worked out by hand from clause 5.1.3.2 (both branches of
|
|
63
|
+
R <= 1/4 and N'_info > 8424), the properties of the block-error model, equal round-robin shares,
|
|
64
|
+
equal long-run proportional-fair time shares, the loss of p^4 of the blocks after four failed
|
|
65
|
+
transmissions, and that the option off changes no fingerprint.
|
|
@@ -60,8 +60,8 @@ options:
|
|
|
60
60
|
-h, --help show this help message and exit
|
|
61
61
|
--only GROUP [GROUP ...]
|
|
62
62
|
check groups: pathloss radio calibration invariants equivalences
|
|
63
|
-
fingerprints extended highway (default: all of them); on
|
|
64
|
-
learning ntn
|
|
63
|
+
fingerprints extended highway values fading (default: all of them); on
|
|
64
|
+
request only: learning ntn
|
|
65
65
|
--full longer checks (three seeds for the radio statistics)
|
|
66
66
|
--ns3 compare with the stored ns-3 / 5G-LENA results (several minutes); only
|
|
67
67
|
this check unless --only names groups
|
|
@@ -51,6 +51,9 @@ Values in **bold** differ from the HandoverLab defaults.
|
|
|
51
51
|
| `radio.energy_p0_w` | 56 | EARTH model, micro base station (Auer et al. 2011, Table 2): 56 W |
|
|
52
52
|
| `radio.energy_slope` | 2.6 | EARTH model, micro base station (Auer et al. 2011, Table 2): 2.6 |
|
|
53
53
|
| `radio.energy_ntrx` | 2 | EARTH model, micro base station (Auer et al. 2011, Eq. 1 and Table 2): 2 transceivers |
|
|
54
|
+
| `radio.fast_fading` | none | off by default; TR 38.901 clause 7.7.2 (TDL-A .. TDL-E) |
|
|
55
|
+
| `radio.delay_spread_ns` | 100 | TR 38.901 Table 7.7.3-1 (nominal delay spread; used with fast_fading) |
|
|
56
|
+
| `radio.fading_k_db` | none | TR 38.901 clause 7.7.6 (unset: the K-factor of the table) |
|
|
54
57
|
| `radio.map_res_m` | **2** | numerical setting |
|
|
55
58
|
| `radio.beams.sectors` | 3 | TR 36.885 clause A.1.3, option 2 (19 x 3 hexagonal cells) |
|
|
56
59
|
| `radio.beams.sector_az0_deg` | **6.587** | TR 38.901 Table 7.8-1 (3 sectors per cell site: 30, 150 and 270 degrees), turned by -23.413 degrees with the layout |
|
|
@@ -94,6 +97,10 @@ Values in **bold** differ from the HandoverLab defaults.
|
|
|
94
97
|
| `protocol.lm_load_per_ue` | 0 | off by default (calibration option) |
|
|
95
98
|
| `protocol.exec_can_fail` | true | TR 36.839: the execution fails when the target is below Qout |
|
|
96
99
|
| `protocol.rlm_holdoff_s` | 0.2 | 0.2 s since 2.0.0: an interpretation of TS 38.133 8.1.2.2 (evaluation over the last T_Evaluate_out, 200 ms in FR1) on a newly joined cell |
|
|
100
|
+
| `protocol.scheduler` | none | off by default (rate model); rr / pf slot scheduler with TS 38.214 MCS and TBS |
|
|
101
|
+
| `protocol.harq_max_tx` | 4 | assumption (transmissions per TB; the network's choice) |
|
|
102
|
+
| `protocol.harq_rtt_slots` | 8 | assumption (HARQ round trip in slots) |
|
|
103
|
+
| `protocol.l2s_loss_db` | 1 | assumption (implementation loss of the block-error model) |
|
|
97
104
|
| `protocol.rrc_detail` | 3gpp | |
|
|
98
105
|
| `traffic.services` | 5 entries | TS 23.501 Table 5.7.4-1 (5QI); thresholds are assumptions |
|
|
99
106
|
| `traffic.se_max` | 7.4 | assumption (spectral-efficiency cap) |
|
|
@@ -55,6 +55,9 @@ Values in **bold** differ from the HandoverLab defaults.
|
|
|
55
55
|
| `radio.energy_p0_w` | 56 | EARTH model, micro base station (Auer et al. 2011, Table 2): 56 W |
|
|
56
56
|
| `radio.energy_slope` | 2.6 | EARTH model, micro base station (Auer et al. 2011, Table 2): 2.6 |
|
|
57
57
|
| `radio.energy_ntrx` | 2 | EARTH model, micro base station (Auer et al. 2011, Eq. 1 and Table 2): 2 transceivers |
|
|
58
|
+
| `radio.fast_fading` | none | off by default; TR 38.901 clause 7.7.2 (TDL-A .. TDL-E) |
|
|
59
|
+
| `radio.delay_spread_ns` | 100 | TR 38.901 Table 7.7.3-1 (nominal delay spread; used with fast_fading) |
|
|
60
|
+
| `radio.fading_k_db` | none | TR 38.901 clause 7.7.6 (unset: the K-factor of the table) |
|
|
58
61
|
| `radio.map_res_m` | **4** | numerical setting (coarser map for the long road) |
|
|
59
62
|
| `protocol.step_s` | 0.01 | numerical setting |
|
|
60
63
|
| `protocol.l1_period_s` | 0.04 | assumption (L1 sample period) |
|
|
@@ -78,6 +81,10 @@ Values in **bold** differ from the HandoverLab defaults.
|
|
|
78
81
|
| `protocol.lm_load_per_ue` | 0 | off by default (calibration option) |
|
|
79
82
|
| `protocol.exec_can_fail` | true | TR 36.839: the execution fails when the target is below Qout |
|
|
80
83
|
| `protocol.rlm_holdoff_s` | 0.2 | 0.2 s since 2.0.0: an interpretation of TS 38.133 8.1.2.2 (evaluation over the last T_Evaluate_out, 200 ms in FR1) on a newly joined cell |
|
|
84
|
+
| `protocol.scheduler` | none | off by default (rate model); rr / pf slot scheduler with TS 38.214 MCS and TBS |
|
|
85
|
+
| `protocol.harq_max_tx` | 4 | assumption (transmissions per TB; the network's choice) |
|
|
86
|
+
| `protocol.harq_rtt_slots` | 8 | assumption (HARQ round trip in slots) |
|
|
87
|
+
| `protocol.l2s_loss_db` | 1 | assumption (implementation loss of the block-error model) |
|
|
81
88
|
| `protocol.rrc_detail` | 3gpp | |
|
|
82
89
|
| `traffic.services` | 5 entries | TS 23.501 Table 5.7.4-1 (5QI); thresholds are assumptions |
|
|
83
90
|
| `traffic.se_max` | 7.4 | assumption (spectral-efficiency cap) |
|
|
@@ -91,6 +91,7 @@ checks) and is part of `handoverlab.stability.LEGACY_1X`.
|
|
|
91
91
|
| Soft LOS state, Eqs. (7.6-18), (7.6-19) | 7.6.3.3 | `radio.soft_los`: power weights LOS_soft^2 and 1 - LOS_soft^2 (no fast fading, so no cross term) | follows (power level) |
|
|
92
92
|
| Multi-frequency: the same LOS state (Step 2) and LSPs (Step 4) on all frequencies of one link | 7.6.5 | layers with `cosited: true` reuse the random fields of the first layer; their `pathloss`, `los_corr_m` and `shadow_decorr_m` must equal those of the first layer (checked since 2.1.0); soft LOS may differ with the frequency, as 7.6.5 allows | follows |
|
|
93
93
|
| O2I car penetration loss N(9, 5^2) per UT | 7.4.3.2 | `radio.penetration_db`, `penetration_sd_db` | follows (option) |
|
|
94
|
+
| Fast fading: TDL-A .. TDL-E taps, Jakes Doppler per tap with f_D = \|v\| / lambda_0, LOS tap of TDL-D / -E at f_S = 0.7 f_D with K1 13.3 / 22 dB, delay scaling Eq. 7.7-1, K-factor change Eq. 7.7.6-1/-2 | 7.7.2 (Tables 7.7.2-1 to -5), 7.7.3, 7.7.6 | `radio.fast_fading` (2.2.0, off by default), `delay_spread_ns`, `fading_k_db`: one TDL per scenario, independent per user-cell link, 32 sinusoids per Rayleigh tap, channel at 4 points of the PDCCH band and 8 of the carrier ([guide](guides/fading.md)); MIMO extension 7.7.5 and CDL not used | follows (option; single-link TDL) |
|
|
94
95
|
|
|
95
96
|
## Map-based channel model (1.12.0, `radio.map_file`)
|
|
96
97
|
|
|
@@ -152,6 +153,7 @@ measurements can be read in the same format, but they are outside TR 38.901 (**a
|
|
|
152
153
|
| T312 (optional, useT312) | TS 38.331 5.3.10, 5.5.4.1 | not modelled | not modelled (optional feature) |
|
|
153
154
|
| Link monitoring restarts on a newly joined cell: the quality is evaluated over the last T_Evaluate_out | TS 38.133 8.1.2.2 (interpretation; no clause defines a hold-off) | `protocol.rlm_holdoff_s` (0.2 s, default since 2.0.0): no out-of-sync for this time after joining a cell, whatever the frequency range | abstraction (interpretation of 8.1.2.2) |
|
|
154
155
|
| In-car penetration loss per user, 9 dB +- 5 dB | TR 38.901 7.4.3.2 | `radio.penetration_db`, `penetration_sd_db`, any speed | follows (option) |
|
|
156
|
+
| Qout / Qin as the BLER of a hypothetical PDCCH on the faded channel | TS 38.133 8.1, Tables 8.1.2.1-1/-2 (QPSK, 24 PRBs) | with `radio.fast_fading` (2.2.0): the MIESM effective SINR of QPSK over the 24-PRB band against `qout_db` / `qin_db` (flat-channel SINRs); without it the wideband SINR | abstraction (no link-level BLER curve) |
|
|
155
157
|
|
|
156
158
|
## Handover procedure
|
|
157
159
|
|
|
@@ -203,6 +205,17 @@ and the FR2 limit of 64 SSBs. The evaluation periods of TS 38.133 are minimum re
|
|
|
203
205
|
longest time a UE may take); HandoverLab uses them as the averaging time constants, a conservative
|
|
204
206
|
reading.
|
|
205
207
|
|
|
208
|
+
## Data plane (2.2.0, `protocol.scheduler`)
|
|
209
|
+
|
|
210
|
+
| What the texts specify | Clause | HandoverLab | Status |
|
|
211
|
+
|---|---|---|---|
|
|
212
|
+
| Slots: 2^mu slots per 1 ms subframe | TS 38.211 Table 4.3.2-1 | slot length 1 ms / 2^mu of the carrier's subcarrier spacing | follows |
|
|
213
|
+
| MCS index table 1 for PDSCH (Q_m, target code rate) | TS 38.214 Table 5.1.3.1-1 | the 29 rows; the highest MCS with a block-error probability of at most 10 % at the reported SINR | follows (table); link adaptation: implementation |
|
|
214
|
+
| Transport block size | TS 38.214 5.1.3.2, Table 5.1.3.2-1 | steps 1 to 4; 12 PDSCH symbols, 12 DMRS REs per PRB, xOverhead 0, one layer | follows |
|
|
215
|
+
| HARQ entity per serving cell, parallel processes, retransmission decoded with the earlier data | TS 38.321 5.3.2.1, 5.3.2.2 | 8 processes per user (TS 38.331: absent nrofHARQ-ProcessesForPDSCH), chase combining, at most `harq_max_tx` transmissions after `harq_rtt_slots` | follows (combining and the number of transmissions: implementation choices) |
|
|
216
|
+
| Block errors of a transport block | not specified (receiver property) | normal approximation of the finite-blocklength error probability on the BICM bit channel, with an implementation loss | abstraction |
|
|
217
|
+
| Scheduling | not specified (gNB) | round robin in frequency or proportional fair in time | abstraction |
|
|
218
|
+
|
|
206
219
|
## Beyond 5G: what is not modelled yet
|
|
207
220
|
|
|
208
221
|
| Rule | Clause | Status |
|
|
@@ -235,7 +248,7 @@ The ns-3 / 5G-LENA build of the comparison study was read at the source (contrib
|
|
|
235
248
|
| CHO, DAPS, LTM, conditional LTM (Rel-16 to 19) | none | all four |
|
|
236
249
|
| Beam failure recovery | none | none |
|
|
237
250
|
| Large-scale channel calibration (TR 38.901 7.8.1) | calibrated by its authors | calibrated (see [radio calibration](calibration-3gpp.md)) |
|
|
238
|
-
| Fast fading, packet-level PHY/MAC/RLC | yes | no
|
|
251
|
+
| Fast fading, packet-level PHY/MAC/RLC | yes | options since 2.2.0: TDL fast fading, a slot scheduler with MCS, TBS and HARQ; no RLC / PDCP |
|
|
239
252
|
|
|
240
253
|
**Reading.** On the rules of the handover procedure and on the procedures of Releases 16 to 19,
|
|
241
254
|
HandoverLab with the 3GPP profile follows the normative texts more closely; on the physical layer
|
|
@@ -226,6 +226,7 @@ output: results/metrics.csv
|
|
|
226
226
|
| | `time_var_db`, `time_var_tau_s` | `1.5`, `1` | time-varying component (moving blockers) |
|
|
227
227
|
| | `l1_error_db` | `1` | error of one L1 RSRP sample |
|
|
228
228
|
| | `energy_p0_w`, `energy_slope`, `energy_ntrx` | `56`, `2.6`, `2` | cell power for the energy metrics (1.5.0; `energy_ntrx` since 2.1.0): EARTH model of a micro base station, Auer et al. 2011 Eq. 1 and Table 2 |
|
|
229
|
+
| | `fast_fading`, `delay_spread_ns`, `fading_k_db` | `null`, `100`, `null` | (2.2.0) TDL fast fading of TR 38.901 clause 7.7.2 (`tdl-a` .. `tdl-e`), its RMS delay spread and an optional K-factor; radio-link monitoring and the rate then use effective SINRs ([guide](guides/fading.md)) |
|
|
229
230
|
| | `penetration_db`, `penetration_sd_db` | `0`, `0` | optional (1.2.0): penetration loss of each user on all its links, drawn once per user (TR 38.901 clause 7.4.3.2: `9`, `5` for a user in a standard car) |
|
|
230
231
|
| | `map_res_m` | `1` | radio-map resolution (street grid) |
|
|
231
232
|
| | `scs_khz` | none | optional (1.10.0): subcarrier spacing for SS-RSRP per resource element; unset: 30 kHz up to 7.125 GHz, 120 kHz above |
|
|
@@ -245,6 +246,8 @@ output: results/metrics.csv
|
|
|
245
246
|
| | `cfg_loss_as_failure` | `false` | check mode: a lost conditional configuration fails like a lost handover command |
|
|
246
247
|
| | `lm_load`, `lm_load_per_ue` | `null`, `0` | optional (1.1.0): interferer load at link monitoring, plus a part per user served by the interfering cell; `null` and `0` keep the load of the data channel ([calibration](calibration.md)) |
|
|
247
248
|
| | `exec_can_fail` | `true` | `false`: the execution always joins the target (ideal random access) |
|
|
249
|
+
| | `rrc_detail` | `3gpp` | since 2.1.0: `3gpp` -- the procedures as audited against TS 38.331 / TS 38.133 / TS 38.300 (RLM counters and indication interval, DAPS source monitoring, LTM candidates kept, CHO at TTT expiry, outcome classes, RRC messages one by one, ...); `simple` -- the engine of 2.0.0 (part of `LEGACY_1X`) |
|
|
250
|
+
| | `scheduler`, `harq_max_tx`, `harq_rtt_slots`, `l2s_loss_db` | `null`, `4`, `8`, `1.0` | (2.2.0) slot scheduler `rr` or `pf` with MCS table 1 and the TBS of TS 38.214, HARQ with 8 processes and chase combining; null keeps the rate model ([guide](guides/scheduler.md)) |
|
|
248
251
|
| | `rlm_holdoff_s` | `0.2` | no out-of-sync on a newly joined cell for this time, as radio-link monitoring restarts there (an interpretation of TS 38.133 8.1.2.2; since 1.3.0, default since 2.0.0; 1.x: `0`) |
|
|
249
252
|
| | `cmd_during_t310` | `receive` | (1.9.0; default since 2.0.0, 1.x: `lost`) a handover or cell switch command that reaches the UE while T310 runs is received at the first step with link-monitoring SINR >= Qout and stops T310 (TS 38.331 5.3.5.5.2); since 2.0.0 a CHO or LTM candidate configuration is received the same way, without stopping T310 (5.3.5.13) |
|
|
250
253
|
| | `t304_s` | `1.0` | T304 (1.9.0; default since 2.0.0, 1.x: none): the execution fails only when T304 expires; the UE joins at the first step with target SINR >= Qout (TS 38.331 5.3.5.8.3) |
|
|
@@ -817,8 +820,10 @@ intervals are wide; the report shows them next to every estimate.
|
|
|
817
820
|
|
|
818
821
|
## 12. Limitations
|
|
819
822
|
|
|
820
|
-
- Received-power level
|
|
821
|
-
|
|
823
|
+
- Received-power level by default: no link-level physical layer, no HARQ, no beam management (one
|
|
824
|
+
beam gain and one isolation factor), no packet-level protocol stack; fast fading with effective
|
|
825
|
+
SINRs and a slot scheduler with MCS and HARQ are options since 2.2.0 ([fading](guides/fading.md),
|
|
826
|
+
[scheduler](guides/scheduler.md)).
|
|
822
827
|
- The failure model uses the SINR thresholds and timers of TR 36.839 with the procedures of TS 38.331 and
|
|
823
828
|
TS 38.133 (see [standard compliance](standard-compliance.md)); it is not calibrated in absolute terms, so
|
|
824
829
|
failure rates are best read relative to each other.
|
|
@@ -33,6 +33,7 @@ writes the report with the versions of Python, NumPy and SciPy and the platform.
|
|
|
33
33
|
| TR 37.885 highway (1.11.0) | geometry and link budget of the two highway cards against TR 37.885, TR 36.885 and TR 38.901; continuity of the received power at the wrap-around; coupling gain to the strongest site against an independent computation (percentiles 5-95 within 0.5 dB); LOS on every link | `verify` group `highway`, `tests/test_highway_tr37885.py` |
|
|
34
34
|
| Legacy settings (2.0.0) | every golden run of 1.12.0 repeated with `LEGACY_1X`: identical event logs (33 of 33) | `verify` group `fingerprints` (section `fingerprints-1x`) |
|
|
35
35
|
| Satellite (2.0.0) | N1 link budget of the 8 S-band LEO cases of TR 38.821 Table 6.1.3.3-1 within 0.1 dB (passed, 0.028 dB); N2 3 dB beamwidth within 0.01 degree of Tables 6.1.1.1-1/-2 (failed for 1 m: 0.014 degree; see the [NTN guide](guides/ntn.md)); N3 orbital speed and nadir footprint (passed) | `verify --only ntn` |
|
|
36
|
+
| Fast fading (2.2.0) | the TDL taps of TR 38.901 clause 7.7.2: Rayleigh with unit power (KS test), the J0 time correlation of the Jakes spectrum, the K-factor of the first TDL-D tap, the delay spread after Eq. 7.7-1 and after a K change (Eq. 7.7.6-1/-2); the effective-SINR mappings exact on a flat channel and never above the mean; the option off changes no fingerprint | `verify` group `fading`, `tests/test_fading.py` |
|
|
36
37
|
| Learning rule (1.11.0) | `a3_bandit` against an exhaustive search over its arms, three criteria fixed before the run (one failed: see the [learning-rule guide](guides/learning-rule.md)) | `verify --only learning` (about 20 minutes) |
|
|
37
38
|
| Imported radio maps (1.12.0) | an exported street-grid map imported again gives the identical event log (every golden case on the street grid); interpolation of measured points with its hold-out error; errors for a wrong format, other sites, a map that does not cover the area, a changed file | `tests/test_mapfile.py` |
|
|
38
39
|
| Compiled kernel (1.11.0) | the golden fingerprints with `run.backend: numba` | `tests/test_v111.py` (with Numba installed) |
|
|
@@ -36,6 +36,8 @@ nav:
|
|
|
36
36
|
- Indoor and rural scenarios: guides/indoor-rural.md
|
|
37
37
|
- Mobility robustness optimisation: guides/mro.md
|
|
38
38
|
- Beams and several carriers: guides/beams-layers.md
|
|
39
|
+
- Fast fading and effective SINR: guides/fading.md
|
|
40
|
+
- Slot scheduler, MCS and HARQ: guides/scheduler.md
|
|
39
41
|
- Your own radio map: guides/radio-maps.md
|
|
40
42
|
- A LEO satellite (NTN): guides/ntn.md
|
|
41
43
|
- Moving from 1.x to 2.0: migration-2.0.md
|
|
@@ -10,7 +10,7 @@ Quick start::
|
|
|
10
10
|
for r in res:
|
|
11
11
|
print(r.rule, r.metrics["handovers_pm"], r.metrics["failures_pm"])
|
|
12
12
|
"""
|
|
13
|
-
__version__ = "2.
|
|
13
|
+
__version__ = "2.2.0"
|
|
14
14
|
|
|
15
15
|
from .config import (ConfigError, Experiment, LayoutConfig, MobilityConfig, ProtocolConfig, RadioConfig, RunConfig,
|
|
16
16
|
Scenario, Service, SpeedGroup, TrafficConfig, load_config)
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
"""Fast fading with the tapped delay line (TDL) models of TR 38.901 (optional, since 2.2.0).
|
|
3
|
+
|
|
4
|
+
``radio.fast_fading`` selects one of TDL-A .. TDL-E (TR 38.901 V19.5.0 clause 7.7.2, Tables 7.7.2-1 to
|
|
5
|
+
7.7.2-5). Each user-cell link fades independently:
|
|
6
|
+
|
|
7
|
+
* the normalised delays are scaled to the RMS delay spread ``radio.delay_spread_ns`` (Eq. 7.7-1,
|
|
8
|
+
tau_scaled = tau_model x DS; Table 7.7.3-1 gives 10, 30, 100, 300 and 1000 ns as examples);
|
|
9
|
+
* for TDL-D and TDL-E the K-factor can be changed (``radio.fading_k_db``; Eq. 7.7.6-1 and 7.7.6-2, after
|
|
10
|
+
which the delays are re-normalised to DS = 1);
|
|
11
|
+
* every Rayleigh tap is a sum of sinusoids with random arrival angles and phases, so that its Doppler
|
|
12
|
+
spectrum tends to the classical (Jakes) shape with the maximum Doppler shift f_D = |v| / lambda_0 (|v| the
|
|
13
|
+
user's speed, lambda_0 the carrier wavelength); the phases advance by one step at a time;
|
|
14
|
+
* the LOS tap of TDL-D / TDL-E is a specular component with the Doppler shift f_S = 0.7 f_D;
|
|
15
|
+
* the tap powers are normalised to a unit sum, so the mean power gain of a link is 1 and the large-scale model
|
|
16
|
+
is unchanged on average.
|
|
17
|
+
|
|
18
|
+
The channel is evaluated at a few frequencies: points spread over the 24-PRB band of the hypothetical PDCCH of
|
|
19
|
+
radio-link monitoring (TS 38.133 Tables 8.1.2.1-1/-2) and points spread over the carrier bandwidth (the
|
|
20
|
+
transmission bandwidth configuration of TS 38.101-1/-2 Table 5.3.2-1).
|
|
21
|
+
"""
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import math
|
|
25
|
+
from typing import Dict, Optional, Tuple
|
|
26
|
+
|
|
27
|
+
import numpy as np
|
|
28
|
+
|
|
29
|
+
C0 = 3.0e8 # TR 38.901 Table 7.4.1-1 note: c = 3.0 x 10^8 m/s
|
|
30
|
+
|
|
31
|
+
#: TR 38.901 V19.5.0 Tables 7.7.2-1 to 7.7.2-5: (normalised delay, power [dB], kind) per tap; kind "L" is the LOS
|
|
32
|
+
#: path of TDL-D / TDL-E (the Rayleigh part of their first tap follows it at the same delay)
|
|
33
|
+
TDL: Dict[str, Tuple[Tuple[float, float, str], ...]] = {
|
|
34
|
+
"tdl-a": ((0.0000, -13.4, "R"), (0.3819, 0.0, "R"), (0.4025, -2.2, "R"), (0.5868, -4.0, "R"),
|
|
35
|
+
(0.4610, -6.0, "R"), (0.5375, -8.2, "R"), (0.6708, -9.9, "R"), (0.5750, -10.5, "R"),
|
|
36
|
+
(0.7618, -7.5, "R"), (1.5375, -15.9, "R"), (1.8978, -6.6, "R"), (2.2242, -16.7, "R"),
|
|
37
|
+
(2.1718, -12.4, "R"), (2.4942, -15.2, "R"), (2.5119, -10.8, "R"), (3.0582, -11.3, "R"),
|
|
38
|
+
(4.0810, -12.7, "R"), (4.4579, -16.2, "R"), (4.5695, -18.3, "R"), (4.7966, -18.9, "R"),
|
|
39
|
+
(5.0066, -16.6, "R"), (5.3043, -19.9, "R"), (9.6586, -29.7, "R")),
|
|
40
|
+
"tdl-b": ((0.0000, 0.0, "R"), (0.1072, -2.2, "R"), (0.2155, -4.0, "R"), (0.2095, -3.2, "R"),
|
|
41
|
+
(0.2870, -9.8, "R"), (0.2986, -1.2, "R"), (0.3752, -3.4, "R"), (0.5055, -5.2, "R"),
|
|
42
|
+
(0.3681, -7.6, "R"), (0.3697, -3.0, "R"), (0.5700, -8.9, "R"), (0.5283, -9.0, "R"),
|
|
43
|
+
(1.1021, -4.8, "R"), (1.2756, -5.7, "R"), (1.5474, -7.5, "R"), (1.7842, -1.9, "R"),
|
|
44
|
+
(2.0169, -7.6, "R"), (2.8294, -12.2, "R"), (3.0219, -9.8, "R"), (3.6187, -11.4, "R"),
|
|
45
|
+
(4.1067, -14.9, "R"), (4.2790, -9.2, "R"), (4.7834, -11.3, "R")),
|
|
46
|
+
"tdl-c": ((0.0, -4.4, "R"), (0.2099, -1.2, "R"), (0.2219, -3.5, "R"), (0.2329, -5.2, "R"),
|
|
47
|
+
(0.2176, -2.5, "R"), (0.6366, 0.0, "R"), (0.6448, -2.2, "R"), (0.6560, -3.9, "R"),
|
|
48
|
+
(0.6584, -7.4, "R"), (0.7935, -7.1, "R"), (0.8213, -10.7, "R"), (0.9336, -11.1, "R"),
|
|
49
|
+
(1.2285, -5.1, "R"), (1.3083, -6.8, "R"), (2.1704, -8.7, "R"), (2.7105, -13.2, "R"),
|
|
50
|
+
(4.2589, -13.9, "R"), (4.6003, -13.9, "R"), (5.4902, -15.8, "R"), (5.6077, -17.1, "R"),
|
|
51
|
+
(6.3065, -16.0, "R"), (6.6374, -15.7, "R"), (7.0427, -21.6, "R"), (8.6523, -22.8, "R")),
|
|
52
|
+
"tdl-d": ((0.0, -0.2, "L"), (0.0, -13.5, "R"), (0.035, -18.8, "R"), (0.612, -21.0, "R"), (1.363, -22.8, "R"),
|
|
53
|
+
(1.405, -17.9, "R"), (1.804, -20.1, "R"), (2.596, -21.9, "R"), (1.775, -22.9, "R"),
|
|
54
|
+
(4.042, -27.8, "R"), (7.937, -23.6, "R"), (9.424, -24.8, "R"), (9.708, -30.0, "R"),
|
|
55
|
+
(12.525, -27.7, "R")),
|
|
56
|
+
"tdl-e": ((0.0, -0.03, "L"), (0.0, -22.03, "R"), (0.5133, -15.8, "R"), (0.5440, -18.1, "R"),
|
|
57
|
+
(0.5630, -19.8, "R"), (0.5440, -22.9, "R"), (0.7112, -22.4, "R"), (1.9092, -18.6, "R"),
|
|
58
|
+
(1.9293, -20.8, "R"), (1.9589, -22.6, "R"), (2.6426, -22.3, "R"), (3.7136, -25.6, "R"),
|
|
59
|
+
(5.4524, -20.2, "R"), (12.0034, -29.8, "R"), (20.6519, -29.2, "R")),
|
|
60
|
+
}
|
|
61
|
+
MODELS = tuple(TDL)
|
|
62
|
+
#: K-factor of the first tap given in the notes of Tables 7.7.2-4 / 7.7.2-5 [dB]
|
|
63
|
+
K_MODEL_DB = {"tdl-d": 13.3, "tdl-e": 22.0}
|
|
64
|
+
N_SINUSOIDS = 32 # sinusoids per Rayleigh tap (16 left a measurable deviation from Rayleigh)
|
|
65
|
+
PDCCH_PRB = 24 # bandwidth of the hypothetical PDCCH (TS 38.133 Tables 8.1.2.1-1/-2)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def rms_delay_spread(delays: np.ndarray, powers: np.ndarray) -> float:
|
|
69
|
+
"""RMS delay spread of a power delay profile (linear powers)."""
|
|
70
|
+
p = powers / powers.sum()
|
|
71
|
+
m = float((p * delays).sum())
|
|
72
|
+
return math.sqrt(max(float((p * delays ** 2).sum()) - m * m, 0.0))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def tdl_profile(model: str, ds_s: float, k_db: Optional[float] = None) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
76
|
+
"""Delays [s], linear powers (unit sum) and LOS flags of the taps of ``model`` at RMS delay spread ``ds_s``.
|
|
77
|
+
|
|
78
|
+
With ``k_db`` (TDL-D / TDL-E only) the Rayleigh tap powers follow Eq. 7.7.6-1, P_scaled = P_model - K_desired
|
|
79
|
+
+ K_model, with K_model of Eq. 7.7.6-2: the LOS power over the sum of the powers of the taps that are rescaled
|
|
80
|
+
(the Rayleigh taps); the delays are then divided by the RMS delay spread that results, so that DS = 1 before
|
|
81
|
+
the scaling of Eq. 7.7-1.
|
|
82
|
+
"""
|
|
83
|
+
taps = TDL[model]
|
|
84
|
+
tau = np.array([t[0] for t in taps])
|
|
85
|
+
p_db = np.array([t[1] for t in taps])
|
|
86
|
+
los = np.array([t[2] == "L" for t in taps])
|
|
87
|
+
if k_db is not None:
|
|
88
|
+
if not los.any():
|
|
89
|
+
raise ValueError("a K-factor applies to the LOS models tdl-d and tdl-e only")
|
|
90
|
+
k_model = p_db[los][0] - 10.0 * np.log10(np.sum(10.0 ** (p_db[~los] / 10.0))) # Eq. 7.7.6-2
|
|
91
|
+
p_db = np.where(los, p_db, p_db - k_db + k_model) # Eq. 7.7.6-1
|
|
92
|
+
p_lin = 10.0 ** (p_db / 10.0)
|
|
93
|
+
tau = tau / rms_delay_spread(tau, p_lin)
|
|
94
|
+
p = 10.0 ** (p_db / 10.0)
|
|
95
|
+
return tau * ds_s, p / p.sum(), los
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def k_factor_db(model: str, k_db: Optional[float] = None) -> float:
|
|
99
|
+
"""K-factor of Eq. 7.7.6-2: LOS power over the sum of the Rayleigh tap powers [dB]."""
|
|
100
|
+
_, p, los = tdl_profile(model, 1.0, k_db)
|
|
101
|
+
return float(10.0 * np.log10(p[los].sum() / p[~los].sum()))
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def first_tap_k_db(model: str) -> float:
|
|
105
|
+
"""K-factor of the first tap alone, as the notes of Tables 7.7.2-4 / 7.7.2-5 give it [dB]."""
|
|
106
|
+
_, p, los = tdl_profile(model, 1.0)
|
|
107
|
+
first = np.nonzero(los)[0][0]
|
|
108
|
+
return float(10.0 * np.log10(p[first] / p[first + 1]))
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def frequencies(bandwidth_mhz: float, scs_khz: float, n_rb: Optional[int], n_rlm: int = 4,
|
|
112
|
+
n_data: int = 8) -> Tuple[np.ndarray, np.ndarray]:
|
|
113
|
+
"""Offsets [Hz] from the carrier centre of the PDCCH points (24 PRBs around the centre) and the data points."""
|
|
114
|
+
rb_hz = 12.0 * scs_khz * 1e3
|
|
115
|
+
n = n_rb if n_rb is not None else int(bandwidth_mhz * 1e3 / (12.0 * scs_khz))
|
|
116
|
+
w_rlm = min(PDCCH_PRB, n) * rb_hz
|
|
117
|
+
w_data = n * rb_hz
|
|
118
|
+
centre = lambda w, k: (np.arange(k) + 0.5) / k * w - w / 2.0 # noqa: E731
|
|
119
|
+
return centre(w_rlm, n_rlm), centre(w_data, n_data)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class TdlFading:
|
|
123
|
+
"""Independent TDL fading of ``U`` x ``M`` links evaluated at the frequencies ``f_hz``.
|
|
124
|
+
|
|
125
|
+
``fd`` (U,) are the users' maximum Doppler shifts [Hz]; each call of :meth:`gains` advances every link by one
|
|
126
|
+
step of ``dt`` seconds and returns |H|^2 (U, M, F). The draws come from ``rng`` once, at construction; every
|
|
127
|
+
sinusoid then turns by a fixed phase per step (one complex multiplication), as the speed of a user is constant.
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
def __init__(self, rng: np.random.Generator, U: int, M: int, model: str, ds_s: float, f_hz: np.ndarray,
|
|
131
|
+
dt: float, fd: np.ndarray, k_db: Optional[float] = None, n_sin: int = N_SINUSOIDS):
|
|
132
|
+
tau, p, los = tdl_profile(model, ds_s, k_db)
|
|
133
|
+
ray = ~los
|
|
134
|
+
L = int(ray.sum())
|
|
135
|
+
w = 2.0 * np.pi * dt * np.asarray(fd, dtype=float) # phase per step at f_D (U,)
|
|
136
|
+
# Rayleigh taps: sum of n_sin sinusoids with uniform arrival angles and phases (Clarke / Jakes spectrum)
|
|
137
|
+
cos_a = np.cos(rng.uniform(0.0, 2.0 * np.pi, (U, M, L, n_sin)))
|
|
138
|
+
self.z = np.exp(1j * rng.uniform(0.0, 2.0 * np.pi, (U, M, L, n_sin))).reshape(U, M, L * n_sin)
|
|
139
|
+
self.rot = np.exp(1j * w[:, None, None, None] * cos_a).reshape(U, M, L * n_sin)
|
|
140
|
+
f = np.asarray(f_hz, dtype=float)
|
|
141
|
+
e_ray = np.sqrt(p[ray])[:, None] * np.exp(-2j * np.pi * tau[ray][:, None] * f[None, :]) # (L, F)
|
|
142
|
+
self.e = np.repeat(e_ray, n_sin, axis=0) / math.sqrt(n_sin) # (L n, F)
|
|
143
|
+
self.los = bool(los.any())
|
|
144
|
+
if self.los: # specular LOS component at f_S = 0.7 f_D with a random start phase
|
|
145
|
+
self.e_los = np.sqrt(p[los][0]) * np.exp(-2j * np.pi * tau[los][0] * f) # (F,)
|
|
146
|
+
self.z_los = np.exp(1j * rng.uniform(0.0, 2.0 * np.pi, (U, M)))
|
|
147
|
+
self.rot_los = np.exp(1j * 0.7 * w)[:, None]
|
|
148
|
+
self.n_f = len(f)
|
|
149
|
+
|
|
150
|
+
def gains(self) -> np.ndarray:
|
|
151
|
+
"""|H|^2 of every link at every frequency after one more step (U, M, F)."""
|
|
152
|
+
self.z *= self.rot
|
|
153
|
+
h = self.z @ self.e # (U, M, F)
|
|
154
|
+
if self.los:
|
|
155
|
+
self.z_los *= self.rot_los
|
|
156
|
+
h += self.z_los[..., None] * self.e_los
|
|
157
|
+
return h.real ** 2 + h.imag ** 2
|