Paper
Part IErrors, Information and Channels

Case Study: Codes in the Wild

November 14, 202645 min readbeginner

Parity in early memories, Hamming's code, the Mariner and Voyager probes, the compact disc, QR codes, ECC memory and 5G radio, each code met at work with its numbers checked and pointed to the Part that teaches it.

Error-Control Strategies and Performance completed the tools for judging a code from the outside, which are its rate, its bit and word error rates at each noise level, its coding gain, and its place in a reliability budget counted in FIT. Distance, Detection and Correction supplied the guarantee underneath those numbers, that a code of minimum distance dd detects d−1d - 1 errors, corrects t=⌊(d−1)/2⌋t = \lfloor (d-1)/2 \rfloor, and handles tt errors and ee erasures together whenever 2t+e<d2t + e < d.

The codes in those chapters were kept small on purpose, and no probe has sent pictures home from Neptune with them. This chapter visits eight systems in which codes carry real traffic, from the memories of early computers to the 5G radio in a phone. Each visit names the code, checks its numbers with the tools already built, and points ahead to the Part that teaches it.

None of the visits is a full treatment. A finite field appears here as 256 symbols with some arithmetic, and a convolutional code as a shift register with two outputs, both waiting for the Parts that define them. Meeting them early shows what problem each design answers, so that the algebra, when it comes, has a job to do.

Every number in the chapter is recomputed by ch10_case_study_codes_in_the_wild.py in the python/ folder of the companion repository ecc-book-lab, and the charts are drawn by ch10_charts.py in the same folder.

Table 1 lists the systems in order, with each code's rate and the Part that teaches it.

Table 1. The systems of this chapter, their codes and rates, and where the book teaches each code

SystemCodeRateTaught in
Byte-parity memorySingle parity per byte, (9,8)(9,8)0.889Part XI
Hamming's 1950 codeHamming (7,4)(7,4)0.571Part II
Mariner 6 and 7First-order Reed–Muller (32,6)(32,6)0.1875Part II
Voyager at Uranus and NeptuneRS(255,223)(255,223) around a rate-1/21/2 convolutional code0.437Parts V, VI and VII
Compact discCross-interleaved RS(28,24)(28,24) and RS(32,28)(32,28)0.75Parts IV and V
QR code, version 1 at level MReed–Solomon (26,16)(26,16) over bytes0.615Part V
Server memoryHsiao (72,64)(72,64) SEC-DED0.889Parts II and XI
5G New RadioLDPC, polar and a (32,K)(32,K) Reed–Muller-type codeLDPC mother rates 0.333 or 0.2Parts IX, X and XII

Source: rates reproduced by ch10_case_study_codes_in_the_wild.py.

01.Parity in Early Memories

Take the byte 10110010. It holds four 1s, so an even-parity memory stores a ninth bit of 0 beside it and keeps the count of 1s in the nine bits even. If one bit flips while the byte sits in memory, the count becomes five, the check on the next read fails, and the hardware knows the byte is wrong. It does not know which bit is wrong, and if two bits flip the count is even again and the damage passes unseen.

That is the single parity code of Distance, Detection and Correction, with n=9n = 9, k=8k = 8 and d=2d = 2, so it detects one error and corrects none. Many computers of the 1950s and 1960s kept such a bit beside each character or byte of memory and checked it on every read, and a failed check usually stopped the machine [1]. A 64-bit word stored as eight bytes then occupies 72 bits, a rate of 8/9=0.8898/9 = 0.889 and a check overhead of 8/64=12.5%8/64 = 12.5\%.

How much protection that buys depends on how often bits flip. Suppose each of the nn bits of a group flips independently with probability pp, as on the binary symmetric channel of Channels, Signals and Likelihoods.

Single parity raises an alarm exactly when the count is odd, with probability 1−Peven1 - P_{\text{even}}, and is silently wrong when the count is even but not zero, with probability Peven−(1−p)nP_{\text{even}} - (1-p)^n. For small pp the alarm rate is close to npnp and the silent rate close to (n2)p2\binom{n}{2} p^2, the chance of exactly two flips. For a 9-bit group that is 9p9p against 36p236p^2. A memory word of eight such groups raises an alarm about 72p72p times per read and fails silently about 8×36p2=288p28 \times 36 p^2 = 288 p^2 times per read, and the worked example Byte Parity against SEC-DED in 72 Bits puts numbers on both.

Figure 1 shows the alternative that replaced it. The same 72 bits can hold 64 data bits and 8 check bits of a SEC-DED code, in which each check bit covers its own subset of the whole word rather than one byte. One flip is then located and corrected, and two are detected. The next section builds the idea from Hamming's original code, and Memory Codes after Hsiao returns to the 72-bit word. Part XI, ECC in Memory, Storage and Links, treats parity where it is still used, on buses, in caches and across links, wherever an alarm can simply trigger a retry.

Two ways to store a 64-bit word in 72 bits. With byte parity the word is eight 9-bit groups, each a data byte followed by its own parity bit, so a flip is seen only by the parity bit of its own byte and an odd number of flips in one byte is detected but not located. With a SEC-DED code the word is 64 data bits followed by 8 check bits, each check bit covering its own subset of all 72 bits, so one flip is located and corrected and two flips are detected. Byte parity: eight groups of 8 data bits and 1 parity bit SEC-DED: 64 data bits and 8 check bits over the whole word byte 1 byte 2 byte 3 byte 4 byte 5 byte 6 byte 7 byte 8 64 data bits 8 checks Each green parity bit sees only its own byte. An odd number of flips in a byte is detected, but no flip is located. Each check bit sees its own subset of all 72 bits. One flip is located and corrected, and two flips are detected.
Figure 1. Byte parity and a SEC-DED code spend the same 8 check bits on a 64-bit word. Parity guards each byte alone, while each SEC-DED check bit covers bits spread across the whole word, so one flip can be located and two detected.

