handoverlab 2.4.1__tar.gz → 2.4.2__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.
Files changed (309) hide show
  1. {handoverlab-2.4.1 → handoverlab-2.4.2}/CHANGELOG.md +42 -1
  2. {handoverlab-2.4.1 → handoverlab-2.4.2}/CITATION.cff +5 -2
  3. {handoverlab-2.4.1 → handoverlab-2.4.2}/PKG-INFO +66 -18
  4. {handoverlab-2.4.1 → handoverlab-2.4.2}/README.md +65 -17
  5. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/calibration-3gpp.md +3 -2
  6. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/comparison.md +2 -2
  7. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/beams-layers.md +9 -8
  8. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/buffers.md +15 -9
  9. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/daps-ltm.md +4 -0
  10. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/dual-connectivity.md +4 -0
  11. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/fading.md +11 -3
  12. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/indoor-rural.md +17 -15
  13. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/learning-rule.md +4 -3
  14. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/mro.md +15 -9
  15. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/scheduler.md +12 -6
  16. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/ue-beams.md +4 -0
  17. handoverlab-2.4.2/docs/images/buffers.png +0 -0
  18. handoverlab-2.4.2/docs/images/dashboard-charts.png +0 -0
  19. handoverlab-2.4.2/docs/images/dashboard-compare.png +0 -0
  20. handoverlab-2.4.2/docs/images/dashboard-where.png +0 -0
  21. handoverlab-2.4.2/docs/images/dashboard.png +0 -0
  22. handoverlab-2.4.2/docs/images/dual-connectivity.png +0 -0
  23. handoverlab-2.4.2/docs/images/fading.png +0 -0
  24. handoverlab-2.4.2/docs/images/mro.png +0 -0
  25. handoverlab-2.4.2/docs/images/procedures.png +0 -0
  26. handoverlab-2.4.2/docs/images/scheduler.png +0 -0
  27. handoverlab-2.4.2/docs/images/traffic.png +0 -0
  28. handoverlab-2.4.2/docs/images/ue-beams.png +0 -0
  29. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/index.md +8 -4
  30. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/performance.md +19 -5
  31. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/indoor-office-4ghz.md +1 -1
  32. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/rural-700mhz.md +1 -1
  33. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/suburban-sma-7ghz.md +1 -1
  34. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/stability.md +1 -0
  35. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/standard-compliance.md +1 -1
  36. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/tutorials/own-rule.md +10 -9
  37. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/tutorials/tuning-study.md +1 -1
  38. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/user_guide.md +27 -14
  39. {handoverlab-2.4.1 → handoverlab-2.4.2}/pyproject.toml +1 -1
  40. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/__init__.py +1 -1
  41. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/scenarios/cards/indoor-office-4ghz.yaml +1 -1
  42. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/scenarios/cards/rural-700mhz.yaml +1 -1
  43. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/scenarios/cards/suburban-sma-7ghz.yaml +1 -1
  44. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab.egg-info/PKG-INFO +66 -18
  45. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab.egg-info/SOURCES.txt +17 -0
  46. handoverlab-2.4.2/tools/make_buffers_figure.py +107 -0
  47. handoverlab-2.4.2/tools/make_dashboard_screenshots.py +219 -0
  48. handoverlab-2.4.2/tools/make_dc_figure.py +127 -0
  49. handoverlab-2.4.2/tools/make_fading_figure.py +127 -0
  50. handoverlab-2.4.2/tools/make_mro_figure.py +135 -0
  51. handoverlab-2.4.2/tools/make_procedures_figure.py +107 -0
  52. handoverlab-2.4.2/tools/make_scheduler_figure.py +138 -0
  53. handoverlab-2.4.2/tools/make_traffic_figure.py +84 -0
  54. handoverlab-2.4.2/tools/make_ue_beams_figure.py +123 -0
  55. handoverlab-2.4.1/docs/images/dashboard-charts.png +0 -0
  56. handoverlab-2.4.1/docs/images/dashboard-compare.png +0 -0
  57. handoverlab-2.4.1/docs/images/dashboard-where.png +0 -0
  58. handoverlab-2.4.1/docs/images/dashboard.png +0 -0
  59. {handoverlab-2.4.1 → handoverlab-2.4.2}/.zenodo.json +0 -0
  60. {handoverlab-2.4.1 → handoverlab-2.4.2}/CODE_OF_CONDUCT.md +0 -0
  61. {handoverlab-2.4.1 → handoverlab-2.4.2}/CONTRIBUTING.md +0 -0
  62. {handoverlab-2.4.1 → handoverlab-2.4.2}/LICENSE +0 -0
  63. {handoverlab-2.4.1 → handoverlab-2.4.2}/MANIFEST.in +0 -0
  64. {handoverlab-2.4.1 → handoverlab-2.4.2}/SECURITY.md +0 -0
  65. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/RELEASING.md +0 -0
  66. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/calibration.md +0 -0
  67. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/add-scenario.md +0 -0
  68. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/ai-mobility.md +0 -0
  69. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/dashboard.md +0 -0
  70. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/export-event-logs.md +0 -0
  71. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/high-speed-train.md +0 -0
  72. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/highway.md +0 -0
  73. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/many-cores.md +0 -0
  74. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/ntn.md +0 -0
  75. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/radio-maps.md +0 -0
  76. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/reproduce.md +0 -0
  77. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/suburban-o2i.md +0 -0
  78. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/guides/upper-mid-band.md +0 -0
  79. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/images/ai-mobility.png +0 -0
  80. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/images/calibration_38901.png +0 -0
  81. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/images/calibration_7ghz.png +0 -0
  82. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/images/new-scenarios.png +0 -0
  83. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/images/ntn-beams.png +0 -0
  84. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/images/radio-map.png +0 -0
  85. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/images/report-comparison.png +0 -0
  86. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/images/report-tuning.png +0 -0
  87. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/images/ssb-beams.png +0 -0
  88. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/migration-2.0.md +0 -0
  89. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/api/config.md +0 -0
  90. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/api/engine.md +0 -0
  91. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/api/eventlog.md +0 -0
  92. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/api/gui.md +0 -0
  93. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/api/index.md +0 -0
  94. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/api/mapfile.md +0 -0
  95. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/api/ntn.md +0 -0
  96. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/api/rules.md +0 -0
  97. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/api/scenarios.md +0 -0
  98. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/api/simulate.md +0 -0
  99. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/api/stability.md +0 -0
  100. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/api/stats.md +0 -0
  101. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/api/studies.md +0 -0
  102. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/api/testing.md +0 -0
  103. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/api/verify.md +0 -0
  104. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/cli.md +0 -0
  105. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference/metrics.md +0 -0
  106. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/reference-study.md +0 -0
  107. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/dense-urban-2layer.md +0 -0
  108. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/dense-urban-2layer.svg +0 -0
  109. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/fr3-urban-15ghz.md +0 -0
  110. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/fr3-urban-15ghz.svg +0 -0
  111. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/highway-tr37885-30ghz.md +0 -0
  112. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/highway-tr37885-30ghz.svg +0 -0
  113. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/highway-tr37885-4ghz.md +0 -0
  114. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/highway-tr37885-4ghz.svg +0 -0
  115. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/hst-fr2-28ghz.md +0 -0
  116. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/hst-fr2-28ghz.svg +0 -0
  117. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/indoor-office-4ghz.svg +0 -0
  118. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/ns3-urban-3.5ghz.md +0 -0
  119. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/ns3-urban-3.5ghz.svg +0 -0
  120. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/ntn-leo600-2ghz.md +0 -0
  121. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/ntn-leo600-2ghz.svg +0 -0
  122. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/open-area-10ghz.md +0 -0
  123. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/open-area-10ghz.svg +0 -0
  124. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/rural-700mhz.svg +0 -0
  125. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/smoke.md +0 -0
  126. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/smoke.svg +0 -0
  127. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/suburban-sma-7ghz.svg +0 -0
  128. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/urban-grid-10ghz.md +0 -0
  129. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/urban-grid-10ghz.svg +0 -0
  130. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/urban-grid-28ghz-beams.md +0 -0
  131. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/urban-grid-28ghz-beams.svg +0 -0
  132. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/urban-macro-tr37885-4ghz.md +0 -0
  133. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/scenarios/urban-macro-tr37885-4ghz.svg +0 -0
  134. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/time-step.md +0 -0
  135. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/tutorials/first-run.md +0 -0
  136. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/tutorials/reading-the-report.md +0 -0
  137. {handoverlab-2.4.1 → handoverlab-2.4.2}/docs/verification.md +0 -0
  138. {handoverlab-2.4.1 → handoverlab-2.4.2}/examples/compare_a3_cho.py +0 -0
  139. {handoverlab-2.4.1 → handoverlab-2.4.2}/examples/open_area.toml +0 -0
  140. {handoverlab-2.4.1 → handoverlab-2.4.2}/examples/radio_map.py +0 -0
  141. {handoverlab-2.4.1 → handoverlab-2.4.2}/examples/smoke.yaml +0 -0
  142. {handoverlab-2.4.1 → handoverlab-2.4.2}/examples/speed_rule.py +0 -0
  143. {handoverlab-2.4.1 → handoverlab-2.4.2}/examples/street_grid.yaml +0 -0
  144. {handoverlab-2.4.1 → handoverlab-2.4.2}/examples/study_reference.yaml +0 -0
  145. {handoverlab-2.4.1 → handoverlab-2.4.2}/examples/study_reference_explore.yaml +0 -0
  146. {handoverlab-2.4.1 → handoverlab-2.4.2}/examples/study_smoke.yaml +0 -0
  147. {handoverlab-2.4.1 → handoverlab-2.4.2}/examples/traffic_models.py +0 -0
  148. {handoverlab-2.4.1 → handoverlab-2.4.2}/mkdocs.yml +0 -0
  149. {handoverlab-2.4.1 → handoverlab-2.4.2}/setup.cfg +0 -0
  150. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/__main__.py +0 -0
  151. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/channel/__init__.py +0 -0
  152. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/channel/antenna.py +0 -0
  153. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/channel/extended.py +0 -0
  154. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/channel/fading.py +0 -0
  155. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/channel/l2s.py +0 -0
  156. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/channel/ntn.py +0 -0
  157. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/channel/pathloss.py +0 -0
  158. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/channel/radiomap.py +0 -0
  159. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/channel/source.py +0 -0
  160. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/cli.py +0 -0
  161. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/config.py +0 -0
  162. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/engine/__init__.py +0 -0
  163. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/engine/_kernels.py +0 -0
  164. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/engine/batch.py +0 -0
  165. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/engine/buffers.py +0 -0
  166. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/engine/core.py +0 -0
  167. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/engine/dual.py +0 -0
  168. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/engine/extended.py +0 -0
  169. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/engine/invariants.py +0 -0
  170. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/engine/metrics.py +0 -0
  171. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/engine/procedures.py +0 -0
  172. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/engine/scheduler.py +0 -0
  173. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/eventlog.py +0 -0
  174. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/gui/__init__.py +0 -0
  175. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/gui/app.py +0 -0
  176. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/gui/logic.py +0 -0
  177. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/io.py +0 -0
  178. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/layout.py +0 -0
  179. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/linklevel.py +0 -0
  180. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/mapfile.py +0 -0
  181. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/measurement.py +0 -0
  182. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/mobility.py +0 -0
  183. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/py.typed +0 -0
  184. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/requirements.py +0 -0
  185. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/rules/__init__.py +0 -0
  186. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/rules/base.py +0 -0
  187. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/rules/builtin.py +0 -0
  188. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/rules/dqn.py +0 -0
  189. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/rules/mro.py +0 -0
  190. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/rules/predict.py +0 -0
  191. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/scenarios/__init__.py +0 -0
  192. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/scenarios/cards/dense-urban-2layer.yaml +0 -0
  193. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/scenarios/cards/fr3-urban-15ghz.yaml +0 -0
  194. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/scenarios/cards/highway-tr37885-30ghz.yaml +0 -0
  195. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/scenarios/cards/highway-tr37885-4ghz.yaml +0 -0
  196. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/scenarios/cards/hst-fr2-28ghz.yaml +0 -0
  197. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/scenarios/cards/ns3-urban-3.5ghz.yaml +0 -0
  198. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/scenarios/cards/ntn-leo600-2ghz.yaml +0 -0
  199. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/scenarios/cards/open-area-10ghz.yaml +0 -0
  200. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/scenarios/cards/smoke.yaml +0 -0
  201. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/scenarios/cards/urban-grid-10ghz.yaml +0 -0
  202. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/scenarios/cards/urban-grid-28ghz-beams.yaml +0 -0
  203. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/scenarios/cards/urban-macro-tr37885-4ghz.yaml +0 -0
  204. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/seeds.py +0 -0
  205. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/simulate.py +0 -0
  206. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/stability.py +0 -0
  207. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/standard.py +0 -0
  208. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/stats.py +0 -0
  209. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/studies/__init__.py +0 -0
  210. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/studies/config.py +0 -0
  211. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/studies/report.py +0 -0
  212. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/studies/runner.py +0 -0
  213. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/studies/status.py +0 -0
  214. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/studies/store.py +0 -0
  215. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/studies/study.py +0 -0
  216. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/studies/tuning.py +0 -0
  217. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/testing.py +0 -0
  218. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/traffic.py +0 -0
  219. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/__init__.py +0 -0
  220. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/aimobility.py +0 -0
  221. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/calibration.py +0 -0
  222. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/data/golden.json +0 -0
  223. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/data/golden_1x.json +0 -0
  224. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/data/ns3_urban_a3.json +0 -0
  225. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/data/r1_165974.csv +0 -0
  226. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/data/r1_2506406.csv +0 -0
  227. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/engine_checks.py +0 -0
  228. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/extended.py +0 -0
  229. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/fading.py +0 -0
  230. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/golden.py +0 -0
  231. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/highway.py +0 -0
  232. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/learning.py +0 -0
  233. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/ns3.py +0 -0
  234. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/ntn.py +0 -0
  235. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/radio.py +0 -0
  236. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/report.py +0 -0
  237. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/scenarios.py +0 -0
  238. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/stored.py +0 -0
  239. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/verify/values.py +0 -0
  240. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab/world.py +0 -0
  241. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab.egg-info/dependency_links.txt +0 -0
  242. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab.egg-info/entry_points.txt +0 -0
  243. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab.egg-info/requires.txt +0 -0
  244. {handoverlab-2.4.1 → handoverlab-2.4.2}/src/handoverlab.egg-info/top_level.txt +0 -0
  245. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/conftest.py +0 -0
  246. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/data/bh6_reference.json +0 -0
  247. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/data/bh6_wide.json +0 -0
  248. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/data/make_bh6_reference.py +0 -0
  249. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/data/make_bh6_wide.py +0 -0
  250. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/data/public_api.json +0 -0
  251. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/helpers.py +0 -0
  252. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_ai_mobility.py +0 -0
  253. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_batch.py +0 -0
  254. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_beams_layers.py +0 -0
  255. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_buffers.py +0 -0
  256. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_calibration.py +0 -0
  257. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_channel_detail.py +0 -0
  258. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_cltm.py +0 -0
  259. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_config_cli.py +0 -0
  260. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_contract.py +0 -0
  261. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_determinism.py +0 -0
  262. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_dqn.py +0 -0
  263. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_engine_triggers.py +0 -0
  264. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_eventlog.py +0 -0
  265. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_fading.py +0 -0
  266. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_gui.py +0 -0
  267. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_highway.py +0 -0
  268. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_highway_tr37885.py +0 -0
  269. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_hst_dc.py +0 -0
  270. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_indoor_rural.py +0 -0
  271. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_invariants.py +0 -0
  272. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_levels_status_extend.py +0 -0
  273. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_lm_model.py +0 -0
  274. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_mapfile.py +0 -0
  275. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_measurement.py +0 -0
  276. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_mro.py +0 -0
  277. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_ntn.py +0 -0
  278. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_pathloss.py +0 -0
  279. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_protocol_3gpp.py +0 -0
  280. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_readme_boundaries.py +0 -0
  281. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_regression_bh6.py +0 -0
  282. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_regression_bh6_wide.py +0 -0
  283. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_rrc_detail.py +0 -0
  284. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_rules_rc2.py +0 -0
  285. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_scenarios.py +0 -0
  286. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_scenarios_230.py +0 -0
  287. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_sched_kernel.py +0 -0
  288. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_scheduler.py +0 -0
  289. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_signalling_energy.py +0 -0
  290. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_stability.py +0 -0
  291. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_stats.py +0 -0
  292. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_study.py +0 -0
  293. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_tools.py +0 -0
  294. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_traffic.py +0 -0
  295. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_tuning.py +0 -0
  296. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_ue_beams.py +0 -0
  297. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_v111.py +0 -0
  298. {handoverlab-2.4.1 → handoverlab-2.4.2}/tests/test_verify.py +0 -0
  299. {handoverlab-2.4.1 → handoverlab-2.4.2}/tools/compare_fingerprints.py +0 -0
  300. {handoverlab-2.4.1 → handoverlab-2.4.2}/tools/make_ai_mobility_figure.py +0 -0
  301. {handoverlab-2.4.1 → handoverlab-2.4.2}/tools/make_beam_figure.py +0 -0
  302. {handoverlab-2.4.1 → handoverlab-2.4.2}/tools/make_calibration_7ghz_figure.py +0 -0
  303. {handoverlab-2.4.1 → handoverlab-2.4.2}/tools/make_calibration_figure.py +0 -0
  304. {handoverlab-2.4.1 → handoverlab-2.4.2}/tools/make_ntn_figure.py +0 -0
  305. {handoverlab-2.4.1 → handoverlab-2.4.2}/tools/make_radiomap_figure.py +0 -0
  306. {handoverlab-2.4.1 → handoverlab-2.4.2}/tools/make_readme_images.py +0 -0
  307. {handoverlab-2.4.1 → handoverlab-2.4.2}/tools/make_scenarios_figure.py +0 -0
  308. {handoverlab-2.4.1 → handoverlab-2.4.2}/tools/mkdocs_hooks.py +0 -0
  309. {handoverlab-2.4.1 → handoverlab-2.4.2}/tools/release_check.py +0 -0
