0% found this document useful (0 votes)
3 views46 pages

Ldpc Complete Guide

The Complete LDPC Learning Guide provides an in-depth exploration of channel coding, from the foundational principles established by Claude Shannon to advanced coding techniques used in modern communication systems like 5G. It covers the evolution of coding theory, including linear block codes, convolutional codes, and turbo codes, emphasizing the importance of structured yet random codes for efficient decoding and error correction. The guide is aimed at engineers and practitioners seeking a comprehensive understanding of the mathematics and intuition behind channel coding.

Uploaded by

19 96
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views46 pages

Ldpc Complete Guide

The Complete LDPC Learning Guide provides an in-depth exploration of channel coding, from the foundational principles established by Claude Shannon to advanced coding techniques used in modern communication systems like 5G. It covers the evolution of coding theory, including linear block codes, convolutional codes, and turbo codes, emphasizing the importance of structured yet random codes for efficient decoding and error correction. The guide is aimed at engineers and practitioners seeking a comprehensive understanding of the mathematics and intuition behind channel coding.

Uploaded by

19 96
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

The Complete LDPC Learning Guide

From Shannon to 5G — Intuition,


Mathematics, and Every Optimization

Who this is for: Engineers and practitioners who want to


understand channel coding deeply — not just "what" but "why",
at every level from intuition to equations to silicon.

PART I: THE FUNDAMENTAL


PROBLEM — WHY CHANNEL CODING
EXISTS

1.1 Shannon's Bombshell (1948)

In 1948, Claude Shannon proved something that shocked


everyone: it is possible to communicate arbitrarily reliably over a
noisy channel, at any rate up to a specific limit — the channel
capacity C. Below capacity, you can make error probability as
small as you want. Above capacity, errors are unavoidable.

The capacity of an AWGN (Additive White Gaussian Noise)


channel is:

C = B · log₂(1 + S/N) [bits/second]

Or in normalized form (bits per channel use):


C = ½ · log₂(1 + SNR) [for real-valued channel]
C = log₂(1 + SNR) [for complex-valued
channel, relevant in 5G]

The catch: Shannon's proof was existential — random codes of


infinite length would achieve it. He gave no construction. The
engineering challenge for 70 years after 1948 was: how do you
build practical codes that actually approach capacity?

1.2 The Intuition Behind Shannon

Think of it this way. If you want to communicate 1 bit per second


reliably, you don't have to send just one signal. You can send a
long sequence of 1s or 0s — a codeword. Two codewords that
are "far apart" in Hamming distance are unlikely to be confused,
even in noise.

Shannon said: pick codewords at random from a large space.


With high probability, random codewords are "spread out" enough
that noise can't flip one into another. The problem? With a random
code of length n, decoding requires checking all 2^k possible
codewords — exponential complexity. Shannon cared about
existence, not complexity.

The entire history of coding theory after 1948 is: find structured
codes that are random enough to approach capacity, but
structured enough to decode efficiently.

1.3 Key Definitions

Code Rate: R = k/n, where k = information bits, n = codeword bits.


Rate tells you the fraction of bits that carry real information. R =
1/2 means half your bits are redundancy.
Hamming Distance d(x,y) = number of positions where
codewords x and y differ.

Minimum Distance d_min = minimum distance between any two


distinct codewords.

Error Correction Capability: A code with minimum distance


d_min can correct t errors where t = ⌊(d_min - 1)/2⌋ and detect
d_min - 1 errors.

Eb/N0 (Energy per Bit over Noise Spectral Density): The "SNR per
bit" — the most common axis on BER plots. The Shannon limit at
a given code rate tells you the minimum Eb/N0 needed for
reliable communication. For rate 1/2, the Shannon limit is about
-0.19 dB.

BER waterfall: the curve of Bit Error Rate vs Eb/N0. Good codes
have a steep waterfall that starts close to the Shannon limit.

PART II: LINEAR BLOCK CODES

2.1 What Makes a Code "Linear"?

A binary code C is linear if and only if: the sum (XOR) of any two
codewords is also a codeword. This means the codewords form
a vector subspace of GF(2)^n.

Why does linearity matter? Because:

The minimum distance = minimum Hamming weight of any


non-zero codeword (simpler to analyze)

Encoding is a matrix multiply: c = m·G

Decoding uses a parity check matrix: H·c^T = 0 for all valid


codewords
2.2 The Generator Matrix G and Parity Check
Matrix H

An (n, k) linear block code is defined by:

Generator Matrix G (k × n): Every codeword c is a linear


combination of rows of G:

c = m · G

where m is the k-bit message vector. The rows of G span the


code space.

Parity Check Matrix H (m × n, where m = n - k): A codeword c is


valid if and only if:

H · c^T = 0 (mod 2)

H encodes the parity constraints. Every row of H is a parity


equation that all valid codewords must satisfy.

Relationship: G and H are orthogonal complements. H · G^T = 0.

Systematic Form

In systematic form, the first k columns of G form an identity


matrix:

G = [I_k | P]

Then H = [-P^T | I_m] (or just [P^T | I_m] over GF(2) since -1 = 1).

The codeword structure is: [message bits | parity bits]. Encoding


is just: send the message, then append parity bits computed from
P.
2.3 Syndrome Decoding

When you receive vector r = c + e (codeword plus error pattern),


compute the syndrome:

s = H · r^T = H · (c + e)^T = H · c^T + H · e^T = 0 +


H · e^T = H · e^T

The syndrome depends only on the error pattern e, not on which


codeword was sent. This is the key insight: different error
patterns have different syndromes (unless errors are
indistinguishable, i.e., differ by a codeword).

Syndrome decoding: pre-compute a lookup table mapping each


syndrome to the most likely error pattern. Then correct: ĉ = r + ê.

Complexity: The table has 2^(n-k) entries (one per syndrome). For
small codes this is fine. For large codes, it explodes — this is the
fundamental problem with classical codes.

2.4 Hamming Codes

The simplest family of perfect single-error-correcting codes.

An (n, k) Hamming code has n = 2^r - 1, k = 2^r - 1 - r for integer r.


The parity check matrix H has all non-zero binary vectors of
length r as its columns (in any order).

Example: r=3 gives (7,4) Hamming code, corrects 1 error.

H = [0 0 0 1 1 1 1]
[0 1 1 0 0 1 1]
[1 0 1 0 1 0 1]

The syndrome of a single-bit error in position i is just the binary


representation of i. Elegant!
Key lesson: Hamming codes are "perfect" in the sphere-packing
sense but have fixed rate ~1 - r/2^r → 1 as r → ∞. They can only
correct 1 error, so they're weak for noisy channels.

2.5 Beyond Hamming: Reed-Solomon, BCH,


Reed-Muller

BCH Codes: Bose-Chaudhuri-Hocquenghem codes. Algebraic