02.Hamming's Code at Bell Labs

Richard Hamming's 1950 paper [1] starts from large computing machines, in which a single failure can stop or spoil a long computation. Parity could only stop the machine. Hamming asked for check bits that would also say where the error was, and his answer for four data bits is still the first code most students meet.

Number seven bit positions from 1 to 7. The data bits d3,d5,d6,d7d_3, d_5, d_6, d_7 go in positions 3, 5, 6 and 7, and check bits go in positions 1, 2 and 4, the powers of two. Each check bit is the XOR of the data bits whose position, written in binary, has a 1 where the check bit's position does, so p1=d3⊕d5⊕d7p_1 = d_3 \oplus d_5 \oplus d_7, p2=d3⊕d6⊕d7p_2 = d_3 \oplus d_6 \oplus d_7 and p4=d5⊕d6⊕d7p_4 = d_5 \oplus d_6 \oplus d_7.

For the data 1011, d3=1d_3 = 1, d5=0d_5 = 0, d6=1d_6 = 1 and d7=1d_7 = 1, so p1=1⊕0⊕1=0p_1 = 1 \oplus 0 \oplus 1 = 0, p2=1⊕1⊕1=1p_2 = 1 \oplus 1 \oplus 1 = 1 and p4=0⊕1⊕1=0p_4 = 0 \oplus 1 \oplus 1 = 0. The codeword, read from position 1 to position 7, is 0110011. Suppose the channel flips position 5, so 0110111 arrives. The receiver lists the positions that hold a 1, which are 2, 3, 5, 6 and 7, and XORs them in binary, 010⊕011⊕101⊕110⊕111=101010 \oplus 011 \oplus 101 \oplus 110 \oplus 111 = 101. The result, called the syndrome, is 5 in binary, and flipping position 5 back restores the codeword.

The same bookkeeping gives the minimum distance. If two words each have position-XOR 0, so does their bitwise XOR, because a position where both words hold a 1 drops out of the combined list and also cancels between the two separate XORs. The code is therefore closed under addition, so the distance between codewords cc and c′c' is the weight of the codeword c⊕c′c \oplus c', and the minimum distance is the least weight of a nonzero codeword. Listing all 16 codewords gives one of weight 0, seven of weight 3, seven of weight 4 and one of weight 7, so d=3d = 3 and the code corrects one error, as Distance, Detection and Correction promised for d=3d = 3.

Figure 2 shows what that buys. Four data bits sent bare over BSC(p)\text{BSC}(p) fail with probability 1−(1−p)41 - (1-p)^4, which is 0.0394 at p=0.01p = 0.01. The Hamming code fails only when two or more of its seven bits flip, with probability

Pw=1−(1−p)7−7p(1−p)6,P_w = 1 - (1-p)^7 - 7p(1-p)^6 ,
(2)

which is 0.00203 at p=0.01p = 0.01, 19.4 times smaller. Three-fold repetition of each data bit does slightly better, 0.00119, but spends 12 bits rather than 7, a rate of 0.333 against 0.571. Both coded curves fall with slope 2 on the logarithmic axes, because both need two flips in the wrong places to fail.

Probability that four data bits are delivered wrong over a binary symmetric channel, for p from 0.0001 to 0.1 on logarithmic axes. Sent bare the block fails with probability 0.0394 at p = 0.01. The Hamming (7,4) code, which corrects any single error in 7 bits, fails with 0.00203, and three-fold repetition, which spends 12 bits, fails with 0.00119. Both coded curves fall with slope 2, since each needs two errors in the wrong place. 1e-8 1e-6 1e-4 1e-2 1 0.0001 0.001 0.01 0.1 bit error probability p of the binary symmetric channel probability the 4 data bits arrive wrong 4 bits sent bare Hamming (7,4), 7 bits each bit sent three times, 12 bits
Figure 2. Block error probability of four data bits over a binary symmetric channel, sent bare, in Hamming's (7,4) code and with three-fold repetition. Data: computed by ch10_charts.py in the companion repository.

Why seven bits? With rr check bits the syndrome takes 2r2^r values. One value must mean no error, and each of the n=k+rn = k + r positions needs its own value so that a single error can be located, so

2r≥k+r+1.2^r \ge k + r + 1 .
(3)

Three check bits allow k+3+1≤8k + 3 + 1 \le 8, so k≤4k \le 4, and the (7,4)(7,4) code meets the bound with nothing to spare, which Part II will call a perfect code. Seven check bits protect up to 27−1−7=1202^7 - 1 - 7 = 120 data bits, while six protect only 26−1−6=572^6 - 1 - 6 = 57, so a 64-bit word needs seven. One further bit holding the parity of all the others turns every codeword of odd weight into one of even weight. The XOR of two even-weight words has even weight, so every distance is now even, and since it was at least 3 it becomes at least 4. That extended code corrects one error and detects two, and with 64+7+1=7264 + 7 + 1 = 72 bits it fits the same 72 bits as byte parity. Part II, Linear Block Codes, develops these codes and the bound in full.