@@ -7,6 +7,46 @@ All notable changes to this project are documented in this file. The format foll
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.4.2] - 2026-10-23
11
+
12
+ No change of results.
13
+
14
+ ### Added
15
+
16
+ - A picture for every option, each drawn from a real run by its own script in `tools/`: the handover
17
+ procedures side by side (`procedures.png`), mobility robustness optimisation (`mro.png`), fast fading
18
+ (`fading.png`), the slot scheduler with the Numba timings (`scheduler.png`), buffers at handover
19
+ (`buffers.png`), dual connectivity (`dual-connectivity.png`), UE receive beams (`ue-beams.png`) and the
20
+ traffic models (`traffic.png`); shown in the README and in each guide.
21
+ - `tools/make_dashboard_screenshots.py`: the dashboard screenshots taken with Edge through the DevTools
22
+ protocol; all four dashboard pictures redone with this version.
23
+
24
+ ### Fixed
25
+
26
+ - The speed-ups stated for 2.4.0 ("8 to 60" times, "50-80" times the rate model) were not all supported by the
27
+ measurements: `docs/performance.md` gives 23 to 59 times for the Numba scheduler and, measured again for 2.4.2
28
+ on the configuration of the scheduler picture, 42 (round robin) and 93 times (proportional fair), with the
29
+ NumPy scheduler about 91 times the rate model. The README, `docs/comparison.md`, the scheduler and fading guides
30
+ and `docs/performance.md` now give these measured numbers.
31
+
32
+ ### Documentation
33
+
34
+ - 7 GHz calibration: README, `docs/comparison.md`, `docs/calibration-3gpp.md` and
35
+ `docs/standard-compliance.md` say which cases they count (at 7 GHz 228 percentiles, largest distance
36
+ 1.69-2.43 dB; with the two 6 GHz reruns 342 percentiles, 1.65-2.88 dB).
37
+ - README model boundaries: the slot scheduler (2.2.0) and the user-plane buffers (2.3.0) listed as options,
38
+ with what is still not modelled.
39
+ - Scenario cards `suburban-sma-7ghz`, `rural-700mhz` and `indoor-office-4ghz`: the 7 GHz calibration of 2.4.0
40
+ and the hard-LOS results of `docs/guides/indoor-rural.md`; scenario pages regenerated.
41
+ - Examples rerun with this version and their numbers, and where needed their conclusions, updated: the guides
42
+ on buffers, MRO (the faster MRO setting is no better), beams and layers, indoor and rural scenarios, the
43
+ learning rule and fast fading; tutorial 2; the README traffic table; the `status` example in the user guide.
44
+ - User guide: all 15 cards, the `a3_pred` rule, `ttt_d2_s`, the layout kinds `indoor` and `ntn`, `run.backend`
45
+ under `run`, `ntn.hpbw_deg` (tabled widths at 2 GHz only), `ntn.los_model` and `radio.vegetation`; the study
46
+ example with a main guard. `docs/index.md`: the current layouts and cards. `docs/stability.md`: the missing
47
+ import. Tutorial 3: the cap of four extensions dates from 2.4.1.
48
+ - Citation with the DOI of 2.4.1.
49
+
10
50
  ## [2.4.1] - 2026-10-22
