Loading content...
While North America developed B8ZS for T1 systems, the international telecommunications community—coordinated by the ITU-T (then CCITT)—developed a parallel solution with different design priorities. High-Density Bipolar 3 (HDB3) emerged as the global standard for E1 systems (2.048 Mbps), used throughout Europe, Asia, Africa, and most of the world outside North America.
The fundamental difference lies in the threshold: where B8ZS waits for 8 consecutive zeros before substitution, HDB3 acts after only 4 zeros. This aggressive approach provides higher transition density and tighter clock recovery—but requires more sophisticated encoding logic.
HDB3 is not merely "B8ZS with a different number." Its substitution algorithm includes an elegant mechanism to maintain DC balance even when substitutions accumulate—a problem that B8ZS's larger windows naturally avoid.
By the end of this page, you will understand HDB3's complete encoding algorithm, including its polarity tracking mechanism that ensures DC balance across all data patterns. You'll learn how the violation pulse and balance pulse work together, and why HDB3 became the dominant global standard for digital line coding.
HDB3 was designed to address the same problem as B8ZS—clock synchronization during zero runs—but with different engineering constraints and priorities.
Why 4 zeros instead of 8?
The choice of 4-zero threshold reflects several considerations:
| Factor | B8ZS (8 zeros) | HDB3 (4 zeros) |
|---|---|---|
| Max transition gap | 7 bit periods | 3 bit periods |
| Clock recovery margin | Adequate for T1 | More robust for E1 |
| Substitution frequency | Lower | Higher |
| Algorithm complexity | Simpler | More complex |
| DC balance handling | Natural (rare substitutions) | Requires tracking |
The DC balance challenge:
With B8ZS, substitutions are relatively rare (8 zeros are less common than 4 zeros). Each substitution is DC-balanced internally, and the infrequency of substitutions means accumulated imbalance is minimal.
HDB3 faces a different situation. With the 4-zero threshold:
HDB3 solves this through a clever parity tracking mechanism that dynamically adjusts the substitution pattern to maintain overall DC balance.
HDB3 = High-Density Bipolar with 3-zeros maximum. The '3' refers to the maximum number of consecutive zeros allowed before substitution kicks in—after 4 zeros, the pattern is replaced. This naming convention focuses on the outcome (maximum 3 zeros in encoded signal) rather than the trigger (4 zeros in data).
HDB3 uses a 4-symbol substitution pattern with two possible configurations. The pattern selection depends on two state variables:
The HDB3 substitution patterns:
| Pulses Since Last Sub | Previous Pulse | Substitution Pattern |
|---|---|---|
| Odd | + | 0 0 0 + |
| Odd | - | 0 0 0 - |
| Even | + | + 0 0 + |
| Even | - | - 0 0 - |
In notation, using B = Balance pulse and V = Violation pulse:
000V (just a violation pulse at position 4)B00V (balance pulse at position 1, violation pulse at position 4)Understanding the pattern components:
Violation Pulse (V): The pulse at position 4 has the same polarity as the previous pulse—a deliberate bipolar violation that marks this as a substitution.
Balance Pulse (B): When used, the pulse at position 1 follows normal AMI alternation. It's added specifically to ensure the overall pulse count remains even, maintaining DC balance.
Odd count pattern (000V):
Only V pulse, same polarity as previous
Since odd pulses preceded this, adding 1 pulse makes total even
Even count pattern (B00V):
B pulse at position 1 (normal polarity)
V pulse at position 4 (same polarity as B)
Two pulses of same polarity maintain DC running sum
The B pulse and V pulse in pattern B00V have the SAME polarity (both violations together). The B pulse violates relative to the running polarity before the four zeros, and V violates relative to B. This double-violation pattern is what distinguishes HDB3 from B8ZS and enables its DC balance maintenance.
The genius of HDB3 lies in its DC balance tracking. Let's trace through how the mechanism works.
State tracking:
The encoder maintains:
polarity: The polarity of the next mark under normal AMI rules (alternates)pulse_count: Number of pulses since last substitution (or start)Balance logic:
The key insight is that DC balance requires an equal number of positive and negative pulses. If pulse_count is odd before a substitution, one more pulse will make it even (balanced). If pulse_count is even, we need either zero or two pulses in the substitution to maintain even parity.
Why odd → 000V and even → B00V?
Let's trace the DC sum:
Case 1: Odd pulse count before substitution
Case 2: Even pulse count before substitution
The elegance is that by alternating between these patterns based on pulse count parity, HDB3 ensures that over any extended sequence, the DC component trends toward zero.
HDB3's DC balance isn't just "usually good"—it's mathematically guaranteed. After every pair of substitutions, the DC sum returns to zero. The maximum DC imbalance is bounded at ±2V (two pulse periods), which is well within acceptable limits for transformer coupling.
The HDB3 encoding algorithm tracks polarity and pulse count to select the appropriate substitution pattern. Here's a complete implementation:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
def hdb3_encode(bit_stream: list[int]) -> list[int]: """ Encode a binary bit stream using HDB3 encoding. State variables: - polarity: Next mark's polarity under AMI rules (alternates: +1/-1) - pulse_count: Number of pulses since last substitution Returns: List of voltage levels: -1, 0, or +1 """ encoded = [] polarity = 1 # Start with positive polarity for first mark pulse_count = 0 # Pulses since last substitution i = 0 while i < len(bit_stream): # Check for 4 consecutive zeros if i <= len(bit_stream) - 4 and bit_stream[i:i+4] == [0, 0, 0, 0]: # Determine substitution pattern based on pulse_count parity if pulse_count % 2 == 1: # Odd number of pulses # Pattern: 0 0 0 V # V has SAME polarity as previous pulse (which is -polarity) # because polarity holds NEXT pulse's polarity v_polarity = -polarity # Same as last transmitted mark encoded.extend([0, 0, 0, v_polarity]) # After V, polarity should flip for next mark # But V violated, so polarity stays the same # Actually, pulse_count becomes 1 (just V) pulse_count = 1 polarity = -v_polarity # Next mark alternates from V else: # Even number of pulses (including 0) # Pattern: B 0 0 V # B has polarity according to normal AMI alternation b_polarity = polarity # V has SAME polarity as B (creating violation after B) v_polarity = b_polarity encoded.extend([b_polarity, 0, 0, v_polarity]) # After this pattern: two pulses of same polarity # Reset pulse_count = 0 (pattern is self-balancing) pulse_count = 0 # Polarity should be opposite of V for next mark polarity = -v_polarity i += 4 else: # Normal AMI encoding if bit_stream[i] == 0: encoded.append(0) else: encoded.append(polarity) polarity = -polarity pulse_count += 1 i += 1 return encoded def hdb3_decode(signal: list[int]) -> list[int]: """ Decode an HDB3 signal back to binary. Look for substitution patterns: - 000V pattern: positions [i:i+4] = [0, 0, 0, ±1] where ±1 is a violation - B00V pattern: positions [i:i+4] = [±1, 0, 0, ±1] where both have same polarity """ decoded = [] i = 0 last_polarity = None # Track for violation detection while i < len(signal): if i <= len(signal) - 4: segment = signal[i:i+4] # Check for B00V pattern (positions 0 and 3 are non-zero with same sign) if segment[0] != 0 and segment[1] == 0 and segment[2] == 0 and segment[3] != 0: if segment[0] == segment[3]: # Same polarity = B00V substitution decoded.extend([0, 0, 0, 0]) last_polarity = segment[3] i += 4 continue # Check for 000V pattern if segment[0] == 0 and segment[1] == 0 and segment[2] == 0 and segment[3] != 0: # This is 000V if position 3 is a violation # We need context to verify, but for decoding we can heuristically # check if it follows the expected pattern decoded.extend([0, 0, 0, 0]) last_polarity = segment[3] i += 4 continue # Normal decoding: non-zero = 1, zero = 0 if signal[i] != 0: last_polarity = signal[i] decoded.append(1) else: decoded.append(0) i += 1 return decoded # Demonstrate HDB3 encodingprint("=== HDB3 Encoding Examples ===\n") # Example 1: Data with four consecutive zerosdata1 = [1, 0, 0, 0, 0, 1, 0, 1]encoded1 = hdb3_encode(data1)print(f"Data: {data1}")print(f"HDB3: {encoded1}")print(f"Pattern used: {'000V (odd count)' if encoded1[1:5] == [0,0,0,encoded1[4]] else 'B00V (even count)'}") # Example 2: Data with multiple zero runsdata2 = [1, 0, 0, 0, 0, 0, 0, 0, 0, 1] # Eight zerosencoded2 = hdb3_encode(data2)print(f"\nData: {data2}")print(f"HDB3: {encoded2}") # Example 3: All zerosdata3 = [0, 0, 0, 0, 0, 0, 0, 0]encoded3 = hdb3_encode(data3)print(f"\nData: {data3}")print(f"HDB3: {encoded3}")# Should show B00V pattern (even count = 0 at start)Detailed encoding trace:
Let's encode 10000100001 step by step:
| Position | Bit | State Before | Action | Output | State After |
|---|---|---|---|---|---|
| 0 | 1 | pol=+1, cnt=0 | Normal mark | +1 | pol=-1, cnt=1 |
| 1-4 | 0000 | pol=-1, cnt=1 | Odd→000V | 0,0,0,-1 | pol=+1, cnt=1 |
| 5 | 1 | pol=+1, cnt=1 | Normal mark | +1 | pol=-1, cnt=2 |
| 6-9 | 0000 | pol=-1, cnt=2 | Even→B00V | -1,0,0,-1 | pol=+1, cnt=0 |
| 10 | 1 | pol=+1, cnt=0 | Normal mark | +1 | pol=-1, cnt=1 |
Result: [+1, 0, 0, 0, -1, +1, -1, 0, 0, -1, +1]
Notice how the first 4-zero run uses 000V (odd count), while the second uses B00V (even count).
For receivers to correctly decode HDB3, they must identify substitution patterns and distinguish them from transmission errors.
Pattern recognition at the receiver:
The receiver scans for bipolar violations (two consecutive marks with same polarity). When found:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
def identify_hdb3_patterns(signal: list[int]) -> dict: """ Scan an HDB3 signal and identify all substitution patterns. Returns locations and types of patterns found. """ patterns = [] errors = [] last_mark_idx = None last_mark_polarity = None for i, level in enumerate(signal): if level == 0: continue # Check for bipolar violation if last_mark_polarity is not None and level == last_mark_polarity: # This is a bipolar violation - is it 000V or B00V? # Check for 000V: positions i-3, i-2, i-1 are all 0 if i >= 3: if signal[i-3] == 0 and signal[i-2] == 0 and signal[i-1] == 0: patterns.append({ "type": "000V", "position": i - 3, "v_polarity": level, "decoded_as": "0000" }) last_mark_polarity = level last_mark_idx = i continue # Check for B00V: position i-3 is same polarity as i if i >= 3: if signal[i-3] == level and signal[i-2] == 0 and signal[i-1] == 0: patterns.append({ "type": "B00V", "position": i - 3, "b_polarity": signal[i-3], "v_polarity": level, "decoded_as": "0000" }) last_mark_polarity = level last_mark_idx = i continue # Neither pattern matched - this is a real error errors.append({ "position": i, "expected_polarity": -last_mark_polarity, "received_polarity": level }) last_mark_polarity = level last_mark_idx = i return { "patterns_found": len(patterns), "patterns": patterns, "errors_found": len(errors), "errors": errors } # Example: Analyze a complex HDB3 signalsignal = [1, 0, 0, 0, -1, -1, 0, 0, -1, 1, -1, 0, 0, -1]# This should contain:# - 000V at position 0-3 (zeros followed by -1 violation after initial +1)# - B00V at position 5-8 (-1, 0, 0, -1 - same polarity) print("Signal analysis:")result = identify_hdb3_patterns(signal)for pattern in result["patterns"]: print(f" {pattern['type']} at position {pattern['position']}")The violation pulse (V) at position 4 is the anchor for pattern detection. Receivers scan for violations, then look backward to classify. This design allows single-pass decoding with only 4 symbols of lookahead buffer.
HDB3 is the standard encoding for E1 digital transmission systems used worldwide (except North America and Japan). Understanding its role in this infrastructure is essential for telecommunications engineering.
The E1 system hierarchy:
E1 is the ITU-T/ETSI standard operating at 2.048 Mbps:
| Parameter | Value | Notes |
|---|---|---|
| Line Rate | 2.048 Mbps | ITU-T G.703 standard |
| Encoding | HDB3 | Mandatory for E1 interfaces |
| Voltage Levels | ±2.37V (75Ω) or ±3V (120Ω) | Depends on impedance |
| Pulse Width | 244 ns (50% duty) | Return-to-zero pulses |
| Maximum zeros | 3 consecutive | HDB3 guarantees this |
| Jitter tolerance | ±0.25 UI | Unit interval tolerance |
Global deployment:
HDB3/E1 is used in:
This makes HDB3 the most widely deployed line coding scheme globally, with installed base significantly exceeding B8ZS/T1.
ISDN Primary Rate Interface (PRI) uses E1/HDB3 outside North America, providing 30 B-channels (voice/data) plus 1 D-channel (signaling). The clear channel capability enabled by HDB3 was essential for ISDN's 64 Kbps unrestricted data channels.
While HDB3 and B8ZS solve the same problem, their different approaches create distinct operational characteristics:
| Characteristic | HDB3 | B8ZS |
|---|---|---|
| Zero threshold | 4 consecutive | 8 consecutive |
| Max zeros in output | 3 | 7 |
| Substitution patterns | 2 (000V, B00V) | 2 (by previous polarity) |
| Pattern complexity | Higher (parity tracking) | Lower (polarity only) |
| Substitution frequency | Higher | Lower |
| Clock recovery robustness | Superior | Adequate |
| Primary standard | ITU-T / E1 | ANSI / T1 |
| Geographic usage | Global (except NA, Japan) | North America |
When to use which:
The choice between HDB3 and B8ZS is rarely made by engineers—it's determined by regional infrastructure standards. However, in system design:
Spectral properties:
HDB3's power spectral density (PSD) differs from B8ZS due to more frequent substitutions:
The higher transition density means HDB3 signals have slightly more high-frequency content than B8ZS, which affects equalization requirements.
Jitter and timing considerations:
HDB3's guaranteed transitions improve jitter performance:
| Metric | Plain AMI | B8ZS | HDB3 |
|---|---|---|---|
| Pattern-dependent jitter | High | Moderate | Low |
| Maximum transition gap | Unlimited | 7 UI | 3 UI |
| PLL lock time | Variable | Stable | Fast |
UI = Unit Interval (one bit period)
The shorter maximum gap means PLLs can use tighter loop bandwidths, reducing susceptibility to noise-induced jitter.
E1 test equipment generates specific patterns to verify HDB3 operation: all-zeros (should produce alternating B00V patterns), pseudo-random sequences (to stress transitions), and specific violation patterns (to verify detection). Standard test patterns are defined in ITU-T O.150 and O.152.
HDB3 represents the international solution to bipolar encoding, providing robust clock recovery and strict DC balance through its sophisticated substitution algorithm.
What's next:
Now that we understand both B8ZS and HDB3, we'll explore how these bipolar schemes provide error detection capabilities in production systems. The next page covers error detection mechanisms, including how intentional violations are distinguished from transmission errors, and how error statistics are used for link quality monitoring.
You now have comprehensive understanding of HDB3—its encoding algorithm, DC balance mechanism, pattern recognition, and application in E1 telecommunications infrastructure. This knowledge is essential for working with international digital transmission systems.