03.The Mariner Reed–Muller Code

In 1969 the probes Mariner 6 and Mariner 7 flew past Mars and sent pictures home over a high-rate channel of 16,200 bits per second [2]. The data were cut into 6-bit pieces, and each piece was sent as one of 64 codewords of 32 bits.

The codewords are easiest to see as functions. Number the 32 positions x=0,1,…,31x = 0, 1, \ldots, 31 and write each position in binary as x5x4x3x2x1x_5 x_4 x_3 x_2 x_1, with x1x_1 the lowest bit. A message is six bits a0,a1,…,a5a_0, a_1, \ldots, a_5, and the codeword bit at position xx is

cx=a0⊕a1x1⊕a2x2⊕a3x3⊕a4x4⊕a5x5.c_x = a_0 \oplus a_1 x_1 \oplus a_2 x_2 \oplus a_3 x_3 \oplus a_4 x_4 \oplus a_5 x_5 .
(4)

With only a1=1a_1 = 1, the bit at xx is x1x_1, which alternates, so the codeword begins 01010101. With only a2=1a_2 = 1, it begins 00110011. Over the full 32 positions those two words differ in 16 places, and that is no accident.

The sum of two such functions is again one of them, so the code is closed under addition, and as in Hamming's Code at Bell Labs the minimum distance is the least nonzero weight, d=16d = 16. The code corrects t=7t = 7 errors in 32 bits at a rate of 6/32=0.18756/32 = 0.1875. It is the first-order Reed–Muller code of length 32, from the papers of Reed and of Muller in 1954 [3] [4], and the JPL engineers called it biorthogonal. Written with +1+1 for a 0 and −1-1 for a 1, the 32 codewords with a0=0a_0 = 0 are mutually orthogonal vectors, since two of them differ in 16 places and agree in 16, and the other 32 codewords are their negatives.

Orthogonality is what makes decoding practical. A receiver can correlate the 32 received signal values against each of the 32 orthogonal patterns, take the pattern with the largest correlation in size, and read a0a_0 from its sign.

Tausworthe, Easterling and Spear put the saving in decibels. At the system's operating error rate, uncoded transmission would have needed Eb/N0=5.20E_b/N_0 = 5.20 dB, while the coded system needed 3.00 dB. In the language of Error-Control Strategies and Performance that is a coding gain of 2.20 dB, a factor of 100.22=1.6610^{0.22} = 1.66 in transmitter power. Uncoded BPSK at 5.20 dB has bit error probability Q(2Eb/N0)=5×10−3Q\bigl(\sqrt{2E_b/N_0}\bigr) = 5 \times 10^{-3}, which locates that operating point.

Figure 3 shows the same code with hard decisions on BSC(p)\text{BSC}(p), where a decoder that corrects up to 7 errors fails only on 8 or more,

Pw=∑j=832(32j)pj(1−p)32−j.P_w = \sum_{j=8}^{32} \binom{32}{j} p^j (1-p)^{32-j} .
(5)

At p=0.05p = 0.05 that is 0.000139, against 0.2649 for the 6 bits sent bare and 0.00693 for five-fold repetition in 30 bits, which The Mariner Code against Five-Fold Repetition works out. Part II teaches Reed–Muller codes of every order with their fast Hadamard decoder, and Part VI explains why correlating soft values beats deciding each bit first.

Probability that a 6-bit word is decoded wrong over a binary symmetric channel, for p from 0.01 to 0.2 on logarithmic axes. At p = 0.05 the bare 6 bits fail with probability 0.2649, five-fold repetition in 30 bits fails with 0.00693, and the 32-bit Reed–Muller code of the Mariner probes, decoded to correct up to 7 errors, fails with 0.000139. Its curve is the steepest because 8 errors are needed to defeat it. 1e-10 1e-8 1e-6 1e-4 1e-2 1 0.01 0.02 0.05 0.1 0.2 bit error probability p of the binary symmetric channel probability a 6-bit word is wrong 6 bits sent bare each bit sent five times, 30 bits Reed–Muller (32,6), up to 7 errors fixed
Figure 3. Word error probability of 6 data bits over a binary symmetric channel, sent bare, with five-fold repetition and in the Mariner (32,6) Reed–Muller code. Data: computed by ch10_charts.py in the companion repository.

04.Voyager and Concatenated Codes

The two Voyager probes, launched in 1977, flew past Jupiter and Saturn, and Voyager 2 went on to Uranus and Neptune [5]. Received power falls with the square of distance, so each encounter was harder to hear than the last, and the coding changed along the way.

The inner code throughout was a convolutional code of constraint length 7 and rate 1/2. Each data bit enters a 7-bit shift register, and two output bits are formed as the parities of the register under two masks, 1111001 and 1011011, written in octal as 171 and 133. A single 1 entering an empty register, followed by zeros, produces the 14 output bits 11 10 11 11 00 01 11, of weight 10. No input that leaves the all-zero register state and returns to it produces a lighter output, so the code's free distance, the convolutional counterpart of minimum distance, is 10. The ground decoded it with Viterbi's algorithm [6], which works on soft decisions and, when it errs, tends to err in short bursts.