codes that can correct multiple errors with bounded complexity.
Parity matrix built from roots of a generator polynomial over
GF(2^m). Efficient decoding via Berlekamp-Massey algorithm.
Used in CDs, DVDs, storage. Performance: good for short blocks,
significantly below capacity.

Reed-Solomon Codes: Operate over GF(2^m) symbols rather than


bits. Extremely popular in practice (QR codes, RAID, satellite).
Optimal minimum distance (MDS codes). But algebraic structure
limits performance in AWGN.

The ceiling problem: All of these algebraic codes hit a ceiling well
below the Shannon limit. Their structured algebraic constraints
that enable efficient decoding also limit their distance spectrum.
To approach Shannon, you need codes with randomness — and
that's exactly what LDPC and turbo codes provide.

PART III: CONVOLUTIONAL CODES

3.1 The Key Difference from Block Codes

Block codes encode k bits into n bits — done, next block.


Convolutional codes have memory — the encoder keeps a state,
and each output symbol depends on the current input and the
encoder's history. This enables sequences that are "spread out" in
time, giving better performance for sequential transmission.

3.2 Convolutional Encoder Structure

A rate-1/n convolutional code with constraint length K:

Has K-1 shift register stages (memory elements)

At each clock cycle: shift in 1 new bit, shift out n encoded bits

Each output is an XOR of specific shift register contents


(defined by generator polynomials g₁, g₂, ..., gₙ)

Example: Rate 1/2, constraint length 3 (K=3), memory m=2:

Register: [u_t, u_{t-1}, u_{t-2}]


g₁ = [1,0,1] → v₁_t = u_t ⊕ u_{t-2}
g₂ = [1,1,1] → v₂_t = u_t ⊕ u_{t-1} ⊕ u_{t-2}

The state of the encoder is the memory contents [u_{t-1}, u_{t-2}].


With m=2 memory bits, there are 4 possible states.

3.3 The Trellis

The beauty of convolutional codes is visualized in the trellis


diagram:

Left column: encoder states at time t

Right column: states at time t+1

Branches: one branch per possible input bit, labeled with


(input bit / output bits)

Every valid codeword sequence corresponds to a path through


the trellis starting at state 0.

This transforms decoding into a shortest-path problem: find the


path through the trellis that is closest (in Hamming distance or
log-likelihood) to the received sequence.

3.4 The Viterbi Algorithm — Hard and Soft


Decision

The Viterbi algorithm is the classic dynamic programming


solution to finding the ML path through the trellis.

Hard-decision Viterbi:

Received bits are sliced to 0/1 before decoding

Metric = Hamming distance between received bits and


branch label

At each trellis step: for each state, keep only the survivor path
(minimum cumulative metric)

Complexity: O(n · 2^m) — linear in block length, exponential in


memory

Soft-decision Viterbi:

Received channel output (real-valued, after matched filter) is


fed directly

Metric = Euclidean distance or log-likelihood ratio

~3dB gain over hard-decision for AWGN

Same complexity structure

Key insight: Soft-decision means preserving the receiver's


uncertainty. A bit received with LLR = 0.1 (barely positive) is very
different from LLR = 5.0 (very confident). Throwing this away
(hard decision) wastes information.

3.5 The BCJR / MAP Algorithm

The BCJR algorithm (Bahl, Cocke, Jelinek, Raviv, 1974) computes


for each bit position t:
P(u_t = 1 | received sequence) and P(u_t = 0 |
received sequence)

It computes the a posteriori probability (APP) of each bit, giving


a soft output — not just a hard decision, but a confidence.

Why does this matter? Viterbi gives you the MAP sequence — the
most likely overall sequence. BCJR gives you the MAP symbol —
the most likely bit at each position. For iterative decoding, you
need soft outputs that can be fed to a second decoder. Viterbi
can't provide this in a useful way; BCJR can.

BCJR in Detail (Forward-Backward Algorithm)

The algorithm works in three passes:

Forward pass: Compute α_t(s) = P(state at time t is s, and


received sequence y_1...y_t)

