Channel Coding: Turbo & Convolutional in LTE 4G
Turbo coding for data, tail-biting convolutional coding for control, and the rate-matching / CRC machinery.
The radio channel corrupts bits β noise, fading and interference all flip them. Channel coding is how LTE fights back: before anything reaches the air, the transmitter adds carefully structured redundancy so the receiver can detect and repair errors without asking for a resend. This page walks the whole transport-block chain grounded in TS 36.212 (multiplexing and channel coding), and contrasts LTE's turbo/convolutional world with the LDPC/Polar codes NR chose later.
Introduction
Channel coding is the forward-error-correction (FEC) layer that sits between the MAC's transport blocks and the modulated symbols that leave the antenna. Its job is to add structured redundancy so the receiver can reconstruct the original bits even when the channel has flipped some of them — and to do so without waiting for a retransmission. In LTE every transport block and every control message passes through some form of channel coding on its way to the physical channel; nothing reaches the air uncoded.
It runs on essentially every transmission, in both directions, on both data and control channels — but LTE deliberately picks a different code for each kind of traffic. Large, variable, HARQ-retransmitted user data gets a turbo code; short, latency-critical control gets a convolutional code; tiny fixed indicators get simple block codes. The choice reflects a basic truth: the code that is best for a 6000-bit data block is not the code that is best for a 2-bit control field.
It matters because coding is the difference between a link that works at the cell edge and one that does not. A stronger code lets the network run higher-order modulation at a given error rate, squeeze more throughput from the same spectrum, and — through HARQ — recover a failed block by combining retransmissions rather than starting over. Understanding the coding chain is understanding where the network's reliability and its peak rates actually come from.
On this page
Why channel coding is needed
In plain words: think of sending a parcel through a rough postal system that sometimes dents or loses pieces. If you pack only the exact item, one bit of damage ruins it. Instead you pack it with padding and a checklist so that even if a corner is crushed, the recipient can tell what was inside and rebuild it from the intact parts — without mailing it back and forth. Channel coding is that padding-and-checklist for bits: it adds just enough redundancy that the receiver repairs the damage on the spot.
Concretely, the radio channel flips bits for three reasons — thermal noise, multipath fading that momentarily nulls the signal, and interference from other transmitters. Without coding, the only remedy is retransmission, which costs latency and throughput and still fails if the channel is persistently bad. Forward error correction breaks that dependency: by sending parity alongside the data, the receiver corrects errors in place. That does two things at once. It keeps latency low, because most blocks decode on the first try; and it raises spectral efficiency, because a link that can correct errors can safely carry a heavier modulation and coding rate than a link that cannot. When correction alone is not enough, coding still pays off — its CRC detects the failure and its rate-matching machinery feeds HARQ, so a retransmission adds fresh parity rather than a wasteful identical copy.
What Channel Coding Is
Channel coding is forward error correction (FEC): you send extra parity bits alongside your data so the receiver can reconstruct the original even when some bits arrive wrong β without the latency of a retransmission. LTE picks its FEC scheme per channel, according to how much data the channel carries and how reliably it must decode.
A mapping from information bits to a longer coded sequence. LTE data channels use a rate 1/3 turbo code; most control channels use a rate 1/3 tail-biting convolutional code; a few tiny control payloads use dedicated block codes.
The channel introduces errors. Redundancy lets the receiver correct them in place, so you keep throughput up and avoid retransmission latency. A stronger code also lets you push higher-order modulation at a given error rate.
The transport block is wrapped in a CRC, split into code blocks, each turbo-encoded into three streams, and rate matching selects exactly the number of coded bits that fit the resource allocation.
LTE predates NR's codes. NR later replaced turbo with LDPC for data and Polar for control, because those scale better to very high throughput and very short messages respectively. LTE was standardised before those matured, so it uses turbo, convolutional and block coding throughout β the subject of this whole page.
Two Code Families, Two Jobs
LTE splits its channels by traffic type, and each type gets the code that suits it. The rule of thumb: big variable payloads that need HARQ get turbo; small latency-critical control gets convolutional; and a handful of very small fixed payloads get block codes.
Data channels β the shared transport channels DL-SCH and UL-SCH, the paging channel PCH, and the multicast channel MCH β carry large, variable-size transport blocks. They use the rate 1/3 turbo code, which performs excellently on long blocks and, crucially, supports incremental-redundancy HARQ.
Control channels carry small, fixed-ish messages that must decode reliably at very low SNR with minimal latency. The broadcast channel PBCH (carrying the MIB), the downlink control channel PDCCH (carrying DCI), and the control format indicator on PCFICH use a rate 1/3 tail-biting convolutional code of constraint length 7. Turbo coding's iterative decoder and its per-block overhead do not pay off on such short payloads, so the simpler convolutional code wins.
The smallest payloads use fixed block codes. The HARQ indicator on PHICH is a single ACK/NACK bit spread by a repetition/orthogonal code, and small uplink control payloads on PUCCH use short block codes β a (20, A) ReedβMuller code for up to 11 bits, extended to a dual-RM (32, O) construction for larger UCI. These are the extreme short-block end of the spectrum, where even a convolutional decoder is overkill.
| Property | Turbo code | Tail-biting convolutional code |
|---|---|---|
| Base rate | 1/3 | 1/3 |
| Structure | Parallel-concatenated, two 8-state constituent encoders + QPP interleaver | Single constraint-length-7 (64-state) encoder, 3 generator polynomials |
| Carries | DL-SCH, UL-SCH, PCH, MCH | PBCH, PDCCH, PCFICH |
| Block size | Long & variable (40β6144 per code block) | Short & small |
| Decoder | Iterative (soft-in soft-out, ping-pong) | Viterbi / wrap-around Viterbi |
| HARQ IR support | Yes β circular buffer + RVs | No (control is not HARQ-combined) |
| Tail overhead | 3 tail bits per constituent encoder (trellis termination) | None β start state = end state (tail-biting) |
Why "tail-biting"? An ordinary convolutional encoder needs extra "tail" bits to flush its shift register to a known zero state, which is wasteful on short messages. Tail-biting initialises the register with the last bits of the message instead, so no tail overhead is added and the start and end states match β the trellis "bites its own tail".
The 1/3 Turbo Code
The turbo code is the workhorse for user data. "Rate 1/3" means for every 1 information bit it produces roughly 3 coded bits β one systematic (the original bit) plus two parity streams.
Structurally it is a parallel-concatenated convolutional code: two identical 8-state constituent convolutional encoders run in parallel. The first encodes the bits in their natural order; the second encodes the same bits after they pass through a QPP interleaver (Quadratic Permutation Polynomial), which scrambles their order. The output is therefore three streams: the systematic bits, parity from encoder 1, and parity from encoder 2. After the block, three tail bits per encoder terminate each trellis.
Why the interleaver matters: the two encoders see the same data in different orders, so a bit pattern that is "weak" (produces low-weight parity) for one encoder is almost always "strong" for the other. At the receiver an iterative decoder passes soft probability estimates (extrinsic information) back and forth between the two halves, converging on the right answer β this ping-pong is what gives turbo codes their near-Shannon-limit performance.
The QPP interleaver is defined for a fixed set of block sizes K, from 40 up to 6144 bits, in 188 discrete steps (small increments at the low end, coarser steps higher up). Its quadratic form Π(i) = (f₁·i + f₂·i²) mod K makes it "maximum contention-free", which lets a hardware decoder split the block across parallel processing units without memory-access collisions. That 6144-bit maximum is exactly why long transport blocks must be segmented first β no single turbo-coded block may exceed it.
Convolutional and Block Codes for Control
Control channels use the tail-biting convolutional code (TBCC). It is a single rate-1/3 encoder with constraint length 7 β a 6-stage shift register, so 64 trellis states β and three generator polynomials (octal 133, 171, 165) producing three output bits per input bit. Because it is tail-biting, the register is preloaded with the last 6 message bits, so decoding uses a wrap-around Viterbi algorithm that assumes the start and end states are equal.
This code sits behind the channels a UE needs before it has any dedicated configuration. PBCH carries the 24-bit MIB, its own 16-bit CRC, and is convolutionally coded then heavily rate-matched and repeated across a 40 ms window for very low-SNR reception. PDCCH carries each DCI (with a 16-bit CRC scrambled by the target RNTI) through the same TBCC, then rate-matches to the aggregation level's CCE budget. PCFICH is the one exception among the "control-family" channels: its 2-bit CFI value is expanded by a fixed 32-bit block code rather than the convolutional encoder.
At the very short end, dedicated block codes handle single-purpose payloads. PHICH repeats one HARQ ACK/NACK bit with orthogonal spreading for robustness, and PUCCH uses ReedβMuller block codes β a (20, A) code for up to 11 information bits, and a dual-RM (32, O) construction for larger uplink control information formats.
The through-line: block length shrinks as reliability-per-bit demand rises. Long data → turbo; short control → convolutional; tiny fixed indicators → block codes. Everything from here on follows the turbo/data path, which is where the interesting transport-block machinery lives.
The Transport-Block Processing Chain
Coding is one stage in a fixed pipeline that TS 36.212 applies to every transport block. Follow one block from the MAC layer down to the coded bits handed to the physical channel.
Stage by stage: a 24-bit CRC (polynomial gCRC24A) is appended to the whole transport block of size A, giving B = A + 24, so the receiver can tell β after decoding β whether the block is error-free (this drives the HARQ ACK/NACK). Code block segmentation then splits any block longer than 6144 bits into turbo-sized pieces, adding a separate 24-bit CRC (polynomial gCRC24B) to each code block so individual pieces can be verified during early-termination decoding. Each code block is turbo-encoded into its three streams, rate matched to fit the resource allocation, and the pieces are concatenated back into one bit stream that is finally scrambled and passed to modulation.
Code Block Segmentation β the Maths
Segmentation is the step most worth understanding precisely, because it is pure arithmetic and it appears constantly in interviews. The goal: take the CRC-attached block of B bits and cut it into C code blocks whose sizes are all valid QPP interleaver sizes (from the 188-entry table) and are as equal as possible, adding a 24-bit CRC per block and padding with filler bits.
Let Z = 6144 be the maximum code block size and L = 24 the per-code-block CRC length.
If B > Z: C = ⌈ B / (Z − L) ⌉ and B′ = B + C · L
So the number of code blocks C is the ceiling of B divided by the usable payload per block (6144 β 24 = 6120), and B′ is the total bit count once every block's own CRC is included. Now the sizes are chosen so that C blocks cover B′ bits using at most two adjacent valid sizes:
K₋ = largest valid interleaver size with K₋ < K₊ (the next size down)
ΔK = K₊ − K₋
C₋ = ⌊ (C · K₊ − B′) / ΔK ⌋ (number of blocks at size K₋)
C₊ = C − C₋ (number of blocks at size K₊)
F = C₊ · K₊ + C₋ · K₋ − B′ (number of filler bits)
The filler bits F are prepended to the very first code block (they are encoded as known zeros, so they cost nothing to decode). The procedure guarantees C₊ · K₊ + C₋ · K₋ = B′ + F, i.e. every bit lands in exactly one code block.
Worked example. Take a transport block of A = 12000 bits.
- TB CRC:
B = 12000 + 24 = 12024. Since 12024 > 6144, we segment. C = ⌈12024 / 6120⌉ = ⌈1.964⌉ = 2code blocks.B′ = 12024 + 2 · 24 = 12072bits to distribute.- Need
K₊ ≥ 12072 / 2 = 6036. The smallest valid size ≥ 6036 isK₊ = 6048; the next size down isK₋ = 6016, soΔK = 32. C₋ = ⌊(2 · 6048 − 12072) / 32⌋ = ⌊24 / 32⌋ = 0, henceC₊ = 2.F = 2 · 6048 + 0 − 12072 = 24filler bits, prepended to code block 0.
Result: two equal 6048-bit code blocks, 24 filler bits in the first, each carrying its own 24-bit CRC β all fed to the turbo encoder.
| Symbol | Meaning | Value in example |
|---|---|---|
A | Transport block size (from MAC) | 12000 |
B | After 24-bit TB CRC (gCRC24A) | 12024 |
Z | Max code block size | 6144 |
C | Number of code blocks | 2 |
B′ | Total bits incl. per-CB CRC | 12072 |
K₊ / K₋ | Larger / smaller valid CB size | 6048 / 6016 |
C₊ / C₋ | Count at each size | 2 / 0 |
F | Filler bits (in first CB) | 24 |
Rate Matching, Redundancy Versions and HARQ
The turbo encoder always produces three streams β but the number of coded bits you can actually send is fixed by the resource allocation and MCS, and that number is almost never exactly three times the input. Rate matching reconciles the two: it selects precisely the right count of coded bits, puncturing (dropping) some or repeating others as needed.
It works in two steps. First, each of the three streams is passed through a sub-block interleaver (a 32-column row/column permutation), which spreads burst errors and orders the bits for graceful puncturing. Second, the interleaved systematic and two parity streams are written into a circular buffer: the systematic bits first, then the two parity streams interlaced. To produce the transmitted bits, the encoder starts reading at a defined position and wraps around the buffer until it has enough.
That starting position is set by the redundancy version (RV), and LTE defines four of them, RV0βRV3, each pointing at a different offset in the circular buffer.
RV = where to start reading the circular buffer. RV0 starts at the systematic bits (self-decodable, best for a first transmission); RV1βRV3 start at later offsets, so each retransmission carries mostly different coded bits rather than an identical copy.
| Redundancy version | Buffer start (concept) | Content emphasis | Typical use |
|---|---|---|---|
RV0 | Beginning (systematic) | Systematic + early parity | 1st transmission (self-decodable) |
RV1 | ~1/4 into buffer | Mostly parity | Later retransmission |
RV2 | ~1/2 into buffer | Fresh parity | 2nd transmission |
RV3 | ~3/4 into buffer | Fresh parity + wrap | 3rd transmission |
This is the engine of HARQ with Incremental Redundancy. When a transport block fails (its TB CRC does not check out), the UE stores the received soft bits instead of discarding them. The retransmission uses a different RV, delivering fresh parity from the circular buffer. The receiver soft-combines the new bits with the stored ones, so the effective code rate drops with every retransmission and the block becomes progressively easier to decode. The RV to use is signalled in the scheduling DCI, and the typical transmission order is RV0, RV2, RV3, RV1 β chosen so early retransmissions add the most new information.
Chase vs Incremental Redundancy: if every retransmission reused RV0 you would get Chase combining (identical copies averaged together). Cycling through different RVs gives Incremental Redundancy β new parity each time β which is stronger, and it is exactly what LTE's circular-buffer rate matching enables.
Finally, after rate matching, code block concatenation simply appends the rate-matched bits of code block 0, then block 1, and so on, into one continuous stream for the physical channel β the exact inverse of segmentation, with no extra bits added.
⚠ Common pitfalls / gotchas
- Confusing the two CRCs.
gCRC24Ais the whole-transport-block CRC that drives HARQ ACK/NACK;gCRC24Bis a per-code-block CRC used only for early-termination decoding. A single-code-block transport block (B ≤ 6144) carries only gCRC24A — no per-CB CRC is added. - Assuming rate 1/3 is the transmitted rate. 1/3 is the mother-code rate; rate matching punctures the circular buffer so a good link runs at an effective rate well above 1/3. The MCS, not the code, sets what is actually sent.
- Reusing RV0 on every retransmission. That gives only Chase combining. Cycling RV0→RV2→RV3→RV1 is what turns HARQ into Incremental Redundancy; the RV is carried in the scheduling
DCIand must be varied. - Forgetting filler bits are known zeros. The
Ffiller bits prepended to code block 0 are not payload — the decoder treats them as known, so mis-accounting for them corrupts the code-block bit budget.
Channel Map and the Contrast with NR
Put the whole scheme in one view β the code and base rate for each transport/physical channel:
| Channel | Carries | Code | Base rate |
|---|---|---|---|
DL-SCH (on PDSCH) | Downlink user data | Turbo (parallel concatenated) | 1/3 |
UL-SCH (on PUSCH) | Uplink user data | Turbo | 1/3 |
PCH | Paging | Turbo | 1/3 |
MCH | Multicast/broadcast (MBMS) | Turbo | 1/3 |
PBCH | Master Information Block | Tail-biting convolutional | 1/3 |
PDCCH / DCI | Control (assignments/grants) | Tail-biting convolutional | 1/3 |
PCFICH | Control format indicator (CFI) | Block code (32-bit) | β |
PHICH | HARQ ACK/NACK | Repetition / orthogonal | β |
PUCCH control | Uplink control info | ReedβMuller block code (20,A)/(32,O) | β |
The base rate 1/3 is only a starting point. Rate matching then adjusts the actual transmitted rate up or down to fit the allocation, which is how a high-MCS, well-conditioned link can run at an effective code rate well above 1/3 (heavy puncturing), while a cell-edge link stays near or below it.
What NR changed. 5G NR kept the same conceptual chain β CRC, segmentation, encode, rate match, concatenate β but swapped the codes. Data channels (DL-SCH/UL-SCH) now use LDPC with two base graphs (BG1 for larger blocks/higher rates, BG2 for smaller blocks/lower rates), because LDPC decoders parallelise to multi-gigabit throughput far better than iterative turbo decoders, and their rate matching uses a limited-buffer circular buffer with the same RV idea. Control (PDCCH/PBCH) uses Polar coding, which excels at the short block lengths of control signalling and replaces LTE's convolutional/ReedβMuller mix. Segmentation also changes: NR's max LDPC code block is 8448 bits (BG1) or 3840 bits (BG2), not 6144. The mental model you built here transfers directly; only the encoder boxes are different.
LTE ↔ NR: the coding pipeline is preserved (CRC → segmentation → encode → rate match → concatenate) but the codes and their sizes change. LTE turbo (max CB 6144, one mother rate 1/3, QPP interleaver) becomes NR LDPC (base graphs BG1/BG2, max CB 8448/3840, native rates as low as ~1/5 for BG2), and LTE's convolutional/ReedβMuller control coding becomes NR Polar (with CRC-aided list decoding) for PDCCH/PBCH — while tiny NR UCI (up to 11 bits) still uses a small block code, echoing LTE's Reed–Muller path. HARQ Incremental Redundancy with multiple RVs survives essentially unchanged, so the retransmission intuition carries straight over.
One-line contrast: LTE = turbo (data) + convolutional/block (control); NR = LDPC (data) + Polar (control). Same pipeline, better-scaling codes.
Summary
Channel coding in LTE is one fixed pipeline (TS 36.212) with the encoder chosen per traffic type: attach a 24-bit gCRC24A to the transport block, segment anything over 6144 bits into equal QPP-valid code blocks (each with its own gCRC24B), turbo-encode each into a systematic plus two parity streams, rate-match through a sub-block interleaver and circular buffer to the exact allocation, then concatenate and hand off to scrambling and modulation. The two numbers most worth carrying away are the 6144-bit turbo/QPP maximum that forces segmentation, and the rate-1/3 mother code that rate matching then punctures or repeats to whatever the MCS demands.
The redundancy versions RV0–RV3 are the hinge between coding and HARQ: each is a different start offset in the circular buffer, so cycling them delivers Incremental Redundancy — fresh parity that soft-combines with stored soft bits to lower the effective rate on every retransmission. Control and tiny payloads take the cheaper paths (tail-biting convolutional for PBCH/PDCCH/PCFICH, Reed–Muller and repetition block codes for PUCCH/PHICH) because turbo's machinery does not pay off on short blocks. NR keeps this exact pipeline but swaps the encoders for LDPC (data) and Polar (control), so everything you have internalised here transfers with only the code boxes changed.
Q. Why does LTE segment a transport block before turbo coding?
A. The QPP interleaver inside the turbo encoder is only defined up to 6144 bits. Any block longer than that (after the TB CRC) is split into equal-size code blocks that each fit the interleaver, and each code block gets its own 24-bit CRC (gCRC24B) on top of the whole-block CRC (gCRC24A).
Q. How do you compute the number of code blocks and their sizes?
A. C = ⌈B / (6144 − 24)⌉ and B′ = B + 24C. Then K₊ is the smallest valid interleaver size with C·K₊ ≥ B′, K₋ the next size down; C₋ = ⌊(C·K₊ − B′)/ΔK⌋, C₊ = C − C₋, and filler F = C₊K₊ + C₋K₋ − B′, placed in the first code block.
Q. What is a redundancy version and how does it enable HARQ?
A. The RV is the starting read position in the rate-matching circular buffer. Different RVs (RV0βRV3) output mostly different coded bits, so a retransmission carries new parity. The receiver soft-combines it with the stored failed copy (Incremental Redundancy), lowering the effective code rate until the block decodes.
Q. Why do control channels use convolutional coding instead of turbo?
A. Control messages (PBCH, PDCCH/DCI) are short. Turbo's iterative decoder and per-block overhead give little benefit on tiny payloads, whereas a constraint-length-7 tail-biting convolutional code decodes with low latency and adds no tail-bit overhead β a better fit for short, latency-critical control.
Q. What is tail-biting and why does LTE use it for control?
A. Tail-biting preloads the encoder's shift register with the last bits of the message so the start and end states are equal, avoiding the flush/tail bits an ordinary convolutional code needs. On short control blocks those tail bits would be a large fractional overhead, so tail-biting saves them.
Q. How does LTE's coding chain differ from NR's?
A. The pipeline (CRC → segmentation → encode → rate match → concatenate) is the same, but NR replaces turbo with LDPC for data (base graphs BG1/BG2, max CB 8448/3840) and convolutional with Polar for control, both of which scale better to very high throughput and very short messages.
Where channel coding connects
Coding sits between the transport block from MAC and the modulated symbols on the air β its CRC drives retransmissions, its code rate is set by the MCS, and its output feeds the shared data channel.