At Jupiter and Saturn an outer Golay code sat around the convolutional code [5], giving an overall rate of 1/2×1/2=0.251/2 \times 1/2 = 0.25. For Uranus and Neptune the outer code became a Reed–Solomon code [7], RS(255,223)(255,223), from an experimental encoder on board. Its symbols are bytes, treated as elements of a field of 256 elements that Part III builds. Each codeword holds 223 data bytes and 32 check bytes, a rate of 0.875 and a check overhead of 32/223=14.3%32/223 = 14.3\%. Its minimum distance is n−k+1=33n - k + 1 = 33, the most any code of that length and dimension can have, as Part V proves, so it corrects 16 wrong bytes in each codeword. A Viterbi burst a few bits long usually lands in one or two bytes, so a byte code counts it as one or two errors rather than many. The overall rate is

R=223255×12=0.437.R = \frac{223}{255} \times \frac{1}{2} = 0.437 .
(6)

Bursts longer than a byte or two are handled by interleaving. With interleaving depth II, the encoder fills II Reed–Solomon codewords and sends their bytes in rotation, one from each codeword in turn, so neighboring bytes on the channel belong to different codewords. A burst of bb consecutive bytes then contains at most ⌈b/I⌉\lceil b/I \rceil bytes of any one codeword, since that codeword's bytes sit II apart. Each codeword survives while ⌈b/I⌉≤16\lceil b/I \rceil \le 16, that is while

b≤16I.b \le 16 I .
(7)

At depth 5 a burst of 80 bytes, 640 bits, is cleared, and at depth 8 one of 128 bytes, 1,024 bits. Figure 4 draws the whole chain.

The concatenated chain that Voyager used at Uranus and Neptune and that CCSDS later standardized. Data bytes enter a Reed–Solomon (255,223) encoder, the outer code, then an interleaver of depth I, then the convolutional encoder with constraint length 7 and rate 1/2, the inner code, and cross the noisy channel. The receiver runs the Viterbi decoder on soft decisions, the deinterleaver spreads the Viterbi decoder's bursts of errors across I Reed–Solomon codewords, and the Reed–Solomon decoder corrects up to 16 wrong bytes in each. outer code, over bytes inner code, over bits Data in Reed–Solomon Interleaver Convolutional Channel Viterbi decoder Deinterleaver Reed–Solomon Data out 223 bytes a block (255,223) encoder depth I K = 7, rate 1/2 noise added soft decisions spreads bursts fixes 16 bytes 10–6or better The inner decoder leaves errors in short bursts. The deinterleaver deals each burst out across I outer codewords, a few bytes to each. Rates multiply: 223/255 × 1/2 = 0.437 data bits per channel bit.
Figure 4. The concatenated chain of Voyager at Uranus and Neptune, later standardized by CCSDS. An outer Reed–Solomon code and an inner convolutional code are separated by an interleaver, so the Viterbi decoder's bursts are spread over several Reed–Solomon codewords.

Ludwig and Taylor report what the outer code bought. A Viterbi output with a bit error rate of about 5×10−35 \times 10^{-3} left the Reed–Solomon decoder at about 10−610^{-6}. A Reed–Solomon decoder also nearly always knows when it has failed. McEliece and Swanson showed [8] that when a codeword carries more errors than the decoder can correct, the chance that it decodes to a wrong codeword rather than reporting failure is less than 1/t!1/t!, which for t=16t = 16 is 1/16!=4.78×10−141/16! = 4.78 \times 10^{-14}, and they computed it for this code as below 3×10−143 \times 10^{-14}. A link whose words fail at 10−510^{-5} therefore hands on a wrong word without a flag at a rate below 3×10−193 \times 10^{-19}.

This chain, Reed–Solomon outside, interleaver, convolutional code inside, became the CCSDS standard for deep-space telemetry [9], which allows interleaving depths up to 8 and a lighter RS(255,239)(255,239) of rate 0.937. Part VII builds the inner code, Part V the outer one, and Part VI explains why a soft inner decoder and a hard outer one pair so well.

Table 2 follows the downlink rate through Voyager 2's four encounters, from Table 6-1 of Ludwig and Taylor. The expected rates scale Jupiter's 115,200 bits per second by the drop in received power the table gives, factors of 1/4, 1/13 and 1/36, which is 28,800, 8,862 and 3,200 bits per second, rounded in the table to about 29,000 and 9,000 for the first two. The achieved rates were 1.5, 3.3 and 6.8 times the expected rates in the table. Saturn had the same code and ground antennas as Jupiter, and Ludwig and Taylor credit its gain to the set of rates available and to differences in priorities and margins, calling the comparison approximate. At Uranus and Neptune two things changed together. The Reed–Solomon code replaced the Golay code, and the ground antennas were enlarged and arrayed so that their signals could be added, so the larger factors belong to both, as Figure 5 notes. The worked example Voyager's Expected Rates checks the factors against the distances.

Table 2. Voyager 2's downlink rates at its four encounters, expected from Jupiter's rate and the fall in received power, and achieved

EncounterYearDistance (AU)Expected (bit/s)Achieved (bit/s)
Jupiter19795.2115,200115,200
Saturn19811029,00044,800
Uranus1986199,00029,900
Neptune1989303,20021,600

Source: Ludwig and Taylor, Table 6-1, with distances from their section 6.3. Ratios reproduced by ch10_case_study_codes_in_the_wild.py.