α_t(s) = Σ_{s'} α_{t-1}(s') · γ_t(s', s)

Backward pass: Compute β_t(s) = P(received y_{t+1}...y_T | state


at time t is s)

β_t(s) = Σ_{s'} γ_{t+1}(s, s') · β_{t+1}(s')

Branch metric γ_t(s', s): probability of transitioning from s' to s at


time t, given received y_t.

γ_t(s', s) = P(y_t | transition s'→s) · P(u_t)

APP computation: The LLR of bit u_t:

L(u_t) = log [ Σ_{(s',s): u_t=1} α_{t-1}(s') ·


γ_t(s',s) · β_t(s) ]
-
log [ Σ_{(s',s): u_t=0} α_{t-1}(s') ·
γ_t(s',s) · β_t(s) ]

BCJR complexity = O(n · 2^m) same as Viterbi. But it gives soft


outputs — the crucial ingredient for turbo decoding.

PART IV: TURBO CODES — THE 1993


REVOLUTION

4.1 The Idea That Changed Everything

In 1993, Berrou, Glavieux, and Thitimajshima presented a coding


scheme that achieved 0.5 dB from the Shannon limit at BER 10^-5
— previously unimaginable. The code, called a "Turbo code,"
worked on a radically different principle: iterate.

The Encoder

Two Recursive Systematic Convolutional (RSC) encoders


connected in parallel:

Input bits m
────────────────────────────────→ (systematic
bits: sent directly)

├──→ RSC Encoder 1 ──→ Parity
bits p₁

└──→ Interleaver (Π) ──→ RSC
Encoder 2 ──→ Parity bits p₂
You transmit: [m, p₁, p₂] (at rate 1/3, or puncture p₁ and p₂
alternately for rate ~1/2).

Why Recursive (vs non-recursive)? RSC encoders have feedback.


This means the encoder can produce high-weight codewords
even from low-weight inputs, dramatically improving minimum
distance. Non-recursive systematic convolutional codes have a
systematic weakness: a low-weight input always produces a low-
weight codeword.

Why two encoders? One encoder alone might have a "blind spot"
— certain input patterns that produce low-weight codewords
(these cause errors). The interleaver scrambles the input order, so
patterns that fool encoder 1 are unlikely to also fool encoder 2.
Together, they cover each other's weaknesses.

4.2 The Interleaver — The Key Ingredient

The interleaver Π is a permutation: it takes the input sequence


and reorders the bits before feeding them to encoder 2.

What interleaving does for performance:

1. Breaks the correlation between the two parity streams — they


provide "independent" error protection

2. The combined minimum distance grows with the interleaver


length N

3. Error events from encoder 1 are "spread" — an error burst in


one domain becomes scattered errors in the other, which
encoder 2 handles well

Effect on error floor: The interleaver gives pseudo-random


properties. For truly random interleavers of size N, the minimum
distance grows as √N — enough to make the error floor extremely
low in practice.
4.3 Iterative Decoding — The Turbo Principle

This is the heart of turbo codes, and it's the same principle LDPC
decoding uses.

The decoder has two SISO (Soft Input / Soft Output) decoders
(using BCJR):

Channel output y → Decoder 1 → Extrinsic LLR₁


→ Interleave → Decoder 2


←────────────── De-interleave
←──────────────── Extrinsic LLR₂ ←───┘

The critical concept: Extrinsic Information

At each decoder, the output LLR for bit u_t is:

L_out(u_t) = L_channel(u_t) + L_a_priori(u_t) +


L_extrinsic(u_t)

The extrinsic part L_extrinsic is what this decoder has learned


about u_t from the other bits (via the code constraints), excluding
what it already knew from the channel and what was fed in as a
priori. This is the new information this decoder contributes.

Why extrinsic, not the full output? If you fed the full posterior
output back as a priori, you'd be "double-counting" the channel
information — the decoder already used that when computing its
output. Feeding only extrinsic information prevents this.

One Iteration:

1. Decoder 1: Uses channel LLR(y_systematic), channel


LLR(y_parity_1), and a_priori from previous iteration (initially
zero). Computes extrinsic LLR₁ for each bit.
2. Interleave LLR₁

3. Decoder 2: Uses channel LLR(y_systematic, interleaved),


channel LLR(y_parity_2), and interleaved LLR₁ as a priori.
Computes extrinsic LLR₂.

4. De-interleave LLR₂ → this becomes a priori for Decoder 1 in


next iteration.

Typically 6-18 iterations. Each iteration, the decoders' estimates


converge. At the end, hard decisions are made on the total
posterior LLR.

Intuition: It's like two people each with partial knowledge of a


puzzle, consulting each other iteratively. Each round, they
incorporate what the other learned, getting closer to the truth.
The "turbo" metaphor: extrinsic information is recycled like the
exhaust gases in a turbocharger — energy that would have been
wasted, fed back to improve the system.

4.4 Why Turbo Codes Approach Shannon —


EXIT Charts

EXIT (Extrinsic Information Transfer) charts visualize iterative


decoding convergence.

For each decoder, plot a curve: given input mutual information I_A
(how much a priori info the decoder receives), what is output
mutual information I_E (how much extrinsic info it produces)?

This curve is monotonically increasing (more a priori → better


extrinsic output)

For decoder 1: I_E₁ = T₁(I_A₁)

For decoder 2: I_E₂ = T₂(I_A₂), but since output of one feeds


into the other: I_A₂ = I_E₁, I_A₁ = I_E₂
If you plot both curves on the same axes (flipping the second),
you get two S-shaped curves. Iterative decoding converges if and
only if the two curves don't cross (except at (1,1)) — there must
be a "tunnel" between them for the decoder trajectories to pass
through to (1,1) (perfect decoding).

This gives a visual design criterion: choose code parameters so


that the EXIT curves form a tunnel at the smallest possible SNR.

4.5 Turbo Code Problems

1. Error floor: At high SNR, the BER curve flattens (a "floor") due
to low-weight codeword events. The floor is determined by
the minimum distance and weight enumerator.

2. Latency: Block length must be large for good performance


(long interleaver), causing encoding/decoding delay. Bad for
URLLC.

3. Parallelism: Trellis decoding has inherent sequential


dependencies. Hard to parallelize heavily.

4. For large block lengths: LDPC beats turbo. This was why 5G
NR chose LDPC for data channels.

PART V: LDPC CODES — GALLAGER'S


GENIUS

5.1 Historical Context

Robert Gallager invented LDPC codes in his 1960 MIT PhD thesis
(published 1963). He invented:

1. The code class (sparse parity check matrix)


2. Iterative decoding algorithms (including the sum-product
algorithm!)

3. Proved that random regular LDPC codes have good distance


properties

Then the codes were forgotten for 35 years. Why? No computing


power to implement iterative decoding in real-time. No theory to
design good codes. The field moved to algebraic codes.

In 1993, Turbo codes appeared and showed that iterative


decoding on graphs could achieve near-Shannon performance.
This triggered a re-examination of everything. In 1995-1996,
MacKay and Neal independently rediscovered LDPC codes and
showed they were just as good, often better than turbo codes for
long blocks.

5.2 Gallager's Intuition — Why Sparse?

The core insight: If you have many parity checks, but each check
involves only a small number of bits, then:

1. Local decoding: Each check equation constrains only a small


subset of bits. This enables local, iterative inference — like
solving a very large crossword puzzle by focusing on
individual clues.

2. Independence: If the graph has few short cycles, then the bits
involved in different checks are "almost independent." This
lets you apply probabilistic reasoning without worrying about
correlations.

3. Complexity: The decoder only processes the non-zero entries


of H. If H has weight w per row, total complexity is O(n·w) —
linear in block length!

4. Distance: A random sparse code still has good minimum


distance (linear in n), because the graph's expansion
properties prevent low-weight codewords.

The contrast with algebraic codes: In Hamming, BCH, etc., H is


highly structured (dense or with algebraic patterns). This
structure gives efficient decoding but limits the distance
distribution. A sparse but "random" H has the good distance
properties of random codes while allowing efficient local
decoding.

5.3 The Parity Check Matrix H

An (n, k) LDPC code is defined by its parity check matrix H (size


m × n, where m = n - k):

n = number of code bits (codeword length)

k = number of information bits

m = number of parity check equations

H is sparse: most entries are 0

A codeword c satisfies H·c^T = 0 (mod 2).

The term "low density" refers to the density (fraction of 1s) in H


being very small — typically a few percent or less.

Column weight d_v: number of 1s in each column of H = number


of parity checks involving each code bit.
Row weight d_c: number of 1s in each row of H = number of code
bits involved in each parity check.

Regular LDPC code: All columns have the same weight d_v
(called variable node degree), all rows have the same weight d_c
(check node degree). Rate R ≥ 1 - d_v/d_c.

Irregular LDPC code: Variable and check node degrees vary. The
degree distribution is described by polynomials:
λ(x) = Σ_i λ_i · x^{i-1} [fraction of edges
connected to variable nodes of degree i]
ρ(x) = Σ_j ρ_j · x^{j-1} [fraction of edges
connected to check nodes of degree j]

Irregular codes, properly designed, can outperform regular codes


and approach capacity much more closely.

5.4 The Tanner Graph — Visualizing the Code

In 1981, Tanner introduced the bipartite graph representation of


LDPC codes (now called the Tanner graph):

Variable Nodes (circles): v₁ v₂ v₃ v₄ v₅ v₆


│╲ │╲ │ │ ╱│╲ │
│ ╲ │ ╲ │ │ ╱ │ ╲ │
Check Nodes (squares): c₁ c₂ c₃ c₄

Variable nodes (v-nodes or bit nodes): one per code bit. The
code bit value is associated with this node.

Check nodes (c-nodes): one per row of H (per parity


equation).

Edge between v_j and c_i: exists if and only if H[i,j] = 1.

Each check node c_i represents the equation: XOR of all variable
nodes connected to it = 0.

Cycles in the Tanner graph: The shortest cycle length is the girth
g. Short cycles (especially length 4, called "4-cycles") cause
correlations between messages in the belief propagation
algorithm, degrading performance. Good LDPC codes are
designed to have large girth (g ≥ 6, ideally g ≥ 8).

Why is the Tanner graph so powerful? It decomposes a global


constraint (H·c=0) into many local constraints. The decoder can
then do local computations at each node and pass messages
along edges — this is belief propagation.

PART VI: BELIEF PROPAGATION —


THE DECODER

6.1 The Big Picture

Belief propagation (also called message passing, sum-product


algorithm) is an algorithm for computing marginal distributions
on factor graphs. It was independently discovered multiple times:
Pearl (1982) in AI, Tanner (1981) in coding, Gallager (1963) in
LDPC, and formalized by Forney, Wiberg, and others.

For LDPC decoding, the goal is: given the received channel
output y, compute for each bit j:

P(c_j = 0 | y) and P(c_j = 1 | y)

and then make decisions based on which is larger.

Why not compute this directly? Because it requires summing


over all 2^k possible codewords — exponential complexity. BP
does it approximately (and exactly for tree graphs) in linear time.

6.2 Log-Likelihood Ratios (LLRs)

Working in the log domain is numerically better than working with


probabilities directly.

Channel LLR for received symbol y_j:


L_ch(j) = log [ P(y_j | c_j = 0) / P(y_j | c_j = 1) ]

For AWGN with BPSK (0 → +1, 1 → -1), variance σ²:

L_ch(j) = 2 · y_j / σ²

The sign of LLR gives the hard decision; the magnitude gives the
confidence. LLR > 0 → decide c_j = 0; LLR < 0 → decide c_j = 1.

Total LLR (a posteriori):

L(c_j | y) = log [ P(c_j = 0 | y) / P(c_j = 1 | y) ]

6.3 The Sum-Product Algorithm (Belief


Propagation) in LLR Domain

Two types of messages flow along edges in the Tanner graph:

Variable → Check messages (what the bit thinks it is):

μ_{v→c}(x) = channel_LLR(v) + Σ_{c' ∈ N(v)\{c}}


μ_{c'→v}

A variable node sends to check c: my channel measurement plus


what all my OTHER check nodes told me.

Check → Variable messages (what the constraint "knows" about


the bit):

In the probability domain, the check node message is:

P(x_v = 0 | x_{v'} for v' ≠ v) = ½ + ½ · ∏_{v' ∈


N(c)\{v}} (1 - 2·P(x_v' = 1))
In the LLR domain, using the key identity tanh(L/2) = (1 -
P(x=1))/P(x=1):

μ_{c→v} = 2 · arctanh( ∏_{v' ∈ N(c)\{v}}


tanh(μ_{v'→c} / 2) )

Or equivalently, using the "box-plus" operation:

μ_{c→v} = (⊕_{v' ∈ N(c)\{v}}) μ_{v'→c}

where a ⊕ b = 2·arctanh(tanh(a/2)·tanh(b/2))
= sign(a)·sign(b) · min(|a|,|b|) +
correction_term

A check node update asks: "Assuming all OTHER bits connected


to me satisfy the parity check, what does that tell me about bit v?"

Posterior LLR for each variable node:

L(c_j) = L_ch(j) + Σ_{c ∈ N(v)} μ_{c→v}

Hard decision: c_j = 0 if L(c_j) > 0, else c_j = 1.

Stopping condition: Either syndrome H·ĉ^T = 0 (valid codeword


found), or maximum iterations reached.

6.4 Flooding vs Layered Scheduling

Flooding (parallel) scheduling:

All variable nodes update simultaneously using old check


messages

All check nodes update simultaneously using old variable


messages

Clean to implement, easy to analyze


One iteration = one full round of both updates

Layered (sequential/turbo) scheduling:

Process rows of H one at a time (one "layer" at a time)

After updating check node i, immediately use the new


message for variable node updates

This creates a serial dependency that is more like the turbo


decoder

Converges ~2× faster than flooding (in terms of iterations


needed)

Requires updating variable node LLRs in-place between layer


updates

Standard in hardware implementations (including 5G NR


decoders)

Why layered converges faster: Information propagates through


the graph more quickly. Each bit gets updated more frequently
with more recent information.

6.5 The Algorithm in Practice

Input: channel LLRs L_ch[j] for j = 0..n-1


Initialize: μ_{v→c}[j,i] = L_ch[j] for all edges
(j,i)
μ_{c→v}[i,j] = 0 for all edges

For iteration t = 1, 2, ..., T_max:


// Check node update
For each check node i:
For each v ∈ N(c_i):
μ_{c→v}[i,v] = 2·arctanh( ∏_{v' ∈ N(c_i)\{v}}
tanh(μ_{v→c}[v',i] / 2) )

// Variable node update


For each variable node j:
L_post[j] = L_ch[j] + Σ_{i ∈ N(v_j)} μ_{c→v}
[i,j]
For each i ∈ N(v_j):
μ_{v→c}[j,i] = L_post[j] - μ_{c→v}[i,j]

// Syndrome check / early termination


ĉ = hard_decision(L_post)
If H · ĉ^T == 0: CONVERGED, output ĉ

Output: hard_decision(L_post) at T_max

PART VII: WHY LDPC IS SO CLOSE TO


SHANNON

7.1 The Capacity-Achieving Property — What


It Means

Shannon showed: there exist codes that achieve capacity. LDPC


codes (properly designed) are provably capacity-achieving — for
appropriately chosen degree distributions, there exist sequences
of LDPC codes such that as block length → ∞, the decoding
threshold under BP approaches the Shannon capacity.

But we need to unpack this: capacity-achieving under what


decoder?

Under ML decoding: many codes achieve or approach


capacity (including simply random codes)

Under BP decoding: LDPC codes are unique — their sparse


structure allows BP, and BP on LDPC codes with good degree
distributions can achieve capacity
Key result (Luby, Mitzenmacher, Shokrollahi, Spielman, 1998): On
the Binary Erasure Channel (BEC), LDPC code ensembles with
optimized degree distributions achieve capacity under BP
decoding. Capacity-achieving sequences were constructed
explicitly.

For AWGN and other channels: the thresholds approach capacity,


with the gap depending on degree distribution design. Irregular
LDPC codes designed via density evolution can get within 0.04
dB of the Shannon limit.

7.2 Density Evolution — The Analytical Tool

Density evolution (DE) (Richardson, Urbanke, 2001) is the key tool


for analyzing and designing LDPC codes.

Setup: Assume infinite block length and tree-like Tanner graph


(no short cycles). Under these assumptions, the messages at
each iteration are independent.

Tracking: At each iteration t, track the probability distribution of


messages. For AWGN, track the mean and variance of LLR
messages (using Gaussian approximation) or the full distribution
(exact DE).

Decoding threshold: For a given channel (parameterized by SNR


or noise level σ²), there is a threshold σ*: if σ < σ* (less noise), BP
decoding succeeds as n → ∞; if σ > σ*, it fails. This threshold is
determined by whether the density evolution equations converge
to the "success" fixed point.

Design: Optimize the degree distribution (λ(x), ρ(x)) to maximize


the threshold σ* (or equivalently, minimize the SNR at which the
code operates reliably). This is a linear programming problem
over the degree distribution coefficients.
Result: Well-designed irregular LDPC codes have thresholds
within 0.04 dB of the Shannon limit for AWGN. Spatially coupled
LDPC codes (SC-LDPC) threshold-saturate to the MAP threshold,
which can equal the Shannon limit.

7.3 Why the Graph Structure Enables Near-


Capacity Performance

Think about what Shannon's random coding proof says: a


randomly chosen code achieves capacity (under ML decoding).
The key is that random codes have "good" distance properties —
most codewords are far apart.

An LDPC code defined by a random sparse H matrix is a random


code restricted to a subspace. For large n:

The minimum distance grows linearly with n (good!)

The weight distribution looks "random" (good!)

But we can decode it efficiently via the sparse structure


(good!)

The catch: BP decoding is NOT ML decoding. BP fails due to


cycles in the Tanner graph. Short cycles cause "message
confusion" — a message arriving at a node contains information
about itself (through a loop), violating the independence
assumption.

For long codes with good graph design (large girth), cycles are
long, and the "independence radius" (how far you can go before
hitting a cycle) grows as ~log(n). For finite block lengths, this
means BP is only approximately right, but the approximation
improves with block length.

The intuition for near-capacity performance:


Long blocks → large girth → long cycles → BP ≈ ML on most
of the graph

Good degree distribution → "balanced" information flow →


efficient error correction

Irregular nodes (degree-2 variable nodes) create "degree-2


chains" that efficiently propagate reliable information into
uncertain bits

7.4 The Connection to Shannon's Random


Coding Argument

Shannon's proof: Pick a random code (random generator matrix).


For any rate R < C, the probability that a random code has bad
performance → 0 as n → ∞.

LDPC's genius: Use a random sparse H matrix. The code is


random, so it inherits the good distance properties. But the
sparsity allows efficient decoding.

The price paid: BP is not ML, so there's a gap. But for long codes,
this gap → 0. That's the content of density evolution: as n → ∞
with the right degree distribution, BP performance → MAP
performance → approaches Shannon.

PART VIII: LDPC ≈ ML DECODER —


THE DEEP CONNECTION

8.1 BP = ML on Trees

The most important fact about belief propagation:


On a tree-structured Tanner graph (no cycles), BP is EXACT
and computes the correct MAP marginals. It IS the ML
decoder.

Proof sketch: On a tree, there are no cycles, so all messages


arriving at a node are independent (computed from disjoint
subtrees). The message-passing updates are exact — they
correctly compute the marginal probability of each bit given the
received sequence.

This is the fundamental theoretical justification for BP: it's not a


heuristic; it's the exact ML decoder for tree codes. We're
extending it heuristically to graphs with cycles.

8.2 Why Cycles Break Exactness

In a graph with cycles, consider a length-4 cycle: v₁ - c₁ - v₂ - c₂ -


v₁. When v₁ sends a message to c₁, it incorporates messages
from c₂. But c₂'s message was influenced by v₂, which was
influenced by c₁, which was influenced by v₁ — a circular
dependency.

This "message confusion" has two effects:

1. BP may not converge (oscillates between different estimates)

2. Even if it converges, it may converge to a wrong answer (a


"pseudocodeword")

Pseudocodewords: Fixed points of the BP equations that do not


correspond to valid codewords. At low SNR, BP may converge to
a pseudocodeword instead of the transmitted codeword, causing
a decoding failure.

The distance from the transmitted codeword to the nearest


pseudocodeword determines the effective minimum distance of
BP decoding — often lower than the true minimum distance.
8.3 Linear Programming (LP) Decoding —
The Bridge to ML

In 2002, Feldman showed that ML decoding of a linear code can


be written as an Integer Linear Program (ILP). The LP relaxation
(dropping the integer constraint) gives an algorithm called LP
decoding:

ML decoding as ILP:

minimize Σ_j (1 - L_ch(j)/2) · x_j (minimize


cost = correlation with channel)
subject to: x = valid codeword ∈ {0,1}^n

LP relaxation: Relax x to the "fundamental polytope" — convex


hull of all codewords, approximately.

Properties of LP decoding:

If LP finds a vertex of the polytope, it must be a codeword (LP


decoding = ML)

If LP finds a fractional solution (non-vertex, non-integer), LP


decoding "fails" but knows it failed

LP decoding dominates ML decoding over all channels


simultaneously (if LP fails, ML would also "fail" in a sense)

LP is closely related to BP: the fixed points of BP are


approximations to the LP solution

This establishes that BP, LP, and ML are all trying to solve the
same underlying optimization problem — ML being the ideal, LP
being its convex relaxation, and BP being an efficient iterative
approximation.
8.4 Ordered Statistics Decoding (OSD) —
Getting Closer to ML

OSD (Fossorier & Lin, 1995) is a post-processing technique that


can get arbitrarily close to ML decoding at the cost of extra
computation:

1. Find the k most reliable bit positions (highest |LLR| values) —


these are the "most reliable basis" (MRB)

2. Perform Gaussian elimination on H to express the code in


systematic form with the MRB columns first

3. Enumerate the 2^order combinations of flipping bits in the


MRB (starting from order 0)

4. For each flip pattern, solve for the remaining bits (parity bits)
and compute the total metric

5. Output the highest-metric valid codeword

At order 0: only try the hard-decision codeword. Very fast, but


suboptimal.
At order d: try all patterns with up to d errors in the MRB.
Approaches ML as d increases.

OSD can be used as a post-processor after BP failure to lower the


error floor.

8.5 The Practical Consequence

For long LDPC codes (n > 10,000) at rates used in 5G:

BP decoding with 20-50 iterations performs within < 0.1 dB of


ML decoding in the waterfall region

The error floor (caused by pseudocodewords and trapping


sets) is where BP diverges from ML
This is why 5G NR LDPC codes were carefully designed with large
girths and specific structure to push pseudocodewords away and
minimize the error floor.

PART IX: PRACTICAL


OPTIMIZATIONS — FROM SMALL
TRICKS TO BIG IDEAS

9.1 The Min-Sum Algorithm — First


Approximation

The exact check node update:

μ_{c→v} = 2·arctanh( ∏_{v' ∈ N(c)\{v}}


tanh(μ_{v'→c} / 2) )

Computing tanh and arctanh in hardware is expensive — requires


lookup tables or Taylor series approximations. The min-sum (MS)
algorithm replaces this with a simple approximation:

Using the identity:

2·arctanh(tanh(a/2)·tanh(b/2)) ≈
sign(a)·sign(b)·min(|a|,|b|)

(exact for |a|=|b|, approximate otherwise — the error is always


positive, meaning MS overestimates message magnitudes)

The check node update becomes:


μ_{c→v} = (∏_{v' ∈ N(c)\{v}} sign(μ_{v'→c})) ·
min_{v' ∈ N(c)\{v}} |μ_{v'→c}|

What this is computationally: XOR of signs (super cheap, just


XOR the sign bits), and minimum of magnitudes (just find the
smallest absolute value).

Performance: 0.2-0.5 dB worse than full SPA for typical codes.


But the complexity reduction is enormous — no transcendental
functions needed.

Implementation trick: You don't need all minimum values — just


the first and second minimum. Store min₁, min₂, and the index
achieving min₁. For any message to v:

If v is the one achieving min₁: use min₂

Otherwise: use min₁

This requires only 2 comparators and minimal storage per check


node.

9.2 Normalized Min-Sum (NMS) —


Correcting the Bias

The min-sum algorithm overestimates message magnitudes


(because the approximation error is always positive). This means
the decoder is "overconfident," which causes degraded
performance.

Fix: Multiply the min-sum output by a correction factor α < 1:

μ_{c→v}^{NMS} = α · (∏ sign(μ_{v'→c})) · min_{v' ∈


N(c)\{v}} |μ_{v'→c}|
Where α comes from: Density evolution. For a given code and
channel, optimize α to maximize threshold. Typical values: α ≈
0.75 - 0.875.

Performance: Within 0.1-0.2 dB of full SPA. Near-SPA


performance at a fraction of the complexity. Used in almost all
practical LDPC decoders.

Implementation cost: One multiplication per check node update


(can be done with shift-add if α = 2^{-k}).

9.3 Offset Min-Sum (OMS) — Additive


Correction

Instead of scaling, subtract a constant β:

μ_{c→v}^{OMS} = (∏ sign(μ_{v'→c})) · max(0, min_{v'


∈ N(c)\{v}} |μ_{v'→c}| - β)

The max(0, ...) prevents negative values.

Comparison with NMS:

OMS: constant shift, works best in the mid-SNR range

NMS: proportional scaling, works well over wider SNR range

For finite-length codes, OMS with a well-chosen β can slightly


outperform NMS

OMS is easier in fixed-point arithmetic (just subtract a


constant)

In 5G NR implementations, both are used depending on


vendor choice

How to find optimal β: Density evolution or simulation. Typical


values: β ≈ 0.15 - 0.5.
9.4 Layered (Row-Layered) Scheduling — 2×
Speedup

As described earlier, process check node rows one at a time,


immediately updating the variable node LLRs in-place.

Algorithm: Store the "intrinsic LLR" for each variable node: L_v =
L_ch + Σ_{all c} μ_{c→v}

When processing row i:

1. For each v ∈ N(c_i):

Compute input to check: m_v = L_v - μ_{c_i→v} (remove


old message from c_i)

2. Compute new check node message μ_{c_i→v}^{new} using


inputs {m_v}

3. Update: L_v += μ_{c_i→v}^{new} - μ_{c_i→v}^{old}

4. Store μ_{c_i→v}^{new} for next iteration

Why faster convergence: At each layer, the variable nodes


immediately incorporate the new check node message. By the
time the next layer is processed, the variable nodes reflect the
most recent information. This creates an effect like serial
updates in iterative solvers — typically 2× faster in terms of
iterations needed for the same BER performance.

Memory implications: Store only one LLR per variable node (the
cumulative intrinsic LLR) plus one message per edge (the check-
to-variable message for the previous iteration). The variable-to-
check message is computed on-the-fly as (L_v - old_check_msg).

9.5 Early Termination — Saving Cycles

Many decoding instances converge well before the maximum


iteration count. Continuing to iterate wastes power and time.
Syndrome-based stopping: After each iteration (or each layer),
compute H·ĉ^T. If it's zero, we have a valid codeword — stop. This
is cheap for structured codes (exploit QC structure, or pipeline
the check).

LLR stability stopping: Stop if the change in all variable node


LLRs between iterations is below a threshold. Less rigorous (can
miss errors) but very simple.

Hybrid: Use syndrome check as primary criterion, with a max


iteration limit as backup.

Statistics: For a well-operating LDPC decoder at operating SNR,


~80% of blocks may converge in half the iterations. Early
termination can give 40-60% average power reduction while
maintaining the same BER.

9.6 The Error Floor Problem — Trapping Sets

At high SNR (well into the waterfall), the BER should decrease
exponentially. But many LDPC codes show an error floor: the BER
curve suddenly flattens and the rate of decrease slows
dramatically.

Cause: Trapping sets and absorbing sets — small subsets of


variable nodes that form "traps" for the BP decoder.

Formal definition: A (a, b) trapping set T is a set of a variable


nodes such that the induced subgraph has b odd-degree check
nodes (check nodes with an odd number of connections to T).
The odd-degree check nodes are called "unsatisfied checks" at
the error floor.

What happens: When error patterns hit these variable nodes, BP


gets "stuck" — it fails to satisfy the unsatisfied checks and
oscillates or converges to a wrong codeword. The trapping set
acts like an attractor for the decoder dynamics.
Example: A (5,3) trapping set means 5 variable nodes and 3 odd-
degree check nodes. These are particularly harmful.

Why low SNR doesn't matter: At low SNR, many bits are
unreliable, so errors are widespread and BP can escape trapping
sets. At high SNR, only a few bits are in error, and if those happen
to form a trapping set, BP fails.

Mitigation Strategies:

Code design level:

Use progressive edge growth (PEG) algorithm to construct


Tanner graphs with large girth and minimal harmful trapping
sets

Use structured codes (QC-LDPC) with carefully chosen


circulant shift values to avoid small trapping sets

Analyze the trapping set enumerator and design to eliminate


small ones

Decoder level:

Post-processing with noise injection: add controlled random


perturbations to LLRs and re-run BP (simulated annealing
approach). This can escape trapping sets.

Multi-pass decoding: Run BP, if syndrome check fails, perturb


and re-run

Ordered statistics post-processing: OSD-0 or OSD-1 on the


unsatisfied checks

9.7 Quantization and Fixed-Point Arithmetic

Real hardware uses fixed-point arithmetic with finite word


lengths. This introduces quantization error.
LLR clipping: LLRs beyond a threshold are clipped to ±LLR_max.
This prevents overflow and is benign for large LLRs (we're already
certain). Typical: 5-6 bits for LLR representation = 32-64 levels =
clip at ±LLR_max ≈ 5-10.

Message quantization: Internal messages (check-to-variable,


variable-to-check) typically use 4-6 bits. Going below 4 bits
causes significant performance loss (0.1-0.3 dB).

Non-uniform quantization: More quantization levels near zero


(uncertain bits need fine resolution), fewer levels at high
magnitudes (already certain). Typical: 6-bit uniform with
appropriate step size works well.

Log-likelihood initialization: From the channel, LLRs are


inherently continuous. The ADC (analog-to-digital converter)
quantizes the received signal. Using 4-5 bits per channel sample
is typical in 5G receivers.

Performance impact: A well-designed 6-bit fixed-point NMS


decoder typically performs within 0.1-0.15 dB of floating-point.
Going to 4 bits: ~0.3-0.5 dB loss.

9.8 Quasi-Cyclic (QC) LDPC Codes —


Hardware Efficiency

The Problem with Random LDPC: Truly random sparse H


matrices have no structure that enables efficient hardware
implementation. Memory addressing, parallelism, and routing are
all complex.

The QC Solution: Construct H as a block matrix of circulant


matrices (cyclic permutation matrices):

H = [P^{a_{00}} P^{a_{01}} ... P^{a_{0,n-1}}]


[P^{a_{10}} P^{a_{11}} ... P^{a_{1,n-1}}]
[ ... ... ... ... ]

where P is the z×z "cyclic shift" (identity matrix shifted by one


position), and P^a means shifted by a positions (P^∞ = 0 matrix).

Hardware benefits:

1. Parallelism: z check nodes can be processed simultaneously


(they're independent within a "layer" of z rows)

2. Memory: The entire H is described by the shift values {a_{ij}}


— compact description

3. Routing: Barrel shifters implement the cyclic shift — regular,


efficient

4. Throughput: z-fold parallelism directly translates to z×


throughput

The "lifting factor" z is chosen based on throughput


requirements. In 5G NR, z ranges from 2 to 384.

Mathematical description: A QC-LDPC code can be described by


its "base graph" B (a smaller matrix where each entry is a
circulant shift value). The actual H is obtained by "lifting" —
replacing each entry a_{ij} with the z×z circulant P^{a_{ij}}.

9.9 Degree Distribution Optimization —


Capacity-Approaching Design

For irregular LDPC codes, the degree distribution (λ, ρ)


dramatically affects performance.

Key insights from density evolution:

Degree-2 variable nodes: very helpful for efficient propagation


(information flows cheaply), but too many cause error floors
(they can be in trapping sets)
High-degree variable nodes: increase code distance but
reduce BP efficiency

Check node degree: higher degree → better minimum


distance, but more complex check nodes

Optimal trade-off: mix of degrees, with many degree-2 and


degree-3 variable nodes and some high-degree ones

Design procedure:

1. Fix the target rate R and code length n

2. Set up density evolution equations as a function of (λ, ρ)

3. Optimize (via linear programming or EXIT chart matching) to


maximize the decoding threshold

4. Verify by simulation for finite length

5. Check the error floor (analyze trapping sets)

The "capacity-approaching" intuition: Degree-2 variable nodes


form "chains" that very efficiently propagate certainty from more
reliable bits to less reliable ones. They're like a wire connecting a
reliable region to an uncertain one. But they have low minimum
distance contribution — so you can't have too many.

9.10 Puncturing and Rate-Compatible Codes

To support multiple code rates (for HARQ and adaptive MCS),


LDPC codes can be designed as rate-compatible:

Puncturing: Remove some parity bits from the codeword before


transmission. Increases rate but reduces redundancy. The
punctured bits are known to the decoder (as "erasures" with LLR
= 0).

Shortening: Set some information bits to zero and don't transmit


them. Decreases rate effectively.
Rate-compatible LDPC (RC-LDPC): A family of codes where
higher-rate codes are obtained by puncturing a mother code.
Designed so all rates in the family have good performance.

In 5G NR: The base graph gives a "base code" and then


puncturing/repetition via the rate matcher selects the actual code
rate for each transport block. The "circular buffer" approach
stores the encoded bits and the rate matcher reads from a
selected starting position.

PART X: 5G NR LDPC — SPECIFIC


DESIGN CHOICES

10.1 The Two Base Graphs

5G NR uses two base graphs:

Base Graph 1 (BG1): For high throughput, large code blocks

46 rows (m_b = 46), 68 columns (n_b = 68) → k_b = 22


information columns

Code rate from 1/3 to 22/24 (≈ 8/9)

Used for: code blocks > 3840 bits, or code rate ≥ 1/4 for
shorter blocks

Maximum code block size: 8448 bits

Base Graph 2 (BG2): For low throughput, small code blocks, low
rate

42 rows, 52 columns → k_b = 10 information columns

Code rate from 1/5 to 2/3

Used for: shorter blocks or lower rates


Why two base graphs: Different applications need different
performance profiles. Control channels (very small blocks, high
reliability) need BG2; data channels (large blocks, high
throughput) need BG1. One base graph optimized for both would
be a compromise.

10.2 The Lifting (Expansion) Process

Given a base graph with entries {a_{ij}} (shift values) and a lifting
factor z:

The actual H is size (m_b × z) × (n_b × z)

Each entry a_{ij} becomes a z×z cyclic permutation matrix


P^{a_{ij}}

Each -1 entry (null) becomes a z×z zero matrix

Lifting sets: 5G defines lifting factor z from a set of 51 possible


values from 2 to 384, organized in 8 "lifting sets" {z_0, 2z_0, 4z_0,
8z_0, ...}. The shift values in the base graph are specified modulo
each z in its set, so the same base graph works for many block
lengths.

Why this design:

Supports a wide range of transport block sizes without


redesigning the code

Enables the same hardware architecture to decode different


code sizes just by changing z

Different z values → different parallelism in hardware

10.3 HARQ Support and the Circular Buffer

LDPC in 5G is designed for Hybrid ARQ (HARQ):


After encoding with LDPC, all n codeword bits are written to a
"circular buffer." For the initial transmission, bits are read starting
from position 0 (or another "redundancy version" starting point).
If the receiver can't decode, the transmitter sends additional bits
(from a different position in the buffer). The receiver combines all
received signals using Chase combining or incremental
redundancy.

Redundancy Versions (RV): 5G defines 4 starting positions (RV0,


RV1, RV2, RV3) in the circular buffer. Each retransmission starts
from a different position, maximizing the new information
provided.

Design implication: The first ~20% of coded bits (the "systematic"


part) should always be sent first (RV0). The LDPC code is
designed with the systematic bits at the beginning of the
codeword, and the structure ensures that even with high
puncturing ratio, the systematic bits are protected.

10.4 The Encoding Algorithm

LDPC encoding requires finding x such that H·x^T = 0 and the first
k bits of x equal the information bits.

For a general H, this requires Gaussian elimination — O(n²)


complexity. For 5G LDPC codes, the structure of H is specially
designed for approximately lower-triangular encoding:

The H matrix, after separating systematic bits from parity bits:

H = [H_A | H_B]

where H_B has a specific structure that enables back-substitution


encoding in O(n) time.
The first m-z parity bits are computed by back-substitution (due
to the lower-triangular structure of H_B[0:m-z, :]). The last z parity
bits require one additional step (solving a small z×z system).

Overall encoding complexity: O(n) — linear in code length.

10.5 Performance Numbers

For 5G NR LDPC with BG1, code rate 1/2, block length n ≈ 4000:

Waterfall at Eb/N0 ≈ 0.8-1.0 dB (Shannon limit: 0 dB for rate


1/2 BPSK)

Gap to Shannon: ~0.8-1.0 dB at BER 10^-5

Error floor: below BER 10^-6 for standard puncturing patterns

At larger block lengths (n ≈ 8448), the gap shrinks to ~0.5 dB.

PART XI: THE FULL OPTIMIZATION


STACK — SUMMARY TABLE

Level Optimization Gain Cost

÷5
Algorithm Min-Sum vs SPA -0.3 dB
complexity

+0.2 dB vs ×1
Algorithm Normalized Min-Sum
MS multiplication

+0.2 dB vs + constant
Algorithm Offset Min-Sum
MS subtract
Level Optimization Gain Cost

Sequential
~0 dB, 2×
Scheduling Layered vs Flooding layer
fewer iters
dependency

~40%
Syndrome
Stopping Early termination power
check per iter
savings

-0.1-0.15 Much smaller


Quantization 6-bit vs float
dB hardware


Structure QC-LDPC ~0 dB
parallelism

Trapping set-free Eliminates Code design


Error floor
design floor complexity

+1-2
Extra
orders of
Post-proc Bit-flip / Noise inject decoder
magnitude
passes
BER

~0.5 dB ~k² Gaussian


Post-proc OSD-0 after BP
near floor elimination

Careful rate-
Flexible
Rate Puncturing/Shortening matching
rates
design

PART XII: FURTHER READING — THE


CANONICAL SOURCES
Primary References (Read in This Order)

Foundations

1. Shannon (1948): "A Mathematical Theory of Communication"


— The original. Read it.

2. Gallager (1963): "Low-Density Parity-Check Codes" — MIT


Press. The source. Gallager's iterative decoder is in here.

3. Berrou et al. (1993): "Near Shannon Limit Error-Correcting


Coding and Decoding: Turbo Codes" — ICC 1993.

LDPC Renaissance

4. MacKay & Neal (1996): "Near Shannon Limit Performance of


Low Density Parity Check Codes" — Electronics Letters.

5. Richardson & Urbanke (2001): "The Capacity of Low-Density


Parity-Check Codes Under Message-Passing Decoding" —
IEEE Trans. IT. The density evolution paper.

6. Richardson, Shokrollahi & Urbanke (2001): "Design of


Capacity-Approaching Irregular Low-Density Parity-Check
Codes" — IEEE Trans. IT.

Algorithms

7. Chen, Dholakia, Eleftheriou, Fossorier, Hu (2005): "Reduced-


Complexity Decoding of LDPC Codes" — IEEE Trans. Comms.
Covers NMS and OMS in detail.

8. Hocevar (2004): "A reduced complexity decoder architecture


via layered decoding of LDPC codes" — IEEE SIPS. The
definitive layered scheduling paper.

Theory

9. Forney (2001): "Codes on graphs: Normal realizations" —


IEEE Trans. IT. Connects everything.
10. Richardson & Urbanke: "Modern Coding Theory" —
Cambridge University Press 2008. The definitive textbook.
Free preprint available.

Practical

11. NPTEL — Andrew Thangaraj: "Error Correcting Codes" lecture


series (YouTube/NPTEL). Excellent, rigorous, free.

12. 3GPP TS 38.212: The actual 5G NR LDPC specification. Read


Sections 5.3 and 5.4.

Advanced

13. Fossorier, Mihaljevic, Imai (1999): "Reduced Complexity


Iterative Decoding of Low-Density Parity Check Codes Based
on Belief Propagation" — Min-Sum paper.

14. Feldman (2003): "Decoding Error-Correcting Codes via Linear


Programming" — PhD thesis, MIT. LP decoding.

15. Dolecek, Zhang, Anantharam, Wainwright, Nikolic: Various


papers on trapping sets and error floors (2008-2012).

APPENDIX: KEY FORMULAS CHEAT


SHEET

Channel Model (AWGN, BPSK)

Transmitted: x ∈ {+1, -1} (mapping: bit 0 → +1, bit 1 → -1)

Received: y = x + n, n ~ N(0, σ²)

Channel LLR: L_ch = 2y/σ² = 4E_s/N_0 · y (where E_s is


symbol energy)

σ² = N_0/2; E_b/N_0 = E_s/(R·N_0)


SPA Check Node Update (exact)

L_{c→v} = 2·arctanh( ∏_{v'≠v} tanh(L_{v'→c}/2) )

Min-Sum Check Node Update (approximate)

L_{c→v} = (∏_{v'≠v} sign(L_{v'→c})) · min_{v'≠v}


|L_{v'→c}|

Normalized Min-Sum

L_{c→v}^{NMS} = α · (∏ sign) · min |L|, α ≈ 0.75-


0.875

Offset Min-Sum

L_{c→v}^{OMS} = (∏ sign) · max(0, min |L| - β), β


≈ 0.15-0.5

Variable Node Update

L_{v→c} = L_ch(v) + Σ_{c'≠c} L_{c'→v}


L_post(v) = L_ch(v) + Σ_{all c} L_{c→v}

Shannon Capacity (AWGN, bits/channel use)

C = log₂(1 + E_s/N_0) [complex channel]


C = ½·log₂(1 + 2R·E_b/N_0) [at rate R, binary input]
Code Rate (QC-LDPC)

R ≈ 1 - m_b/n_b = k_b/n_b [approximately, ignoring


punctured bits]

For BG1: R_max = 22/24 ≈ 8/9; For BG2: R_max = 10/12 ≈ 5/6

Guide synthesized from: Richardson & Urbanke "Modern Coding


Theory," MacKay "Information Theory, Inference, and Learning
Algorithms" (free online), Chen et al. 2005 (NMS/OMS), Hocevar
2004 (layered decoding), NPTEL lecture series by Thangaraj and
Budhiraja, 3GPP TS 38.212 v18.x, "Channel Coding Toward 6G"
(Rowshan et al., arXiv 2405.07547), and "Demystifying 5G Polar and
LDPC Codes" (arXiv 2502.11053).

You might also like