11
51
 
12
52
  No change of results.
@@ -1080,7 +1120,8 @@ First alpha release (stage 1: the core simulator).
1080
1120
  - Documentation: README, user guide, contribution guide, citation file; CI on Linux, Windows and
1081
1121
  macOS with Python 3.9-3.12.
1082
1122
 
1083
- [Unreleased]: https://github.com/mjs19971997/handoverlab/compare/v2.4.1...HEAD
1123
+ [Unreleased]: https://github.com/mjs19971997/handoverlab/compare/v2.4.2...HEAD
1124
+ [2.4.2]: https://github.com/mjs19971997/handoverlab/compare/v2.4.1...v2.4.2
1084
1125
  [2.4.1]: https://github.com/mjs19971997/handoverlab/compare/v2.4.0...v2.4.1
1085
1126
  [2.4.0]: https://github.com/mjs19971997/handoverlab/compare/v2.3.0...v2.4.0
1086
1127
  [2.3.0]: https://github.com/mjs19971997/handoverlab/compare/v2.2.0...v2.3.0
@@ -14,7 +14,7 @@ abstract: >-
14
14
  handover rules (including a measurement-prediction rule after TR 38.744), equal-budget tuning
15
15
  studies with paired statistics, and verification against hand-computed values, golden event-log
16
16
  fingerprints, the 3GPP large-scale calibration and ns-3 / 5G-LENA.
17
- version: "2.4.1"
17
+ version: "2.4.2"
18
18
  doi: 10.5281/zenodo.23409131
19
19
  identifiers:
20
20
  - type: doi
@@ -29,7 +29,10 @@ identifiers:
29
29
  - type: doi
30
30
  value: 10.5281/zenodo.23582521
31
31
  description: "Version 2.4.0 on Zenodo"
32
- date-released: 2026-10-22
32
+ - type: doi
33
+ value: 10.5281/zenodo.23585308
34
+ description: "Version 2.4.1 on Zenodo"
35
+ date-released: 2026-10-23
33
36
  license: MIT
34
37
  repository-code: "https://github.com/mjs19971997/handoverlab"
35
38
  url: "https://mjs19971997.github.io/handoverlab/"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: handoverlab
3
- Version: 2.4.1
3
+ Version: 2.4.2
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
@@ -70,7 +70,7 @@ received-power-level radio model from TR 38.901 (TR 38.811 for the satellite) (o
70
70
  and several carriers), an L3-filtered measurement chain, a radio-link failure model, and an
71
71
  outcome label for every handover attempt.
72
72
 