Voyager's downlink data rates at its four planetary encounters on a logarithmic axis. Jupiter set the reference of 115,200 bits per second. The inverse-square fall of received power with distance predicts the dashed curve, and the solid curve is the maximum rate achieved. Saturn used the same code and antennas as Jupiter, and its gain came from the rates available and the margins chosen. At Uranus and Neptune the Reed–Solomon code and an enlarged, arrayed ground system both contributed. In bits per second, Saturn had 29,000 expected and 44,800 achieved, Uranus had 9,000 expected and 29,900 achieved, Neptune had 3,200 expected and 21,600 achieved. 1,000 3,000 10,000 30,000 100,000 Jupiter Saturn Uranus Neptune planet at encounter downlink data rate, bits per second 44,800 29,000 29,900 9,000 21,600 3,200 115,200 expected from the drop in received power achieved by Voyager
Figure 5. Voyager's downlink rates at Jupiter, Saturn, Uranus and Neptune, as expected from the inverse-square fall in received power and as achieved. Data: Ludwig and Taylor, Table 6-1, plotted by ch10_charts.py in the companion repository.

05.The Compact Disc

Philips and Sony launched the compact disc in 1982 [10], and its error correction had to survive what listeners do to discs, fingerprints, dust and scratches. Those do not flip scattered bits. They wipe out a stretch of track, and with it every bit in a run of consecutive frames.

Stereo audio at 44,100 samples per second per channel, with 16 bits per sample, is 44,100×16×2=1,411,20044{,}100 \times 16 \times 2 = 1{,}411{,}200 bits per second, or 176,400 bytes. The disc groups six stereo samples, 24 bytes, into a frame. The error-correcting encoder adds 8 check bytes, making 32, so its rate is 24/32=0.7524/32 = 0.75. A control byte joins them, each byte becomes 14 channel bits plus 3 merging bits under the modulation called EFM, and a 24-bit synchronization pattern with its 3 merging bits starts the frame, 27+17+32×17=58827 + 17 + 32 \times 17 = 588 channel bits in all [11]. At 7,350 frames per second the disc delivers 4,321,800 channel bits per second, of which only 192/588=32.7%192/588 = 32.7\% are audio.

Figure 6 shows the encoder, called cross-interleaved Reed–Solomon coding, or CIRC. The 24 audio bytes enter the C2 encoder, RS(28,24)(28,24), which adds 4 bytes. The 28 bytes then pass through delay lines, byte ii held back by 4i4i frames, from 0 up to 108. The C1 encoder, RS(32,28)(32,28), adds 4 more bytes across each outgoing frame. Both codes have d=n−k+1=5d = n - k + 1 = 5. The two codes see the data in different arrangements, C1 across the 32 bytes of one outgoing frame, and C2 across bytes taken from 28 different frames.

The compact disc's cross-interleaved Reed–Solomon encoder. Each frame's 24 audio bytes enter the C2 encoder, RS(28,24), which adds 4 Q bytes. The 28 bytes then pass through delay lines of 0, 4, 8 and up to 108 frames, so byte i of a C2 codeword leaves 4i frames after byte 0. The C1 encoder, RS(32,28), adds 4 P bytes across each outgoing frame, and EFM and sync turn the frame into 588 channel bits. Below, the 28 bytes of one C2 codeword sit 4 frames apart along the disc, and a burst of 16 lost frames reaches only bytes 1 to 4, which C2 can fill as erasures. Audio C2 encoder Delay lines C1 encoder EFM, sync 6 stereo samples RS(28,24), Q 0 to 27 × 4 frames RS(32,28), P 588 bits 24 28 28 32 bytes per frame between the stages Where the 28 bytes of one C2 codeword land on the disc frame 0 frame 108 byte 27 a 16-frame burst The burst erases bytes 1 to 4 only, one byte in each frame it covers that holds this codeword.
Figure 6. The compact disc's CIRC encoder. Delay lines between the C2 and C1 encoders place the bytes of each C2 codeword 4 frames apart on the disc, so a burst of lost frames removes only a few bytes from any one C2 codeword.

The player runs the two codes in reverse. The C1 decoder checks each frame, corrects small damage, and when a frame looks badly hit it marks all of that frame's bytes as erasures. After the delays are undone, each C2 codeword is gathered from 28 frames spread 4 apart over 109 frames.

Distance, Detection and Correction showed that a code of distance dd fills ee erasures whenever e<de < d, so C2 fills up to 4. A burst is therefore survivable while ⌈B/4⌉≤4\lceil B/4 \rceil \le 4, that is up to B=16B = 16 frames, which is 16/7,350=2.1816/7{,}350 = 2.18 ms of music and, at the disc's track speed of 1.2 to 1.4 m/s, 2.6 to 3.0 mm of track. Figure 7 draws the staircase. The real encoder also delays alternate bytes by one frame after C1, which splits a short burst between two C1 words, and before C2 delays and reorders audio bytes by two frames, which helps the player conceal what it cannot correct [11]. This model leaves both out. Part IV treats bursts and interleavers in general, and Part V decodes errors and erasures together.

Number of bytes of one C2 codeword that a burst of lost frames removes, against the burst length from 0 to 40 frames. Because the delay lines put 4 frames between consecutive bytes of a C2 codeword, a burst of B frames removes at most ceil(B/4) bytes, a staircase. C2 fills up to 4 erasures, so the longest burst it survives is 16 frames, 4 bytes, about 2.18 milliseconds of playing time, while a 17-frame burst can remove 5. 0 2 4 6 8 10 0 8 16 24 32 40 length of the burst, in consecutive frames lost from the disc bytes lost from one C2 codeword C2 fills at most 4 erasures 16 frames, 2.18 ms
Figure 7. Bytes of one C2 codeword removed by a burst of lost frames. The staircase stays within C2's four erasures up to a burst of 16 frames. Data: computed by ch10_charts.py in the companion repository.

