handoverlab 2.2.0__tar.gz → 2.3.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.
Files changed (273) hide show
  1. {handoverlab-2.2.0 → handoverlab-2.3.0}/CHANGELOG.md +73 -1
  2. {handoverlab-2.2.0 → handoverlab-2.3.0}/CITATION.cff +1 -1
  3. {handoverlab-2.2.0 → handoverlab-2.3.0}/PKG-INFO +11 -8
  4. {handoverlab-2.2.0 → handoverlab-2.3.0}/README.md +10 -7
  5. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/calibration.md +32 -5
  6. handoverlab-2.3.0/docs/guides/buffers.md +117 -0
  7. handoverlab-2.3.0/docs/guides/dual-connectivity.md +114 -0
  8. handoverlab-2.3.0/docs/guides/high-speed-train.md +102 -0
  9. handoverlab-2.3.0/docs/guides/suburban-o2i.md +97 -0
  10. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/cli.md +1 -1
  11. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/metrics.md +25 -0
  12. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/highway-tr37885-30ghz.md +6 -0
  13. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/highway-tr37885-4ghz.md +6 -0
  14. handoverlab-2.3.0/docs/scenarios/hst-fr2-28ghz.md +161 -0
  15. handoverlab-2.3.0/docs/scenarios/hst-fr2-28ghz.svg +18 -0
  16. handoverlab-2.3.0/docs/scenarios/suburban-sma-7ghz.md +107 -0
  17. handoverlab-2.3.0/docs/scenarios/suburban-sma-7ghz.svg +15 -0
  18. handoverlab-2.3.0/docs/scenarios/urban-macro-tr37885-4ghz.md +110 -0
  19. handoverlab-2.3.0/docs/scenarios/urban-macro-tr37885-4ghz.svg +48 -0
  20. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/standard-compliance.md +60 -2
  21. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/user_guide.md +10 -3
  22. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/verification.md +1 -0
  23. {handoverlab-2.2.0 → handoverlab-2.3.0}/mkdocs.yml +7 -0
  24. {handoverlab-2.2.0 → handoverlab-2.3.0}/pyproject.toml +1 -1
  25. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/__init__.py +1 -1
  26. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/channel/antenna.py +14 -11
  27. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/channel/extended.py +2 -2
  28. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/channel/pathloss.py +142 -14
  29. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/channel/radiomap.py +9 -5
  30. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/channel/source.py +15 -5
  31. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/config.py +159 -7
  32. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/engine/batch.py +2 -1
  33. handoverlab-2.3.0/src/handoverlab/engine/buffers.py +313 -0
  34. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/engine/core.py +55 -5
  35. handoverlab-2.3.0/src/handoverlab/engine/dual.py +335 -0
  36. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/engine/extended.py +3 -0
  37. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/engine/metrics.py +51 -0
  38. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/engine/scheduler.py +23 -2
  39. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/mobility.py +12 -7
  40. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/scenarios/__init__.py +18 -1
  41. handoverlab-2.3.0/src/handoverlab/scenarios/cards/hst-fr2-28ghz.yaml +97 -0
  42. handoverlab-2.3.0/src/handoverlab/scenarios/cards/suburban-sma-7ghz.yaml +63 -0
  43. handoverlab-2.3.0/src/handoverlab/scenarios/cards/urban-macro-tr37885-4ghz.yaml +70 -0
  44. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/seeds.py +2 -1
  45. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/simulate.py +2 -1
  46. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/__init__.py +7 -1
  47. handoverlab-2.3.0/src/handoverlab/verify/scenarios.py +343 -0
  48. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/world.py +6 -3
  49. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab.egg-info/PKG-INFO +11 -8
  50. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab.egg-info/SOURCES.txt +19 -0
  51. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/data/public_api.json +37 -0
  52. handoverlab-2.3.0/tests/test_buffers.py +206 -0
  53. handoverlab-2.3.0/tests/test_hst_dc.py +191 -0
  54. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_indoor_rural.py +1 -1
  55. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_pathloss.py +2 -2
  56. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_scenarios.py +3 -2
  57. handoverlab-2.3.0/tests/test_scenarios_230.py +195 -0
  58. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_verify.py +1 -1
  59. {handoverlab-2.2.0 → handoverlab-2.3.0}/.zenodo.json +0 -0
  60. {handoverlab-2.2.0 → handoverlab-2.3.0}/CODE_OF_CONDUCT.md +0 -0
  61. {handoverlab-2.2.0 → handoverlab-2.3.0}/CONTRIBUTING.md +0 -0
  62. {handoverlab-2.2.0 → handoverlab-2.3.0}/LICENSE +0 -0
  63. {handoverlab-2.2.0 → handoverlab-2.3.0}/MANIFEST.in +0 -0
  64. {handoverlab-2.2.0 → handoverlab-2.3.0}/SECURITY.md +0 -0
  65. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/RELEASING.md +0 -0
  66. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/calibration-3gpp.md +0 -0
  67. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/guides/add-scenario.md +0 -0
  68. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/guides/beams-layers.md +0 -0
  69. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/guides/daps-ltm.md +0 -0
  70. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/guides/dashboard.md +0 -0
  71. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/guides/export-event-logs.md +0 -0
  72. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/guides/fading.md +0 -0
  73. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/guides/highway.md +0 -0
  74. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/guides/indoor-rural.md +0 -0
  75. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/guides/learning-rule.md +0 -0
  76. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/guides/many-cores.md +0 -0
  77. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/guides/mro.md +0 -0
  78. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/guides/ntn.md +0 -0
  79. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/guides/radio-maps.md +0 -0
  80. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/guides/reproduce.md +0 -0
  81. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/guides/scheduler.md +0 -0
  82. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/guides/upper-mid-band.md +0 -0
  83. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/images/calibration_38901.png +0 -0
  84. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/images/dashboard-charts.png +0 -0
  85. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/images/dashboard-compare.png +0 -0
  86. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/images/dashboard-where.png +0 -0
  87. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/images/dashboard.png +0 -0
  88. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/images/ntn-beams.png +0 -0
  89. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/images/radio-map.png +0 -0
  90. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/images/report-comparison.png +0 -0
  91. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/images/report-tuning.png +0 -0
  92. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/images/ssb-beams.png +0 -0
  93. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/index.md +0 -0
  94. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/migration-2.0.md +0 -0
  95. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/performance.md +0 -0
  96. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/api/config.md +0 -0
  97. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/api/engine.md +0 -0
  98. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/api/eventlog.md +0 -0
  99. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/api/gui.md +0 -0
  100. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/api/index.md +0 -0
  101. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/api/mapfile.md +0 -0
  102. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/api/ntn.md +0 -0
  103. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/api/rules.md +0 -0
  104. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/api/scenarios.md +0 -0
  105. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/api/simulate.md +0 -0
  106. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/api/stability.md +0 -0
  107. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/api/stats.md +0 -0
  108. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/api/studies.md +0 -0
  109. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/api/testing.md +0 -0
  110. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference/api/verify.md +0 -0
  111. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/reference-study.md +0 -0
  112. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/dense-urban-2layer.md +0 -0
  113. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/dense-urban-2layer.svg +0 -0
  114. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/fr3-urban-15ghz.md +0 -0
  115. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/fr3-urban-15ghz.svg +0 -0
  116. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/highway-tr37885-30ghz.svg +0 -0
  117. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/highway-tr37885-4ghz.svg +0 -0
  118. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/indoor-office-4ghz.md +0 -0
  119. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/indoor-office-4ghz.svg +0 -0
  120. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/ns3-urban-3.5ghz.md +0 -0
  121. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/ns3-urban-3.5ghz.svg +0 -0
  122. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/ntn-leo600-2ghz.md +0 -0
  123. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/ntn-leo600-2ghz.svg +0 -0
  124. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/open-area-10ghz.md +0 -0
  125. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/open-area-10ghz.svg +0 -0
  126. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/rural-700mhz.md +0 -0
  127. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/rural-700mhz.svg +0 -0
  128. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/smoke.md +0 -0
  129. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/smoke.svg +0 -0
  130. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/urban-grid-10ghz.md +0 -0
  131. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/urban-grid-10ghz.svg +0 -0
  132. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/urban-grid-28ghz-beams.md +0 -0
  133. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/scenarios/urban-grid-28ghz-beams.svg +0 -0
  134. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/stability.md +0 -0
  135. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/time-step.md +0 -0
  136. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/tutorials/first-run.md +0 -0
  137. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/tutorials/own-rule.md +0 -0
  138. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/tutorials/reading-the-report.md +0 -0
  139. {handoverlab-2.2.0 → handoverlab-2.3.0}/docs/tutorials/tuning-study.md +0 -0
  140. {handoverlab-2.2.0 → handoverlab-2.3.0}/examples/compare_a3_cho.py +0 -0
  141. {handoverlab-2.2.0 → handoverlab-2.3.0}/examples/open_area.toml +0 -0
  142. {handoverlab-2.2.0 → handoverlab-2.3.0}/examples/radio_map.py +0 -0
  143. {handoverlab-2.2.0 → handoverlab-2.3.0}/examples/smoke.yaml +0 -0
  144. {handoverlab-2.2.0 → handoverlab-2.3.0}/examples/speed_rule.py +0 -0
  145. {handoverlab-2.2.0 → handoverlab-2.3.0}/examples/street_grid.yaml +0 -0
  146. {handoverlab-2.2.0 → handoverlab-2.3.0}/examples/study_reference.yaml +0 -0
  147. {handoverlab-2.2.0 → handoverlab-2.3.0}/examples/study_reference_explore.yaml +0 -0
  148. {handoverlab-2.2.0 → handoverlab-2.3.0}/examples/study_smoke.yaml +0 -0
  149. {handoverlab-2.2.0 → handoverlab-2.3.0}/examples/traffic_models.py +0 -0
  150. {handoverlab-2.2.0 → handoverlab-2.3.0}/setup.cfg +0 -0
  151. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/__main__.py +0 -0
  152. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/channel/__init__.py +0 -0
  153. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/channel/fading.py +0 -0
  154. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/channel/l2s.py +0 -0
  155. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/channel/ntn.py +0 -0
  156. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/cli.py +0 -0
  157. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/engine/__init__.py +0 -0
  158. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/engine/_kernels.py +0 -0
  159. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/engine/invariants.py +0 -0
  160. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/engine/procedures.py +0 -0
  161. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/eventlog.py +0 -0
  162. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/gui/__init__.py +0 -0
  163. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/gui/app.py +0 -0
  164. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/gui/logic.py +0 -0
  165. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/io.py +0 -0
  166. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/layout.py +0 -0
  167. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/linklevel.py +0 -0
  168. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/mapfile.py +0 -0
  169. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/measurement.py +0 -0
  170. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/py.typed +0 -0
  171. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/requirements.py +0 -0
  172. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/rules/__init__.py +0 -0
  173. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/rules/base.py +0 -0
  174. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/rules/builtin.py +0 -0
  175. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/rules/dqn.py +0 -0
  176. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/rules/mro.py +0 -0
  177. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/scenarios/cards/dense-urban-2layer.yaml +0 -0
  178. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/scenarios/cards/fr3-urban-15ghz.yaml +0 -0
  179. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/scenarios/cards/highway-tr37885-30ghz.yaml +0 -0
  180. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/scenarios/cards/highway-tr37885-4ghz.yaml +0 -0
  181. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/scenarios/cards/indoor-office-4ghz.yaml +0 -0
  182. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/scenarios/cards/ns3-urban-3.5ghz.yaml +0 -0
  183. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/scenarios/cards/ntn-leo600-2ghz.yaml +0 -0
  184. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/scenarios/cards/open-area-10ghz.yaml +0 -0
  185. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/scenarios/cards/rural-700mhz.yaml +0 -0
  186. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/scenarios/cards/smoke.yaml +0 -0
  187. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/scenarios/cards/urban-grid-10ghz.yaml +0 -0
  188. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/scenarios/cards/urban-grid-28ghz-beams.yaml +0 -0
  189. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/stability.py +0 -0
  190. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/standard.py +0 -0
  191. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/stats.py +0 -0
  192. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/studies/__init__.py +0 -0
  193. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/studies/config.py +0 -0
  194. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/studies/report.py +0 -0
  195. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/studies/runner.py +0 -0
  196. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/studies/status.py +0 -0
  197. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/studies/store.py +0 -0
  198. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/studies/study.py +0 -0
  199. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/studies/tuning.py +0 -0
  200. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/testing.py +0 -0
  201. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/traffic.py +0 -0
  202. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/calibration.py +0 -0
  203. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/data/golden.json +0 -0
  204. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/data/golden_1x.json +0 -0
  205. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/data/ns3_urban_a3.json +0 -0
  206. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/data/r1_165974.csv +0 -0
  207. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/engine_checks.py +0 -0
  208. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/extended.py +0 -0
  209. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/fading.py +0 -0
  210. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/golden.py +0 -0
  211. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/highway.py +0 -0
  212. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/learning.py +0 -0
  213. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/ns3.py +0 -0
  214. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/ntn.py +0 -0
  215. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/radio.py +0 -0
  216. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/report.py +0 -0
  217. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/stored.py +0 -0
  218. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab/verify/values.py +0 -0
  219. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab.egg-info/dependency_links.txt +0 -0
  220. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab.egg-info/entry_points.txt +0 -0
  221. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab.egg-info/requires.txt +0 -0
  222. {handoverlab-2.2.0 → handoverlab-2.3.0}/src/handoverlab.egg-info/top_level.txt +0 -0
  223. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/conftest.py +0 -0
  224. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/data/bh6_reference.json +0 -0
  225. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/data/bh6_wide.json +0 -0
  226. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/data/make_bh6_reference.py +0 -0
  227. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/data/make_bh6_wide.py +0 -0
  228. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/helpers.py +0 -0
  229. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_batch.py +0 -0
  230. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_beams_layers.py +0 -0
  231. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_calibration.py +0 -0
  232. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_channel_detail.py +0 -0
  233. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_cltm.py +0 -0
  234. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_config_cli.py +0 -0
  235. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_contract.py +0 -0
  236. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_determinism.py +0 -0
  237. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_dqn.py +0 -0
  238. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_engine_triggers.py +0 -0
  239. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_eventlog.py +0 -0
  240. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_fading.py +0 -0
  241. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_gui.py +0 -0
  242. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_highway.py +0 -0
  243. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_highway_tr37885.py +0 -0
  244. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_invariants.py +0 -0
  245. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_levels_status_extend.py +0 -0
  246. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_lm_model.py +0 -0
  247. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_mapfile.py +0 -0
  248. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_measurement.py +0 -0
  249. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_mro.py +0 -0
  250. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_ntn.py +0 -0
  251. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_protocol_3gpp.py +0 -0
  252. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_readme_boundaries.py +0 -0
  253. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_regression_bh6.py +0 -0
  254. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_regression_bh6_wide.py +0 -0
  255. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_rrc_detail.py +0 -0
  256. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_rules_rc2.py +0 -0
  257. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_scheduler.py +0 -0
  258. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_signalling_energy.py +0 -0
  259. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_stability.py +0 -0
  260. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_stats.py +0 -0
  261. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_study.py +0 -0
  262. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_tools.py +0 -0
  263. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_traffic.py +0 -0
  264. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_tuning.py +0 -0
  265. {handoverlab-2.2.0 → handoverlab-2.3.0}/tests/test_v111.py +0 -0
  266. {handoverlab-2.2.0 → handoverlab-2.3.0}/tools/compare_fingerprints.py +0 -0
  267. {handoverlab-2.2.0 → handoverlab-2.3.0}/tools/make_beam_figure.py +0 -0
  268. {handoverlab-2.2.0 → handoverlab-2.3.0}/tools/make_calibration_figure.py +0 -0
  269. {handoverlab-2.2.0 → handoverlab-2.3.0}/tools/make_ntn_figure.py +0 -0
  270. {handoverlab-2.2.0 → handoverlab-2.3.0}/tools/make_radiomap_figure.py +0 -0
  271. {handoverlab-2.2.0 → handoverlab-2.3.0}/tools/make_readme_images.py +0 -0
  272. {handoverlab-2.2.0 → handoverlab-2.3.0}/tools/mkdocs_hooks.py +0 -0
  273. {handoverlab-2.2.0 → handoverlab-2.3.0}/tools/release_check.py +0 -0
