A serial link has transitions everywhere, thanks to its encoding, and passes all its tests. Then a test sends a long block of data with many more 1s than 0s, all still with plenty of transitions. Errors appear, getting worse the longer the imbalance lasts, and the eye diagram shows the whole signal slowly sliding off centre.
Why would the proportion of ones and zeros matter, when every bit has a clean transition?
The obvious answer is that only transitions matter: the receiver needs edges to recover its clock and levels to decide each bit, and the mix of values is the data's business. That is true for a DC-coupled link, where the wire carries the true voltage. Many fast links are AC-coupled: a capacitor in series blocks any steady voltage, so the two sides can sit at different DC levels. A capacitor passes changes but not averages, so the received signal's centre drifts towards the recent average of the data. If the data stays unbalanced for long, the centre slides, called baseline wander, and the receiver's threshold ends up too close to one of the levels.
Count +1 for every 1 sent and −1 for every 0. That running total is the running disparity. For an AC-coupled link to stay centred, it must stay within a small bound, all the time, not just on average over a long run. A code is DC-balanced if it guarantees that bound whatever the data:
Scheme | How it controls disparity | Bound |
|---|---|---|
Raw NRZ | It does not | None: grows with any imbalance in the data |
Manchester | Every bit is one high half and one low half | ±1 within a bit, 0 at every bit boundary |
8b/10b | Each byte has two possible 10-bit codes with opposite imbalance; the encoder picks the one that pushes the running disparity back towards zero | Small and fixed |
Scrambling | Makes the data look random, so ones and zeros are about equal on average | Statistical: grows slowly, with no hard bound |
The model sends 10,000 bytes of 0xFF, the worst imbalance, three ways and records the largest running disparity seen: raw NRZ, NRZ after a scrambler, and Manchester.
"""Running disparity: ones minus zeros sent so far.
An AC-coupled link cannot carry a lasting excess of ones or zeros, so the running
disparity must stay small. Compare three ways of sending a long run of 0xFF bytes:
raw NRZ, scrambled NRZ, and Manchester (two half-bit symbols per bit, always one of each).
"""
def lfsr_bits(n, state=0x1):
out = []
for _ in range(n): # x^15 + x^14 + 1, a common scrambling polynomial
bit = ((state >> 14) ^ (state >> 13)) & 1
state = ((state << 1) | bit) & 0x7FFF
out.append(bit)
return out
def max_abs_rd(symbols):
rd, worst = 0, 0
for s in symbols:
rd += 1 if s else -1
worst = max(worst, abs(rd))
return worst
N = 80_000 # 10,000 bytes of 0xFF
data = [1] * N
scr = [d ^ p for d, p in zip(data, lfsr_bits(N))]
manch = [s for d in data for s in ((0, 1) if d else (1, 0))]
print(f"{'bits sent':>10} {'raw NRZ':>9} {'scrambled':>10} {'Manchester':>11}")
for n in (1_000, 10_000, 80_000):
r, s, m = max_abs_rd(data[:n]), max_abs_rd(scr[:n]), max_abs_rd(manch[: 2 * n])
print(f"{n:10d} {r:9d} {s:10d} {m:11d}")
assert max_abs_rd(data) == N and max_abs_rd(manch) == 1 and max_abs_rd(scr) < N // 100
print("PASS: raw data drifts without limit, scrambled data drifts slowly, Manchester stays within 1")It prints:
bits sent raw NRZ scrambled Manchester
1000 1000 177 1
10000 10000 230 1
80000 80000 237 1
PASS: raw data drifts without limit, scrambled data drifts slowly, Manchester stays within 1Raw data drifts by one for every bit, without limit. Manchester never exceeds 1. The scrambled stream is the interesting case: its disparity is much smaller than the raw data's, but it is not bounded. It wanders like a random walk, growing roughly with the square root of the length. That is why links that rely on scrambling for balance size their AC coupling and receiver to tolerate a statistical amount of wander, while 8b/10b links get a hard guarantee in exchange for their 20% overhead.
Approach | Balance guarantee | Cost |
|---|---|---|
DC-couple the link | Not needed | Both ends must share a common voltage range; harder across boards and cables |
Manchester | Hard, per bit | Twice the bandwidth |
8b/10b and similar balanced block codes | Hard, small bound | 20% overhead (for 8b/10b) |
Scrambling with a long-period sequence | Statistical | Almost none in bandwidth; the receiver must tolerate some wander |
Protocol | How it handles balance |
|---|---|
PCI Express Gen1–2 | 8b/10b: running disparity selects between each byte's two code groups, keeping the line DC-balanced. |
PCI Express Gen3–5 and 64b/66b links | Scrambled payloads with a 2-bit sync header: balance is statistical, which the much lower overhead pays for. |
A test pattern meant to stress a link happens to be the scrambler's own sequence XORed with a constant, so after scrambling it becomes a long, strongly unbalanced stream (illustrative). Such "killer patterns" exist for any scrambler: data equal to the scrambling sequence turns into constants on the wire. On a link that relies on scrambling alone for balance, such a pattern causes baseline wander and errors. Real designs defend against it with sync headers that always contain a transition, with receivers that tolerate wander, and with test patterns chosen to probe this case deliberately.
Not for balance: with no series capacitor, the receiver sees the true levels. Transitions for clock recovery may still be needed, but disparity does not shift the baseline.
Scrambled bits behave like random coin flips, and the running sum of random ±1 steps wanders, typically growing with the square root of the number of bits. Nothing pushes it back.
Many bytes have two code groups, one with more 1s and one with more 0s (or balanced ones). The encoder picks whichever moves the running disparity back towards zero.
AC-coupled links block the average level, so unbalanced data causes baseline wander and errors even with clean transitions.
Running disparity (ones minus zeros so far) must stay bounded; Manchester and 8b/10b guarantee it, scrambling only makes it likely.
Verify balance with worst-case patterns, not random data.