♪ NOW PLAYING 0 Old Flame Like A Dream | *** thanks for stopping by my corner of the web *** best viewed at 800x600 *** sign my guestbook *** The Turbo Shock of 1993Channel Coding When we left Gallager’s sparse graphs, his iterative decoder had gone to sleep in a 1963 monograph, and the field had settled into a comfortable pessimism. By the early 1990s the working belief was that the last two decibels separating practical codes from Shannon’s promise could only be bought with exponentially growing complexity: longer constraint lengths, bigger trellises, decoders that doubled in cost for every fraction of a decibel gained. Then, at the ICC conference in Geneva in May 1993, three researchers from a French telecommunications school presented a seven-page paper claiming to reach within half a decibel of the Shannon limit using two small convolutional codes and a scrambler. The claim was so far ahead of everything else that several reviewers assumed it was a measurement error. It was not. This page walks through what Berrou, Glavieux and Thitimajshima actually built: the encoder, the full decoder derivation, and the worked example that reveals which inputs a turbo code actually has to fear. Background and MotivationTo feel the shock, you need the 1992 baseline. The workhorse of deep-space and satellite communication was the convolutional code decoded by the Viterbi algorithm, whose complexity grows as in the constraint length ; practical decoders topped out around . The most powerful deployed system, the CCSDS standard, concatenated a Reed-Solomon outer code with a convolutional inner code and still sat roughly 2 to 3 dB from capacity. Everyone knew Shannon’s theorem promised more, and the opener explained why his proof gave no construction: random codes achieve capacity but cannot be decoded. The consensus was that this gap was structural. Berrou’s paper reported a bit error rate of at dB for a rate-1/2 code. The Shannon limit for rate-1/2 binary signalling sits near 0.2 dB, so the gap to capacity was about half a decibel, an order of magnitude closer than anything in deployment. And the decoder was not exponential in anything: it was two small trellis decoders taking turns. The paper opens with a structural observation that motivates the whole construction. Compare a non-systematic convolutional (NSC) code with a systematic code of the same memory. At high SNR the NSC code wins: its free distance is better. At low SNR the ordering generally reverses, because a systematic code transmits the information bits in the clear and the decoder gets to observe them directly. Berrou’s insight is that a recursive systematic convolutional (RSC) code captures both virtues at once. It is systematic, so every information bit has a direct channel observation, which an iterative decoder turns out to need. And it has the same distance spectrum as its parent NSC code, because the two encoders generate exactly the same set of codewords; only the mapping from inputs to codewords differs. That last sentence sounds like a technicality. Hold onto it, because by the end of this page it will look like the most consequential fact in the paper, and the next page will prove it is. The Encoder: Parallel Concatenation via an InterleaverShannon showed that long random codes are good; the whole problem is decoding them. Berrou’s construction sidesteps the problem rather than solving it. Take two simple rate-1/2 RSC encoders. Feed the information bits to the first one directly, and to the second one after scrambling them with a long pseudo-random interleaver . Transmit the information bits once, plus the parity from both encoders: One systematic stream plus two parity streams makes the concatenation naturally rate 1/3. Berrou punctures the two parity streams alternately (transmit on even , on odd ) to reach rate 1/2 overall; in his accounting each constituent code then operates at rate 2/3. Notice what is not transmitted: the second encoder’s systematic output. It would be a permutation of bits already sent, zero new information and pure rate loss, so it is simply discarded. The interleaver is the heart of the scheme, and there are two ways to see why, both worth holding in your head at once. The first view is randomness: the overall code has block length where is the interleaver length, and Berrou used . A code that long, built randomly, would approach capacity by Shannon’s own argument. The interleaver is the injected randomness, and, crucially, it costs the decoder nothing, because the decoder never confronts the long code as a whole. It only ever decodes the two small constituent codes on their own trellises. The second view is decorrelation: if some input pattern happens to produce low-weight parity out of encoder 1, the interleaver makes it overwhelmingly likely that the permuted pattern produces high-weight parity out of encoder 2. Inputs that are bad for one encoder are good for the other. The worked example at the end of this page shows exactly which patterns can defeat this protection, and Gallager would have recognized the spirit immediately: build global structure from local pieces, and let randomness do the heavy lifting. The constituent encoder deserves a closer look, because “recursive” is doing more work than it appears to. Start from an NSC code with generator polynomials . Convert it to RSC form by feeding the output of one generator back into the input and making the information bit itself the first output:
The shift register now stores the fed-back sequence , not the raw input . That is the entire difference between the recursive and nonrecursive encoders, and it changes everything. Berrou’s code has (memory 4), feedback generator and feedforward generator , giving the transfer function
Look at that second entry: the feedback polynomial sits in the denominator, so the parity response to a single input 1 is a division of polynomials, and the impulse response is infinite. A nonrecursive encoder forgets a lone input bit after steps; a recursive encoder never does. File that fact away. The worked example below turns it into the property that makes the whole construction stand up. The BCJR Decoding AlgorithmThe Viterbi algorithm finds the single most likely sequence through the trellis and outputs hard bits. That is exactly the wrong tool here, because an iterative decoder needs, for each individual bit, a soft measure of reliability that it can hand to its partner. What we need is the symbol-by-symbol maximum a posteriori (MAP) decoder: for each bit , compute the posterior probability given the entire received block. The algorithm that does this on a trellis is the BCJR algorithm of Bahl, Cocke, Jelinek and Raviv, published in 1974 and largely ignored for two decades because it was more expensive than Viterbi for no gain in hard-decision performance. Berrou calls it “the modified Bahl et al. algorithm”; his contribution is adapting it to RSC codes and, crucially, extracting from its output the piece that is safe to pass between decoders. One convention note before the formulas, because it bites everyone who reads the original paper: Berrou defines his log-likelihood ratio as , with the 1-hypothesis on top. These notes use the opposite convention, 0 on top, which flips every sign. Always check the convention before comparing formulas across papers. BCJR runs on the trellis of one constituent code and is built from four quantities:
Rather than quote these, let us derive them; the derivation is short and every step of the iterative decoder falls out of it. Start from the joint quantity that a trellis makes natural. For a transition at time , define : the probability of that particular transition together with the entire received block. Because the information bit is determined by which transition was taken, summing over all transitions carrying gives , and the posterior LLR is
Now split the observations into past, present and future, , and factorize:
This factorization is exact, and it is exactly where the trellis structure earns its keep. Two conditional-independence facts justify it: given the state , the present transition is independent of the past observations, so the middle factor needs no further conditioning; and given , the future observations are independent of everything earlier, so the last factor is a clean conditional. The state is a sufficient summary of history. This is the Markov property doing for the trellis what the cycle-free assumption did for Gallager’s graphs. The recursions now write themselves. Expanding by conditioning on the previous state gives the forward sweep , initialized by the known starting state: , otherwise. Symmetrically, the backward sweep is . Its initialization depends on termination: if the trellis is driven back to the zero state at the end of the block, and zero elsewhere; if it is not terminated (a common situation for the second constituent encoder, for reasons the worked example makes clear), you must admit ignorance and set uniform over all states, a small but genuine loss. What remains is the branch metric, and here is where the physics of the channel enters. Factor into an a priori part and a channel part: . For a rate-1/2 systematic code over the binary-input AWGN channel, write the received pair as , the transmitted BPSK pair as with , amplitude and noise variance . The Gaussian density contributes . Expand the squares: the terms and the terms are identical for every hypothesis, so they cancel in the ratio and can be dropped, leaving only the cross terms:
The constant is the channel reliability: how much one channel observation is worth, in LLR units. Finally express the a priori factor through the incoming LLR . Since and the systematic symbol is , a line of algebra gives (the omitted prefactor is common to both hypotheses and cancels). Collecting everything:
Read the two exponents. The first depends on the transition only through the bit it carries; it is identical for every branch with the same information bit. The second depends on the parity symbol, which genuinely varies from branch to branch. That structural split is about to become the single most important formula on this page. The Extrinsic-Information DecompositionBecause the first exponential in the boxed branch metric is the same for every transition with the same , we can peel it off. Define the parity-only branch metric , so that . Substitute into the LLR. In the numerator, every term has and hence ; in the denominator, . The common factor pulls straight out of each sum:
and the logarithm splits it into three additive pieces:
where is built from the parity-only metrics. This is not an assertion; we have just proved it. And notice what does not contain: no , and no . It is what the decoder learned about bit from the parity constraints binding it to the other bits, which is to say, genuinely new information the other decoder does not already have. Berrou calls it the extrinsic information, and in practice you extract it by subtraction: . Why does this matter so much? Suppose you skipped the subtraction and passed the full posterior from decoder 1 to decoder 2 (this is, incidentally, the classic turbo implementation bug). Decoder 2 would receive back its own prior opinion , dressed up as fresh evidence. It would reinforce that opinion, pass the reinforced version back, and the loop would converge, confidently, to whatever it happened to believe first. The system becomes a rumor mill: two decoders congratulating each other on agreeing, with the agreement anchored to nothing. The observable symptom is distinctive: the BER improves for two or three iterations and then gets worse. The extrinsic rule is the only thing preventing this positive feedback, and if the idea feels familiar, it should: it is precisely the discipline built into Gallager’s 1963 update rule, where a message sent along an edge deliberately excludes the information that arrived along that same edge. Berrou reinvented the principle, apparently unaware of the precedent, thirty years later. One honest caveat. The independence of from is exact only at time directly; the metrics and were themselves computed by recursions that touched bit ‘s prior through other paths. On a cycle-free graph the independence would be perfect; on a turbo code’s graph (which has cycles, closed through the interleaver) a residual correlation survives. This is why iterative turbo decoding is not exactly maximum-likelihood, and it is why the damping fix described below earns its keep. Berrou devotes a full section of the paper to the statistics of the extrinsic values, and his Figure 6 records an observation that looks minor and turns out to be prophetic: the histogram of the extrinsic quantity starts out visibly non-Gaussian at the first iteration and converges toward a clean Gaussian with mean as the iterations proceed. Six years later that empirical remark became the foundation of EXIT-chart analysis, a story for a later page. Log-Domain Implementation and the Max-Log-MAP ApproximationAs written, the recursions multiply probabilities across a block of symbols, which underflows any floating-point format long before the end of the sweep. The fix is the same one every probabilistic algorithm eventually adopts: work with logarithms. Let , , . Products become sums, but sums become log-sums-of-exponentials:
where the two-argument operator is
The identity takes one line to prove: factor out of the sum and what remains inside the logarithm is . The operator is associative and commutative, so longer sums fold pairwise. The practical miracle is that the correction term is a one-dimensional function of the gap : in hardware it is an eight-entry lookup table, which is the entire reason exact log-MAP decoding is affordable. Even in the log domain the metrics need per-step normalization (subtract from every state); since is a difference, any constant common to all states cancels exactly. The output LLR becomes a difference of two trees, one over the branches and one over the branches. One more property is worth noting because it will matter when this series reaches the 5G throughput wars: cannot start until the whole block has arrived, so BCJR is inherently non-causal and serial in a way Viterbi is not. Max-Log-MAP is the simplification everyone actually ships: drop the correction term, so becomes plain . This is equivalent to keeping only the single best path through each half of the trellis, a kind of soft Viterbi. It costs roughly 0.3 to 0.5 dB, and it has a systematic bias: by ignoring all but the best path, it overestimates the reliability of its own conclusions. The standard remedy is to scale the extrinsic output by a factor of about 0.7 before passing it on. If you have read the LDPC entry, this should ring a loud bell: the min-sum approximation to Gallager’s check-node rule has exactly the same failure (keeping only the dominant term overstates confidence) and exactly the same fix (scale the message down by a constant near 0.75). This is not a coincidence and it is worth stating as a series thread: max-only approximations to soft-sum computations are systematically overconfident, and a single scalar damping factor recovers most of the loss. We will meet the phenomenon again. Iterative Decoding and Extrinsic ScalingThe pieces now assemble into the machine. Each constituent decoder is a soft-in soft-out MAP module: it consumes the channel observations of its own parity stream, the systematic observations, and an a priori LLR per bit supplied by the other decoder, and it produces an extrinsic LLR per bit. One iteration is one pass through DEC 1 followed by DEC 2. Decoder 1’s extrinsic output, interleaved, becomes decoder 2’s a priori input; decoder 2’s extrinsic output, de-interleaved, comes back as decoder 1’s prior for the next round. The loop starts with (no prior knowledge), and after the final iteration you hard-decide each bit from decoder 2’s full posterior , de-interleaved. Berrou ran up to 18 iterations; his Figure 5 shows the characteristic diminishing returns, with most of the gain arriving by iteration 6 to 8 and the curves nearly superimposed past 12. That saturation is worth internalizing as its own lesson: more iterations do not always help, and without further precautions they can actively hurt. A fixed iteration count, a CRC-based early stop, or a cross-entropy convergence test are the standard termination rules. Simulating a rate-1/3 turbo code with a 1024-bit interleaver and exact log-MAP decoding reproduces that behavior directly: ![]() Two features of that picture are worth naming, because both recur throughout this series. The first is the diminishing returns already described: the early iterations buy whole decibels, the later ones buy almost nothing, so a sensible decoder stops early rather than running a fixed large count. The second is the flattening at the bottom right, where every curve converges onto the same floor regardless of iteration count. That floor is not a simulation artifact and no amount of extra iterating will remove it, because it is a property of the code rather than the decoder. Explaining exactly where it comes from is the business of the next entry. The “further precautions” phrase is not idle. Berrou observed in his experiments that the BER could increase from one iteration to the next: the residual correlation we flagged above lets overconfident extrinsic values feed on themselves. His remedy is a soft saturation applied to the extrinsic quantity before it is passed on:
Small values pass almost untouched; large values are compressed toward a ceiling. Modern implementations achieve the same effect by multiplying by a constant near 0.7, or by clipping at a maximum. Recognize this as the same medicine prescribed in the previous section for Max-Log-MAP, and the same medicine min-sum LDPC decoders take: wherever an iterative decoder’s messages run more confident than the evidence justifies, a scalar damping factor restores stability. Three superficially different tricks, one phenomenon. For the record, here are the parameters behind the headline result, from Berrou’s own experiment:
A Numerical Example: Input-Weight AnalysisEverything so far explains how a turbo code is decoded. This last section starts to explain why it is good, by tracing an RSC encoder’s response to the simplest possible inputs. Take the small 4-state RSC(7,5): feedback polynomial , feedforward . The state is the register pair , the recursion is , and the parity output is . First, feed it a single 1 followed by zeros: starting from state .
Watch the state column: after the impulse, the register cycles through with period 3 (which is for a primitive feedback polynomial of degree ) and never returns to . The parity stream is periodic and never stops: this is the infinite impulse response promised earlier, now visible in a table. A weight-1 input drives an RSC encoder into an error event of infinite parity weight. Two immediate consequences. First, the smallest input weight that can produce a finite-weight error event in a recursive encoder is 2; in the standard notation, , whereas a nonrecursive encoder has a finite impulse response and . Second, you cannot terminate an RSC trellis by appending zeros the way you terminate an ordinary convolutional code: zeros at the input leave the feedback loop cycling forever, and forcing the state home requires feeding the register contents back at the input (a switched tail). This is exactly why the second constituent encoder often goes unterminated, and why its recursion gets the uniform initialization mentioned in the derivation. Now feed it a weight-2 input with the two 1s separated by the cycle period:
The second 1, arriving exactly one period after the first, cancels the circulating pattern and closes the loop back to the zero state. Input weight , parity weight , constituent codeword weight 6. This is the shortest finite-weight error event the encoder has. Now assemble the consequence for the concatenated code. Build the rate-1/3 PCCC from two copies of this RSC(7,5). The dominant low-weight event comes from a weight-2 input that closes the loop in both encoders (both the original pattern and its interleaved image hitting a period-multiple spacing), and its total transmitted weight is
This quantity, the minimum total weight over weight-2 inputs, is called the effective free distance. Compare it with the constituent code’s own free distance: , achieved by the weight-3 input , which produces parity for a total of (trace it through the recursion yourself; it is a three-row table). Here is the counterintuitive design lesson hiding in that comparison: when you choose constituent codes for a turbo code, is not the figure of merit. You optimize , the distance associated specifically with weight-2 inputs, because weight-2 events turn out to be the only ones that survive the interleaver’s protection in quantity. Fifty years of coding theory had taught designers to maximize minimum distance above all else; turbo codes quietly demote it. Justifying that demotion (why weight 2 and only weight 2, and what exactly the interleaver does to the rest) requires the analysis machinery of the next page. Check YourselfBefore moving on, test the machinery. Answers are folded below.
Answers
Where This Leaves UsBerrou, Glavieux and Thitimajshima built a code of length 196,608 that no decoder ever confronts whole: two weak recursive systematic convolutional encoders, coupled through a 65,536-bit interleaver, decoded by two BCJR modules passing carefully filtered opinions back and forth. We derived the full decoder on this page: the forward-backward recursions from the Markov property of the trellis, the branch metric from the Gaussian channel, and, rather than asserting it, we proved the three-term decomposition that identifies exactly which part of a decoder’s belief is safe to share. Two ingredients carried all the weight, and neither is obvious: the constituent encoders must be recursive, and the decoders must exchange only extrinsic information, a principle that already lived, unnoticed, in Gallager’s 1963 update rule. Around the edges we collected the practical folklore: Max-Log-MAP’s overconfidence and its 0.7 scaling factor (the same disease and cure as min-sum LDPC decoding), Berrou’s damping fix, the impossibility of terminating an RSC with zeros, and the strange arithmetic of the worked example, where the code’s real vulnerability is weight-2 inputs and the design target is , not . But notice what this page has not done. It showed that the construction works, at 0.7 dB, to five nines of the field’s astonishment; it traced how every box in the decoder computes; and it gestured, through one worked example, at why recursion matters. The actual explanation is still owed. Why exactly does the interleaver reward and punish nothing else? Why does an encoder property (recursion) matter when the recursive and nonrecursive encoders generate the same code? And why does performance improve with interleaver length in the coefficient but never in the slope? Berrou’s paper contains almost no theory; it took Benedetto and Montorsi three more years to supply it. That analysis, the uniform interleaver and the interleaver-gain exponent , is the next page. ← Gallager's Sparse GraphsIndexWhy Turbo Codes Work → |