Access: RACH, connection setup and DRX¶
By default every robot is connected and awake for the whole episode. NRConfig(rach=True) and NRConfig(drx=True) turn on a per-robot access state machine on level L2 (core/access.py). A robot is scheduled, in either direction, only while it is connected and awake. Its messages wait in the queue otherwise, so the frame buffer, the timeouts and the AoI apply as usual.
from isaac_net.core import NRConfig, make_engine
from isaac_net.core.energy import EnergyConfig
cfg = NRConfig(rach=True, rach_initial="idle", rach_release_after_ms=2000,
drx=True, drx_inactivity_ms=100, drx_cycle_ms=160, drx_on_ms=10,
energy=EnergyConfig(drx_sleep_power_w=0.002))
net = make_engine("L2", E, R, "cuda", cfg, backend="graph")
out = net.step(None, poses)
out["access_state"] # [E, R] 0 idle, 1 RACH, 2 connected, 3 DRX-dormant (at the step's last slot)
out["rach_attempts"] # [E, R] preambles sent this step
out["access_sleep_frac"] # [E, R] share of the step dormant or idle (read by EnergyLoop)
net.counters()["access"] # rach_attempts, rach_collisions, rach_successes, rach_failures, rrc_releases
State machine¶
UL or DL data arrives
IDLE (0) ----------------------> RACH (1) --- preamble alone at its RO ---> RAR + Msg3/Msg4 ---> CONNECTED (2)
^ | ^ | ^
| | | backoff U[0, rach_backoff_ms], next RO | |
| +---+ same preamble as another robot of the cell (collision) | |
| rach_max_attempts failures: the procedure restarts | |
| | |
+------------------ rach_release_after_ms without activity (RRC release) -------------------+ |
|
CONNECTED (2) <---- next on-duration, or UL data with drx_ul_wake="sr" ----> DORMANT (3) |
----- drx_inactivity_ms without scheduling activity ------> -----------+
Fields¶
| Field | Default | Meaning | Source |
|---|---|---|---|
rach |
False | contention-based random access before a robot is served | TS 38.321 §5.1 |
rach_occasion_slots |
20 | RACH occasion (RO) period; the RO is the first UL-capable slot of each window. Must be a multiple of the TDD period | TS 38.211 §6.3.3.2 (PRACH configuration period) |
rach_preambles |
64 | contention-based preambles per cell and RO | TS 38.211 §6.3.3.1 (64 preambles per cell) |
rach_rar_window_slots |
10 | preamble to RAR; the RAR is taken at the end of the window | TS 38.321 §5.1.4 (ra-ResponseWindow) |
rach_msg3_slots |
10 | RAR to contention resolution (Msg3 on PUSCH, Msg4) | TS 38.321 §5.1.5 |
rach_backoff_ms |
20 | backoff after a collision, uniform in [0, value] | TS 38.321 §5.1.4, Table 7.2-1 |
rach_max_attempts |
10 | preambleTransMax | TS 38.321 §5.1.4, TS 38.331 |
rach_initial |
"connected" | state after a reset: "connected" (as without RACH) or "idle" (a fleet that powers on) | — |
rach_release_after_ms |
None | RRC release to idle after this much inactivity; None = never | TS 38.331 (RRCRelease), network inactivity timer |
drx |
False | connected-mode DRX | TS 38.321 §5.7 |
drx_inactivity_ms |
100 | drx-InactivityTimer | TS 38.321 §5.7, TS 38.331 DRX-Config |
drx_cycle_ms |
160 | drx-LongCycle | same |
drx_on_ms |
10 | drx-onDurationTimer | same |
drx_short_cycle_ms |
None | drx-ShortCycle; None = no short cycle | same |
drx_short_cycles |
2 | drx-ShortCycleTimer, in short cycles | same |
drx_start_offset_ms |
0 | drx-StartOffset | same |
drx_ul_wake |
"sr" | UL data while dormant: "sr" wakes the robot at once (a pending SR counts as Active Time), "on_duration" waits for the next on-duration | TS 38.321 §5.7 (Active Time) |
EnergyConfig.drx_sleep_power_w (default None = idle_power_w) is the power while DRX-dormant or idle; see background-energy-sharding.md.
How it is modelled¶
Gating. The access stage ANDs its mask into MacLink.sched_ok, the mask the handover interruption already uses, for every UL and DL data slot. The MAC code is unchanged. With several cells the mask is combined with the handover mask. The SR state machine keeps running while a robot is not schedulable, so its grant is ready when it becomes schedulable, which stands for the buffer status that Msg3 carries.
RACH. UL data (a submit() before the step or a traffic-model message at its arrival slot) or DL data for an idle robot starts the procedure. The robot sends a preamble at the first RO at or after the arrival. Each robot draws one of rach_preambles preambles from the engine's counter RNG. Two or more robots of the same env and cell that draw the same preamble at the same RO collide. The counts per (env, cell, preamble) come from one scatter_add over [E, C · preambles], with no loop over robots. A collision fails for every robot involved, since Msg3 capture is not modelled. A successful robot is served from RO + rach_rar_window_slots + rach_msg3_slots on. A colliding robot learns of the failure at the same time, backs off, and retries at the next RO after the backoff. For 32 robots that power on together on 64 preambles, the share whose first preamble succeeds matches (63/64)^31 = 0.614 (tested over 256 envs).
RLF re-establishment. With rach=True and radio link failure on (rlf=True, several cells, multicell.md), re-establishment goes through this RACH model instead of the fixed reest_delay_ms. When the cell search of CellAssociation selects a suitable cell, after the RLF declaration or for a robot that went idle at T311 expiry, the robot enters RACH toward that cell and contends with that cell's robots. Contention resolution ends the outage: the robot is served, and attached to the new cell, from RO + rach_rar_window_slots + rach_msg3_slots on, so out["rlf"] covers the access delay, and collisions, backoff and failed procedures count as for any other attempt. The stage draws its ROs at the start of each control step, so a selection made during a step uses the first RO of the next step at the earliest. The interface is two calls on CellAssociation: take_reest_requests() returns the robots that selected a cell and the slot of the selection, and rach_connected(mask, g) reports the slot from which service starts. Both use fixed [E, R] masks and no host sync. With rach=False the fixed reest_delay_ms applies as before (tested bitwise against the engine before the change).
DRX. A connected robot is awake (Active Time) while the inactivity timer runs, during the on-duration of its cycle, or, with drx_ul_wake="sr", while it has UL data. The inactivity timer restarts in every slot in which the robot is awake and has data or a waiting HARQ process in that direction. This stands for the PDCCH of a new transmission, so the timer starts once the buffers have drained. On-durations follow the global slot clock (the SFN), so an env's resets do not move them. DL data for a dormant robot waits for the next on-duration.
Randomness and batching. The preamble and backoff draws use the engine's counter RNG (sites 16 and 17 of nr_rng.py), keyed by seed, env, episode and step. An env's access process therefore does not depend on E, on other envs' resets, or on sharding (tested). All state is fixed-shape [E, R], and nothing syncs with the host. The graph backend registers the stage's state with its other state and captures it, and the triton backend runs the same stage around its fused kernel. A partial reset returns the reset envs to rach_initial and clears their procedures.
Backends and levels¶
| Backend | RACH / DRX |
|---|---|
reference |
yes |
graph |
yes (same ops as the reference; GPU equivalence test test_graph_backend_bitwise_equal_reference) |
triton |
yes: AccessStage.pre and post (releases, triggers, ROs, collisions, backoff, the step outputs) run as torch code around the fused kernel, which evaluates the per-slot schedulable mask (connected, DRX Active Time) itself and updates the last scheduling activity and the sleeping slots in place (constexpr ACCESS); with the access gate the UL and DL slots run in one kernel, because the DRX and release timers couple the two links. Equal to the reference to float rounding (GPU test test_g2_triton_teacher_forced[ul_access]); see NR engine backends |
Every level other than L2 refuses rach=True or drx=True (make_engine raises), and unused_fields("L2") lists the RACH fields as unused while rach is False and the DRX fields while drx is False.
What 5G-LENA does¶
5G-LENA models contention-based RACH (preamble, RAR, Msg3) with ideal or real RRC. It has no DRX. Together with the energy model, DRX here gives the wake-up latency of DL commands and the battery saving of sleeping robots, which 5G-LENA cannot show.
Limitations¶
- No Msg3 capture: every collision fails for all robots involved. Preamble detection is otherwise perfect, and the RAR always fits.
- No contention-free RACH, also not at RLF re-establishment, and no RACH on handover. A handover keeps its own interruption model.
- Paging is not modelled: DL data for an idle robot starts RACH at its arrival.
- The RRC release is decided per control step from the step's first data arrival.
- With several cells, a robot contends in the cell it was associated with at the end of the previous step.
- DRX has no separate HARQ RTT or retransmission timers. A waiting HARQ process keeps an awake robot awake, and a dormant robot's retransmission waits for the next on-duration.
access_sleep_fracis sampled at the slots the engine runs, which is every slot with data symbols of an active direction. On an uplink-only config those are the UL slots.- RLF re-establishment through RACH: T301 (the re-establishment timer) is not modelled, so a robot whose procedures keep failing retries until it connects instead of going idle; while the robot waits for its first RO,
access_statestill shows its state before the failure.