Lesson 04 / 14
Roaming and Band Steering
As the handover threshold drops from 30 to 14, false admit falls from 8 to 0 and false deny rises from 0 to 8; early handover and late handover are two ends of the same dial, and fixing one direction grows the other.
Contents
The previous lesson overlapped cells on purpose: so no gap would remain, neighboring cells’ edges were deliberately overlapped. The measurement swept the budget and the clients stood still — none of the forty clients moved.
Overlap was built exactly for those who move. A client at the edge hears two points at once; as it walks, one weakens and the other strengthens. Then the association decision is made not once but repeatedly, and every time the same question is asked: should I let go of what I have? What this lesson measures is the threshold of that question. Raising the threshold lets the client go early; lowering it makes it stick to a weak point. Both are errors, and they do not show up in the same numbers.
Who Makes the Handover Decision
Roaming is a client moving its bond from one access point to another. The first thing that has to be said is who holds the decision: the decision belongs to the client. The network can eject a client from a point, tell it about its neighbors, even suggest that it go to a specific point; but the client itself chooses which point to associate with.
This directly explains why the measurement is two-directional. The only thing in the network’s hands is thresholds: below which signal strength the client is told “I’m not holding you anymore,” what gets reported in the neighbor list. The threshold is what the network writes; the decision is what the client makes.
# taught handover sequence , fictional and not executed
1. point A -> client neighbor report
A: channel 4 , measured signal 21
B: channel 1 , measured signal 29
C: channel 7 , measured signal 12
2. client decision
signal in hand 21 , threshold 22 -> let go
3. client -> point B association request
4. point B -> client association response
result: accept , granted tier 4
5. point A old bond dropped
<-- frame loss occurs between step 2 and step 3
The note under the fifth step is roaming’s real cost. Between two associations, the client is bound to no point at all; frames arriving in that interval drop. If the interval is short, upper layers absorb it as a latency ripple; if it is long, the connection looks broken. There are other things that have to be re-established during a handover, and one of them is the subject of the next lesson.
The first step also has a cost, and it is less visible. If the client does not know its neighbors, it has to find them itself; finding them means listening to other channels. While it listens to a channel, it is not on its own channel — meaning it misses frames arriving at that moment. Scanning produces loss even when no handover happens. The more often a client scans, the fresher its knowledge of neighbors, and the more frames it misses.
A neighbor report exists exactly to ease this trade-off: the network hands the client the list it should search. The client now listens to the three points reported instead of ten channels. But who writes the report is the previous lesson’s question — an independent access point does not know its neighbors, and without a shared view there is no list either. This is where roaming’s quality connects back to where the decision is made.
Early Handover and Late Handover
The measurement’s fiction is a corridor: two access points stand 50 m apart, and every client
sits somewhere along this line. The client’s distance to A is the first lesson’s distance
field; its distance to B is 50 - distance.
Intent, in its plainest form, is this: the client should belong to whichever point it is closer to. The overlap from the previous lesson creates an ambiguity here — a client between 20 and 30 m is counted inside both cells. For the oracle to give a single answer, the nearest-point rule is chosen; the corridor’s midpoint, 25 m, is the boundary.
The mechanism, though, does not know what intent can know. The client does not measure its own position; it only measures the signal strength of the point it currently holds, and lets go when that strength drops below the threshold. Because signal strength depends on both distance and interference, two clients at the same distance let go at different times.
Two errors follow from this:
- Early handover — the client lets go while still close to A. Intent would have held it back, the mechanism let it through: false admit.
- Late handover — the client sticks to A while already close to B. Intent would have let it through, the mechanism held it back: false deny.
What Band Steering Does Not Know
Band steering is a second handover decision: should the client be placed on the wide band, whose range is short but whose tier ceiling is high, or the narrow band, whose range is long but whose ceiling is low?
The right answer depends on what the client would actually get on the wide band. The problem is: the client has not tried the wide band yet. When the steering decision is made, only the narrow-band reading is in hand, and the decision is made from that reading alone. The rule is a proxy measurement — it does not measure what it wants to measure, it measures something else correlated with it.
The measurement’s assumptions:
- WN22. Forty clients; distance and interference come from the first lesson’s fiction. The signal budget is fixed at 52 in the roaming measurement.
- WN23. The corridor fiction: two points stand 50 m apart; the client’s distance to B is
50 - distance. Intent is the nearest-point rule; the boundary is 25 m. - WN24. The mechanism sees only the signal strength of the point it currently holds. Position, B’s signal, and the client’s direction of travel do not enter the measurement.
- WN25. The swept handover thresholds are 30, 26, 22, 18, and 14. Only the threshold changes at a time.
- WN26. In the ping-pong measurement, the signal is assumed to swing by 3 units over a short time. A client is counted as unstable if its swing interval crosses both the drop threshold and the return threshold; at hysteresis margin 0 the two thresholds coincide.
- WN27. In band steering, the narrow band is modeled with budget 58, the wide band with
budget 46; the wide band’s tier ceiling is double (
2 × tier). This is the fiction of the range–speed trade-off. - WN28. Band intent comes from the oracle: if a client would truly get more on the wide band, it belongs there. The oracle knows both bands’ tiers.
- WN29. The steering rule sees only the narrow-band reading. The wide-band reading does not enter the decision; if it did, this would be a measurement, not a rule.
- WN30. The set is forty clients; the smallest measurable difference is 1/40 = 0.025.
Measurement
"""Roaming and band steering: early handover and late handover are two separate errors.""" SEED = 20260811 POWER = 52 CORRIDOR = 50 # distance between the two access points, meters SWING = 3 # the range the signal swings over a short time TIERS = ((34, 6), (28, 4), (22, 2), (18, 1)) def generator(seed): d = seed % 2147483646 + 1 def r(n): nonlocal d d = (d * 48271) % 2147483647 return d % n return r def clients(count=40, seed=SEED): r, pool = generator(seed), [] for i in range(count): pool.append({"no": i + 1, "distance": 5 + r(41), "interference": r(13)}) return pool def signal(c, power=POWER): return power - c["distance"] - c["interference"] def rate_tier(c, power=POWER): for threshold, tier in TIERS: if signal(c, power) >= threshold: return tier return 0 def gap(events, intent, mechanism): d = {"correct_admit": 0, "correct_deny": 0, "false_admit": 0, "false_deny": 0} for e in events: n, m = intent(e), mechanism(e) if n and m: d["correct_admit"] += 1 elif not n and not m: d["correct_deny"] += 1 elif m: d["false_admit"] += 1 else: d["false_deny"] += 1 return d def handover_intent(c): """The client should belong to whichever point it is closer to.""" return c["distance"] > CORRIDOR / 2 def handover(c, threshold): """Mechanism: if the signal from the point in hand drops below the threshold, let go.""" return signal(c) < threshold def unstable(c, threshold, margin): """If the signal's swing crosses both thresholds as it moves, the client ping-pongs.""" return threshold + margin - SWING <= signal(c) <= threshold + SWING pool = clients() print(f"clients {len(pool)} | corridor {CORRIDOR} m | should belong to B " f"{sum(1 for c in pool if handover_intent(c))}") print() print(f"{'threshold':>9s} {'crossed':>7s} {'correct':>7s} {'false admit':>12s} " f"{'false deny':>12s}") for threshold in (30, 26, 22, 18, 14): d = gap(pool, handover_intent, lambda c, t=threshold: handover(c, t)) print(f"{threshold:9d} {d['correct_admit'] + d['false_admit']:7d} " f"{d['correct_admit'] + d['correct_deny']:7d} {d['false_admit']:12d} " f"{d['false_deny']:12d}") print() print(f"{'hysteresis margin':>17s} {'unstable clients':>17s}") for margin in (0, 2, 4, 6): print(f"{margin:17d} {sum(1 for c in pool if unstable(c, 22, margin)):17d}") print() NARROW, WIDE = 58, 46 def rate_narrow(c): return rate_tier(c, NARROW) def rate_wide(c): """Wide band: short range, double the tier ceiling.""" return 2 * rate_tier(c, WIDE) def band_intent(c): return rate_wide(c) > rate_narrow(c) def steering(c, threshold): """Decision is made from the narrow-band reading alone; the wide band has not been tried yet.""" return signal(c, NARROW) >= threshold print(f"{'steering threshold':>19s} {'pushed to wide':>14s} {'correct':>7s} " f"{'false admit':>12s} {'false deny':>12s}") for threshold in (44, 40, 36, 32): d = gap(pool, band_intent, lambda c, t=threshold: steering(c, t)) print(f"{threshold:19d} {d['correct_admit'] + d['false_admit']:14d} " f"{d['correct_admit'] + d['correct_deny']:7d} {d['false_admit']:12d} " f"{d['false_deny']:12d}") print() print(f"clients that truly belong on the wide band: {sum(1 for c in pool if band_intent(c))}") print("tier lost by false admits (no, narrow tier, wide tier):") print([(c["no"], rate_narrow(c), rate_wide(c)) for c in pool if steering(c, 36) and not band_intent(c)])
clients 40 | corridor 50 m | should belong to B 19
threshold crossed correct false admit false deny
30 27 32 8 0
26 27 32 8 0
22 19 36 2 2
18 17 36 1 3
14 11 32 0 8
hysteresis margin unstable clients
0 9
2 9
4 6
6 2
steering threshold pushed to wide correct false admit false deny
44 7 38 0 2
40 9 40 0 0
36 13 36 4 0
32 13 36 4 0
clients that truly belong on the wide band: 9
tier lost by false admits (no, narrow tier, wide tier):
[(1, 6, 4), (11, 6, 4), (23, 6, 4), (36, 6, 4)]
The Threshold Shifts the Balance
The top table turns a single dial, and two columns move in opposite directions.
At threshold 30, false admit is 8, false deny is 0. Clients let go while still close to A; eight of them have crossed to B while still on A’s side. No one is late, because the threshold is so high that everyone leaves ahead of time.
At threshold 14, the opposite: false admit is 0, false deny is 8. No one leaves early, and eight clients stick to A while already close to B. A client that sticks both keeps its own tier low and holds the medium for longer; the shared-time calculation from the first lesson shows up here again.
The three middle rows show where the balance shifts: 2/2, 1/3, and, in between, 30 and 26 giving the same row. The two rows coming out identical is a resolution effect of the fiction — no client’s signal strength falls between 26 and 30, so moving the threshold across that interval changes no decision at all. The measurement band (WN30, 0.025) cannot see this gap.
The rule to read is: early handover and late handover are two ends of the same dial. An operator who receives only sticking complaints raises the threshold and ends the sticking; the moment it ends, early handover begins, and that too is a complaint — a different one, because early handover produces short outages while sticking produces continuous slowness. A measurement that does not count the two directions separately can do nothing but move the dial from one end to the other.
Ping-Pong and Hysteresis
The middle table counts a different flaw. Signal strength is not constant; it swings by a few units over a short time (WN26). A client sitting right at the threshold’s edge makes the decision to let go because of this swing, then returns, then lets go again. This is called ping-pong, and it produces a frame loss on every round.
In the single-threshold mechanism (hysteresis margin 0), 9 of the forty clients sit inside this band. Raising the margin to 4 drops the unstable clients to 6, to 6 drops it to 2. The mechanism is this: the drop threshold and the return threshold are separated; a client lets go only when the signal falls below the lower threshold, and returns only when it rises above the upper one. The gap between them absorbs the swing.
The margin’s cost is read in the table above. Holding the drop threshold fixed and raising the return threshold makes returning harder: a client that went to the wrong point stays there longer. Hysteresis reduces instability and lengthens the life of a wrong decision. Margin 2 changing nothing is the same resolution problem — a 2-unit margin sits below a 3-unit swing and removes no client from the band.
A Decision Made from a Wrong Reading
The bottom table measures band steering. Of the forty clients, 9 truly belong on the wide band; the steering rule tries to guess this from the narrow-band reading.
At threshold 44 the rule pushes 7 clients: false admit 0, false deny 2. The rule is cautious; it sends no one to the wrong place, but it fails to run two clients on the band they deserve. At threshold 36, 13 clients are pushed: false admit 4, false deny 0. These four are listed in the last row and their cost is plain — they would have gotten tier 6 on the narrow band and get 4 on the wide band. The rule slows down exactly the clients it pushed to “improve.”
The threshold 40 row gives 40/40 correct: 0 false admit, 0 false deny. This row has to be read carefully. It does not show that the rule is correct; it shows that, in this set, that particular cut happens to coincide with intent. The rule still does not measure what it wants to measure — it never sees the wide-band reading (WN29). The same threshold could well be wrong on a different client distribution, because a proxy measurement’s accuracy depends on the set it is measuring.
And threshold 36 and 32 giving the same row is the counterpart of the 30–26 pair in the table above: there are intervals where moving the threshold changes no decision at all. It cannot be assumed that every time a threshold is “adjusted,” something has actually changed.
Summary
- The client makes the roaming decision; the only mechanism in the network’s hands is thresholds. The measure is therefore the gap between the network’s intent and the client’s decision.
- As the handover threshold drops from 30 to 14, false admit is 8, 8, 2, 1, 0, false deny is 0, 0, 2, 3, 8. Early handover and late handover are two ends of the same dial.
- In the single-threshold mechanism, 9 clients sit in the ping-pong band; at hysteresis margins 4 and 6 this drops to 6 and 2, but the life of a wrong decision lengthens.
- The band steering rule never sees the wide band’s reading; at threshold 44, 2 clients do not go to the band they deserve, at threshold 36, 4 clients are dropped from tier 6 to tier 4.
- There are intervals where changing the threshold changes no decision (30–26 and 36–32); that an adjustment was effective cannot be inferred from the adjustment having been made.
Next Step
Up to this point, the medium determined who got through. Distance, interference, budget, and threshold — all four were physical or numerical quantities, and none of them asked who the client was. Everyone standing inside the cell associated, no one standing outside could associate; distance was what drew the boundary.
So what happens if an identity condition is added to the crossing? Then association passes two tests: is the client close enough, and is the client acceptable? The next lesson builds this second test and counts the same two directions there too — the identity condition admits some clients it should not, and denies some it should not.
To keep your progress and take notes, Log in
My notes
Log in to take notes.