06.QR Codes

A QR code is a grid of dark and light squares called modules. The smallest, version 1, is 21×21=44121 \times 21 = 441 modules, and each version adds 4 to the side, so version vv is 17+4v17 + 4v modules wide, 57 for version 10 and 177 for version 40, the largest [12]. In version 1 the three finder squares in the corners with their light borders, the timing lines between them, the format information and one fixed dark module use 233 modules, leaving 208 for data, which is 26 codewords of 8 bits.

Those 26 codewords form one Reed–Solomon codeword over bytes. The maker of the symbol picks one of four error-correction levels, L, M, Q and H, which split the 26 into data and check codewords as Table 3 shows [13]. A Reed–Solomon code with n−kn - k check symbols has minimum distance n−k+1n - k + 1, as Part V proves, so by the rule 2t+e<d2t + e < d of Distance, Detection and Correction it handles tt errors and ee erasures together whenever

2t+e≤n−k.2t + e \le n - k .
(9)

Level M, for example, uses 16 data codewords and 10 check codewords, a rate of 16/26=0.61516/26 = 0.615. Ten check codewords could correct 5 wrong codewords at unknown places, or fill 10 at known places, though in version 1 the standard reserves part of that, so 1-M corrects 4.

Table 3. The four error-correction levels of a version 1 QR code, with 26 codewords in all

LevelData codewords kkCheck codewords n−kn - kCorrects ⌊(n−k)/2⌋\lfloor (n-k)/2 \rfloorShare of 26Rated by DENSO WAVEBytes of message
L197311.5%about 7%17
M1610519.2%about 15%14
Q1313623.1%about 25%11
H917830.8%about 30%7

Source: codeword counts from ISO/IEC 18004 and DENSO WAVE, the rest reproduced by ch10_case_study_codes_in_the_wild.py.

DENSO WAVE, which created the QR code, rates the four levels as restoring about 7, 15, 25 and 30 percent of codewords [14]. The bound ⌊(n−k)/2⌋\lfloor (n-k)/2 \rfloor gives 11.5, 19.2, 23.1 and 30.8 percent of 26. The ratings are approximate figures meant for every version. In its smallest symbols the standard holds a few check codewords back to guard against decoding to a wrong message, 3 at level L, 2 at M and 1 at Q and H in version 1, so version 1 corrects (7−3)/2=2(7-3)/2 = 2 codewords at level L and (10−2)/2=4(10-2)/2 = 4 at level M, which are 7.7%7.7\% and 15.4%15.4\% [13]. At level Q it corrects 6, which is 6/26=23.1%6/26 = 23.1\%, a little below the rated 25%. That reserve makes the decoder report failure rather than guess wrong.

Larger versions split their codewords into several Reed–Solomon blocks and interleave the blocks' bytes across the symbol, so a smudge in one corner is shared among blocks rather than concentrated in one, the same defense as the compact disc's delay lines. The room left for a message follows from the data codewords. In byte mode a 4-bit mode indicator and an 8-bit character count come first, so version 1 at level M carries ⌊(128−12)/8⌋=14\lfloor (128 - 12)/8 \rfloor = 14 bytes. Part V builds these codes and their decoders, and Part III, Finite Fields and Their Arithmetic, the byte arithmetic under them.

07.Memory Codes after Hsiao

A SEC-DED code is easiest to describe by its check matrix HH, with one row per check bit and one column per stored bit. Column jj is the syndrome that a single flip at position jj produces, as the binary number jj was for Hamming's code. Correcting one error needs the 72 columns to be distinct and nonzero. Detecting two needs the XOR of any two columns to be neither zero nor equal to a column, so that a double error is never mistaken for a single one.

In 1970 M. Y. Hsiao of IBM proposed choosing every column with an odd number of 1s [15].

For 64 data bits and 8 check bits Hsiao's recipe takes the 8 columns of weight 1 for the check bits themselves, all (83)=56\binom{8}{3} = 56 columns of weight 3, and 8 columns of weight 5, which makes 72. The matrix holds 216 ones, exactly 27 in each row. Each syndrome bit is therefore the XOR of 27 bits, which a tree of two-input XOR gates finishes in ⌈log⁡227⌉=5\lceil \log_2 27 \rceil = 5 levels. The extended Hamming code of Hamming's Code at Bell Labs, built from the lightest columns that work, needs 258 ones, because its overall parity row covers all 72 bits and takes ⌈log⁡272⌉=7\lceil \log_2 72 \rceil = 7 levels. Hsiao's matrix saves 42 ones, 16%, and two gate levels on the slowest path, which matters because the check runs on every read from memory. The same recipe gives a (39,32)(39,32) code for 32-bit words with 103 ones.

Codes of this kind became the usual protection for server memory, which stores each 64-bit word in 72 bits [15], as Figure 1 showed. Field studies have since found memory errors in large server fleets to be far more common than laboratory estimates suggested [16], which pushed designs beyond single-bit correction toward codes that survive the loss of a whole memory chip. Part II derives the extended Hamming and Hsiao codes, and Part XI, ECC in Memory, Storage and Links, follows memory protection from there.

08.5G New Radio