@@ -7,6 +7,77 @@ All notable changes to this project are documented in this file. The format foll
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.3.0] - 2026-10-22
11
+
12
+ ### Added
13
+
14
+ - User-plane buffers at handover as an option (`protocol.buffers`: `am` or `um`, off by default): one downlink
15
+ bearer per user whose PDCP data wait in a FIFO at the gNB, data forwarding over Xn (`protocol.forwarding`,
16
+ `protocol.xn_delay_s`) for baseline handover, CHO and LTM / CLTM (late forwarding after HANDOVER SUCCESS unless
17
+ `protocol.early_forwarding`) and DAPS (the source keeps sending, copies to the target), re-establishment with
18
+ and without forwarding, the PDCP discard timer of TS 38.331 (`protocol.discard_timer_s`), and with the slot
19
+ scheduler the HARQ data at a MAC reset (lost with RLC UM, re-sent with AM) and TBs lost after the last HARQ
20
+ transmission. Sources: TS 38.300 V19.4.0 9.2.3.1-9.2.3.7, TS 38.322 V19.2.0 4.4 / 5.1.2, TS 38.323 V19.1.0
21
+ 5.1.2 / 5.3 / 5.5. New metrics `pdcp_delivered_kbyte_pm`, `pdcp_lost_*`, `pdcp_forwarded_*`, `pdcp_delay_ms`,
22
+ `pdcp_delay_p95_ms`, `pdcp_delay_forwarded_ms` (0 without the option). Base engine only. With the option off
23
+ every result is unchanged. Guide: `docs/guides/buffers.md`.
24
+ - Suburban macro (SMa) of TR 38.901 V19.5.0 (`radio.pathloss: sma`, 0.5-37 GHz): the LOS and NLOS path loss of
25
+ Table 7.4.1-1 (h = 10 m, W = 10 m; the NLOS row is used as printed, without a max() with the LOS loss, so for a
26
+ UT high up close to a site NLOS can lie below LOS) and the LOS probability of Table 7.4.2-1 with the vegetation
27
+ density `radio.vegetation` (0, 0.1, 0.2); heights checked against the applicability ranges (25-35 m, 1-14 m).
28
+ - O2I building penetration loss of indoor users (TR 38.901 clause 7.4.3.1): a speed group with `indoor: true`
29
+ marks indoor users; each gets PL_tw + 0.5 d2D-in + N(0, sigma_P^2) on all its links, drawn once
30
+ (`radio.o2i_model`: `low`, `high`, `low_a` for SMa, or `mixed`; `radio.o2i_d_in_max_m`; SMa residential /
31
+ commercial buildings 90 % / 10 %), from its own random stream; an indoor user gets no car penetration loss.
32
+ The LOS state and the shadowing of an indoor user stay those of its position (stated abstraction, measured by
33
+ `verify`).
34
+ - `radio.building_los: false` on the street grid: sites above the rooftops, the LOS state from the LOS probability
35
+ alone (TR 37.885 clause 6.2.1); `radio.env_height_m`: one effective environment height for the UMa / UMi
36
+ breakpoint (TR 37.885: 0.25 m).
37
+ - Scenario cards `urban-macro-tr37885-4ghz` (the TR 37.885 urban grid below 6 GHz with 500 m macro sites on the
38
+ hexagonal layout of TR 36.885 Figure A.1.3-1, UMa at 4 GHz, h_E 0.25 m, vehicles at 60 km/h; the wrap-around is
39
+ replaced by the lattice sites within 1000 m of the grid) and `suburban-sma-7ghz` (11 SMa sites at 1299 m,
40
+ 7 GHz, 80 % indoor users with the low-loss A model, 20 % in cars). Guide: `docs/guides/suburban-o2i.md`.
41
+ - Optional `verify` group `scenarios` (`--only scenarios`; criteria fixed before the first run), reported as it
42
+ came: 7 pass, 3 fail. The urban macro coupling gain lies 0.3-1.2 dB below an independent computation around
43
+ the median in every block of seeds (cause open; the LOS share close to the sites is a little low); the check
44
+ of the outdoor SMa users fails on sampling noise (40 seeds pooled: within 0.54 dB); a TR-exact treatment of
45
+ indoor users (LOS at d2D-out, O2I shadowing 8 dB) gives a 2.0 dB wider upper tail (95 % point) than the
46
+ simulator's abstraction, with the median within 0.1 dB.
47
+ - Scenario card `hst-fr2-28ghz`: the FR2 high-speed train of TR 38.854 V18.0.0 as its system-level mobility
48
+ study sets it up (Table 6.3.8.1-1): one train with one roof-mounted CPE at 350 km/h on a straight track, an RRH
49
+ every 700 m on one side, 10 m from the track (Scenario-A), one panel of 8 x 8 elements with one SSB beam per RRH
50
+ pointing along the track at the next RRH, every RRH its own cell (L3 handover, no DPS), 28 GHz, 50 MHz,
51
+ 120 kHz, 31 dBm, TR 38.901 RMa LOS only, no inter-cell interference, N310 = N311 = 2 and the TS 38.133
52
+ measurement periods of the legacy requirements (480 ms). Guide: `docs/guides/high-speed-train.md`, with the
53
+ pre-registered comparison against the TR's results.
54
+ - `radio.beams.am_db`: A_m of the TR 38.901 Table 7.3-1 element pattern (default 30 dB, unchanged results); a
55
+ larger value lowers the back lobe, as the antenna "without back lobe" of the TR 38.854 mobility study.
56
+ - Dual connectivity as an option (`protocol.dc`, off by default): NR-DC of TS 37.340 V19.3.0 with the master cell
57
+ group on the scenario's other carriers and a secondary cell group (one PSCell) on the cells of one layer of
58
+ `radio.layers`: SN addition on event A4 (clause 10.2), PSCell change on event A3 (clauses 10.5, 10.6) and SN
59
+ release (clause 10.4), each prepared between the nodes and sent over the MCG, random access on the PSCell under
60
+ T304; separate radio-link monitoring and SCG radio-link failure (TS 38.331 5.3.10.3); SCG failures reported to
61
+ the MN, which releases the SCG (clause 7.7); an MCG failure releases the SCG (TS 38.331 5.3.7.2); at an MCG
62
+ handover the SN is kept or released (`on_mcg_ho`, clause 10.7). The MCG behaves exactly as without the SCG.
63
+ New metrics `sn_additions_pm`, `sn_addition_failures_pm`, `pscell_changes_pm`, `pscell_change_failures_pm`,
64
+ `sn_releases_pm`, `scg_rlf_pm`, `scg_failures_pm`, `scg_released_by_mcg_pm`, `scg_time_share`,
65
+ `scg_rate_mbps`, `pscell_change_interruption_s_pm`, `dc_rrc_messages_pm` (zero without the option). Guide:
66
+ `docs/guides/dual-connectivity.md`, with what is left out.
67
+
68
+ ### Documentation
69
+
70
+ - Fresh held-out check N3 of the failure model on 40 new ns-3 runs, limits fixed before the runs: a fixed
71
+ link-monitoring interferer load (`protocol.lm_load` 0.15, chosen on the earlier runs) raises the failure level
72
+ from 0.16 to 0.47 of ns-3's and the failure order from 0.78 to 0.95; the level check (0.67-1.5) fails, so the
73
+ setting is reported, not adopted. The recovery time after a failure is set against the bounds of TS 38.133
74
+ clause 6.2.1.2.1 (about 0.28-1.55 s), which the default 1.0 s meets. `docs/calibration.md`.
75
+
76
+ ### Not done
77
+
78
+ - The 7 GHz large-scale calibration of TR 38.901 clause 7.8.1 (Table 7.8-1A): the TR gives the results only by
79
+ reference to R1-2506406, which this release does not include.
80
+
10
81
  ## [2.2.0] - 2026-10-22
