How to study DAPS handover and L1/L2-triggered mobility¶
Since 1.0.0rc2 HandoverLab has two procedures next to baseline and conditional handover:
| Rule | Procedure | Specification | What changes compared with a3 |
|---|---|---|---|
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 |
ltm |
L1/L2-triggered mobility (Rel-18) | TS 38.300 clause 9.2.3.5 | candidates configured in advance; the switch is decided on unfiltered L1 reports and sent as a MAC CE; short RACH-less execution |
cltm |
conditional LTM (Rel-19 work on LTM, since 1.6.0) | as ltm for the candidates and the execution |
the UE decides the switch on its L1 measurements and executes at once: no cell switch command that could arrive late |
Both run on the same worlds and seeds as every other rule, so they can be compared pairwise with
a3 and cho in an experiment or a study. The user guide describes the
model in detail; this page shows how to use it.
1. Compare the four procedures¶
# procedures.yaml
schema: 1
scenario: {base: smoke, radio: {isolation: 1.0}, mobility: {users: 20, profile: veh30}}
seeds: [1, 2, 3]
rules:
- {rule: a3, off_db: 3.0, ttt_s: 0.16}
- {rule: daps, off_db: 3.0, ttt_s: 0.16}
- {rule: cho, o_prep_db: -2.0, o_exec_db: 3.0, ttt_exec_s: 0.08}
- {rule: ltm, o_prep_db: -3.0, o_switch_db: 2.0, ttt_switch_s: 0.08}
- {rule: cltm, o_prep_db: -3.0, o_switch_db: 2.0, ttt_switch_s: 0.08}
output: results/procedures.csv
handoverlab run procedures.yaml --events results/procedures-events.csv
radio.isolation: 1.0 and fast users make failures likely, so that the differences between the
procedures show. Read the columns:
interruption_exec_s_pm: DAPS removes the execution gap (0 with the defaultinterruption_s); LTM shortens it to itsexec_s(20 ms instead ofexec_s= 40 ms of the scenario).outage_pct,rate_mbps: with DAPS the user keeps its rate through the execution.too_early_pmagainstfailures_pm: for DAPS an execution that cannot join the target and falls back to the source istoo_earlybut not a failure. Count the fallbacks in the event log:
import handoverlab as hl
rows = hl.read_events("results/procedures-events.csv")
fallbacks = sum(1 for e in rows if e["cause"] == "daps_fallback")
n_preparations,n_unused_preparations,prepared_cells_mean: for LTM these count candidate configurations, the signalling an early configuration costs.
2. Change one thing at a time¶
The DAPS parameters switch its two mechanisms on and off, so their contributions can be separated on the same seeds:
rules:
- {rule: daps, name: DAPS, off_db: 3.0, ttt_s: 0.16}
- {rule: daps, name: DAPS-no-fallback, off_db: 3.0, ttt_s: 0.16, fallback: false}
- {rule: daps, name: DAPS-no-source-data, off_db: 3.0, ttt_s: 0.16, source_data: false}
- {rule: daps, name: as-A3, off_db: 3.0, ttt_s: 0.16, fallback: false, source_data: false}
The last one gives exactly the results of {rule: a3, off_db: 3.0, ttt_s: 0.16}; the test suite
checks this equivalence.
For LTM the main parameters are the candidate offset o_prep_db (how early, and how many cells, are
configured), the switch offset o_switch_db with ttt_switch_s (L1 samples are noisier than L3
measurements: a short ttt_switch_s reacts fast but switches back and forth), and the timing
cmd_delay_s and exec_s. recovery: false turns off the recovery into a candidate after a
failure.
3. Tune them fairly¶
In a study, give each procedure the same tuning budget (see the tuning tutorial):
methods:
A3:
rule: a3
grid: {off_db: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0], ttt_s: [0.0, 0.04, 0.08, 0.16, 0.32]}
natural_bounds: {ttt_s: lower}
DAPS:
rule: daps
grid: {off_db: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0], ttt_s: [0.0, 0.04, 0.08, 0.16, 0.32]}
natural_bounds: {ttt_s: lower}
LTM:
rule: ltm
fixed: {o_prep_db: -3.0, n_max: 4}
grid: {o_switch_db: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0], ttt_switch_s: [0.0, 0.04, 0.08, 0.16, 0.32]}
natural_bounds: {ttt_switch_s: lower}
Add interruption_exec_s_pm and outage_pct to compare.metrics to see what the procedures buy.
4. Follow single users¶
With --event-level full the trace contains two new events: switch (an LTM cell switch command
is sent; value: the switch offset) and fallback (a DAPS execution returned to the source; value:
the source SINR). handoverlab.eventlog.serving_cells, which the dashboard map uses, puts a user
back into its source cell after a fallback.
5. Write your own DAPS or LTM rule¶
Subclass hl.DAPSRule (hooks a3_offsets and time_to_trigger, like a baseline rule) or
hl.LTMRule (hooks prep_offsets on L3 measurements and switch_offsets, which may use the
unfiltered L1 samples obs.l1_dbm), and check it with the contract kit:
import numpy as np
import handoverlab as hl
from handoverlab.testing import check_rule
class SpeedLTM(hl.LTMRule):
"""LTM whose switch offset grows for slow users (fewer switches back and forth)."""
def __init__(self, o_switch_db=2.0, name="LTM-speed"):
super().__init__(name)
self.o_switch_db = o_switch_db
self.report_offset_db = -3.0
def params(self):
return dict(o_switch_db=self.o_switch_db)
def prep_offsets(self, obs):
return -3.0
def switch_offsets(self, obs):
off = self.o_switch_db + 2.0 * (obs.speed < 5.0) # (U,)
return np.repeat(off[:, None], obs.l1_dbm.shape[1], axis=1) # a scalar or (U, M)
check_rule(SpeedLTM, {"o_switch_db": 2.0})
Limits of the model¶
- DAPS: since 2.1.0 the source link is monitored during the execution (TS 38.331 5.3.10.1): T310 of the source is not stopped, a source radio-link failure while T304 runs releases the source, and the UE falls back only if no source failure was detected (5.3.5.8.3); no DAPS from FR2 to FR2 and none for NTN (TS 38.300). Uplink and the PDCP details of dual protocol stacks are not modelled; the source carries the user's full rate until the target is joined or the source fails.
- LTM: L1 reports arrive at every L1 sample with the scenario's L1 error, without beam-level reports or reporting delay; candidate configurations use the preparation delay and the loss model of conditional configurations; early timing-advance acquisition always succeeds. Since 2.1.0 the other candidates stay configured after a cell switch (TS 38.331 5.3.5.18.6) and a switch between FR1 and FR2 takes 20 ms more (TS 38.133 6.3.1.3).
- Conditional LTM (
cltm): the switch condition is modelled like the LTM switch condition (one offset and a time-to-trigger on L1 samples), since the Rel-19 condition was not frozen when the rule was written; the UE-side evaluation has no reporting delay.