73
- > **Status: 2.4.1** (`python -m pip install handoverlab`). The public surface (configuration and
73
+ > **Status: 2.4.2** (`python -m pip install handoverlab`). The public surface (configuration and
74
74
  > result formats with a schema version, the rule interface, metric names, commands and the
75
75
  > documented Python names) follows the [stability policy](https://github.com/mjs19971997/handoverlab/blob/main/docs/stability.md): within 2.x it only grows,
76
76
  > and anything removed is deprecated first. 2.0.0 makes the 3GPP values the defaults (the protocol profile,
@@ -150,6 +150,47 @@ accurate than sample and hold 400 ms ahead (1.84 / 2.66 / 3.14 dB against 2.38 /
150
150
 
151
151
  ![Prediction error against horizon for the ridge predictor and sample and hold at 30, 60 and 90 km/h](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/ai-mobility.png)
152
152
 
153
+ **Handover procedures side by side.** On one card failures fall from 0.6 (A3) to 0.2 (LTM and CLTM) per
154
+ UE-minute; DAPS has no execution interruption; LTM pays with 192 RRC messages per UE-minute against 45 for A3:
155
+
156
+ ![Failures and ping-pong, interruption and RRC messages for A3, CHO, DAPS, LTM and CLTM](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/procedures.png)
157
+
158
+ **Mobility robustness optimisation.** `a3_mro` moves the offset of every cell pair from its own failures;
159
+ here 17 pairs move and failures fall from 0.22 to 0.14 per UE-minute when starting from 3 dB:
160
+
161
+ ![Cell-pair offsets over time under a3_mro, and failures against fixed A3](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/mro.png)
162
+
163
+ **Fast fading.** With TDL-A or TDL-C the 5th percentile of the link-monitoring SINR on the ns-3 card falls
164
+ from 8.3 dB to 3.8 and 3.4 dB:
165
+
166
+ ![Received power of one vehicle with no fading, TDL-A and TDL-C, and the distribution of the link-monitoring SINR](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/fading.png)
167
+
168
+ **Slot scheduler.** Round robin and proportional fair with the MCS, TBS and HARQ of TS 38.214; with
169
+ `run.backend: numba` the same runs take 2.2 s and 1.0 s instead of 92.7 s and 93.3 s with NumPy, with identical
170
+ fingerprints (the default rate model takes about 1.0 s for the same run):
171
+
172
+ ![Delivered rate of each vehicle against its SINR for round robin and proportional fair, and the wall time with NumPy and Numba](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/scheduler.png)
173
+
174
+ **Buffers at handover.** Without data forwarding A3 loses 2.17 % of the data and DAPS 0.34 %; with
175
+ forwarding nothing is lost, and the forwarded data wait 85-349 ms:
176
+
177
+ ![Lost data with and without forwarding, and the PDCP delay, for A3, CHO, DAPS and LTM](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/buffers.png)
178
+
179
+ **Dual connectivity.** A 4 GHz master cell and a 30 GHz secondary cell: the secondary cell group carries data
180
+ 96 % of the time and 183 Mbit/s per user, against 10.1 Mbit/s on the master cell group:
181
+
182
+ ![One user's 4 GHz master cell and 30 GHz secondary cell over time with the dual-connectivity events, and the procedure rates](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/dual-connectivity.png)
183
+
184
+ **UE receive beams.** Two panels with DFT beams (peak gain 13.7 dBi) raise the mean SINR from 10.9 to 19.2 dB
185
+ and cut failures from 3.60 to 1.44 per UE-minute; a beam sweep keeps them at 3.36:
186
+
187
+ ![Receive beam patterns of a two-panel UE, and SINR and failures for four UE receive-beam setups](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/ue-beams.png)
188
+
189
+ **Traffic models.** The same handovers (11.3 per UE-minute) under fixed rates, full buffer, periodic packets and FTP model 3,
190
+ with very different rate, cell load and energy per bit:
191
+
192
+ ![Rate, cell load and energy per bit for the four traffic models](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/traffic.png)
193
+
153
194
  ## What it models
154
195
 
155
196
  - **Scenarios**: the TR 37.885 urban street grid (configurable number of blocks; 433 m x 250 m
@@ -213,7 +254,7 @@ the clause-by-clause detail is in [standard compliance](https://github.com/mjs19
213
254
  | Channel | TR 38.901 path loss and LOS (UMi, UMa, RMa, SMa, InH), LOS from buildings, spatially consistent LOS and shadowing, car and O2I building 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; indoor users keep the LOS state and shadowing of their position; 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 |
214
255
  | Beams and carriers | SSB beams per sector, cell quality from beams, beam failure detection and recovery, several carriers with gaps and Event A5; dual connectivity (NR-DC: SN addition, PSCell change, SN release, SCG failure; option since 2.3.0) | the TR 38.901 antenna element and DFT beams; isotropic UE unless UE receive panels are set (option since 2.4.0); the SCG as one PSCell with a full-buffer share | UE transmit beams and polarisation, conditional PSCell change, fast MCG recovery |
215
256
  | Mobility | street-following vehicles (60 km/h, two lanes), highway lanes at 70/140 km/h, a train at 350 km/h (TR 38.854), random waypoints, pedestrians | constant speed per user | handheld rotation and body blockage |
216
- | 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 |
257
+ | Traffic and load | constant rates per 5QI, full buffer, periodic, FTP model 3; cell load drives interference; options: a slot scheduler (`protocol.scheduler`: round robin or proportional fair) with the MCS, TBS and HARQ of TS 38.214 (since 2.2.0), and user-plane buffers at handover (`protocol.buffers`: simplified PDCP / RLC in AM or UM with Xn data forwarding, since 2.3.0) | by default the rate from the SINR (Shannon-type mapping) without a scheduler; with the scheduler the channel is held for the 10 ms step and the MCS is chosen from the SINR of one measurement interval earlier (no CSI reports); buffers: downlink only, one bearer per user, the interruption quantised to the measurement interval; both options need the base engine (no beams, layers, NTN or TS 38.133 periods) | uplink data, CSI-based link adaptation, PDCP reordering and status reports at the UE, TCP and applications |
217
258
  | Measurements | L1 samples with error, TS 38.331 L3 filter, TS 38.133 measurement periods and gaps (option) | wideband RSRP; SS-RSRP per resource element with beams/carriers | RSRQ, CSI reporting |
218
259
  | Procedures | baseline (A3), CHO, DAPS, LTM, conditional LTM, CHO with D1/D2 for satellites, A3/A5 between carriers; rules `a3`, `a3a5`, `a3_mro`, `a3_bandit`, `dqn`, `a3_pred`, `cho`, `cho_d2`, `daps`, `ltm`, `cltm` | fixed preparation, command and execution delays; re-establishment always succeeds after a fixed outage | condEventT1, RACH-less NTN handover, Xn signalling in detail |
219
260
  | Failure model | Qout/Qin with windows, N310/N311/T310, T304, command received during T310, re-establishment, link-monitoring restart | Qout/Qin as SINR thresholds (TR 36.839 values) instead of the BLER of a hypothetical PDCCH | BLER-based link monitoring; absolute failure rates are not calibrated: compare rules with each other |
@@ -254,8 +295,10 @@ Ericsson, Nokia, Samsung, Qualcomm and others), for UMa, UMi and the indoor offi
254
295
  30 GHz. 325 of 342 compared percentiles are inside the range, none is more than about 1 dB from
255
296
  the industry mean, and `handoverlab verify` repeats the check
256
297
  ([details](https://github.com/mjs19971997/handoverlab/blob/main/docs/calibration-3gpp.md)). Since 2.4.0 the
257
- same check runs at 7 GHz (Table 7.8-1A) against the companies of R1-2506406: all 342 percentiles lie inside
258
- their range, but 1.65-2.88 dB from their mean, which misses the 1.5 dB criterion set before the run.
298
+ same check runs for Table 7.8-1A against the companies of R1-2506406. At 7 GHz (UMa, UMi and SMa with ISD
299
+ 1299 m and 1732 m) all 228 percentiles lie inside their range, but the largest distance from their mean is
300
+ 1.69-2.43 dB, which misses the 1.5 dB criterion set before the run; the two 6 GHz reruns of UMa and UMi with
301
+ the updated model add 114 percentiles, also all inside, at 1.65 and 2.88 dB.
259
302
 
260
303
  ![CDFs of coupling loss and geometry for UMa, UMi and SMa at 7 GHz, with the HandoverLab curve inside the company range of R1-2506406](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/calibration_7ghz.png)
261
304
 
@@ -304,8 +347,8 @@ L1/L2-triggered mobility.
304
347
 
305
348
  - **2.4.0**: UE receive beams (panels of TR 38.802, best beam or a sweep); a measurement-prediction rule after
306
349
  TR 38.744 (`a3_pred`: predicted Event A3 or measurement skipping, sample and hold or a trained ridge
307
- predictor); the slot scheduler as a compiled kernel (`run.backend: numba`, bit-identical, 8-60 times
308
- faster); the 7 GHz large-scale calibration against the companies of R1-2506406 (every percentile inside the
350
+ predictor); the slot scheduler as a compiled kernel (`run.backend: numba`, bit-identical; on the ns-3 card
351
+ 42 times (`rr`) and 93 times (`pf`) faster than the NumPy loop); the 7 GHz large-scale calibration against the companies of R1-2506406 (every percentile inside the
309
352
  range, the distance to the mean criterion missed); a [comparison with other simulators](https://github.com/mjs19971997/handoverlab/blob/main/docs/comparison.md).
310
353
  - **2.3.0**: user-plane buffers at handover (PDCP / RLC, Xn data forwarding for baseline, conditional, DAPS and
311
354
  L1/L2-triggered handover); the TR 37.885 urban macro grid, suburban macro (SMa) and O2I penetration of indoor
@@ -436,13 +479,13 @@ traffic models (one seed, 30 users, 60 s on the urban grid at 10 GHz):
436
479
 
437
480
  ```text
438
481
  model cell load rate [Mbit/s] delivered SINR [dB] failures/UE-min
439
- fixed 0.28 14.25 0.98 24.3 0.12
440
- full_buffer 0.52 725.93 0.49 21.9 0.08
441
- periodic 0.28 0.04 0.80 24.4 0.12
442
- ftp3 0.28 3.93 0.85 24.4 0.12
482
+ fixed 0.28 14.10 0.97 23.6 0.08
483
+ full_buffer 0.52 717.77 0.48 21.2 0.08
484
+ periodic 0.28 0.04 0.86 23.7 0.08
485
+ ftp3 0.28 3.93 0.87 23.7 0.08
443
486
  ```
444
487
 
445
- Busier cells interfere more: under full buffer the SINR drops by about 2.5 dB. With one seed each
488
+ Busier cells interfere more: under full buffer the SINR drops by about 2.4 dB. With one seed each
446
489
  failure rate counts only a few failures; compare them over several seeds.
447
490
 
448
491
  The full script is [examples/compare_a3_cho.py](https://github.com/mjs19971997/handoverlab/blob/main/examples/compare_a3_cho.py). Writing your own
@@ -524,9 +567,11 @@ the pages are plain Markdown in [docs/](https://github.com/mjs19971997/handoverl
524
567
  25. 2.3.0: buffers at handover, urban macro, SMa and O2I, the high-speed train, dual connectivity.
525
568
  26. 2.4.0: UE receive beams, the TR 38.744 prediction rule, the compiled
526
569
  scheduler, the 7 GHz calibration and the comparison with other simulators.
527
- 27. **2.4.1 (this release)**: pictures, citation and tutorials brought up to date; the example study
570
+ 27. 2.4.1: pictures, citation and tutorials brought up to date; the example study
528
571
  completes again; no change of results.
529
- 28. Later (planned, not done), staying a handover simulator: the effect of a handover on what the user
572
+ 28. **2.4.2 (this release)**: every option has a picture; the dashboard pictures show the current version;
573
+ guide and tutorial examples rerun; facts made consistent; no change of results.
574
+ 29. Later (planned, not done), staying a handover simulator: the effect of a handover on what the user
530
575
  sees (simple TCP and application models on top of the buffers), MIMO as an SINR gain, hundreds of
531
576
  users per run, and one scenario definition that also runs in ns-3; condEventT1 and earth-fixed beams.
532
577
 
@@ -535,8 +580,11 @@ the pages are plain Markdown in [docs/](https://github.com/mjs19971997/handoverl
535
580
  If you use HandoverLab, please cite it as described in [CITATION.cff](https://github.com/mjs19971997/handoverlab/blob/main/CITATION.cff) (GitHub shows
536
581
  it under *Cite this repository*). Every release is archived on Zenodo:
537
582
  [doi:10.5281/zenodo.23409131](https://doi.org/10.5281/zenodo.23409131) cites all versions (it resolves to
538
- the latest). To cite the exact version you used, take its DOI from the version list on that page; version
539
- 2.4.0 is [doi:10.5281/zenodo.23582521](https://doi.org/10.5281/zenodo.23582521).
583
+ the latest). To cite the exact version you used, take its DOI from the version list on that page, where
584
+ the DOI of the latest version is listed; for example, version 2.4.1 is
585
+ [doi:10.5281/zenodo.23585308](https://doi.org/10.5281/zenodo.23585308) and version 2.4.0
586
+ [doi:10.5281/zenodo.23582521](https://doi.org/10.5281/zenodo.23582521). The BibTeX entry below cites 2.4.1;
587
+ replace version and DOI with those of the version you used.
540
588
 
541
589
  ```bibtex
542
590
  @software{handoverlab,
@@ -544,8 +592,8 @@ the latest). To cite the exact version you used, take its DOI from the version l
544
592
  title = {{HandoverLab}: system-level handover simulator for 5G-Advanced and beyond-5G research},
545
593
  year = {2026},
546
594
  publisher = {Zenodo},
547
- version = {2.4.0},
548
- doi = {10.5281/zenodo.23582521},
595
+ version = {2.4.1},
596
+ doi = {10.5281/zenodo.23585308},
549
597
  url = {https://github.com/mjs19971997/handoverlab}
550
598
  }
551
599
  ```
@@ -12,7 +12,7 @@ received-power-level radio model from TR 38.901 (TR 38.811 for the satellite) (o
12
12
  and several carriers), an L3-filtered measurement chain, a radio-link failure model, and an
13
13
  outcome label for every handover attempt.
14
14
 
15
- > **Status: 2.4.1** (`python -m pip install handoverlab`). The public surface (configuration and
15
+ > **Status: 2.4.2** (`python -m pip install handoverlab`). The public surface (configuration and
16
16
  > result formats with a schema version, the rule interface, metric names, commands and the
17
17
  > documented Python names) follows the [stability policy](https://github.com/mjs19971997/handoverlab/blob/main/docs/stability.md): within 2.x it only grows,
18
18
  > and anything removed is deprecated first. 2.0.0 makes the 3GPP values the defaults (the protocol profile,
@@ -92,6 +92,47 @@ accurate than sample and hold 400 ms ahead (1.84 / 2.66 / 3.14 dB against 2.38 /
92
92
 
93
93
  ![Prediction error against horizon for the ridge predictor and sample and hold at 30, 60 and 90 km/h](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/ai-mobility.png)
94
94
 
95
+ **Handover procedures side by side.** On one card failures fall from 0.6 (A3) to 0.2 (LTM and CLTM) per
96
+ UE-minute; DAPS has no execution interruption; LTM pays with 192 RRC messages per UE-minute against 45 for A3:
97
+
98
+ ![Failures and ping-pong, interruption and RRC messages for A3, CHO, DAPS, LTM and CLTM](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/procedures.png)
99
+
100
+ **Mobility robustness optimisation.** `a3_mro` moves the offset of every cell pair from its own failures;
101
+ here 17 pairs move and failures fall from 0.22 to 0.14 per UE-minute when starting from 3 dB:
102
+
103
+ ![Cell-pair offsets over time under a3_mro, and failures against fixed A3](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/mro.png)
104
+
105
+ **Fast fading.** With TDL-A or TDL-C the 5th percentile of the link-monitoring SINR on the ns-3 card falls
106
+ from 8.3 dB to 3.8 and 3.4 dB:
107
+
108
+ ![Received power of one vehicle with no fading, TDL-A and TDL-C, and the distribution of the link-monitoring SINR](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/fading.png)
109
+
110
+ **Slot scheduler.** Round robin and proportional fair with the MCS, TBS and HARQ of TS 38.214; with
111
+ `run.backend: numba` the same runs take 2.2 s and 1.0 s instead of 92.7 s and 93.3 s with NumPy, with identical
112
+ fingerprints (the default rate model takes about 1.0 s for the same run):
113
+
114
+ ![Delivered rate of each vehicle against its SINR for round robin and proportional fair, and the wall time with NumPy and Numba](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/scheduler.png)
115
+
116
+ **Buffers at handover.** Without data forwarding A3 loses 2.17 % of the data and DAPS 0.34 %; with
117
+ forwarding nothing is lost, and the forwarded data wait 85-349 ms:
118
+
119
+ ![Lost data with and without forwarding, and the PDCP delay, for A3, CHO, DAPS and LTM](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/buffers.png)
120
+
121
+ **Dual connectivity.** A 4 GHz master cell and a 30 GHz secondary cell: the secondary cell group carries data
122
+ 96 % of the time and 183 Mbit/s per user, against 10.1 Mbit/s on the master cell group:
123
+
124
+ ![One user's 4 GHz master cell and 30 GHz secondary cell over time with the dual-connectivity events, and the procedure rates](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/dual-connectivity.png)
125
+
126
+ **UE receive beams.** Two panels with DFT beams (peak gain 13.7 dBi) raise the mean SINR from 10.9 to 19.2 dB
127
+ and cut failures from 3.60 to 1.44 per UE-minute; a beam sweep keeps them at 3.36:
128
+
129
+ ![Receive beam patterns of a two-panel UE, and SINR and failures for four UE receive-beam setups](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/ue-beams.png)
130
+
131
+ **Traffic models.** The same handovers (11.3 per UE-minute) under fixed rates, full buffer, periodic packets and FTP model 3,
132
+ with very different rate, cell load and energy per bit:
133
+
134
+ ![Rate, cell load and energy per bit for the four traffic models](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/traffic.png)
135
+
95
136
  ## What it models
96
137
 
97
138
  - **Scenarios**: the TR 37.885 urban street grid (configurable number of blocks; 433 m x 250 m
@@ -155,7 +196,7 @@ the clause-by-clause detail is in [standard compliance](https://github.com/mjs19
155
196
  | Channel | TR 38.901 path loss and LOS (UMi, UMa, RMa, SMa, InH), LOS from buildings, spatially consistent LOS and shadowing, car and O2I building 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; indoor users keep the LOS state and shadowing of their position; 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 |
156
197
  | Beams and carriers | SSB beams per sector, cell quality from beams, beam failure detection and recovery, several carriers with gaps and Event A5; dual connectivity (NR-DC: SN addition, PSCell change, SN release, SCG failure; option since 2.3.0) | the TR 38.901 antenna element and DFT beams; isotropic UE unless UE receive panels are set (option since 2.4.0); the SCG as one PSCell with a full-buffer share | UE transmit beams and polarisation, conditional PSCell change, fast MCG recovery |
157
198
  | Mobility | street-following vehicles (60 km/h, two lanes), highway lanes at 70/140 km/h, a train at 350 km/h (TR 38.854), random waypoints, pedestrians | constant speed per user | handheld rotation and body blockage |
158
- | 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 |
199
+ | Traffic and load | constant rates per 5QI, full buffer, periodic, FTP model 3; cell load drives interference; options: a slot scheduler (`protocol.scheduler`: round robin or proportional fair) with the MCS, TBS and HARQ of TS 38.214 (since 2.2.0), and user-plane buffers at handover (`protocol.buffers`: simplified PDCP / RLC in AM or UM with Xn data forwarding, since 2.3.0) | by default the rate from the SINR (Shannon-type mapping) without a scheduler; with the scheduler the channel is held for the 10 ms step and the MCS is chosen from the SINR of one measurement interval earlier (no CSI reports); buffers: downlink only, one bearer per user, the interruption quantised to the measurement interval; both options need the base engine (no beams, layers, NTN or TS 38.133 periods) | uplink data, CSI-based link adaptation, PDCP reordering and status reports at the UE, TCP and applications |
159
200
  | Measurements | L1 samples with error, TS 38.331 L3 filter, TS 38.133 measurement periods and gaps (option) | wideband RSRP; SS-RSRP per resource element with beams/carriers | RSRQ, CSI reporting |
160
201
  | Procedures | baseline (A3), CHO, DAPS, LTM, conditional LTM, CHO with D1/D2 for satellites, A3/A5 between carriers; rules `a3`, `a3a5`, `a3_mro`, `a3_bandit`, `dqn`, `a3_pred`, `cho`, `cho_d2`, `daps`, `ltm`, `cltm` | fixed preparation, command and execution delays; re-establishment always succeeds after a fixed outage | condEventT1, RACH-less NTN handover, Xn signalling in detail |
161
202
  | Failure model | Qout/Qin with windows, N310/N311/T310, T304, command received during T310, re-establishment, link-monitoring restart | Qout/Qin as SINR thresholds (TR 36.839 values) instead of the BLER of a hypothetical PDCCH | BLER-based link monitoring; absolute failure rates are not calibrated: compare rules with each other |
@@ -196,8 +237,10 @@ Ericsson, Nokia, Samsung, Qualcomm and others), for UMa, UMi and the indoor offi
196
237
  30 GHz. 325 of 342 compared percentiles are inside the range, none is more than about 1 dB from
197
238
  the industry mean, and `handoverlab verify` repeats the check
198
239
  ([details](https://github.com/mjs19971997/handoverlab/blob/main/docs/calibration-3gpp.md)). Since 2.4.0 the
199
- same check runs at 7 GHz (Table 7.8-1A) against the companies of R1-2506406: all 342 percentiles lie inside
200
- their range, but 1.65-2.88 dB from their mean, which misses the 1.5 dB criterion set before the run.
240
+ same check runs for Table 7.8-1A against the companies of R1-2506406. At 7 GHz (UMa, UMi and SMa with ISD
241
+ 1299 m and 1732 m) all 228 percentiles lie inside their range, but the largest distance from their mean is
242
+ 1.69-2.43 dB, which misses the 1.5 dB criterion set before the run; the two 6 GHz reruns of UMa and UMi with
243
+ the updated model add 114 percentiles, also all inside, at 1.65 and 2.88 dB.
201
244
 
202
245
  ![CDFs of coupling loss and geometry for UMa, UMi and SMa at 7 GHz, with the HandoverLab curve inside the company range of R1-2506406](https://raw.githubusercontent.com/mjs19971997/handoverlab/main/docs/images/calibration_7ghz.png)
203
246
 
@@ -246,8 +289,8 @@ L1/L2-triggered mobility.
246
289
 
247
290
  - **2.4.0**: UE receive beams (panels of TR 38.802, best beam or a sweep); a measurement-prediction rule after
248
291
  TR 38.744 (`a3_pred`: predicted Event A3 or measurement skipping, sample and hold or a trained ridge
249
- predictor); the slot scheduler as a compiled kernel (`run.backend: numba`, bit-identical, 8-60 times
250
- faster); the 7 GHz large-scale calibration against the companies of R1-2506406 (every percentile inside the
292
+ predictor); the slot scheduler as a compiled kernel (`run.backend: numba`, bit-identical; on the ns-3 card
293
+ 42 times (`rr`) and 93 times (`pf`) faster than the NumPy loop); the 7 GHz large-scale calibration against the companies of R1-2506406 (every percentile inside the
251
294
  range, the distance to the mean criterion missed); a [comparison with other simulators](https://github.com/mjs19971997/handoverlab/blob/main/docs/comparison.md).
252
295
  - **2.3.0**: user-plane buffers at handover (PDCP / RLC, Xn data forwarding for baseline, conditional, DAPS and
253
296
  L1/L2-triggered handover); the TR 37.885 urban macro grid, suburban macro (SMa) and O2I penetration of indoor
@@ -378,13 +421,13 @@ traffic models (one seed, 30 users, 60 s on the urban grid at 10 GHz):
378
421
 
379
422
  ```text
380
423
  model cell load rate [Mbit/s] delivered SINR [dB] failures/UE-min
381
- fixed 0.28 14.25 0.98 24.3 0.12
382
- full_buffer 0.52 725.93 0.49 21.9 0.08
383
- periodic 0.28 0.04 0.80 24.4 0.12
384
- ftp3 0.28 3.93 0.85 24.4 0.12
424
+ fixed 0.28 14.10 0.97 23.6 0.08
425
+ full_buffer 0.52 717.77 0.48 21.2 0.08
426
+ periodic 0.28 0.04 0.86 23.7 0.08
427
+ ftp3 0.28 3.93 0.87 23.7 0.08
385
428
  ```
386
429
 
387
- Busier cells interfere more: under full buffer the SINR drops by about 2.5 dB. With one seed each
430
+ Busier cells interfere more: under full buffer the SINR drops by about 2.4 dB. With one seed each
388
431
  failure rate counts only a few failures; compare them over several seeds.
389
432
 
390
433
  The full script is [examples/compare_a3_cho.py](https://github.com/mjs19971997/handoverlab/blob/main/examples/compare_a3_cho.py). Writing your own
@@ -466,9 +509,11 @@ the pages are plain Markdown in [docs/](https://github.com/mjs19971997/handoverl
466
509
  25. 2.3.0: buffers at handover, urban macro, SMa and O2I, the high-speed train, dual connectivity.
467
510
  26. 2.4.0: UE receive beams, the TR 38.744 prediction rule, the compiled
468
511
  scheduler, the 7 GHz calibration and the comparison with other simulators.
469
- 27. **2.4.1 (this release)**: pictures, citation and tutorials brought up to date; the example study
512
+ 27. 2.4.1: pictures, citation and tutorials brought up to date; the example study
470
513
  completes again; no change of results.
471
- 28. Later (planned, not done), staying a handover simulator: the effect of a handover on what the user
514
+ 28. **2.4.2 (this release)**: every option has a picture; the dashboard pictures show the current version;
515
+ guide and tutorial examples rerun; facts made consistent; no change of results.
516
+ 29. Later (planned, not done), staying a handover simulator: the effect of a handover on what the user
472
517
  sees (simple TCP and application models on top of the buffers), MIMO as an SINR gain, hundreds of
473
518
  users per run, and one scenario definition that also runs in ns-3; condEventT1 and earth-fixed beams.
474
519
 
@@ -477,8 +522,11 @@ the pages are plain Markdown in [docs/](https://github.com/mjs19971997/handoverl
477
522
  If you use HandoverLab, please cite it as described in [CITATION.cff](https://github.com/mjs19971997/handoverlab/blob/main/CITATION.cff) (GitHub shows
478
523
  it under *Cite this repository*). Every release is archived on Zenodo:
479
524
  [doi:10.5281/zenodo.23409131](https://doi.org/10.5281/zenodo.23409131) cites all versions (it resolves to
480
- the latest). To cite the exact version you used, take its DOI from the version list on that page; version
481
- 2.4.0 is [doi:10.5281/zenodo.23582521](https://doi.org/10.5281/zenodo.23582521).
525
+ the latest). To cite the exact version you used, take its DOI from the version list on that page, where
526
+ the DOI of the latest version is listed; for example, version 2.4.1 is
527
+ [doi:10.5281/zenodo.23585308](https://doi.org/10.5281/zenodo.23585308) and version 2.4.0
528
+ [doi:10.5281/zenodo.23582521](https://doi.org/10.5281/zenodo.23582521). The BibTeX entry below cites 2.4.1;
529
+ replace version and DOI with those of the version you used.
482
530
 
483
531
  ```bibtex
484
532
  @software{handoverlab,
@@ -486,8 +534,8 @@ the latest). To cite the exact version you used, take its DOI from the version l
486
534
  title = {{HandoverLab}: system-level handover simulator for 5G-Advanced and beyond-5G research},
487
535
  year = {2026},
488
536
  publisher = {Zenodo},
489
- version = {2.4.0},
490
- doi = {10.5281/zenodo.23582521},
537
+ version = {2.4.1},
538
+ doi = {10.5281/zenodo.23585308},
491
539
  url = {https://github.com/mjs19971997/handoverlab}
492
540
  }
493
541
  ```
@@ -91,8 +91,9 @@ InterDigital and ZTE, "Calibration Results for 7 - 24 GHz SI";
91
91
  `Calibration_LS_v35`, based on TR 38.901 V19.0.0). The criteria were fixed before the first run: every
92
92
  percentile 5-95 % inside the company range widened by 0.5 dB (C1, the rule of the cases above), and the
93
93
  largest distance from the company mean at most 1.5 dB per case (C2). Result, 30 000 users per case, seed 1:
94
- **C1 passes for all 18 case-metric pairs (342 of 342 percentiles strictly inside the range); C2 fails for all
95
- six cases (largest distance 1.65-2.88 dB).** `handoverlab verify` runs C1 as checks and C2 as notes in the
94
+ **C1 passes for all 18 case-metric pairs of the six cases (342 of 342 percentiles strictly inside the range;
95
+ 228 of 228 for the four 7 GHz cases); C2 fails for all six cases (largest distance 1.65-2.88 dB; 1.69-2.43 dB
96
+ for the four 7 GHz cases, 1.65 and 2.88 dB for the two 6 GHz reruns).** `handoverlab verify` runs C1 as checks and C2 as notes in the
96
97
  group `calibration`.
97
98
 
98
99
  **The reference.** `src/handoverlab/verify/data/r1_2506406.csv` keeps, in the format of `r1_165974.csv`, the
@@ -41,7 +41,7 @@ Tools compared (latest release found on 2026-10-22):
41
41
 
42
42
  | Tool | NTN | Beams | Fast fading and link-to-system mapping | Scheduler |
43
43
  |---|---|---|---|---|
44
- | HandoverLab 2.4.0 | one LEO satellite with earth-moving beams (TR 38.811, TR 38.821), CHO with D2; no several satellites, Doppler or earth-fixed beams ([NTN guide](guides/ntn.md)) | SSB beams per sector from the TR 38.901 element and DFT beams, cell quality from beams, beam failure detection and recovery; UE receive beams optional (1, 2 or 4 panels, [UE beams](guides/ue-beams.md)), isotropic UE by default; no MIMO ([beams](guides/beams-layers.md)) | off by default (large-scale channel with a slow time-varying part); option: TDL-A to TDL-E with MIESM for link monitoring and a capacity-equivalent SINR for the rate; no CDL ([fading](guides/fading.md)) | by default a rate model without a scheduler; option: slot scheduler RR or PF with MCS, TBS and HARQ (base engine only; with `run.backend: numba` 11-59 times faster than its NumPy loop, bit-identical) ([scheduler](guides/scheduler.md)) |
44
+ | HandoverLab 2.4.0 | one LEO satellite with earth-moving beams (TR 38.811, TR 38.821), CHO with D2; no several satellites, Doppler or earth-fixed beams ([NTN guide](guides/ntn.md)) | SSB beams per sector from the TR 38.901 element and DFT beams, cell quality from beams, beam failure detection and recovery; UE receive beams optional (1, 2 or 4 panels, [UE beams](guides/ue-beams.md)), isotropic UE by default; no MIMO ([beams](guides/beams-layers.md)) | off by default (large-scale channel with a slow time-varying part); option: TDL-A to TDL-E with MIESM for link monitoring and a capacity-equivalent SINR for the rate; no CDL ([fading](guides/fading.md)) | by default a rate model without a scheduler; option: slot scheduler RR or PF with MCS, TBS and HARQ (base engine only; with `run.backend: numba` bit-identical and, on the ns-3 card, 42 (`rr`) and 93 (`pf`) times faster than its NumPy loop) ([scheduler](guides/scheduler.md)) |
45
45
  | ns-3 5G-LENA v5.1 | NTN channel (TR 38.811, from ns-3 mainline [L9]) and a LEO mobility example [L1, L2] | ideal and SRS-based realistic beamforming; beam management "Simplified model; no SSB blocks" [L1]; quasi-omni beams in the RRC / handover context [L3] | TR 38.901 with fast fading; EESM-based PHY abstraction with SINR-BLER tables [L1, L8] | PF, RR, MR, QoS-aware, RL-based; OFDMA and TDMA [L1] |
46
46
  | ns-3 mmWave v8.0 | TR 38.811 channel inherited from ns-3.42; no NTN protocol features stated [M2] | SVD- and DFT-based beamforming; NR beam tracking listed as future work [M1, M3] | TR 38.901 channel, ray-tracing and measured traces; EESM error model from 5G-LENA [M1, M3] | flexible-TTI RR, PF, max-rate, max-weight [M1] |
47
47
  | Simu5G 1.8.0 | not in the official release; separate third-party work exists [S10] | not stated; antenna-gain link budget only [S1] | path loss, LOS and shadowing of TR 36.814 / 36.873 / 38.901 with Jakes or Rayleigh fading; reception from SINR and BLER curves [S5, S6] | MAX C/I, PF, DRR, QoS-aware PF [S1] |
@@ -54,7 +54,7 @@ Tools compared (latest release found on 2026-10-22):
54
54
 
55
55
  | Tool | Speed and scale | Validation against 3GPP |
56
56
  |---|---|---|
57
- | HandoverLab 2.4.0 | one process: 2 rules, 40 users, 76 cells, 60 s simulated in 10-15 s on a modest virtual machine (1.11.0 timings, [performance](performance.md)); many rules share one world; no published figures for thousands of nodes | large-scale calibration of TR 38.901 clause 7.8.1 against the 21 companies of R1-165974 (325 of 342 percentiles inside the range) and at 7 GHz against R1-2506406 (all 342 percentiles inside the range, 1.7-2.9 dB from the company mean, [details](calibration-3gpp.md)); handover counts against ns-3 / 5G-LENA; failure levels differ from ns-3 ([calibration](calibration.md)); clause-by-clause [standard compliance](standard-compliance.md) |
57
+ | HandoverLab 2.4.0 | one process: 2 rules, 40 users, 76 cells, 60 s simulated in 10-15 s on a modest virtual machine (1.11.0 timings, [performance](performance.md)); many rules share one world; no published figures for thousands of nodes | large-scale calibration of TR 38.901 clause 7.8.1 against the 21 companies of R1-165974 (325 of 342 percentiles inside the range) and against R1-2506406 (at 7 GHz all 228 percentiles of UMa, UMi and SMa inside the company range, largest distance from the company mean 1.69-2.43 dB; with the two 6 GHz reruns 342 percentiles, 1.65-2.88 dB, [details](calibration-3gpp.md)); handover counts against ns-3 / 5G-LENA; failure levels differ from ns-3 ([calibration](calibration.md)); clause-by-clause [standard compliance](standard-compliance.md) |
58
58
  | ns-3 5G-LENA v5.1 | runtime numbers: not stated for the module; a MIMO channel speed-up of up to 16 times is reported in a WNS3 paper [L11]; the calibration scenario has 12 gNBs and 120 UEs [L10] | calibrated in 3GPP outdoor reference scenarios (SIMPAT 2022) [L7]; calibration examples for RP-180524 [L2]; mobility checked against TR 36.839 (v5.1) [L5] |
59
59
  | ns-3 mmWave v8.0 | not stated | not stated (examples "verify its correct functioning" [M6]) |
60
60
  | Simu5G 1.8.0 | background cells and UEs for large scenarios; real-time emulation of "hundreds of simulated users and tens of cells" on one desktop [S1, S9] | PHY abstraction validated in 3GPP-based scenarios [S8]; fingerprint regression tests [S1] |
@@ -50,15 +50,16 @@ UE-minute):
50
50
 
51
51
  | Rule | Handovers | Failures | Beam switches | Beam failures | recovered | ended in RLF | Interruption [s] | SINR [dB] |
52
52
  |---|---|---|---|---|---|---|---|---|
53
- | A3 | 25.0 | 1.50 | 46.6 | 2.58 | 1.27 | 0.80 | 2.53 | 14.0 |
54
- | CHO | 25.9 | 1.23 | 49.5 | 1.98 | 1.32 | 0.45 | 1.77 | 15.5 |
55
- | LTM | 31.3 | 0.80 | 51.1 | 1.55 | 0.93 | 0.28 | 1.12 | 16.0 |
56
- | CLTM | 31.4 | 0.75 | 50.1 | 1.38 | 0.88 | 0.25 | 1.09 | 16.4 |
53
+ | A3 | 20.4 | 5.50 | 42.9 | 11.43 | 4.83 | 5.42 | 6.36 | 9.8 |
54
+ | CHO | 22.0 | 3.88 | 46.6 | 8.73 | 4.12 | 3.83 | 3.67 | 11.6 |
55
+ | LTM | 30.6 | 2.80 | 50.0 | 7.33 | 3.30 | 2.75 | 2.60 | 13.1 |
56
+ | CLTM | 30.6 | 2.72 | 49.6 | 7.40 | 3.60 | 2.67 | 2.55 | 13.5 |
57
57
 
58
- Half to two thirds of the detected beam failures are recovered on another beam of the same cell; most
59
- of the rest end in a radio-link failure because no beam of the serving cell is good enough any more
60
- (the user needed a handover), a few are ended by a handover. Faster cell changes (LTM, conditional LTM) leave fewer
61
- beam failures to recover.
58
+ A little less than half (42-49 %) of the detected beam failures are recovered on another beam of the
59
+ same cell; 36-47 % end in a radio-link failure because no beam of the serving cell is good enough any
60
+ more (the user needed a handover), and these make up 98-99 % of the failures; the rest (9-17 %) are
61
+ ended by a handover. Faster cell changes (LTM, conditional LTM) leave fewer beam failures to recover
62
+ (7.3-7.4 per UE-minute against 11.4 with A3).
62
63
 
63
64
  ## 2. Two carriers: a macro layer and a small-cell layer
64
65
 
@@ -8,6 +8,10 @@ delayed by the interruption. It works with every procedure (baseline handover su
8
8
  DAPS, LTM and conditional LTM). It is off by default; with it off every result of 2.2.0 is
9
9
  unchanged bit for bit (the new metrics are 0).
10
10
 
11
+ ![Lost data with and without forwarding, and the PDCP delay, for A3, CHO, DAPS and LTM](../images/buffers.png)
12
+
13
+ *Without forwarding A3 loses 2.17 % of the data, CHO 1.16 %, DAPS 0.34 % and LTM 0.41 %; with forwarding nothing is lost, and the forwarded data wait 85-349 ms.*
14
+
11
15
  ```yaml
12
16
  scenario:
13
17
  base: smoke
@@ -97,15 +101,17 @@ forwarding and links below Qout (no data in the rate model) add.
97
101
 
98
102
  | Rule | forwarded kbyte/UE-min | lost share without forwarding | mean PDCP delay | delay of forwarded data |
99
103
  |---|---|---|---|---|
100
- | A3 | 6.2 | 2.1 % | 2.9 ms | 123 ms |
101
- | CHO (late / early forwarding) | 4.2 | 1.4 % | 1.3 ms | 80 / 70 ms |
102
- | DAPS | 6.2 (copies) | 0 | 2.6 ms | 157 ms |
103
- | LTM | 1.6 | 0.5 % | 0.6 ms | 92 ms |
104
-
105
- With forwarding nothing is lost. Late forwarding adds the 2 x 5 ms wait for CHO; for LTM the wait
106
- ends before the next measurement instant and does not show. DAPS gains little here: most of its
107
- executions start with the source SINR already below Qout, where the rate model sends nothing, so the
108
- data left for the target are the oldest ones.
104
+ | A3 | 7.4 | 2.2 % | 8.3 ms | 313 ms |
105
+ | CHO (late / early forwarding) | 3.5 | 1.2 % | 1.1 / 0.9 ms | 85 / 75 ms |
106
+ | DAPS | 6.7 (copies) | 0.3 % (all at failures) | 6.4 ms | 349 ms |
107
+ | LTM | 1.2 | 0.4 % | 0.4 ms | 94 ms |
108
+
109
+ With forwarding nothing is lost. Without it DAPS loses no data at its executions; its 0.3 % are
110
+ lost at failures and re-establishments. Late forwarding adds the 2 x 5 ms wait for CHO; for LTM the
111
+ wait ends before the next measurement instant and does not show (94 ms either way). DAPS gains
112
+ little here: most of its executions start with the source SINR already below Qout, where the rate
113
+ model sends nothing, so the data left for the target are the oldest ones, and its forwarded data
114
+ wait longest (349 ms).
109
115
 
110
116
  ## 7. Checks
111
117
 
@@ -2,6 +2,10 @@
2
2
 
3
3
  Since 1.0.0rc2 HandoverLab has two procedures next to baseline and conditional handover:
4
4
 
5
+ ![Failures and ping-pong, interruption and RRC messages for A3, CHO, DAPS, LTM and CLTM](../images/procedures.png)
6
+
7
+ *On one card failures fall from 0.6 (A3) to 0.2 (LTM and CLTM) per UE-minute; DAPS has no execution interruption; LTM sends 192 RRC messages per UE-minute against 45 for A3.*
8
+
5
9
  | Rule | Procedure | Specification | What changes compared with `a3` |
6
10
  |---|---|---|---|
7
11
  | `daps` | DAPS handover (Rel-16) | TS 38.300 clause 9.2.3.2, TS 38.331 clause 5.3.5.8.3 | the source keeps serving during the execution; a failed execution falls back to the source |
@@ -4,6 +4,10 @@ Since 2.3.0 a user can hold a secondary cell group (SCG) next to its master cell
4
4
  NR-DC case of TS 37.340 V19.3.0 clause 4.1.3.3, one gNB as master node (MN) and another as secondary
5
5
  node (SN). The option `protocol.dc` is off by default; with it off every result stays as it was.
6
6
 
7
+ ![One user's 4 GHz master cell and 30 GHz secondary cell over time with the dual-connectivity events, and the procedure rates](../images/dual-connectivity.png)
8
+
9
+ *The SCG carries data 96 % of the time; per UE-minute there are 21.1 PSCell changes and 16.3 MCG handovers, and per user the SCG carries 183 Mbit/s against 10.1 Mbit/s on the MCG.*
10
+
7
11
  The model is the simplest consistent subset that a system-level simulator needs: when an SCG is
8
12
  added, changed or lost, what that costs in signalling and interruption, and how much time the
9
13
  user spends with a second link. The MCG behaves exactly as without dual connectivity: its handover
@@ -6,6 +6,10 @@ slow time-varying component, with radio-link monitoring on the wideband SINR. Si
6
6
  the SINR at several frequencies to one effective SINR. It is off by default; with it off every
7
7
  result of 2.1.0 is unchanged bit for bit.
8
8
 
9
+ ![Received power of one vehicle with no fading, TDL-A and TDL-C, and the distribution of the link-monitoring SINR](../images/fading.png)
10
+
11
+ *On the ns-3 card (10 vehicles, 20 s) the 5th percentile of the link-monitoring SINR falls from 8.3 dB without fading to 3.8 dB (TDL-A) and 3.4 dB (TDL-C); the MIESM value of QPSK saturates at 18.5 dB.*
12
+
9
13
  ```yaml
10
14
  scenario:
11
15
  base: ns3-urban-3.5ghz
@@ -45,9 +49,13 @@ another simulator is used; a BLER per MCS (TS 38.214 tables) follows with the sl
45
49
 
46
50
  ## 3. Cost and limits
47
51
 
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.
52
+ - The engine takes about 10 times as long (32 sinusoids per tap, every step; 10 users on the
53
+ ns-3 card, 20 s simulated, without building the world, median of seven runs: 7.7 s with `tdl-a`
54
+ and 7.8 s with `tdl-c` instead of 0.74 s, with the default traffic of the card; the 1.02 s of the
55
+ [scheduler measurement](../performance.md) is another session with full-buffer traffic, and machine load
56
+ changes such times by up to a factor of two); many
57
+ rules on one world the same (24 rules: 53 s instead of 5.4 s), as the batched and compiled loops
58
+ are not used with fading.
51
59
  - This version needs the base engine: no beams, layers, NTN or TS 38.133 periods
52
60
  (`meas_periods: sample`, `rlm_eval: fixed`); such a configuration is refused.
53
61
  - The step stays 10 ms. At 30 m/s and 3.5 GHz the coherence time is about 1 ms, so successive
@@ -69,27 +69,29 @@ Means over three seeds per user-minute, with the cards as they are and with the
69
69
 
70
70
  | Scenario | Rule | LOS state | Handovers | Failures | Unnecessary | Ping-pong | Interruption [s] |
71
71
  |---|---|---|---|---|---|---|---|
72
- | indoor | A3 3 dB 160 ms | soft | 6.74 | 0.02 | 2.82 | 0.41 | 0.29 |
73
- | indoor | A3 3 dB 160 ms | hard | 7.12 | 0.16 | 3.04 | 0.46 | 0.45 |
74
- | indoor | A3 5 dB 320 ms | soft | 4.74 | 0.10 | 1.28 | 0.06 | 0.29 |
75
- | indoor | `a3_mro` | soft | 6.69 | 0.02 | 2.80 | 0.40 | 0.29 |
76
- | rural | A3 3 dB 160 ms | soft | 11.93 | 0.33 | 6.86 | 1.71 | 0.82 |
77
- | rural | A3 3 dB 160 ms | hard | 13.16 | 1.41 | 7.58 | 1.95 | 1.97 |
78
- | rural | A3 5 dB 320 ms | soft | 7.80 | 0.42 | 3.49 | 0.39 | 0.74 |
79
- | rural | `a3_mro` | soft | 10.36 | 0.23 | 5.55 | 1.15 | 0.65 |
80
-
81
- - **Indoors**, many handovers are unnecessary or ping-pong even at walking speed, because every
82
- neighbour is close. This is the point of the scenario: a rule has to avoid switching between
83
- nearly equal cells. A larger offset and time-to-trigger halve the unnecessary handovers at the
84
- price of more late ones.
72
+ | indoor | A3 3 dB 160 ms | soft | 3.81 | 0.00 | 0.86 | 0.02 | 0.15 |
73
+ | indoor | A3 3 dB 160 ms | hard | 3.95 | 0.00 | 0.96 | 0.05 | 0.16 |
74
+ | indoor | A3 5 dB 320 ms | soft | 2.91 | 0.02 | 0.23 | 0.00 | 0.14 |
75
+ | indoor | `a3_mro` | soft | 3.77 | 0.00 | 0.84 | 0.02 | 0.15 |
76
+ | rural | A3 3 dB 160 ms | soft | 13.07 | 0.07 | 7.58 | 1.82 | 0.67 |
77
+ | rural | A3 3 dB 160 ms | hard | 15.62 | 0.18 | 9.24 | 2.57 | 1.06 |
78
+ | rural | A3 5 dB 320 ms | soft | 8.86 | 0.21 | 4.09 | 0.45 | 0.63 |
79
+ | rural | `a3_mro` | soft | 10.56 | 0.08 | 5.51 | 0.97 | 0.56 |
80
+
81
+ - **Indoors**, about a quarter of the handovers are unnecessary even at walking speed (0.86 of 3.81
82
+ per user-minute), because every neighbour is close; ping-pong is rare. This is the point of the
83
+ scenario: a rule has to avoid switching between nearly equal cells. A larger offset and
84
+ time-to-trigger cut the unnecessary handovers by about three quarters at the price of a few late
85
+ ones (0.02 failures per user-minute, all too late, against none).
85
86
  - **In rural cells**, the handover rate is far above what the cell size alone would give, and most
86
87
  handovers are unnecessary: the 8 dB shadowing with 120 m decorrelation, uncorrelated between
87
88
  sites (TR 38.901 clause 7.5 step 4; half correlated until 2.0.0), moves the best cell often at
88
89
  120 km/h. Compare rules with each other here, and do
89
90
  not read the absolute handover rate as that of a real rural network.
90
91
  - **Hard against soft LOS**: with the hard switch, a link jumps by about 20 dB (RMa at 1-2 km) or
91
- about 15 dB (InH at 20 m) when its state changes, and these jumps cause most failures. The soft state
92
- removes most of them without changing the handover rate much.
92
+ about 15 dB (InH at 20 m) when its state changes. In rural cells these jumps raise the failures from
93
+ 0.07 to 0.18 per user-minute and the handovers by about a fifth (13.07 to 15.62); indoors there are
94
+ no failures with either state, and the hard switch adds only a few handovers (3.81 to 3.95).
93
95
  - The failure model is not calibrated in absolute terms in any scenario; read failure rates
94
96
  relative to each other.
95
97