11
82
 
12
83
  ### Added
@@ -934,7 +1005,8 @@ First alpha release (stage 1: the core simulator).
934
1005
  - Documentation: README, user guide, contribution guide, citation file; CI on Linux, Windows and
935
1006
  macOS with Python 3.9-3.12.
936
1007
 
937
- [Unreleased]: https://github.com/mjs19971997/handoverlab/compare/v2.2.0...HEAD
1008
+ [Unreleased]: https://github.com/mjs19971997/handoverlab/compare/v2.3.0...HEAD
1009
+ [2.3.0]: https://github.com/mjs19971997/handoverlab/compare/v2.2.0...v2.3.0
938
1010
  [2.2.0]: https://github.com/mjs19971997/handoverlab/compare/v2.1.0...v2.2.0
939
1011
  [2.1.0]: https://github.com/mjs19971997/handoverlab/compare/v2.0.0...v2.1.0
940
1012
  [2.0.0]: https://github.com/mjs19971997/handoverlab/compare/v1.12.0...v2.0.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.2.0"
14
+ version: "2.3.0"
15
15
  doi: 10.5281/zenodo.23409131
16
16
  identifiers:
17
17
  - type: doi
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: handoverlab
3
- Version: 2.2.0
3
+ Version: 2.3.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
@@ -142,10 +142,12 @@ event D2 of Release 18:
142
142
  - **Scenarios**: the TR 37.885 urban street grid (configurable number of blocks; 433 m x 250 m
143
143
  pitch, 20 m streets) with sites on the pavement, an open area with a hexagonal site grid, the