The 5G New Radio standard, 3GPP TS 38.212 [17], uses three families of codes. User data travel in low-density parity-check (LDPC) codes, introduced by Gallager in 1962 [18]. Control messages use polar codes, introduced by Arıkan in 2009 [19], with mother codes of length up to 512 on the downlink and 1,024 on the uplink. The shortest control messages, 3 to 11 bits, use a (32,K)(32,K) block code, and blocks that fail are resent under hybrid ARQ.

An NR LDPC code is built from a small base graph, a matrix of 0s and 1s, by replacing each 1 with a Zc×ZcZ_c \times Z_c identity matrix whose columns are cyclically shifted, and each 0 with a block of zeros. The lifting size ZcZ_c comes from the 51 values a⋅2j≤384a \cdot 2^j \le 384 with aa in {2,3,5,7,9,11,13,15}\{2, 3, 5, 7, 9, 11, 13, 15\}, from 2 to 384, so one pair of base graphs serves blocks of almost any size. Base graph 1 has 22 information columns and serves code blocks up to 22×384=8,44822 \times 384 = 8{,}448 bits at a lowest rate of 22/66=1/322/66 = 1/3. Base graph 2 has 10 information columns, serves blocks up to 3,840 bits, and reaches rate 10/50=1/510/50 = 1/5. The denominators are 66 and 50 rather than the full widths of the graphs because the first 2Zc2Z_c information bits are never sent.

A transport block of AA bits first gains a CRC, 16 bits when A≤3,824A \le 3{,}824 and 24 bits above that, giving BB bits. Base graph 2 is chosen for small blocks and low rates, when A≤292A \le 292, or A≤3,824A \le 3{,}824 with code rate R≤0.67R \le 0.67, or R≤0.25R \le 0.25, and base graph 1 otherwise. The lifting size is the smallest ZcZ_c with KbZc≥BK_b Z_c \ge B, where KbK_b is 22 for base graph 1 and between 6 and 10 for base graph 2 depending on BB. The code block then holds 22Zc22 Z_c or 10Zc10 Z_c bits, the shortfall filled with zero bits that the decoder knows and the transmitter never sends.

After encoding, the N=66ZcN = 66 Z_c or 50Zc50 Z_c coded bits sit in a circular buffer, drawn in Figure 8. Each transmission reads its bits clockwise from a starting point set by its redundancy version rvrv, wrapping past the end. For base graph 2, with a buffer of NcbN_{cb} bits, the start is

k0=⌊crvNcb50Zc⌋Zc,crv∈{0,13,25,43},k_0 = \left\lfloor \frac{c_{rv} N_{cb}}{50 Z_c} \right\rfloor Z_c , \qquad c_{rv} \in \{0, 13, 25, 43\} ,
(10)

which for the full buffer, Ncb=50ZcN_{cb} = 50 Z_c, is simply 00, 13Zc13Z_c, 25Zc25Z_c and 43Zc43Z_c. Base graph 1 uses 17, 33 and 56 over 66 in the same way. A first transmission at rv0 sends mostly information bits and the first parity bits. If the receiver fails and asks again, the next version starts elsewhere and brings parity the receiver has not seen, and the receiver combines both transmissions into one stronger code of lower rate. That is the type-II hybrid ARQ, or incremental redundancy, of Error-Control Strategies and Performance. Parts IX and X build LDPC and polar codes and their decoders.

The circular buffer of a 5G NR LDPC code block for base graph 2 with lifting size Zc = 104. The encoder output of N = 50 Zc = 5,200 bits is drawn as a ring, its first 8 Zc systematic bits followed by 42 Zc parity bits, since the first 2 Zc systematic bits are never sent. Redundancy versions rv0, rv1, rv2 and rv3 start reading at 0, 13 Zc, 25 Zc and 43 Zc, that is at bits 0, 1,352, 2,600 and 4,472, and each transmission reads its bits clockwise from its own start, wrapping past the end. rv0 starts at 0 rv1 starts at 13 Zc rv2 starts at 25 Zc rv3 starts at 43 Zc systematic, 8 Zc parity, 42 Zc N = 50 Zc5,200 bits Base graph 2 with Zc = 104. The first 2 Zc systematic bits are never sent. Each transmission reads its bits clockwise from its own start, wrapping past the end.
Figure 8. The circular buffer of a 5G NR LDPC code block for base graph 2 with Zc = 104, and the four starting points of the redundancy versions.

The (32,K)(32,K) code for the shortest messages is defined by a table of 11 basis sequences of length 32. Its first sequence is all 1s, and across the 32 positions the next five take all 32 patterns of five bits. For K=6K = 6 the code is therefore the set of words a0⊕a1x1⊕⋯⊕a5x5a_0 \oplus a_1 x_1 \oplus \cdots \oplus a_5 x_5 with the positions in another order, the code of The Mariner Reed–Muller Code again, with d=16d = 16. Adding basis sequences to carry more bits lowers the distance to 12 for K=7K = 7 to 10, and to 10 for K=11K = 11. A code that carried pictures from Mars in 1969 thus carries a phone's shortest control messages in the 5G standard.

09.Looking Ahead

Each of the eight designs matched its code to the errors it expected. Memories with rare, independent flips moved from parity to a SEC-DED code chosen for speed. Deep-space links paired a soft inner decoder with a byte-level outer code and spread the bursts between them. The compact disc and the QR code expect damage in patches and answer with Reed–Solomon codes over bytes and with interleaving, and 5G adapts its code to the block size and the channel with every transmission. Every number in the chapter followed from the tools of the first Part, distance, the binomial tail, coding gain and erasures, while the codes themselves were taken on trust.