144
144
  TR 37.885 highway (since 1.11.0 with wrap-around, LOS-only links and both site layouts of
145
- TR 36.885, below and above 6 GHz), the TR 38.901 indoor office, rural macro cells, a LEO satellite with
145
+ TR 36.885, below and above 6 GHz), the TR 37.885 urban grid with 500 m macro sites (since 2.3.0), the
146
+ TR 38.901 indoor office, rural and suburban (SMa, since 2.3.0) macro cells, a LEO satellite with
146
147
  earth-moving beams (since 2.0.0, TR 38.811 and TR 38.821), explicit site lists, and built-in scenario
147
148
  cards (`handoverlab scenarios`).
148
- - **Channel**: TR 38.901 UMi street canyon, UMa, RMa and InH-Office path loss (LOS/NLOS); line of sight from the
149
+ - **Channel**: TR 38.901 UMi street canyon, UMa, RMa, SMa (since 2.3.0) and InH-Office path loss (LOS/NLOS); O2I
150
+ building penetration loss of indoor users (since 2.3.0); line of sight from the
149
151
  building geometry plus the spatially consistent LOS state, hard or soft; spatially correlated shadowing; a
150
152
  time-varying component; L1 measurement error; beam gain and load-coupled interference;
151
153
  optionally a penetration loss per user (in-car loss of TR 38.901); or, since 1.12.0, your own radio
@@ -189,10 +191,10 @@ the clause-by-clause detail is in [standard compliance](https://github.com/mjs19
189
191
 
190
192
  | Part | Modelled | Abstracted | Not modelled |
191
193
  |---|---|---|---|
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 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
- | 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
- | 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 |
194
+ | 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 TR 37.885 urban macro grid without wrap-around (`urban-macro-tr37885-4ghz`) | several satellites |
195
+ | 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 |
196
+ | 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; the SCG as one PSCell with a full-buffer share | UE-side beamforming, conditional PSCell change, fast MCG recovery |
197
+ | 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 |
196
198
  | 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 |
197
199
  | 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 |
198
200
  | 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`, `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 |
@@ -201,7 +203,8 @@ the clause-by-clause detail is in [standard compliance](https://github.com/mjs19
201
203
 
202
204
  Built-in cards: `smoke`, `urban-grid-10ghz`, `fr3-urban-15ghz`, `urban-grid-28ghz-beams`, `dense-urban-2layer`,
203
205
  `open-area-10ghz`, `ns3-urban-3.5ghz`, `highway-tr37885-4ghz`, `highway-tr37885-30ghz`, `indoor-office-4ghz`,
204
- `rural-700mhz`, `ntn-leo600-2ghz`; each names the source of every value and its own limitations.
206
+ `rural-700mhz`, `ntn-leo600-2ghz`, `urban-macro-tr37885-4ghz`, `suburban-sma-7ghz`, `hst-fr2-28ghz`; each
207
+ names the source of every value and its own limitations.
205
208
 
206
209
  ## Scope: 5G-Advanced and beyond 5G
207
210
 
@@ -84,10 +84,12 @@ event D2 of Release 18:
84
84
  - **Scenarios**: the TR 37.885 urban street grid (configurable number of blocks; 433 m x 250 m
85
85
  pitch, 20 m streets) with sites on the pavement, an open area with a hexagonal site grid, the
86
86
  TR 37.885 highway (since 1.11.0 with wrap-around, LOS-only links and both site layouts of
87
- TR 36.885, below and above 6 GHz), the TR 38.901 indoor office, rural macro cells, a LEO satellite with
87
+ TR 36.885, below and above 6 GHz), the TR 37.885 urban grid with 500 m macro sites (since 2.3.0), the
88
+ TR 38.901 indoor office, rural and suburban (SMa, since 2.3.0) macro cells, a LEO satellite with
88
89
  earth-moving beams (since 2.0.0, TR 38.811 and TR 38.821), explicit site lists, and built-in scenario
89
90
  cards (`handoverlab scenarios`).
90
- - **Channel**: TR 38.901 UMi street canyon, UMa, RMa and InH-Office path loss (LOS/NLOS); line of sight from the
91
+ - **Channel**: TR 38.901 UMi street canyon, UMa, RMa, SMa (since 2.3.0) and InH-Office path loss (LOS/NLOS); O2I
92
+ building penetration loss of indoor users (since 2.3.0); line of sight from the
91
93
  building geometry plus the spatially consistent LOS state, hard or soft; spatially correlated shadowing; a
92
94
  time-varying component; L1 measurement error; beam gain and load-coupled interference;
93
95
  optionally a penetration loss per user (in-car loss of TR 38.901); or, since 1.12.0, your own radio
@@ -131,10 +133,10 @@ the clause-by-clause detail is in [standard compliance](https://github.com/mjs19
131
133
 
132
134
  | Part | Modelled | Abstracted | Not modelled |
133
135
  |---|---|---|---|
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 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
- | 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
- | 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 |
136
+ | 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 TR 37.885 urban macro grid without wrap-around (`urban-macro-tr37885-4ghz`) | several satellites |
137
+ | 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 |
138
+ | 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; the SCG as one PSCell with a full-buffer share | UE-side beamforming, conditional PSCell change, fast MCG recovery |
139
+ | 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 |
138
140
  | 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 |
139
141
  | 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 |
140
142
  | 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`, `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 |
@@ -143,7 +145,8 @@ the clause-by-clause detail is in [standard compliance](https://github.com/mjs19
143
145
 
144
146
  Built-in cards: `smoke`, `urban-grid-10ghz`, `fr3-urban-15ghz`, `urban-grid-28ghz-beams`, `dense-urban-2layer`,
145
147
  `open-area-10ghz`, `ns3-urban-3.5ghz`, `highway-tr37885-4ghz`, `highway-tr37885-30ghz`, `indoor-office-4ghz`,
146
- `rural-700mhz`, `ntn-leo600-2ghz`; each names the source of every value and its own limitations.
148
+ `rural-700mhz`, `ntn-leo600-2ghz`, `urban-macro-tr37885-4ghz`, `suburban-sma-7ghz`, `hst-fr2-28ghz`; each
149
+ names the source of every value and its own limitations.
147
150
 
148
151
  ## Scope: 5G-Advanced and beyond 5G
149
152
 
@@ -22,11 +22,38 @@ registered (2.1.0 defaults gave the same verdicts):
22
22
  | Recovery: time without connection per failure | 0.09 s | 1.0 s (`reest_s`) | ratio 0.67-1.5 | fails |
23
23
  | Execution failures | none in any cell | 0-5 % | needs 10 in ns-3 | not measurable |
24
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.
25
+ ns-3's full traffic is an overload too (more than a cell can carry), so both simulators fill the
26
+ cells; the difference is what link monitoring sees. In ns-3 its SINR hardly moves with the data
27
+ load; in HandoverLab it follows the data load by default (ns-3 has fewer failures at full traffic,
28
+ 90 to 34 and 13 to 3; HandoverLab many more, 18 to 521 and 4 to 175). TS 38.133 V19.6.0 clause 8.1
29
+ evaluates the link on a hypothetical PDCCH, and the neighbours' control channels and reference
30
+ signals are sent whatever the data load; `protocol.lm_load` gives link monitoring such a fixed
31
+ interferer load.
32
+
33
+ On recovery, the standard does not fix one value: TS 38.133 V19.6.0 clause 6.2.1.2.1 bounds the
34
+ re-establishment delay by 50 ms + T_identify_intra_NR (known FR1 cell: max(200 ms, 5 T_SMTC), Table
35
+ 6.2.1.2.1-1) + T_SI-NR + T_PRACH (at most the SSB-to-PRACH association period + 10 ms, TS 38.213
36
+ Table 8.1-1), followed by RRCReestablishment processing of 10 ms (TS 38.331 V19.4.0 Table 12.1-1).
37
+ That is about 0.28 s when the system information is already held and about 1.55 s with the T_SI of
38
+ 1280 ms of the test case A.6.3.2.1.1.2. HandoverLab's `reest_s` of 1.0 s lies inside; ns-3 (ideal
39
+ RRC) takes 0.09 s, below both. The recovery time was therefore not changed towards ns-3.
40
+
41
+ **Fresh held-out check N3 (2.3.0).** One setting was chosen on the light-traffic N2 cells above
42
+ (`protocol.lm_load` 0.15, with `protocol.exec_can_fail` false, as ns-3 has ideal execution) and
43
+ tested on 40 new ns-3 runs (seeds 301-305, ISD 200 / 400 m, 12 / 24 m/s, TTT 100 / 640 ms, light
44
+ traffic), with limits fixed before the runs:
45
+
46
+ | Check | Limit | Fixed link-monitoring load 0.15 | Default link monitoring |
47
+ |---|---|---|---|
48
+ | Failure level, sum HandoverLab / sum ns-3 | 0.67-1.5 | 0.47, fails | 0.16, fails |
49
+ | Failure order over the 8 cells (Spearman) | at least 0.8 | 0.95, passes | 0.78, fails |
50
+ | Handover rate, median ratio | 0.8-1.25 | 0.93, passes | 0.96, passes |
51
+ | Direction of the TTT effect on failures | 3 of 4 | 4, passes | 4, passes |
52
+
53
+ At TTT 100 ms the fixed load gives ns-3's failure counts (17 against 14, 11 against 10); at
54
+ TTT 640 ms it gives about half of them (84 against 180, 68 against 193), the known effect of ns-3's
55
+ slow out-of-sync detection (below). As fixed in advance, the setting is not adopted because the
56
+ level check fails; it is reported here, and no further tuning was done on these runs.
30
57
 
31
58
  **Summary (1.5.0).** Handover and unnecessary-handover rates of HandoverLab agree with ns-3 /
32
59
  5G-LENA. For failure rates, the order of settings and conditions agrees on part A and on both
@@ -0,0 +1,117 @@
1
+ # User-plane buffers at handover
2
+
3
+ By default HandoverLab counts the time a handover interrupts the data (`interruption_s_pm`) but not
4
+ what happens to the data themselves. Since 2.3.0 the option `protocol.buffers` adds a simplified
5
+ PDCP / RLC model of the downlink: every user has one data radio bearer whose data wait in a FIFO at
6
+ the gNB that holds its PDCP entity, are forwarded to the target cell over Xn, and may be lost or
7
+ delayed by the interruption. It works with every procedure (baseline handover such as A3, CHO,
8
+ DAPS, LTM and conditional LTM). It is off by default; with it off every result of 2.2.0 is
9
+ unchanged bit for bit (the new metrics are 0).
10
+
11
+ ```yaml
12
+ scenario:
13
+ base: smoke
14
+ traffic: {model: periodic} # periodic, ftp3 or fixed (constant-rate arrivals); not full_buffer
15
+ protocol:
16
+ buffers: am # RLC mode of the bearer: am or um; null: off
17
+ forwarding: true # the source forwards its data to the target over Xn
18
+ early_forwarding: false # CHO and LTM: forward before the execution instead of after it
19
+ xn_delay_s: 0.005 # one-way Xn delay [s] (assumption)
20
+ discard_timer_s: null # PDCP discard timer [s]: null (infinity) or a TS 38.331 value
21
+ sdu_bytes: null # SDU size for the SDU counts (null: packet_bytes or 1500)
22
+ ```
23
+
24
+ It combines with the slot scheduler (`protocol.scheduler`, see [scheduler](scheduler.md)): the data
25
+ in the HARQ processes then take part (see section 2).
26
+
27
+ ## 1. What happens at a handover
28
+
29
+ | Procedure | Source | HandoverLab |
30
+ |---|---|---|
31
+ | Baseline handover (A3, A3/A5, ...) | TS 38.300 V19.4.0 9.2.3.2.1 NOTE 2 (forwarding may start with the command), 9.2.3.2.2, 9.2.3.2.3 | when the UE leaves the source, the source forwards its FIFO and the data arriving until the completion; the target can send them `xn_delay_s` after they were forwarded and sends them before new data |
32
+ | CHO | 9.2.3.4.2 NOTE 2, 9.2.3.4.3, 9.2.3.4.4 | late forwarding: the source forwards once HANDOVER SUCCESS tells it the target, so the data are at the target 2 x `xn_delay_s` after the completion; `early_forwarding`: the data are at the target when the UE arrives |
33
+ | LTM, conditional LTM | 9.2.3.5.2 step 9a, NOTE 4, NOTE 5; 9.2.3.5.3; 9.2.3.7.1 | every cell of HandoverLab is its own gNB, so a cell switch is inter-gNB LTM: late or early forwarding as for CHO |
34
+ | DAPS | 9.2.3.2.2 (DAPS), 9.2.3.2.3 | the forwarding tunnel always exists; the source keeps sending during the execution and forwards every SN-assigned SDU as a copy; the target sends the rest at the completion, without loss or wait; a fallback keeps the data at the source |
35
+ | Failure and re-establishment | 9.2.3.3 steps 6/7 | with forwarding the data of the last gNB move to the new cell and can be sent `xn_delay_s` after the re-establishment; a recovery into a prepared cell (CHO, LTM) is forwarded as an execution of that procedure; without forwarding the data are lost in another cell and kept in the same cell |
36
+ | Discard timer | TS 38.323 V19.1.0 5.3; TS 38.331 PDCP-Config discardTimer | data older than `discard_timer_s` are discarded (lost) |
37
+
38
+ Without forwarding (`forwarding: false`) the data at the source and the data arriving there until the
39
+ completion are lost at every execution (not with DAPS, which always forwards).
40
+
41
+ ## 2. AM and UM
42
+
43
+ The RLC mode matters for the data that the lower layers hold when the UE leaves: with the slot
44
+ scheduler, the data in the HARQ processes. An RRC handover needs a MAC reset and an RLC
45
+ re-establishment (TS 38.300 9.2.3.1; TS 38.322 V19.2.0 5.1.2 discards the RLC PDUs). With RLC AM
46
+ these data are not acknowledged, so they are forwarded and sent again by the target (9.2.3.2.2:
47
+ the target re-transmits all forwarded data); with RLC UM no PDCP SDU is re-transmitted in the
48
+ target, so they are lost. A transport block lost after the last HARQ transmission is sent again by
49
+ RLC ARQ with AM and lost with UM (ARQ exists only for AM, TS 38.322 4.4). Without the slot
50
+ scheduler the rate model delivers at once, there are no data in the lower layers, and AM and UM give
51
+ the same results.
52
+
53
+ ## 3. Delay
54
+
55
+ The data plane keeps the measurement interval of the rate model or the scheduler (40 ms by
56
+ default), and a user executing at a measurement instant gets no data in that interval, as in 2.2.0.
57
+ Within an interval the data of a user leave the FIFO as a fluid, at the larger of its round-robin
58
+ share of the free carrier at its spectral efficiency and the rate needed to send what the interval
59
+ delivers; data arrive at the start of their interval. The PDCP delay of a byte is its delivery time
60
+ minus its arrival at the gNB; `pdcp_delay_ms` is the byte-weighted mean, `pdcp_delay_p95_ms` the
61
+ 95th percentile (1 ms bins) and `pdcp_delay_forwarded_ms` the mean over the data that a target sent
62
+ after forwarding. The fluid leaves out the slot and HARQ latency of the air interface, so without a
63
+ handover small packets see delays far below 1 ms; the delay metrics mainly show what interruptions,
64
+ forwarding and links below Qout (no data in the rate model) add.
65
+
66
+ ## 4. Metrics
67
+
68
+ | Metric | Unit | Meaning |
69
+ |---|---|---|
70
+ | `pdcp_delivered_kbyte_pm` | kbyte/UE-min | data delivered |
71
+ | `pdcp_lost_kbyte_pm`, `pdcp_lost_share` | kbyte/UE-min, 1 | data lost, and the lost share of what arrived |
72
+ | `pdcp_lost_handover_kbyte_pm` | kbyte/UE-min | lost at executions (no forwarding; HARQ data with UM) |
73
+ | `pdcp_lost_failure_kbyte_pm` | kbyte/UE-min | lost at failures and re-establishments |
74
+ | `pdcp_lost_discard_kbyte_pm` | kbyte/UE-min | discarded by the discard timer |
75
+ | `pdcp_lost_harq_kbyte_pm` | kbyte/UE-min | transport blocks lost after the last HARQ transmission with UM |
76
+ | `pdcp_lost_sdus_pm`, `pdcp_forwarded_sdus_pm` | 1/UE-min | lost and forwarded data in SDUs of `sdu_bytes` |
77
+ | `pdcp_forwarded_kbyte_pm` | kbyte/UE-min | data forwarded over Xn (DAPS: the copies, duplicates included) |
78
+ | `pdcp_delay_ms`, `pdcp_delay_p95_ms`, `pdcp_delay_forwarded_ms` | ms | PDCP delay |
79
+
80
+ ## 5. Assumptions and limits
81
+
82
+ - Assumptions (not in the texts): the Xn delay; whether the network forwards ("may"); that the gNB
83
+ uses the discardTimer values for its downlink data (TS 38.323 defines the timer for the
84
+ transmitting entity); SN assignment on arrival at the source (DAPS forwards SN-assigned SDUs);
85
+ 1500-byte SDUs for the SDU counts of non-periodic traffic; copies sent by early forwarding to
86
+ candidates that are not used are not counted.
87
+ - Downlink only, one bearer per user; no PDCP reordering or duplicates at the UE, no PDCP status
88
+ report, no path-switch delay (the path switches at the completion), no intra-CU LTM.
89
+ - The interruption in the data plane is quantised to the measurement interval (as the rate of
90
+ 2.2.0); a DAPS source that has a radio link failure during the execution stops sending.
91
+ - This version needs the base engine (no beams, layers, NTN or TS 38.133 periods) and is not run in
92
+ the batched engine; `full_buffer` traffic is rejected (no arrivals, no delay).
93
+
94
+ ## 6. An example
95
+
96
+ `smoke` card, 15 users, 30 s, two seeds, RLC AM, periodic traffic (100-byte packets every 20 ms):
97
+
98
+ | Rule | forwarded kbyte/UE-min | lost share without forwarding | mean PDCP delay | delay of forwarded data |
99
+ |---|---|---|---|---|
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.
109
+
110
+ ## 7. Checks
111
+
112
+ `tests/test_buffers.py` holds the criteria fixed before the code: hand-computed cases for every procedure (forwarded bytes, losses,
113
+ delays with and without the late-forwarding wait, DAPS, HARQ data with AM and UM, the discard timer,
114
+ re-establishment with and without forwarding), conservation (arrived = delivered + lost + queued,
115
+ checked at the end of every run with the option) for A3, CHO, DAPS, LTM and CLTM with AM and UM,
116
+ with and without the slot scheduler, HARQ losses with UM and none with AM, a delay below one
117
+ interval without handovers, and that the option off changes no fingerprint.
@@ -0,0 +1,114 @@
1
+ # How to study dual connectivity (NR-DC)
2
+
3
+ Since 2.3.0 a user can hold a secondary cell group (SCG) next to its master cell group (MCG): the
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
+ node (SN). The option `protocol.dc` is off by default; with it off every result stays as it was.
6
+
7
+ The model is the simplest consistent subset that a system-level simulator needs: when an SCG is
8
+ added, changed or lost, what that costs in signalling and interruption, and how much time the
9
+ user spends with a second link. The MCG behaves exactly as without dual connectivity: its handover
10
+ rule, radio-link monitoring, failures and re-establishment do not see the SCG (a test checks that the
11
+ MCG event log is the same whether an SN is ever added or not).
12
+
13
+ ## 1. Turn it on
14
+
15
+ The SCG lives on the cells of one entry of `radio.layers`, on a carrier that no MCG cell uses. The
16
+ built-in `dense-urban-2layer` card has a 4 GHz macro layer and a 30 GHz micro layer, which makes
17
+ an FR1 MCG and an FR2 SCG:
18
+
19
+ ```yaml
20
+ # dc.yaml
21
+ schema: 1
22
+ scenario:
23
+ base: dense-urban-2layer
24
+ protocol:
25
+ dc: {scg_layer: micro-30ghz}
26
+ seeds: [1, 2, 3]
27
+ rules:
28
+ - {rule: a3, off_db: 3.0, ttt_s: 0.16}
29
+ output: results/dc.csv
30
+ ```
31
+
32
+ ```bash
33
+ handoverlab run dc.yaml
34
+ ```
35
+
36
+ | Key of `protocol.dc` | Default | Meaning |
37
+ |---|---|---|
38
+ | `scg_layer` | first entry of `radio.layers` | layer whose cells form the SCG |
39
+ | `add_thresh_dbm`, `add_ttt_s` | `-110`, `0.16` | SN addition: event A4, the best SCG cell's L3 SS-RSRP per RE above the threshold for the time-to-trigger |
40
+ | `change_off_db`, `change_ttt_s` | `3`, `0.16` | PSCell change: event A3 among the SCG cells |
41
+ | `release_thresh_dbm`, `release_ttt_s` | `-120`, `0.16` | SN release: the PSCell's L3 SS-RSRP below the threshold |
42
+ | `prep_s`, `exec_s` | `protocol.prep_s`, `protocol.exec_s` | preparation between the nodes; random access on the PSCell |
43
+ | `on_mcg_ho` | `keep` | at an MCG handover the target MN keeps the SN (`keep`) or releases it (`release`) |
44
+
45
+ The MCG uses the base layer and any other layer; it never hands over to an SCG cell, so
46
+ `inter_frequency_handovers_pm` counts only handovers between MCG carriers.
47
+
48
+ ## 2. What is modelled (TS 37.340 V19.3.0, TS 38.331 V18.11.0)
49
+
50
+ | Procedure | Clause | In HandoverLab |
51
+ |---|---|---|
52
+ | SN addition, initiated by the MN on its measurements | 7.2, 10.2.2 | A4 held for `add_ttt_s` while the MCG is connected; `prep_s` (SN Addition Request / Acknowledge); RRC reconfiguration over the MCG; random access on the new PSCell after `exec_s`; the SCG joins when the PSCell SINR reaches Qout while T304 runs |
53
+ | SN change and PSCell change within the SN | 10.5.2, 10.6 | A3 among SCG cells, then the same steps; no SCG data from the command until the target is joined |
54
+ | SN release | 10.4.2 | PSCell below `release_thresh_dbm` for `release_ttt_s`, released after `prep_s` |
55
+ | SCG radio-link failure | 7.7; TS 38.331 5.3.10.3 | own Qout / Qin filters, N310 / N311 indications and T310 on the PSCell, with the protocol's constants |
56
+ | SCG failure handling | 7.7; TS 38.331 5.7.3 | SCG RLF and failed additions or changes are reported to the MN (SCGFailureInformation) instead of a re-establishment; the MN releases the SCG |
57
+ | MCG failure | 7.7; TS 38.331 5.3.7.2 | re-establishment, which performs the MR-DC release |
58
+ | Inter-MN handover | 10.7 | `on_mcg_ho`: the SN is kept or released |
59
+
60
+ Every SCG reconfiguration is sent over the MCG (SRB1). One that falls due while the MCG is not
61
+ connected or its T310 runs is dropped (the trigger starts again). The SCG cells' L1 samples enter
62
+ an L3 filter of their own (TS 38.331 5.5.3.2 with the reference period of the SCG carrier). The
63
+ PSCell sends on its strongest SSB beam of the current L1 instant (ideal SCG beam management), and
64
+ the other cells of the SCG carrier interfere with their load.
65
+
66
+ **SCG data.** An SCG user receives W x min(log2(1 + SINR), se_max) x (1 - background load of the
67
+ PSCell) / (SCG users of that PSCell): a full-buffer share of the PSCell, reported as
68
+ `scg_rate_mbps`. The MCG rate (`rate_mbps`) is computed as without dual connectivity; the two are
69
+ not split by a bearer model.
70
+
71
+ ## 3. Metrics
72
+
73
+ `sn_additions_pm`, `sn_addition_failures_pm`, `pscell_changes_pm`, `pscell_change_failures_pm`,
74
+ `sn_releases_pm`, `scg_rlf_pm`, `scg_failures_pm` (RLF + failed additions + failed changes),
75
+ `scg_released_by_mcg_pm`, `scg_time_share`, `scg_rate_mbps`, `pscell_change_interruption_s_pm` and
76
+ `dc_rrc_messages_pm` (see [the metric reference](../reference/metrics.md)). With the event-log level
77
+ `full` the procedure trace has the SCG events `sn_add_request` (value: the time the A4 condition was
78
+ entered), `sn_add`, `sn_add_failure`, `pscell_change`, `pscell_change_failure`, `scg_rlf`,
79
+ `sn_release`, `scg_release_mcg_failure` and `scg_release_mcg_ho`.
80
+
81
+ ## 4. What is left out
82
+
83
+ - Other MR-DC options (EN-DC, NGEN-DC, NE-DC) and SCells in either cell group.
84
+ - Fast MCG link recovery (T316); SCG deactivation and activation (clause 7.13).
85
+ - Conditional PSCell addition and change (CPA, CPC, subsequent CPAC; clause 10.2.3), SCG LTM, CHO with
86
+ candidate SCGs (clauses 10.19, 10.20).
87
+ - Split SRB and SRB3 (clauses 7.5, 7.6): every SCG message goes over the MCG.
88
+ - Bearer types, PDCP duplication, data forwarding, the SN status transfer and the path switch.
89
+ - The MN's choice to keep or change the SN after an SCG failure (the model always releases it) and
90
+ to change the SN at an inter-MN handover.
91
+ - Measurement gaps for the SCG carrier and UE capability coordination; the uplink; SCG beam management
92
+ (the strongest beam is used).
93
+
94
+ ## 5. Pre-registered checks (2.3.0)
95
+
96
+ Criteria fixed before the runs. World: `dense-urban-2layer` with `protocol.dc: {scg_layer: micro-30ghz}`
97
+ (20 users, 120 s, 100 s measured), rule A3 3 dB / 160 ms, seeds 1-3.
98
+
99
+ | Check | Result |
100
+ |---|---|
101
+ | D1: with `protocol.dc` unset every existing test and golden fingerprint is unchanged | pass |
102
+ | D2: the MCG event log is the same with an SN never added (`add_thresh_dbm: 1000`) and with `on_mcg_ho: release` | pass (4 of 4 comparisons, seeds 1 and 2; also a test) |
103
+ | D3: every started addition or change ends once as success, failure or drop | pass (test) |
104
+ | D4: addition timing = A4 entry + TTT + preparation + random access; PSCell changes happen; an MCG failure releases the SCG | pass (tests) |
105
+ | D5a: a 10 dB lower addition threshold raises the SCG time share | **fail**: no change at all (0.953 both). In this dense micro layer the best SCG cell is above -110 dBm everywhere, so the A4 threshold never binds; the time without SCG comes from MCG failures (each releases the SCG) and the addition delay. |
106
+ | D5b: more PSCell changes than MCG handovers (9 micro sites per macro site) | pass (20.2 vs 18.0 per UE-min) |
107
+ | D5c: more SCG failures at 60 km/h than at 30 km/h | pass (0.25 vs 0.03 per UE-min) |
108
+
109
+ Mean of the three seeds at 30 km/h (default thresholds, SN kept at MCG handovers): SCG time share 0.95,
110
+ 20.2 PSCell changes and 1.3 SN additions per UE-min, 1.3 SCG releases per UE-min by MCG failures,
111
+ 0.03 SCG failures per UE-min (all failed additions or changes, no SCG radio-link failure), SCG rate
112
+ 184 Mbit/s per user next to an MCG rate of 10 Mbit/s. At 60 km/h: time share 0.91, 30 PSCell changes,
113
+ 0.25 SCG failures and 2.5 releases by MCG failures per UE-min. With `on_mcg_ho: release` the SN is
114
+ re-added after every MCG handover (17-18 additions per UE-min) and the time share falls to 0.85.
@@ -0,0 +1,102 @@
1
+ # How to study a high-speed train in FR2
2
+
3
+ Since 2.3.0 the built-in card [`hst-fr2-28ghz`](../scenarios/hst-fr2-28ghz.md) follows the FR2
4
+ high-speed train deployment of TR 38.854 V18.0.0 as its system-level mobility study sets it up
5
+ (Table 6.3.8.1-1, Scenario-A, unidirectional RRHs, without DPS):
6
+
7
+ | | TR 38.854 | Card |
8
+ |---|---|---|
9
+ | Track and RRHs | one train on one straight track, RRHs on one side, Ds 700 m, Dmin 10 m, 12 sites (Tables 5.1-1, 5.2-1, 6.3.8.1-1) | highway layout with one track, 12 sites 700 m apart at 10 m, wrap-around |
10
+ | RRH | 15 m, 31 dBm, panel [1, 1, 8, 8, 2], one SSB beam into the boresight, the panel pointing at the track where the next site is | one sector, one SSB beam, 8 x 8 panel, azimuth 180.82 deg, zenith 90.82 deg |
11
+ | CPE | 5 m, panel [1, 1, 4, 4, 2] of 5 dBi elements pointing to the RRHs, 350 km/h | one gain of 17.04 dB, 97.22 m/s |
12
+ | Carrier, channel | 28 GHz, 50 MHz, 120 kHz, TR 38.901 RMa LOS only, one CPE, no inter-cell interference, DL full buffer | the same, no background load |
13
+ | Handover, RLM | A3 3 dB, TTT 80 ms, SMTC 20 ms, measurement period 480 ms (N = 8), N310 = N311 = 2, Qout / Qin -8 / -6 dB, 600 / 300 ms | rule `{a3, off_db: 3, ttt_s: 0.08}`, TS 38.133 periods, the same RLM values |
14
+
15
+ Each RRH is its own cell ("each BBU has only one RRH", TR 38.854 clause 6.3.4.1), so the train hands
16
+ over at every RRH: about every Ds / v = 700 m / 97.2 m/s = 7.2 s.
17
+
18
+ ## 1. Run it in both directions
19
+
20
+ All RRHs of the card point west. A train going east travels towards the serving beams (the
21
+ "opposite direction" of the TR: train east, RRHs west), a train going west away from them ("same
22
+ direction"). The card has one train per run and draws its direction from the seed; pointing the
23
+ RRHs east on the same seeds gives the other direction on the same trajectories:
24
+
25
+ ```yaml
26
+ # hst.yaml
27
+ schema: 1
28
+ scenario: hst-fr2-28ghz
29
+ seeds: {first: 1, last: 20}
30
+ rules:
31
+ - {rule: a3, off_db: 3.0, ttt_s: 0.08}
32
+ output: results/hst-west.csv
33
+ ```
34
+
35
+ and a second file `hst-east.yaml` with the RRHs pointing east (`359.18 = -atan(10 / 700)` degrees):
36
+
37
+ ```yaml
38
+ schema: 1
39
+ scenario: {base: hst-fr2-28ghz, radio: {beams: {sector_az0_deg: 359.18}}}
40
+ seeds: {first: 1, last: 20}
41
+ rules:
42
+ - {rule: a3, off_db: 3.0, ttt_s: 0.08}
43
+ output: results/hst-east.csv
44
+ ```
45
+
46
+ ```bash
47
+ handoverlab run hst.yaml
48
+ handoverlab run hst-east.yaml
49
+ ```
50
+
51
+ Scenario-B (Dmin 150 m) is an override: `layout.site_offset_m: 149.98` and the beams aimed again.
52
+
53
+ ## 2. What the TR describes, and what HandoverLab gives
54
+
55
+ Criteria fixed before the runs (pre-registered); 40 seeds x 2 RRH orientations, 100 s measured per run
56
+ (4000 CPE-seconds per direction), rule A3 3 dB / 80 ms. The TR's values are read from its bar charts
57
+ (Figures 6.3.4.1.1.1-1 to -4, legacy requirements, uni-directional Scenario-A without DPS).
58
+
59
+ | | Same direction: TR / HandoverLab | Opposite direction: TR / HandoverLab |
60
+ |---|---|---|
61
+ | Handovers per CPE-second, no DRX | 0.152 / 0.139 | 0.150 / 0.145 |
62
+ | Time of stay in a cell [s] | 6.54 / 7.22 | 6.66 / 6.92 |
63
+ | Ping-pong handovers [%] | 3.95 / 0.0 | 3.36 / 0.35 |
64
+ | Mobility failures (RLF + HOF) [% of handovers and failures] | 0 / 0 | 2.1 / 0 |
65
+ | Time below Qout or interrupted [% of time] | about 0.7 / 0.55 | 1.8 / 2.4 |
66
+
67
+ | Check | Result |
68
+ |---|---|
69
+ | H1: received power from the serving RRH >= -50 dBm along its stretch (TR 6.3.3.1.1) | **fail as registered**: from 43 m to 700 m in front of the RRH it is -45.8 dBm or more, but within 10-42 m of the RRH it drops to -115 dBm, in the vertical null of the 8-element column (the CPE passes 10 m below the beam's tilt). The TR's statement does not cover the area under the RRH. |
70
+ | H2: handovers per CPE-second in [0.125, 0.181] in both directions | pass (0.139 same, 0.145 opposite) |
71
+ | H3: no failure in the same direction | pass (0 in 40 runs) |
72
+ | H4: with DRX-40 periods, failures only in the opposite direction | **fail**: no failure in either direction. The emulation registered for it (`rx_sweep_n: 24`) did not lengthen the L3 measurement period, which in TS 38.133 Table 9.2.5.2-2 is ceil(M_meas) T_SMTC with M_meas = 24 already containing N = 8; the runs were identical to those without DRX except for the RLM windows. |
73
+
74
+ Exploratory, after that finding (not pass/fail): the DRX-40 period of 1440 ms through
75
+ `protocol.ssb_period_s: 0.06` with the RLM windows of 3.6 / 1.8 s, 20 seeds per orientation:
76
+ still no failure in either direction. With the element back lobe removed as in the TR's mobility study
77
+ (`radio.beams.am_db: 100`), the opposite direction spends 28.8 % of the time below Qout (same
78
+ direction 0.6 %; TR at DRX 40: 40.3 % and about 0.7 %), but none of it ends in a radio-link failure:
79
+ radio-link monitoring averages the linear SINR over 3.6 s, and the strong signal before the RRH keeps
80
+ that average above Qout. With the 480 ms measurement period of no DRX, removing the back lobe raises the opposite direction's
81
+ time below Qout from 2.4 % to 8.6 %, again without failure.
82
+
83
+ What this means for a study with the card:
84
+
85
+ - The geometry, link budget and handover rhythm follow the TR: one handover per RRH, about 7 s apart,
86
+ and the asymmetry of the two directions shows in the time below Qout.
87
+ - The failure side of the TR's result (2.1 % without DRX, about 70 % at DRX 40 in the opposite
88
+ direction) is not reproduced. Two simplifications are the likely reason (not tested one by one): the CPE has one gain towards all RRHs
89
+ (in the TR the CPE panel faces the serving RRHs, so the source RRH falls behind the panel once the
90
+ CPE passes it), and radio-link monitoring is a smoothed SINR threshold, not the BLER of a hypothetical PDCCH.
91
+ Use the card for handover timing, rates and outage; do not read absolute failure rates from it.
92
+
93
+ ## 3. Limits
94
+
95
+ - One gain for the CPE towards every RRH: the RRHs behind the CPE get the same gain as those in front,
96
+ which overstates the received power right after the CPE passes an RRH.
97
+ - The RRH element has the back lobe of TR 38.901 Table 7.3-1 (A_m 30 dB, as TR 38.854 Table 6.1.1.1);
98
+ the TR's mobility study used "an antenna model without back lobe" (clause 6.3.4.1.3).
99
+ `radio.beams.am_db` raises A_m.
100
+ - No DRX, DPS / SFN, multi-TRP, Doppler or fast fading, uplink timing, tunnels or cell-detection delay.
101
+ - Radio-link monitoring on the SSB link quality with the CSI-RS evaluation periods of the TR as time
102
+ constants.