The next chapter stops taking error rates on trust. It builds a channel simulator in Python for the binary symmetric, erasure and Gaussian channels, runs repetition and parity codes through it, and checks the measured error rates and their confidence intervals against the closed forms of the earlier chapters. The chapter after it puts a parity generator and checker into hardware. Part II then opens the first family met here, linear block codes, starting from the Hamming codes of Hamming's Code at Bell Labs.

10.Worked Examples

11.Exercises

References

  1. [1]Hamming, Richard W. (1950). “Error Detecting and Error Correcting Codes.” Bell System Technical Journal, 29(2), pp. 147–160. doi:10.1002/j.1538-7305.1950.tb00463.x
  2. [2]Tausworthe, Robert C. and Easterling, Mahlon F. and Spear, A. J. (1969). “A High-Rate Telemetry System for the Mariner Mars 1969 Mission.” JPL Technical Report 32-1354 (NASA-CR-100550), Jet Propulsion Laboratory. https://ntrs.nasa.gov/citations/19690012788
  3. [3]Reed, Irving S. (1954). “A Class of Multiple-Error-Correcting Codes and the Decoding Scheme.” Transactions of the IRE Professional Group on Information Theory, 4(4), pp. 38–49. doi:10.1109/TIT.1954.1057465
  4. [4]Muller, David E. (1954). “Application of Boolean Algebra to Switching Circuit Design and to Error Detection.” Transactions of the IRE Professional Group on Electronic Computers, EC-3(3), pp. 6–12. doi:10.1109/IREPGELC.1954.6499441
  5. [5]Ludwig, Roger and Taylor, Jim (2002). “Voyager Telecommunications.” DESCANSO Design and Performance Summary Series, Article 4, Jet Propulsion Laboratory. March 2002. https://descanso.jpl.nasa.gov/DPSummary/Descanso4--Voyager_new.pdf
  6. [6]Viterbi, Andrew J. (1967). “Error Bounds for Convolutional Codes and an Asymptotically Optimum Decoding Algorithm.” IEEE Transactions on Information Theory, 13(2), pp. 260–269. doi:10.1109/TIT.1967.1054010
  7. [7]Reed, Irving S. and Solomon, Gustave (1960). “Polynomial Codes over Certain Finite Fields.” Journal of the Society for Industrial and Applied Mathematics, 8(2), pp. 300–304. doi:10.1137/0108018
  8. [8]McEliece, Robert J. and Swanson, Laif (1986). “On the Decoder Error Probability for Reed-Solomon Codes.” TDA Progress Report 42-84, Jet Propulsion Laboratory. Covers October to December 1985. https://ntrs.nasa.gov/citations/19860013319
  9. [9]Consultative Committee for Space Data Systems “TM Synchronization and Channel Coding.” CCSDS 131.0-B-5, Blue Book. Issue 5. https://public.ccsds.org/Pubs/131x0b5.pdf
  10. [10]Immink, Kees A. Schouhamer (1998). “The Compact Disc Story.” Journal of the Audio Engineering Society, 46(5), pp. 458–465. https://www.aes.org/e-lib/browse.cfm?elib=12144
  11. [11]Ecma International (1996). “Data Interchange on Read-Only 120 mm Optical Data Disks (CD-ROM).” Standard ECMA-130, 2nd edition. https://ecma-international.org/publications-and-standards/standards/ecma-130/
  12. [12]DENSO WAVE “Information Capacity and Versions of the QR Code.” QRcode.com. Read 2026-11-14. https://www.qrcode.com/en/about/version.html
  13. [13]ISO/IEC (2015). “Information Technology, Automatic Identification and Data Capture Techniques, QR Code Bar Code Symbology Specification.” ISO/IEC 18004:2015. https://www.iso.org/standard/62021.html
  14. [14]DENSO WAVE “Error Correction Feature.” QRcode.com. Read 2026-11-13. https://www.qrcode.com/en/about/error_correction.html
  15. [15]Hsiao, M. Y. (1970). “A Class of Optimal Minimum Odd-weight-column SEC-DED Codes.” IBM Journal of Research and Development, 14(4), pp. 395–401. doi:10.1147/rd.144.0395
  16. [16]Schroeder, Bianca and Pinheiro, Eduardo and Weber, Wolf-Dietrich (2009). “DRAM Errors in the Wild: A Large-Scale Field Study.” In Proceedings of the Eleventh International Joint Conference on Measurement and Modeling of Computer Systems (SIGMETRICS '09), pp. 193–204. doi:10.1145/1555349.1555372
  17. [17]3GPP (2017). “NR; Multiplexing and Channel Coding.” 3GPP Technical Specification 38.212. First issued in Release 15; later releases revise it. https://www.3gpp.org/dynareport/38212.htm
  18. [18]Gallager, Robert G. (1962). “Low-Density Parity-Check Codes.” IRE Transactions on Information Theory, 8(1), pp. 21–28. doi:10.1109/TIT.1962.1057683
  19. [19]Arikan, Erdal (2009). “Channel Polarization: A Method for Constructing Capacity-Achieving Codes for Symmetric Binary-Input Memoryless Channels.” IEEE Transactions on Information Theory, 55(7), pp. 3051–3073. doi:10.1109/TIT.2009.2021379

— Anirban

Hardware–software at the seam where compilers meet microcode.

FeedbackBook modePaper
error-correction-codinginformation-and-channels