算法的故事 / 第一季第二季目录0 / 30 章已读

第二季 · 第 48 章

被划伤的光盘为什么还能读?

《算法的故事》第二季 · 第四篇:穿越噪声的信息——里德、所罗门与有限域上的多项式纠错革命1982年10月1日,日本。索尼公司推出了一台新的音乐播放设备。它不需要把唱针压在黑胶唱片的沟槽中。也不需要将磁带穿过磁头。它使用激光,读取一张直径12厘米、表面闪烁着彩虹色光泽的圆盘。这台设备叫作CDP-101。它是索尼首款商业化CD播放器,也是最早投入市场的CD播放器之一。唱片上的音乐已经不再是直接刻录的模拟波形。它被转换成大量数字符号。每秒44100次采样。每次采样16位。左右两个立体声声道。激光读取光盘上的细微结构,再经过电路处理,最终还原出人耳能够听见的声音。这项产品的出现,是索尼和飞利浦多年共同研发的结果。他们在1980年完成了重要的技术标准协商,并于1982年将产品推向市场。 [Sony Group Portal][Philips]但现在,我们想象一个非常普通的意外。一张CD使用了一段时间。表面出现灰尘。或者,在取放过程中留下了一条划痕。激光经过受损区域时,某些原本应该被准确读取的数字符号,可能无法被正确识别。按最直接的逻辑推断:数字数据错了。音乐就应该断裂。甚至可能发出刺耳的杂音。可是,令人意外的是,轻微损伤并不一定让CD立即无法播放。播放器仍可能连续输出音乐。听起来仿佛什么也没有发生。它并不是通过猜测演奏者的旋律,来重新创作缺失的音乐。也不是因为数字光盘永远不会发生读取错误。真正的原因之一,是光盘里的音频数据经过了特殊编码。这些编码额外保存了经过数学设计的冗余信息。当部分符号受损时,播放器有机会利用尚未损坏的符号,恢复原本的数据。这套机制包含一项重要的数学技术:里德—所罗门码(Reed–Solomon Code)。它的思想,甚至比第一台CD播放器早诞生二十多年。1960年,两位在麻省理工学院林肯实验室工作的研究者,发表了一篇只有五页的论文。他们是:欧文·斯托伊·里德(Irving S. Reed)。以及:古斯塔夫·所罗门(Gustave Solomon)。论文的题目是:Polynomial Codes Over Certain Finite Fields《某些有限域上的多项式编码》。里德与所罗门1960年论文首页,发表于《Journal of the Society for Industrial and Applied Mathematics》第8卷第2期,第300—304页。论文明确讨论了多符号纠错和成片错误的问题。[Department of Mathematics]这篇论文提出了一种出人意料的办法。不要把原始数据仅仅看作一串等待传输的数字。而是将它看作一个多项式的系数。然后,在许多不同位置计算这个多项式的值。把这些值作为编码后的数据,发送出去。接收端即使丢失了一部分数值,仍然有机会恢复原来的多项式。只要损坏数量没有超过编码能够承受的范围。因为一个低次数多项式,并不需要无限多个采样点,才能被唯一确定。这项数学性质,后来成为纠错编码历史中极其重要的基础。从卫星通信,到光盘与二维码,都能找到里德—所罗门码或其相关编码技术的应用。 [MIT Lincoln Laboratory]这一章,我们将从一张被划伤的光盘出发。穿过1960年的数学论文。回到十九世纪的有限域理论。再亲手构造一套可以恢复丢失符号的纠错算法。最终,你将明白:为什么一条损坏了部分数据的消息,仍然可能包含足够的信息,让我们完整找回它原来的样子。

第一幕:光盘上的一道伤痕,为什么可能变成连续的数字错误?

要理解CD为什么需要特殊纠错技术,我们首先需要知道:光盘究竟怎样保存音乐?

一张CD表面,并没有直接刻着声音波形

黑胶唱片通过唱针与沟槽之间的机械关系,还原声音。CD则完全不同。在标准音频CD中,音乐首先经过数字采样和量化。对于双声道音频:每秒44100组采样。每个声道每个采样16位。所以,不计附加编码和其他开销,原始数字音频数据率为:44100×16×244100\times16\times2也就是:1 411 200 bits/s\boxed{1\,411\,200\text{ bits/s}}约为:1.4112 Mbit/s1.4112\text{ Mbit/s}这是未压缩的双声道PCM音频数据率。实际记录在光盘上的信道比特流,还要包含纠错、调制、同步和控制信息,因此不能简单地将这个数字当作光盘表面的全部物理比特率。

激光读取的是什么?

一张标准CD包含一条螺旋形信息轨道。轨道上存在细微的凹坑(pit)与平坦区域(land)。播放器使用激光和光电检测设备,感知这些结构产生的光学信号差异。经过时钟恢复、数字解调及其他处理后,得到存储的数字信息。但现实中的读取过程并不完美。塑料材料可能存在缺陷。表面可能出现指纹或灰尘。划痕可能干扰激光信号。当这些影响足够严重时,接收端就可能获得错误符号,甚至无法可靠判定某些符号。参加过CD研发的飞利浦工程师 Hans B. Peek,在2010年发表于《IEEE Communications Magazine》的历史回顾中,明确讨论了塑料缺陷、指纹与划痕所造成的随机错误和连续突发错误。[Philips]

随机错误与突发错误,不是一回事

假设原始数据为:
text
1 0 1 1 0 0 1 0 1 0 1 1 0 1 0 0
如果只出现少量分散的错误:
text
1 0 1 1 1 0 1 0 1 0 1 1 0 0 0 0
        ↑                 ↑
我们称它们为比较分散的错误。但如果某一段连续区域全部受到破坏:
text
1 0 1 1 ? ? ? ? ? ? 1 1 0 1 0 0
        └─────────┘
          连续损坏
情况就不同了。这类集中发生在相邻位置上的错误,通常被称为:突发错误(Burst Error)。对于某些通信与存储介质,突发错误比单独的随机错误更难处理。因为它可能一次破坏很多相邻的比特。而上一章研究的普通汉明(7,4)码,只能保证纠正一个比特翻转。如果一处物理损伤使同一个短码字中的多个比特同时出错,就可能超过它的纠错能力。

CD为什么特别关注突发错误?

因为光盘的表面损伤具有空间连续性。如果一条划痕影响了激光沿轨道读取的一段区域,那么相邻时间读取的若干符号,都可能受到影响。因此,不能简单地假设每一次错误都完全独立。光盘纠错系统不仅需要应对孤立错误。还需要考虑:某段连续区域的数据同时受损。这正是后来CD使用交织技术的重要原因。
图48-1:两种错误分布
分散错误错误分布在相距较远的位置
突发错误连续多个存储符号共同受损
红色表示损坏位置。示意图并不意味着每条真实CD划痕一定造成固定长度的数字错误。
现在,我们获得了本章的第一个真正问题。如果某种物理损伤,会集中破坏一段连续的数据:能不能把原本集中发生的错误,变成纠错算法更容易处理的形式?答案是可以的。但在理解那项技术之前,我们还需要知道:怎样构造能够修复整个符号,而不只是单个比特的编码?这就需要回到1960年的麻省理工学院林肯实验室。

第二幕:1950年代的林肯实验室,两位数学家开始合作

1950年代的美国,数字通信和计算机技术正在迅速发展。冷战背景下,雷达、计算机和远程通信成为重要研究方向。位于马萨诸塞州列克星敦的麻省理工学院林肯实验室,参与了大量相关研究。研究者们希望:雷达数据能够可靠传输。数字计算设备能够处理复杂的检测任务。远距离通信即使受到噪声干扰,也能尽可能准确地传递信息。1951年至1960年,欧文·里德就在这家实验室工作。根据美国国家工程院2014年的纪念传记,他在这段时期研究过计算机程序设计、雷达数据分析、Reed–Muller码和后来的Reed–Solomon码。[国家科学院]

欧文·里德:从阿拉斯加走出的数学家

欧文·斯托伊·里德(1923—2012)。美国国家工程院在纪念传记中强调了他对数字计算机、雷达、信号处理及多错误纠正编码的长期贡献。[国家科学院]里德1923年11月12日出生于华盛顿州西雅图。他在阿拉斯加的费尔班克斯长大。早年曾在阿拉斯加大学学习。之后转入加州理工学院。1944年获得学士学位。1949年获得数学博士学位。第二次世界大战期间,他曾在美国海军担任雷达技术员。战后,又参与了MADDIDA数字计算设备的研发工作。这使他的研究经历从数学、雷达延伸到了数字计算机。进入林肯实验室之后,里德进一步接触到数字通信中的错误控制问题。[国家科学院]但在1950年代,纠错编码并不是一片空白。上一章的理查德·汉明,已经于1950年正式发表了单错误纠正编码。里德本人还与 David E. Muller 的相关工作共同构成了后来的 Reed–Muller 码研究方向。1954年,里德发表过一项多错误纠正编码研究。因此,他并不是直到1959年才突然开始关注编码问题。1960年的成果,是他此前研究道路的一次重要延伸。

古斯塔夫·所罗门:一位拥有纯数学背景的合作者

所罗门1930年出生于纽约布鲁克林。他在1956年于麻省理工学院取得数学博士学位。后来在林肯实验室从事相关研究。与里德相比,他的研究训练更偏向抽象数学。根据里德1997年接受《WIRED》采访时的回忆,两人于1957年相识,并开始共同发展后来被称为Reed–Solomon码的思想。[WIRED]这项合作的成功,正好体现了数学研究中一种重要的结合。一方长期研究数字通信与纠错应用。另一方熟悉抽象代数与有限域理论。他们共同面对的问题是:能不能用一种新的代数结构,构造出能够纠正多个错误的编码?

一段有真实采访支持的生活细节

在1997年的采访中,里德还回忆,所罗门是一位十分热爱音乐的人。他喜欢歌剧,也曾研究音乐教学。而里德则更偏向持续投入计算与技术研究。采访中,一位共同认识他们的研究者,也谈到了两人截然不同的工作风格。[WIRED]这项细节十分有趣。因为几十年后,他们共同发展的纠错码,进入了数以亿计的音乐CD播放器。但我们不能因此编造:“所罗门因为热爱歌剧,所以专门发明了能够保护音乐光盘的编码。”没有证据支持这种因果关系。1960年,商业CD尚未出现。他们面对的是更一般的数字通信与错误纠正问题。CD是后来受益于这项数学研究的应用,而非其已经预见的具体产品。

论文究竟是什么时候完成的?

原始论文的书目信息非常清楚。题目:Polynomial Codes Over Certain Finite Fields。投稿日期:1959年1月21日。修订日期:1959年8月26日。正式发表:1960年6月。刊登于《Journal of the Society for Industrial and Applied Mathematics》第8卷第2期,第300—304页。原文页脚还写明,研究在林肯实验室完成,得到美国军方相关合同支持。[SIAM Journal on Applied Mathematics][Department of Mathematics]所以,更准确的历史表述是:这项成果在1959年之前就已经形成。1960年是正式期刊论文的发表年份。而林肯实验室本身也成为这项研究不可分割的历史背景。现在,让我们看看:这两位研究者究竟将什么数学思想引入了纠错编码。

第三幕:回到法国数学家伽罗瓦——为什么不能直接使用普通整数?

如果你还记得上一章,我们用0和1构造汉明码。所有校验计算都在二元域:F2\mathbb F_2上进行。例如:1+1=01+1=0因为加法采用模2计算。这项结构让异或运算成为一种非常自然的计算工具。但Reed–Solomon码希望做一件更加复杂的事情。它要把多个符号当作一个整体来处理。而这些符号,不一定只有0和1两种取值。

假设每个符号包含8个比特

那么,每个符号可以有:28=2562^8=256种不同数值。例如:00000000到:11111111也就是整数表示中的:0∼2550\sim255我们希望对这些符号进行:加法。乘法。除法。以及多项式计算。但是,直接使用普通整数算术,并不一定能够让结果一直停留在0到255的范围内。比如:200×200=40000200\times200=40000已经远远超过一个字节能够表示的范围。如果简单地对256取余,是否就得到一个适合多项式运算的数学系统?不行。因为:Z/256Z\mathbb Z/256\mathbb Z虽然能够进行模256加法与乘法,但它不是一个域。例如,2没有模256的乘法逆元。因为不存在整数 xx 使:2x≡1(mod256)2x\equiv1\pmod{256}所以,不能保证所有非零元素都能参与除法。而多项式插值与编码理论,恰恰需要能够可靠执行除法。这就引出了:有限域(Finite Field)。

什么是域?

简单来说,一个域是能够进行加、减、乘,以及除以非零元素的代数结构。普通有理数:Q\mathbb Q构成一个域。实数:R\mathbb R也构成一个域。但我们想要的是:只包含有限数量元素的域。比如:F7\mathbb F_7这个有限域包含:{0,1,2,3,4,5,6}\{0,1,2,3,4,5,6\}全部加减乘除都在模7意义下进行。例如:5+4≡2(mod7)5+4\equiv2\pmod7因为:9≡2(mod7)9\equiv2\pmod7再例如:3×5=15≡1(mod7)3\times5=15\equiv1\pmod7因此,5是3在模7意义下的乘法逆元。也就是:3−1≡5(mod7)3^{-1}\equiv5\pmod7我们可以在这个七元素的世界里,正常进行代数计算。

为什么7可以,256却不能直接使用同样的整数取模方法?

因为:77是素数。模素数构成的整数剩余类:Fp\mathbb F_p是一个域。但是:256256不是素数。直接模256运算得到的结构,存在非零元素无法求逆的问题。不过,这并不意味着包含256个元素的有限域不存在。它确实存在。记作:GF(28)\boxed{\mathrm{GF}(2^8)}或者:F256\mathbb F_{256}只是它的构造,不能简单依赖普通整数模256。我们需要把8位符号表示成系数属于 F2\mathbb F_2 的多项式,再使用一个合适的八次不可约多项式进行模多项式运算。例如,某些编码系统采用:p(x)=x8+x4+x3+x2+1p(x)=x^8+x^4+x^3+x^2+1作为域构造所需的不可约多项式。实际采用哪个多项式,取决于具体标准。如果使用不同的多项式或不同的符号表示,底层运算表也会发生变化。

为什么要把这种结构与伽罗瓦联系起来?

十九世纪法国数学家 埃瓦里斯特·伽罗瓦 的研究,帮助建立了后来发展为现代抽象代数的重要思想。为了纪念他,有限域也经常被称为:伽罗瓦域(Galois Field)。常用符号:GF(q)\mathrm{GF}(q)但必须准确区分:里德与所罗门并不是伽罗瓦域的发明者。他们利用已经发展成熟的有限域数学,将它转化为一种强大的编码构造工具。这项思想在1960年论文中表现得非常清楚。作者直接从有限域的元素出发,构造多项式:P(x)=a0+a1x+⋯+ak−1xk−1P(x)=a_0+a_1x+\cdots+a_{k-1}x^{k-1}再将它在多个不同域元素上的取值作为编码结果。[Department of Mathematics]

为什么本章先使用 F7\mathbb F_7,而不直接使用256元素域?

因为七元素域更容易手算。比如:6+5≡4(mod7)6+5\equiv4\pmod74×3≡5(mod7)4\times3\equiv5\pmod7我们能够亲手验证所有结果。而256元素的扩域运算,需要引入多项式约简与乘法逆元。数学上并不困难,但会遮蔽本章最重要的第一层思想。所以,接下来我们先使用:F7\mathbb F_7构造一份小型Reed–Solomon码。请记住:这只是一份教学模型。真实CD中的编码使用8位符号组成的:GF(28)\mathrm{GF}(2^8)其物理编码结构也更加复杂。两者使用的有限域不同,但核心多项式思想是一致的。

第四幕:三个数字变成六个数字——多项式竟然能保存冗余

现在,我们开始构造本章的第一套真正的Reed–Solomon码。先暂时不用真实光盘上的256元素有限域。我们选择只有七个元素的:F7={0,1,2,3,4,5,6}\mathbb F_7=\{0,1,2,3,4,5,6\}所有加、减、乘、除运算,都按照模7的规则进行。

第一步:把消息变成多项式

假设我们需要发送三个数字:2, 3, 1\boxed{2,\ 3,\ 1}普通的传输方式,是直接发送这三个符号。如果中间某个符号丢失,我们可能就无法恢复完整消息。但里德与所罗门提出了不同的办法。将三个数看作多项式的系数。第一个数作为常数项。第二个数作为一次项系数。第三个数作为二次项系数。因此:P(x)=2+3x+x2\boxed{P(x)=2+3x+x^2}此时,原始消息已经不再只是三个独立数字。它变成了一个具体的二次多项式。

第二步:在六个不同位置计算它的值

我们选择:x=0,1,2,3,4,5x=0,1,2,3,4,5依次计算:P(0),P(1),…,P(5)P(0),P(1),\ldots,P(5)但必须记住:一切计算都在模7意义下进行。当:x=0x=0时:P(0)=2P(0)=2当:x=1x=1时:P(1)=2+3+1=6P(1)=2+3+1=6当:x=2x=2时:P(2)=2+6+4=12P(2)=2+6+4=12模7得到:P(2)=5P(2)=5继续计算:P(3)=2+9+9=20≡6(mod7)P(3)=2+9+9=20\equiv6\pmod7P(4)=2+12+16=30≡2(mod7)P(4)=2+12+16=30\equiv2\pmod7P(5)=2+15+25=42≡0(mod7)P(5)=2+15+25=42\equiv0\pmod7所以,我们得到六个编码符号:2, 6, 5, 6, 2, 0\boxed{2,\ 6,\ 5,\ 6,\ 2,\ 0}
图48-2:从三个多项式系数到六个编码符号
原始消息 · 三个有限域元素

2

3

1

P(x)=2+3x+x2(mod7)P(x)=2+3x+x^2\pmod7
在六个不同位置取值
x=0

2

x=1

6

x=2

5

x=3

6

x=4

2

x=5

0

这是定义在有限域 F7\mathbb F_7 上、长度6、消息长度3的教学型Reed–Solomon码。真实CD使用的是 GF(28)\mathrm{GF}(2^8) 上的不同参数和实现。
这看起来有点奇怪。我们明明只需要传输:33个数字。为什么要发送:66个?因为额外的三个数,并不是随意添加的。它们全部来自同一个多项式。它们之间拥有严格的代数联系。因此,即使其中某些数丢失,其余数值仍可能足以重新确定原来的多项式。这便是编码冗余发挥作用的地方。

第三步:为什么它不等于简单重复消息?

如果我们使用最简单的重复法:(2,3,1)→(2,3,1,2,3,1)(2,3,1)\rightarrow(2,3,1,2,3,1)那么,每个数字只是直接复制一次。但Reed–Solomon编码得到:(2,6,5,6,2,0)(2,6,5,6,2,0)它不是原始消息的机械重复。它是通过多项式计算出来的一组相关符号。这种关系比逐个重复更丰富。每个编码符号都携带了关于多个原始系数的联合信息。因此,某个位置丢失时,并不一定只能依赖该位置的另一份副本来恢复。我们可以利用其他位置上的多项式取值,重新解出原来的全部系数。

第四步:这套编码到底叫什么参数?

我们发送:k=3k=3个原始符号。编码后得到:n=6n=6个符号。因此,它是一种:RS(6,3)\boxed{RS(6,3)}编码。这里的符号来自:F7\mathbb F_7编码率为:R=kn=36=12R=\frac{k}{n}=\frac36=\frac12也就是:50%。我们用三个额外的符号,换取了对损坏数据的恢复能力。但它究竟能够恢复多少个受损符号?要回答这个问题,先考虑一种相对容易的情况:我们已经知道哪些位置的数据丢失了。

第五幕:只剩三个正确数字,为什么仍然能够恢复全部消息?

现在,假设我们刚刚生成的六位码字:(2,6,5,6,2,0)(2,6,5,6,2,0)在传输过程中遭遇损坏。其中三个位置无法读取。接收端只知道:P(0)=2P(0)=2P(1)=6P(1)=6P(3)=6P(3)=6其他三个位置的数据不见了。收到的情况可以写成:(2,6,?,6,?,?)\boxed{(2,6,?,6,?,?)}这里的问号表示:我们知道这些位置的数据不可用。它们并不是数值零。而是:擦除(Erasure)。

错误与擦除,有一项根本区别

假设发送端发送:55如果接收端收到:22并且误以为2是正确的,那么这属于错误。接收端不知道这个位置已经损坏。但如果接收端收到一个明确的信号:“这个位置的数据无法可靠判定。”那么它可以将该符号标记为擦除。这时,接收端至少知道:哪个位置不可靠。虽然仍不知道原来的正确值是多少。因此:
  • **错误(Error):**位置未知,收到的值可能不正确。
  • **擦除(Erasure):**位置已知,但正确值缺失或被宣布不可信。
这种区别对于纠错能力具有重大影响。因为定位错误本身需要额外信息。如果错误位置已经知道,恢复工作就相对容易一些。

三个点,为什么足以确定一个二次多项式?

我们知道:P(x)=a0+a1x+a2x2P(x)=a_0+a_1x+a_2x^2未知数共有三个:a0,a1,a2a_0,\quad a_1,\quad a_2现在,接收端获得三个正确取值:P(0)=2P(0)=2P(1)=6P(1)=6P(3)=6P(3)=6代入多项式:a0=2a_0=2a0+a1+a2=6a_0+a_1+a_2=6a0+3a1+9a2=6a_0+3a_1+9a_2=6全部在:F7\mathbb F_7上计算。由第一条:a0=2a_0=2代入第二条:a1+a2=4a_1+a_2=4第三条则变成:3a1+9a2=43a_1+9a_2=4因为:9≡2(mod7)9\equiv2\pmod7所以:3a1+2a2=43a_1+2a_2=4将:a1+a2=4a_1+a_2=4乘以3:3a1+3a2=12≡5(mod7)3a_1+3a_2=12\equiv5\pmod7两式相减:−a2≡−1(mod7)-a_2\equiv-1\pmod7因此:a2=1\boxed{a_2=1}再得到:a1=3\boxed{a_1=3}加上:a0=2a_0=2我们成功恢复:P(x)=2+3x+x2\boxed{P(x)=2+3x+x^2}于是,原始消息:2,3,1\boxed{2,3,1}完整恢复。而且,我们可以重新计算所有六个编码位置:2,6,5,6,2,0\boxed{2,6,5,6,2,0}
图48-3:知道三个正确位置,就可以恢复整个二次多项式
x=0

2

x=1

6

x=2

?

x=3

6

x=4

?

x=5

?

有限域上的三点插值
P(x)=2+3x+x2P(x)=2+3x+x^2
重新计算全部编码符号
x=0

2

x=1

6

x=2

5

x=3

6

x=4

2

x=5

0

绿色表示已知或成功恢复的数值;红色表示被擦除的位置。恢复依赖三个已知值正确,且位于互不相同的有限域采样点。

为什么任意三个正确取值都够?

这不是因为我们恰好选了:x=0,1,3x=0,1,3而是因为二次多项式有一项更加普遍的性质。在一个域上,两个不同的次数不超过2的多项式,不可能在三个不同位置上拥有完全相同的取值。证明非常简单。假设有两个不同的二次以内多项式:P(x),Q(x)P(x),\quad Q(x)它们在三个不同位置上的取值全部相同。那么:R(x)=P(x)−Q(x)R(x)=P(x)-Q(x)就是一个非零且次数不超过2的多项式。但它在三个不同位置上都为零。也就是说,它拥有至少三个不同的根。然而,一个非零的二次以内多项式,在域上最多只能有两个不同的根。矛盾。因此,原来的两个多项式不可能不同。所以,只要三个正确采样点的横坐标互不相同,它们就能够唯一确定二次以内的多项式。这项性质就是多项式插值的根本基础。

为什么不能把普通实数图像直接当成有限域图像?

你可能在数学课上看到:三个点确定一条抛物线。这项直觉非常有帮助。但这里的多项式不是在普通实数平面上运算。我们使用的是:F7\mathbb F_7因此,所有坐标与函数值都经过模7计算。例如:P(2)=12≡5(mod7)P(2)=12\equiv5\pmod7并不是普通实数曲线上高度为12的点。所以,图像可以帮助理解插值,但真正的计算必须在有限域里进行。

这正好对应1960年的原始论文

里德和所罗门在论文中明确写道:如果有一个次数低于消息长度的多项式,那么在足够多的不同域元素上取值,就能获得一组相关的编码符号。当正确取值位置足够多时,能够通过求解方程恢复系数。原始论文还使用范德蒙德行列式(Vandermonde Determinant),说明为什么这些方程能够唯一确定多项式。[Department of Mathematics]因此,我们刚才的三点恢复,不是为现代教学随意编造的一项技巧。它正是1960年论文所采用的核心数学思想的简化版本。

第六幕:如果错误的位置也不知道,为什么恢复能力就会下降?

刚才,我们成功恢复了三个丢失符号。因为接收端知道:第3、5、6个编码位置不可靠。但现在,假设接收端收到全部六个数字。其中某个数字却被错误地替换成了另一个合法数值。接收端并不知道究竟是哪一位出了问题。例如,原来的码字:(2,6,5,6,2,0)(2,6,5,6,2,0)在第3个符号位置发生错误。数值5被改成4。接收端得到:(2,6,4,6,2,0)\boxed{(2,6,4,6,2,0)}它没有收到一个明确的问号。只收到一个看起来正常的数值:44这就是未知位置的符号错误。

为什么比擦除更加困难?

在擦除情况下,我们知道哪些方程不能使用。只需要从剩余的正确点中,选择足够多的方程求解多项式。而在未知错误情况下,我们首先需要判断:六个点中,究竟哪些点仍然可信?例如:P(0)=2P(0)=2P(1)=6P(1)=6P(2)=4P(2)=4P(3)=6P(3)=6P(4)=2P(4)=2P(5)=0P(5)=0这六个方程,不可能全部由原来的二次多项式同时满足。但接收端并不知道哪条方程是错的。于是,我们不能只是随便选择前三个点。如果恰好选中了损坏位置,就可能推导出错误的多项式。

在本例中,可以寻找与最多五个点一致的二次多项式

假设我们知道:整份六符号码字中,最多只有一个符号发生错误。那么,真正的多项式应该至少与五个接收取值一致。我们可以尝试寻找:Q(x)=b0+b1x+b2x2Q(x)=b_0+b_1x+b_2x^2使得:Q(xi)=yiQ(x_i)=y_i在尽可能多的位置成立。如果发现某个二次多项式与六个接收值中的五个一致,那么剩下的一个位置,就可能是错误所在的位置。但这里的问题是:为什么这个多项式应该是唯一的?为什么不会存在另一个不同的二次多项式,也与五个点一致?答案来自上一章已经学过的:最小码距(Minimum Distance)。

Reed–Solomon码的最小码距

假设原始消息包含:kk个符号。我们把它表示成次数低于:kk的多项式。然后在:nn个互不相同的域元素上计算取值。考虑任意两个不同的合法编码多项式:P(x),Q(x)P(x),\quad Q(x)它们的差:R(x)=P(x)−Q(x)R(x)=P(x)-Q(x)是一个非零的次数不超过:k−1k-1的多项式。因此,它最多只能在:k−1k-1个不同采样点上为零。也就是说,两个不同合法码字,最多只有:k−1k-1个符号位置相同。那么,至少有:n−(k−1)n-(k-1)个符号位置不同。所以:dmin⁡≥n−k+1d_{\min}\ge n-k+1另一方面,我们可以构造两个合法多项式,使它们的差恰好在 k−1k-1 个采样点上为零。因此,对于标准的Reed–Solomon求值码:dmin⁡=n−k+1\boxed{d_{\min}=n-k+1}这是Reed–Solomon码最重要的数学性质之一。它使Reed–Solomon码成为一类最大距离可分码(Maximum Distance Separable,MDS)。其最小码距达到Singleton界。

本例的纠错能力

我们使用:n=6,k=3n=6,\qquad k=3所以:dmin⁡=6−3+1=4d_{\min}=6-3+1=4也就是:dmin⁡=4\boxed{d_{\min}=4}根据上一章的码距理论,保证纠正的未知位置符号错误数量为:t=⌊dmin⁡−12⌋t=\left\lfloor\frac{d_{\min}-1}{2}\right\rfloor代入:t=⌊32⌋=1t=\left\lfloor\frac32\right\rfloor=1因此,本例能够保证:纠正1个未知位置的符号错误\boxed{\text{纠正1个未知位置的符号错误}}如果错误位置已经知道,那么它可以保证恢复:dmin⁡−1=3d_{\min}-1=3个擦除。也就是说:恢复3个已知位置的擦除\boxed{\text{恢复3个已知位置的擦除}}

如果同时存在错误与擦除呢?

假设:ee是未知位置错误数量。ss是已知位置擦除数量。那么,对于标准Reed–Solomon码,在常见的唯一译码条件下,满足:2e+s≤n−k\boxed{2e+s\le n-k}即可保证唯一恢复。对于我们这份:RS(6,3)RS(6,3)编码:n−k=3n-k=3因此:2e+s≤3\boxed{2e+s\le3}
图48-4:三份冗余能够承担多少错误与擦除?
未知错误 ee已知擦除 ss代价 2e+s2e+s保证恢复?
000是
033是
102是
113是
124无通用保证
204无通用保证
为什么一个未知错误,相当于消耗两份冗余预算?直观地说,是因为它不仅破坏了某个取值。还隐藏了损坏发生的位置。接收端需要推断:错误在哪里?原来的正确值是多少?而擦除已经告知错误位置,因此只需要恢复缺失的取值。所以,未知错误通常需要更多纠错冗余。这也解释了真实纠错系统为什么非常重视:尽早标记某些符号是否不可信。如果底层检测器能够可靠判断一个符号可能损坏,它就能将该位置作为擦除信息提供给后续译码器。而不是让上层算法把错误数值当成普通数据处理。这种设计,对于光盘中的多级纠错系统尤其重要。

第七幕:互动实验室——破坏六个符号,看看多项式还能不能活下来

现在,我们把上一幕的数学推导变成一次可以直接操作的实验。原始消息固定为:(2,3,1)(2,3,1)对应的多项式:P(x)=2+3x+x2(mod7)P(x)=2+3x+x^2\pmod7六个编码符号:(2,6,5,6,2,0)(2,6,5,6,2,0)你可以对任意一个编码符号施加两种不同的破坏。第一种:将它擦除。接收端知道这个位置的数据不可用。第二种:将它改成一个错误的数值。接收端看到的是一个普通数字,不知道它已经被修改。实验中的译码器会枚举全部:73=3437^3=343种可能的二次以内多项式。寻找与现有接收数据最一致的候选。然后根据:2e+s≤32e+s\le3判断在给定的设计纠错半径内,是否存在唯一候选。这种穷举法非常适合教学。但它并不是工业Reed–Solomon译码器真正采用的高效算法。

实验一:亲自修改编码符号

图48-5:Reed–Solomon (6,3) 纠错实验台单击下面的符号格:正常 → 擦除 → 数值被篡改 → 恢复正常。实验使用 F7\mathbb F_7,每个符号都是0到6之间的一个有限域元素。
发送端原始消息及多项式

(2, 3, 1)

P(x)=2+3x+x2(mod7)P(x)=2+3x+x^2\pmod7
点击编码符号,模拟损坏
已知位置的擦除
未知位置的数值错误
擦除数 s

0

实验施加的错误数 e

0

冗余消耗 2e+s

0 / 3

译码器结果唯一候选
找到设计纠错半径内的唯一多项式恢复的多项式系数

(2, 3, 1)

重新计算的六个编码符号
2
6
5
6
2
0
本次原始消息成功恢复
每个被修改的数值统一加1(模7),只为方便复现实验。实际错误可能改为任意其他域元素。绿色结果依赖所显示的唯一候选条件;超出 2e+s≤32e+s\le3 时,即使译码器输出候选,也不再拥有通用恢复保证。

实验观察一:为什么擦除三个仍然能恢复?

选择:“擦除3处”。你会得到:(2,6,?,6,?,?)(2,6,?,6,?,?)接收端知道剩下哪三个位置正确。因此,可以从三个正确点直接恢复二次多项式。这是我们在第五幕亲手计算过的结果。

实验观察二:为什么一个未知错误也能恢复?

点击:“错误1处”。接收端得到六个数值。其中一个不正确。但因为:2×1+0≤32\times1+0\le3所以,在该纠错范围内,真正的多项式是唯一的。程序能够通过比较所有候选多项式,找到它。

实验观察三:一个错误加一个擦除

点击:“错误1处+擦除1处”。此时:2e+s=2×1+1=32e+s=2\times1+1=3刚好用完全部冗余预算。因此,理论上仍然可以唯一恢复。

实验观察四:为什么两个未知错误没有保证?

选择:“错误2处”。此时:2e+s=42e+s=4超过:n−k=3n-k=3因此,不再拥有唯一恢复保证。对于我们当前的特定改错模式,译码器可能找不到处于允许错误半径内的候选。在其他超过纠错能力的错误模式下,也可能发生更危险的情况:接收端找到一条满足内部检查的错误码字,并将其当成解码结果。所以:超出纠错能力,不只是可能恢复失败,还可能在某些模式下产生错误恢复结果。真正的工程系统必须认真对待这种局限。

第八幕:一条划痕,怎样被“打散”成许多个小错误?

现在,我们终于回到开篇的那张CD。如果一条划痕连续破坏多个符号,那么即使使用Reed–Solomon码,也可能超过单个码字的纠错能力。例如,我们刚才构造的:RS(6,3)RS(6,3)只能保证纠正一个未知位置的符号错误。假设物理损伤连续破坏四个符号。如果这四个符号恰好都属于同一份码字,那么一个码字就遭遇了四个错误。显然超过它的保证范围。那么,能不能让这四个连续损坏的符号,分别属于四份不同的码字?可以。这便是:交织(Interleaving)。

先看没有交织的情况

假设有四份不同的码字:A。B。C。D。每份码字有六个符号。如果我们按最直观的方式依次发送:
text
AAAAAA BBBBBB CCCCCC DDDDDD
假设某次物理损坏,连续破坏第5、6、7、8个传输符号。那么:A的最后两个符号损坏。B的前两个符号损坏。A、B各有两个错误。如果每份码字只能保证纠正一个错误,就无法保证恢复。

交织以后,顺序会怎样?

现在,我们改为:先发送A的第一个符号。再发送B的第一个符号。然后C的第一个符号。最后D的第一个符号。接着再发送它们的第二个符号。于是,物理发送顺序变成:
text
ABCD ABCD ABCD ABCD ABCD ABCD
如果同样连续损坏四个传输符号,它们恰好会分别来自:A、B、C、D。于是,每个码字只受到一个符号错误。对于能够纠正一个符号错误的编码,四份码字就都有机会被分别恢复。

交织并没有改变原来的纠错码

这点非常重要。交织没有增强单份码字的最小距离。也没有直接增加更多纠错符号。它改变的是:不同码字中的符号,在物理传输或存储时的排列顺序。这样,一段连续的物理损坏,经过反交织以后,就可能被分散到多个不同码字中。每份码字分别处理自己承担的少量错误。这就是交织能够增强突发错误抵抗能力的重要原因。

实验二:移动一道连续损坏,比较交织前后

图48-6:把突发错误打散成分散错误有A、B、C、D四份码字,每份6个符号。橙红色边框表示同一次连续4符号损坏。拖动滑块改变损坏发生的位置。
第 5 位
未交织:AAAAAA BBBBBB CCCCCC DDDDDD
A
A
A
A
A
A
B
B
B
B
B
B
C
C
C
C
C
C
D
D
D
D
D
D
A 损坏 2 个
B 损坏 2 个
C 损坏 0 个
D 损坏 0 个

交织后:ABCD ABCD ABCD ABCD ABCD ABCD
A
B
C
D
A
B
C
D
A
B
C
D
A
B
C
D
A
B
C
D
A
B
C
D
A 损坏 1 个
B 损坏 1 个
C 损坏 1 个
D 损坏 1 个
如果每个码字最多纠正1个未知符号错误
不交织的纠错保证至少一份超出保证范围
交织后的纠错保证四份均在保证范围内
教学模型只展示一种简单的轮流交织,不是CD所使用的完整CIRC。它假设所有损坏位置均属于未知符号错误,且每份码字具有单符号纠错能力。

为什么交织深度不能无限增加?

假设我们拥有1000份码字。如果把它们全部深度交织,一段物理突发错误可能被分散得非常广泛。但是,这也会带来新的问题。接收端必须等待足够多的符号,才能把各份码字重新整理出来。交织越深,可能需要越多的缓冲存储。通信延迟也可能增加。因此,交织技术需要在:突发错误抵抗能力。内存开销。传输延迟。以及实现复杂性之间寻找平衡。这也是为什么真实CD并不是简单地把四份码字轮流发送一遍。它使用更加复杂的:交叉交织里德—所罗门编码(Cross-Interleaved Reed–Solomon Code)。简称:CIRC\boxed{\mathrm{CIRC}}下一幕,我们就来看看:飞利浦与索尼,怎样将1960年的数学理论真正带入了1980年的光盘标准。

第九幕:1980年,飞利浦与索尼怎样把多项式装进一张音乐光盘?

现在,时间回到1970年代末。荷兰飞利浦与日本索尼,正在推动数字音频光盘成为一种共同标准。这项工作并不简单。两家公司必须在许多技术问题上达成一致。光盘直径。采样频率。数字音频位数。读取方式。调制编码。以及纠错机制。如果这些参数不同,一家公司生产的光盘,可能就无法在另一家公司的播放器中正常使用。

1979年8月,双方开始关键协商

根据飞利浦工程师 Hans B. Peek 后来的亲历者回顾,双方于1979年8月27日至28日,在荷兰埃因霍温举行了第一轮标准协商会议。其中,纠错编码和调制编码是需要投入最多讨论时间的技术问题之一。他们进行了多轮通信、计算机模拟和实际光盘性能测量。到1980年6月17日至18日,双方在东京完成最后一次相关标准会议。最终,数字音频CD采用:纠错编码:CIRC。调制编码:EFM(Eight-to-Fourteen Modulation)。这两项技术并不相同。EFM主要负责将数字数据转换成适合光盘物理记录与时钟恢复的信道码。CIRC则负责错误控制。不能将它们混为一种编码。[Philips]

CIRC为什么需要两层Reed–Solomon码?

标准音频CD并不是只对全部音乐数据执行一次简单的RS编码。它采用两层交叉交织的Reed–Solomon码。常见的表示是:第一层:C1=RS(32,28)\boxed{C_1=RS(32,28)}第二层:C2=RS(28,24)\boxed{C_2=RS(28,24)}两者都在256元素的有限域上工作。也就是:GF(28)\mathrm{GF}(2^8)每个符号是8位。对应一个字节大小的有限域元素。两层编码各自具有四个冗余符号。因此:n−k=4n-k=4最小码距:dmin⁡=n−k+1=5d_{\min}=n-k+1=5所以,单独一层在标准唯一译码条件下,可以保证:纠正最多两个未知位置的符号错误。或者恢复最多四个已知位置的擦除。也可以处理满足:2e+s≤42e+s\le4的混合情况。这些参数既可见于相关技术文献,也可见于IEC音频CD标准的CIRC部分。[Compact Disc Digital Audio System Standard][audiopub.co.kr]

两层编码的整体信息比例是多少?

首先,24个原始数据符号经过C2编码,变成28个符号。然后,通过相应的交织和另一层编码,最终形成32符号的编码结构。因此,综合编码率是:R=2428×2832R=\frac{24}{28}\times\frac{28}{32}中间的28相互抵消。所以:R=2432=34\boxed{R=\frac{24}{32}=\frac34}也就是75%。平均每24个原始数据字节,对应32个编码符号位置。其中,8个符号承载纠错所需的冗余。但这并不代表光盘的完整物理存储比特中,只有25%被用于纠错。因为标准CD还需要同步、控制、EFM调制及其他结构。这里的75%仅表示上述CIRC数据与冗余符号的编码率。

交织在中间发挥什么作用?

如果只使用两层RS码,却让同一份码字里的所有符号紧挨着存储,那么一条连续划痕仍然可能同时破坏其中大量符号。所以,CD还要将不同数据块的符号,经过精心设计的延迟和交叉排列。这样,物理上连续受损的一段数据,在反交织以后,就有机会被分散到多个纠错码字中。而每份码字只需要承担其中的一小部分损坏。
图48-7:CIRC的概念工作流程
1
数字音频将PCM音频整理成适合编码的数据符号

2
第一层RS编码加入一组代数纠错冗余

3
交叉交织和延迟重新排列多个码字的符号,使连续损伤分散

4
第二层RS编码加入另一组纠错冗余,形成组合保护

5
光盘读出与逆向处理先进行底层纠错与反交织,再执行另一层纠错
这是概念图,不是CIRC标准精确的延迟线布线与符号排列。实际CIRC还包含特殊的数据交换、延迟、校验生成与接收端控制策略。

如果第一层无法完全纠正某些错误呢?

这是CIRC设计中另一个重要细节。在适当的接收策略下,第一层译码器除了直接纠正部分错误,还可以识别某些无法可靠修复的数据。它可能向后续处理阶段提供错误标记。当这些数据经过反交织后,第二层纠错器便可以利用错误标记,将相关符号作为擦除处理。为什么这有帮助?因为我们刚才已经证明:对于相同的冗余数量,已知位置的擦除,通常比未知位置的错误更容易恢复。例如:RS(28,24)RS(28,24)拥有四个冗余符号。可以保证:两个未知位置的符号错误。或者:四个已知位置的擦除。因此,一项底层可靠性判断,可能帮助上层译码器更加有效地使用纠错预算。但必须强调:只有错误位置标记本身可靠,才能安全地将它用于擦除处理。错误的标记也可能影响译码结果。

如果纠错能力还是不够呢?

假设光盘损坏得更加严重。纠错系统无法完整恢复某些音频数据。播放器还可以采用其他音频处理策略。例如:利用前后相邻的音频样本,对局部无法恢复的声音作插值估计。或者,在严重不可恢复的情况下,进行静音处理,避免突然出现令人不适的强烈噪声。但这项技术必须与纠错严格区分。纠错,是利用编码冗余,恢复原本的数字数据。插值掩蔽,是在无法正确恢复原始数据时,生成听感上尽可能平滑的近似输出。后者并没有真正知道原来的音乐样本究竟是多少。它只是尽量减少听觉上的异常。因此,一张划痕过大的CD,仍然可能出现:跳音。静音。播放中断。或者完全无法读取。这并不违反Reed–Solomon理论。因为任何有限长度的纠错码,都有明确的错误承受能力。

一个必须纠正的常见说法

有人会说:“CD之所以不怕划痕,是因为使用了里德—所罗门码。”这句话表达了部分事实,但并不完整。真实原因包括:光学读取结构对于部分表面缺陷的天然容忍。信号检测与调制技术。交叉交织。两级RS纠错。错误标记与擦除处理。以及在必要时采用的音频错误掩蔽。因此,不能把CD系统的全部可靠性功劳,只归于单独一个多项式公式。数学编码提供了关键能力,但让它成为可靠产品,还需要完整的光学、电子、信号处理与标准化工程。

第十幕:1960年的数学思想,怎样才能成为真正高速运行的译码器?

我们刚才的互动实验使用了一种非常直接的译码方法。把所有可能的多项式都枚举出来。然后寻找与接收数据最一致的一种。对于:F7\mathbb F_7上的二次多项式,候选数量只有:73=3437^3=343这是很小的规模。但对于真实CD使用的256元素有限域,以及更加长的数据块,情况就完全不同了。假设原始消息包含:k=24k=24个符号。每个符号有256种可能。那么,所有可能的消息数量为:25624=2192\boxed{256^{24}=2^{192}}这显然无法通过穷举全部候选来实际译码。因此,里德—所罗门码虽然在数学上非常优美,但怎样高效地定位和修正错误,是一项需要进一步解决的工程问题。

原始论文的译码思路

1960年原始论文中,里德和所罗门主要使用多项式取值与插值的观点。在足够多的正确符号存在时,可以根据不同采样点恢复多项式。为了处理未知位置错误,也可以考虑由不同的点子集推断候选多项式,再根据一致性判断正确消息。但这种直接的组合式处理,在错误数量较大时,会遭遇复杂度问题。因此,原始论文并不等于已经给出了后来所有高速RS硬件采用的最终译码算法。

1960年代,译码算法继续发展

后来的编码理论研究者,开始寻找更加高效的代数译码方法。其中,埃尔温·伯利坎普(Elwyn Berlekamp)在1960年代的重要研究,推动了对BCH码和Reed–Solomon码的高效译码。1968年前后,相关代数译码方法得到系统发展。随后,詹姆斯·梅西(James Massey)进一步将相关算法与最短线性递推关系联系起来。后来,人们将一种重要算法称作:Berlekamp–Massey Algorithm。此外,还有:Chien搜索。Forney公式。基于扩展欧几里得算法的译码方法。它们共同构成现代代数纠错译码技术的重要基础。1988年,Robert J. McEliece 为NASA喷气推进实验室撰写了一篇研究报告,专门统一分析了Berlekamp、Berlekamp–Massey、欧几里得算法等不同RS译码方案。[tda.jpl.nasa.gov][NASA Technical Reports Server (NTRS)]

现代译码通常需要解决三件事

对于一份受到错误破坏的RS码字,译码器往往需要完成:首先,判断接收码字是否满足编码约束。如果存在错误,计算与错误有关的校验信息。接着,确定错误位置。最后,计算这些位置上究竟需要修改多少数值。这与汉明码具有明显的思想联系。汉明码通过伴随式直接定位单比特错误。Reed–Solomon码则面对更加复杂的多符号错误。通常需要先建立错误定位多项式,再确定错误位置及错误幅度。
图48-8:高效Reed–Solomon译码的典型结构
1
计算校验综合量检测码字是否符合代数约束,获得与错误相关的信息

2
求解错误定位关系例如通过Berlekamp–Massey或其他代数算法构造错误定位多项式

3
寻找错误位置根据错误定位多项式确定哪些符号位置可能受到损坏

4
计算错误幅度确定每个错误位置应该进行怎样的有限域修正

5
校验并输出在设计能力范围内验证结果,报告纠正状态或失败
不同RS编码表示和译码算法的具体步骤可能不同。此图用于说明现代代数译码的常见组成,不意味着所有实现都执行完全相同的运算顺序。

这项历史为什么重要?

因为它说明:证明一种优秀的码存在,与构造一种实际可用的高速译码器,是两项不同的研究任务。里德与所罗门给出了具有最大距离性质的编码结构。后来的数学家继续研究如何在存在大量错误时,高效求解恢复问题。再后来,工程师将这些算法转化成实际硬件和软件。直到1980年代,它们进入了可以大规模销售的消费电子设备。这与我们在第46章看到的香农理论,形成了很有意思的呼应。香农证明了可靠通信的理论极限。里德与所罗门发展了具有优美代数结构的编码方案。后来的译码算法研究,则进一步让这些数学构造能够高效运行。每一步都不可缺少。

第十一幕:Python实战——不用纠错库,恢复真正被损坏的数据

现在,我们将前面的数学推导实现成一份完整的Python程序。这份程序可以:把三个原始符号编码成六个符号。模拟某些符号被擦除。模拟某些符号被错误替换。通过有限域多项式插值,恢复候选消息。并根据设计的错误预算,判断是否拥有唯一可接受的解。它不依赖第三方Reed–Solomon库。只使用Python标准库。

第一步:有限域运算

在:F7\mathbb F_7中,加、减、乘都可以直接模7计算。除法则需要求模逆元。例如:3−1≡5(mod7)3^{-1}\equiv5\pmod7所以:23\frac23在模7意义下,可以写成:2×5=10≡3(mod7)2\times5=10\equiv3\pmod7Python提供了:
python
pow(a, -1, 7)
用于计算模7的逆元。因为7是素数,所以只要:a≢0(mod7)a\not\equiv0\pmod7逆元就存在。

第二步:拉格朗日插值

假设我们知道三个不同的采样点:(x0,y0)(x_0,y_0)(x1,y1)(x_1,y_1)(x2,y2)(x_2,y_2)那么,对应的二次以内多项式,可以通过拉格朗日插值公式构造:P(x)=∑i=02yi∏j=0j≠i2x−xjxi−xj\boxed{ P(x)= \sum_{i=0}^{2} y_i \prod_{\substack{j=0\\j\ne i}}^{2} \frac{x-x_j}{x_i-x_j} }所有计算都在有限域上进行。分母:xi−xjx_i-x_j只要采样位置互不相同,就不会等于零。因此,在域中可以计算其逆元。这项公式将三个正确取值,转换成原始多项式。

第三步:完整代码

python

from itertools import combinations

MOD = 7
X_VALUES = list(range(6))

# (6,3) Reed-Solomon 教学码
N = 6
K = 3


def evaluate(coeff, x):
    """
    计算P(x),系数从低次到高次排列。
    例如(2,3,1)代表2+3x+x^2。
    """
    result = 0

    for a in reversed(coeff):
        result = (result*x + a) % MOD

    return result


def encode(message):
    """
    3个有限域符号 -> 6个编码符号
    """
    if len(message) != K:
        raise ValueError("消息必须恰好包含3个符号")

    if any(not (0 <= v < MOD) for v in message):
        raise ValueError("每个符号必须位于0到6之间")

    return [
        evaluate(message, x)
        for x in X_VALUES
    ]


def multiply_linear(poly, root):
    """
    将多项式poly乘以(x-root),模7。
    系数采用低次在前的形式。
    """
    out = [0] * (len(poly) + 1)

    for degree, value in enumerate(poly):
        out[degree] = (
            out[degree] - root*value
        ) % MOD

        out[degree+1] = (
            out[degree+1] + value
        ) % MOD

    return out


def interpolate_three(points):
    """
    通过3个互不相同的正确采样点,
    恢复次数小于3的多项式系数。
    """
    if len(points) != 3:
        raise ValueError("必须提供3个采样点")

    coeff = [0, 0, 0]

    for i, (xi, yi) in enumerate(points):

        basis = [1]
        denominator = 1

        for j, (xj, _) in enumerate(points):
            if i == j:
                continue

            basis = multiply_linear(basis, xj)

            denominator = (
                denominator * (xi-xj)
            ) % MOD

        inverse = pow(denominator, -1, MOD)
        scale = yi * inverse % MOD

        for d in range(K):
            coeff[d] = (
                coeff[d] + scale*basis[d]
            ) % MOD

    return tuple(coeff)


def decode(received):
    """
    Reed-Solomon (6,3) 教学版译码。

    received为6个符号,每个值:
      0..6 = 收到的符号
      None = 已知位置擦除

    选择3个未擦除的位置进行多项式插值,
    检查候选多项式与全部未擦除值的差异。

    若存在唯一候选且满足设计纠错半径,
    则返回恢复的原始消息与码字。

    注意:不负责验证实际错误是否超出保证范围。
    """

    if len(received) != N:
        raise ValueError("必须有6个接收位置")

    known = [
        (i, value)
        for i, value in enumerate(received)
        if value is not None
    ]

    erasures = N - len(known)

    if erasures > N-K:
        return {
            "status": "uncorrectable",
            "reason": "已知位置擦除过多"
        }

    # 最多能安全处理的未知错误数
    max_errors = (N-K-erasures)//2

    # 收集全部3点插值生成的不同候选
    candidates = set()

    for subset in combinations(known, K):
        coeff = interpolate_three(subset)
        candidates.add(coeff)

    valid = []

    for coeff in candidates:
        mismatches = sum(
            evaluate(coeff, x) != value
            for x, value in known
        )

        if mismatches <= max_errors:
            valid.append((coeff, mismatches))

    if len(valid) != 1:
        return {
            "status": "uncorrectable",
            "reason": "无唯一的设计半径内候选"
        }

    coeff, errors = valid[0]

    return {
        "status": "decoded",
        "message": list(coeff),
        "codeword": encode(coeff),
        "unknown_errors": errors,
        "erasures": erasures
    }


original = [2, 3, 1]
encoded = encode(original)

print("原始消息:", original)
print("六位码字:", encoded)

# 情况A:三个已知位置擦除
case_a = [2, 6, None, 6, None, None]

# 情况B:第3个位置出现未知符号错误
case_b = [2, 6, 4, 6, 2, 0]

# 情况C:一个擦除 + 一个未知错误
case_c = [2, None, 4, 6, 2, 0]

# 情况D:两个未知符号错误
case_d = [2, 0, 4, 6, 2, 0]

for title, case in [
    ("三个擦除", case_a),
    ("一个未知错误", case_b),
    ("一个错误加一个擦除", case_c),
    ("两个未知错误", case_d),
]:
    print()
    print(title)
    print("接收:", case)
    print("译码:", decode(case))

    result = decode(case)

    if title != "两个未知错误":
        assert result["status"] == "decoded"
        assert result["message"] == original

print()
print("所有保证范围内的测试通过")

这段代码为什么比枚举343个多项式更有意思?

我们在互动实验中,枚举全部:73=3437^3=343种二次以内多项式。这当然能够完成小规模纠错。但在这份Python程序中,我们改用另一种方法。从收到的正确或可能正确的采样点中,选取三个。由它们插值得到一个候选多项式。再检查该候选是否与其余接收数据一致。例如,六个位置都没有被擦除,那么三个位置的组合数量为:(63)=20\binom63=20也就是说,最多只需要尝试20种三点组合,而不是全部343种可能的系数。对于当前小型例子,这已经减少了候选生成数量。但对于更大规模的真实RS码,组合数量:(nk)\binom nk仍然可能十分庞大。因此,这份程序依然属于教学版译码器。专业实现通常需要使用更加高效的代数方法。

最值得注意的一段程序

python
max_errors = (N-K-erasures)//2
它直接来自:2e+s≤n−k2e+s\le n-k假设擦除数量是:ss则允许的未知错误数量最多为:emax⁡=⌊n−k−s2⌋e_{\max}= \left\lfloor \frac{n-k-s}{2} \right\rfloor这让数学上的纠错保证,转化成了程序的明确判断条件。

程序还有一项刻意保留的限制

它寻找的是:在设计纠错半径内,唯一满足接收数据的候选码字。但如果实际发生的错误已经超出设计能力,译码器就可能:拒绝恢复。或者在某些特殊错误模式下,输出一条并非原始消息的码字。如果没有额外的完整性校验或错误检测信息,译码器不一定能够发现每一种超范围误纠。因此,我们不能在程序输出:
text
status: decoded
之后,就无条件宣称真实消息必定正确。这项保证仍然依赖:实际错误与擦除数量不超过编码的设计能力。这与上一章SECDED的限制,是同一种数学原则。

第十二幕:如果每个符号是一个字节,纠错能力会发生什么变化?

在前面的教学例子里,我们使用了:F7\mathbb F_7因此,每个符号只能取0到6的值。但在很多实际数字系统中,一个符号包含:88个比特。于是,我们需要:GF(256)\mathrm{GF}(256)这个拥有256个元素的有限域。

一个字节受到多位损坏,仍然只算一个符号错误

这正是Reed–Solomon码在某些存储与通信场景中十分有用的原因。假设一份码字的每个符号对应一个字节。某个字节原来是:
text
10110010
传输后变成:
text
01001101
八个比特都可能不同。但如果这个字节整体被视为一个有限域符号,那么对于RS码而言:这是一个符号错误。而不是八个独立的符号错误。如果编码能够纠正两个未知符号错误,那么它在理论上可以处理:至多两个符号位置上的任意错误数值。每个符号内部究竟有多少比特发生改变,并不影响按符号计数的纠错能力。

这与汉明码有什么区别?

汉明(7,4)码通常直接以单个比特作为纠错基本单位。因此,讨论的是:哪个比特翻转?而字节级Reed–Solomon码的基本单位是:有限域符号。因此,讨论的是:哪个符号位置被替换成了错误数值?这项区别,对于连续突发错误尤其重要。如果物理损坏集中在某几个符号位置,即使同一符号内部多个比特同时受损,也仍然可以按符号错误处理。不过,不能把它理解成:一个字节级RS码可以无限容忍任意多的连续错误比特。真正重要的是:这些错误最终跨越了多少个不同的RS符号位置。如果跨越了太多符号,仍然会超过纠错能力。

真实CD每层拥有四个冗余符号

前面已经知道:C1=RS(32,28)C_1=RS(32,28)C2=RS(28,24)C_2=RS(28,24)每一层都满足:n−k=4n-k=4因此:dmin⁡=5d_{\min}=5可以保证纠正:2 个未知符号错误\boxed{2\text{ 个未知符号错误}}或者恢复:4 个已知位置擦除\boxed{4\text{ 个已知位置擦除}}如果每个符号都是8位,那么一次符号错误可能对应其中一位、数位甚至全部八位出现差异。这正是符号级纠错与比特级纠错之间的重要区别。

有限域上的加法仍然很简单

在:GF(28)\mathrm{GF}(2^8)中,每个元素可以使用八位二进制数表示。域元素相加,就是按位异或。例如:
text
10110010
和:
text
01101101
相加:
text
11011111
因为:1⊕0=11\oplus0=11⊕1=01\oplus1=0所以:a+b=a⊕b\boxed{a+b=a\oplus b}在这个表示中,有限域加法非常适合数字电路实现。但有限域乘法不能简单地使用普通整数乘法或模256乘法。它需要根据选定的不可约多项式进行约简。例如,经典音频CD使用的相关标准中,有限域构造涉及:x8+x4+x3+x2+1\boxed{x^8+x^4+x^3+x^2+1}对应的二进制多项式表示是:0x11D\boxed{0x11D}这是标准音频CD中的一项具体技术参数。[Compact Disc Digital Audio System Standard]

Python:体验真正的GF(256)乘法

下面,我们只实现有限域的乘法,不构造完整工业级RS编码器。
python

PRIMITIVE_POLY = 0x11D


def gf256_add(a, b):
    """GF(2^8)中的加法就是异或。"""
    return a ^ b


def gf256_mul(a, b):
    """
    GF(2^8)乘法。

    使用不可约多项式:
    x^8 + x^4 + x^3 + x^2 + 1

    对应0x11D。
    """

    result = 0

    for _ in range(8):

        if b & 1:
            result ^= a

        b >>= 1
        a <<= 1

        # 若产生x^8项,使用域多项式约简
        if a & 0x100:
            a ^= PRIMITIVE_POLY

    return result & 0xFF


print("加法示例:")
print(
    hex(gf256_add(0xB2, 0x6D))
)

print("乘法示例:")
print(
    hex(gf256_mul(0xB2, 0x6D))
)

# 有限域中的加法逆元等于自身
assert gf256_add(0xB2, 0xB2) == 0

# 零元素乘任何元素仍然为零
assert gf256_mul(0xB2, 0) == 0

# 单位元乘任何元素保持不变
assert gf256_mul(0xB2, 1) == 0xB2

print("基本有限域运算测试通过")
这段代码展示了一项非常深刻的数学与工程联系。我们并没有使用普通的十进制加减乘除。而是在一个只有256个元素的代数系统中进行运算。但这套运算依然满足域的基本规律。因此,可以用它计算多项式。可以用它求逆元。也可以用它构造具有严格最小距离保证的纠错编码。这说明:现代数字通信里的“数学”,并不是只存在于工程师写论文的黑板上。它还可以被转化为非常具体的异或门、移位寄存器和有限域运算电路。

第十三幕:从深空探测器到二维码——为什么这种编码跨越了完全不同的设备?

到了今天,里德—所罗门码早已不局限于音乐CD。麻省理工学院林肯实验室在回顾其历史贡献时,明确列举了这项技术的重要应用,包括:深空与卫星通信。CD和DVD。二维码。以及数字电视等系统。[MIT Lincoln Laboratory]这看起来有些不可思议。一张音乐光盘。一台航天探测器。一个贴在包装箱上的二维码。它们似乎没有什么共同之处。但从数学角度看,它们都可能面对同一个问题。原始数据经过存储、传输或读取以后,一部分符号可能不再可靠。怎样利用额外冗余,恢复这些数据?

第一项应用:深空通信

假设一台探测器位于距离地球很远的位置。它拍摄了一张照片。然后将照片数据通过无线电发送回地球。信号经过漫长距离传播。到达地球时,可能非常微弱。接收设备必须面对噪声与各种通信限制。因此,航天通信系统需要高度可靠的编码技术。在不同年代的航天任务中,使用过多种纠错码与级联编码方案。例如,某些深空通信系统将卷积码与Reed–Solomon码组合使用,以进一步改善错误控制能力。1988年,Robert J. McEliece 在喷气推进实验室的技术报告中,明确将Reed–Solomon译码与麦哲伦号任务的高速下行遥测系统联系起来。[tda.jpl.nasa.gov]但不能因此认为:所有现代深空探测器都使用完全相同的一套RS编码。不同任务可能采用不同的通信标准和纠错技术。这里最值得记住的,是一种共同的设计原则:当重新发送非常昂贵、信号十分微弱或通信距离巨大时,能够在接收端自动恢复错误,具有非常高的价值。

第二项应用:二维码

现在,想象一张贴在商品外包装上的二维码。它可能沾上灰尘。某个角落可能被磨损。甚至有一部分图案被遮挡。但手机依然可能识别出其中的信息。这是因为二维码系统不仅设计了定位图形,还在数据层加入了纠错编码。二维码的发明者 DENSO WAVE 在官方技术资料中明确指出:二维码使用Reed–Solomon码提供错误恢复能力。常见的QR Code提供四个纠错等级。
纠错等级约可恢复的码字比例
L7%
M15%
Q25%
H30%
这些比例是对纠错码字恢复能力的近似描述,并不是保证任意位置的同等面积被完全涂黑后,二维码仍能正常识别。[DENSO WAVE]为什么要特别区分?因为一张二维码能够被读取,还依赖:定位图形。几何校正。采样。格式信息。以及其他图像处理过程。如果破坏了关键的定位结构,扫描器可能无法正确确定二维码的位置与方向。即使数据区域内部的RS纠错能力尚未耗尽,整个识别过程也可能失败。因此,不能把“纠错等级H约30%”,简单解释成:“无论把二维码哪30%的面积涂黑,它都能恢复。”

第三项应用:数据存储

在某些数字存储介质中,数据并不是一位一位孤立受损的。损坏可能具有连续性。例如:光学存储中的局部读取错误。磁性存储中的某些介质缺陷。或者其他造成连续数据块不可靠的情况。因此,符号级纠错与交织技术,在相关存储系统里具有实际用途。但这里同样需要注意:不同存储设备可能使用不同的ECC方案。不能把“硬盘拥有纠错能力”直接等同于“所有硬盘都使用相同的Reed–Solomon码”。现代设备可能使用更加复杂的组合结构。具体算法应当以对应设备、接口和控制器的技术资料为准。

为什么同一种编码思想能够跨越这么多领域?

因为Reed–Solomon码并不依赖消息必须是音乐。也不依赖数据必须来自一张图片。它只要求我们能够将消息表示为有限域符号。然后利用多项式结构产生具有一定冗余的编码。无论这些符号最终被保存到哪里:光盘。无线电信道。二维条码。还是其他存储介质。只要适用的错误模型与译码条件得到满足,相关代数关系就可以发挥作用。这正是优秀算法的重要特征之一。它并不是为某种单一设备而存在,而是抓住了不同设备背后共同的数学问题。

第十四幕:1997年,两位发明者的名字终于回到了大众视野

1997年7月16日,《WIRED》发表了一篇文章。题目:Code Warriors Fought Errors Byte by Byte中文大意是:《编码战士逐字节对抗错误》。文章采访了已经退休的欧文·里德。那时,Reed–Solomon码早已广泛应用于消费电子设备。CD播放器几乎成为现代家庭音乐设备的代名词之一。DVD也正在兴起。但是,许多普通消费者并不知道:这些设备背后,有两位数学家的名字。

里德的一句玩笑

在采访中,里德谈到科学家与商业产品之间的关系。他以幽默的方式指出,数学家并不容易因为理论成果获得与商业规模相称的财富。采访还谈到:所罗门已经于1996年1月去世。两位发明者虽然获得了专业奖项与同行认可,但在大众市场中并不广为人知。[WIRED]这段历史很值得思考。因为我们经常看到:一项产品取得巨大的商业成功。但支撑产品的基础数学研究,可能早在几十年前就已经完成。而基础研究者也未必能够直接预见其未来的所有应用。

1960年的论文,甚至没有直接面向CD

1960年,里德与所罗门发表论文时:第一台商业CD播放器尚未出现。二维码也尚未发明。很多后来重要的数字通信技术,都还在发展初期。因此,他们并不是专门在研究:如何修复被划伤的音乐光盘?他们面对的是更广泛的数学问题:怎样利用有限域中的多项式,构造能够纠正多个符号错误的编码?当他们找到答案后,这项数学工具就能够被后来的工程师用于各种新设备。这也是本系列一直希望保留的真实科学史结构。发明某项基础算法的人,不一定是后来最著名产品的制造者。

两位研究者的后半生

里德于1963年进入南加州大学任教。在电气工程、计算机科学、雷达信号处理和编码理论等领域继续工作。他于1982年获得IEEE信息论学会香农奖。1989年获得IEEE理查德·汉明奖。1995年与所罗门共同获得IEEE Masaru Ibuka消费电子奖。里德于2012年9月11日在圣莫尼卡去世。美国国家工程院后来在纪念传记中,对其长期贡献作出了详细回顾。[国家科学院]所罗门则于1996年去世。他的工作除了Reed–Solomon码,还涉及其他有限域与编码理论研究。他也以热爱歌剧与音乐活动而闻名。这让两位研究者的经历显得更加鲜明。他们的性格与生活兴趣可能十分不同。但在1950年代末,却共同将一项抽象代数思想转化成了极具实用价值的编码方法。

为什么只用五页,就能够留下这么大的影响?

1960年的论文确实只有五页。这并不意味着它所解决的问题很简单。恰恰相反。它将复杂的错误恢复问题,转化成了一项结构清楚的多项式问题。将数据看成系数。将编码看成求值。将恢复看成插值与错误定位。将可靠性与最小码距联系起来。最后,利用有限域上的代数性质,给出严格的纠错能力。于是,一个具体的技术难题,变成了一项可以反复研究、推广与实现的数学结构。这就是为什么,几十年以后,我们仍然在学习这篇论文。

尾声:一条划痕不能抹去的,不仅是音乐,还有一项数学思想

让我们再回到1982年10月。第一批商业CD播放器开始进入消费者的生活。人们看到了一种新的音乐媒介。它没有传统唱针。不需要磁带。能够通过激光读取光盘上保存的数字音频。但光盘终究是一件物理物品。它会沾上灰尘。可能留下指纹。也可能受到划伤。如果每一次物理损坏,都必然导致数字音乐无法恢复,那么这项技术的实用性就会受到严重限制。因此,工程师必须面对一个问题:怎样让存储介质不完美,却仍然能够尽可能准确地恢复数据?他们使用了复杂的光学与电子技术。设计了适合光盘记录的调制方式。引入了交织。并采用了两级Reed–Solomon编码。其中,数学纠错机制发挥了关键作用。但这套数学思想并不是1982年才出现。二十多年前,林肯实验室的里德与所罗门,就已经开始研究:怎样用多项式表示消息?怎样让多个计算出的函数值,包含恢复原始消息所需要的冗余?以及:如果某些取值被噪声破坏,如何重新找到原来的多项式?

三位研究者,三个不同的数学问题

回顾我们已经完成的三章:
《穿越噪声的信息》· 第46—48章
第46章
1948年 · 香农的信息论证明有噪信道存在可靠通信的理论容量极限,并用信息熵量化消息的不确定性。

第47章
1950年 · 汉明的单错误纠正码通过重叠校验和独特的错误位置标识,使计算机能够定位并纠正单个比特翻转。

第48章
1960年 · 里德—所罗门码利用有限域多项式与插值,将消息扩展为具有最大距离性质的符号码字,从而恢复一定数量的错误与擦除。
这三项研究并不是同一问题的简单重复。香农研究:什么是可靠通信的理论极限?汉明研究:如何设计一种能够自动纠正错误的具体编码?里德与所罗门进一步研究:如何利用代数结构,有效抵抗多个符号受到损坏的情况?它们共同构成了现代错误控制编码发展道路上的重要阶段。

最值得记住的三个公式

第一个公式,是Reed–Solomon编码的核心:P(x)=a0+a1x+⋯+ak−1xk−1\boxed{ P(x)=a_0+a_1x+\cdots+a_{k-1}x^{k-1} }原始数据成为多项式的系数。编码结果则来自多个不同位置的取值。第二个公式,是它的最小码距:dmin⁡=n−k+1\boxed{d_{\min}=n-k+1}它说明,不同合法码字之间至少存在多少个符号差异。第三个公式,则给出错误与擦除的唯一译码保证:2e+s≤n−k\boxed{2e+s\le n-k}其中:ee 是未知位置的符号错误数量。ss 是已知位置的擦除数量。n−kn-k 是冗余符号数量。这个不等式非常值得记住。因为它解释了很多实际系统中的设计选择。为什么检测器要尽可能标记不可信符号?因为已知位置的擦除通常比未知位置错误更容易恢复。为什么交织有用?因为它能够将物理上连续的一段损坏,分散到不同码字中。为什么某条划痕不会立刻毁掉CD音乐?因为经过光学读取、交织和纠错处理之后,损坏仍可能处在可恢复范围内。为什么某些划痕依然会让CD无法播放?因为任何有限长度的编码,都有自己的纠错极限。

数学并没有修复塑料表面

还有一项非常重要的理解。Reed–Solomon码不会让光盘表面的划痕消失。它不能把已经磨损的塑料重新恢复。也不能让激光读取硬件永远不会出错。它做的是:让一份经过特定编码的数据,即使有部分符号无法正确读出,仍然保留足够的代数约束,用于恢复原来的信息。这是一项十分精妙的思想转变。我们不必保证每个物理存储位置都完美无缺。而是可以通过精心设计的信息表示方式,让一定范围内的局部损坏不再必然意味着整份消息丢失。这也是计算机系统可靠性设计中的一个重要原则。硬件故障不可能完全消失。通信噪声也不可能始终为零。但系统可以通过冗余、检测、纠错与合理的恢复策略,提高最终结果的可靠性。

1960年的五页论文,终于进入了千家万户

回望两位发明者。里德长期研究雷达、计算与数字通信。所罗门拥有深厚的数学背景,也热爱音乐和歌剧。他们在林肯实验室合作,将有限域上的多项式变成了新的纠错编码。1959年,论文提交期刊。1960年,正式发表。后来,更多数学家解决了高效译码问题。再后来,工程师将这些算法转化为硬件。1980年,飞利浦与索尼完成了CD纠错技术的关键标准协商。1982年,商业CD播放器进入市场。此时,普通消费者只需要把一张银色圆盘放进机器。按下播放键。便可以听见音乐。他们不需要知道:什么是伽罗瓦域?什么是多项式插值?什么是最小码距?什么是交叉交织?但这并不意味着这些数学知识不重要。恰恰相反。它们已经被隐藏在设备内部,成为让设备正常工作的基础能力。这就是许多经典算法最终走向现实世界的方式。当它成熟到足够可靠时,用户甚至不需要再意识到它的存在。

历史档案:从1959年的论文投稿,到1982年的音乐光盘

年份事件历史意义
1951—1960年Irving Reed在MIT林肯实验室工作研究计算机、雷达、数字通信及纠错编码
1957年前后Reed与Solomon开始合作根据里德后来的采访回忆,两人在这一时期共同发展相关编码思想
1959年1月21日原始论文投稿Reed–Solomon研究成果已形成
1959年8月26日论文完成修订期刊正式发表前的修改
1960年6月Reed与Solomon论文发表提出有限域上的多项式纠错码
1960年代高效代数译码研究持续发展为更实用的RS译码技术奠定基础
1979年8月飞利浦与索尼举行CD标准协商包含纠错与调制方式的技术讨论
1980年6月双方完成关键标准协商采用CIRC与EFM
1982年10月1日索尼CDP-101上市CD技术进入商业消费市场
1995年Reed与Solomon共同获得IEEE Masaru Ibuka奖认可其编码成果对消费电子的重要贡献

主要参考文献与一手资料

1960年 · 原始论文Reed & Solomon — Polynomial Codes Over Certain Finite Fields(完整PDF)最重要的一手文献。原文第300—304页,介绍有限域、多项式取值编码、插值恢复及多符号错误的处理。建议重点阅读论文第一页和第二页。

1960年 · SIAM期刊官方书目SIAM — Polynomial Codes Over Certain Finite Fields用于核查题目、作者、期刊卷期、300—304页,以及1959年投稿与1960年发表的日期。

MIT林肯实验室 · 历史回顾Empowering Digital Communications林肯实验室对Reed–Solomon码发明背景及其在航天通信、CD/DVD和QR码等领域影响的官方回顾。

2014年 · 欧文·里德纪念传记美国国家工程院 — Irving S. Reed由Solomon W. Golomb撰写。用于核查里德的教育、雷达与计算机研究、林肯实验室时期,以及后来的学术贡献和奖项。

2010年 · CD参与者的研发历史Hans B. Peek — The Emergence of the Compact Disc发表于《IEEE Communications Magazine》。记录飞利浦与索尼1979—1980年的标准协商、光盘错误问题、CIRC与EFM的选择过程。

索尼官方 · CD产品历史Sony Group History — Digitizing Music用于核查CD标准研发、采样参数、1982年10月1日CDP-101上市及早期商业化过程。

1988年 · RS译码算法理论Robert J. McEliece — The Decoding of Reed–Solomon CodesNASA/JPL技术报告,统一研究Berlekamp、Berlekamp–Massey、欧几里得算法等多种Reed–Solomon译码方法。

DENSO WAVE官方 · QR Code纠错机制QRcode.com — Error Correction Feature用于核查二维码采用Reed–Solomon码以及L、M、Q、H四个纠错等级的定义和局限。
**史实与教学重构说明:**本章关于1960年论文、1959年投稿日期、林肯实验室背景、1979—1980年CD标准研发及1982年产品上市的叙述,依据上述史料。开篇的光盘划痕场景用于教学,不代表1982年10月1日曾发生一场特定的划痕演示。本章使用 F7\mathbb F_7 构造的 RS(6,3)RS(6,3) 码,是为了方便手算而采用的现代教学实例,并非1960年论文原样给出的示例,也不是标准音频CD的编码参数。互动实验与Python程序同样不构成生产级解码器。所有唯一译码保证都依赖 2e+s≤n−k2e+s\le n-k 等条件。超过能力边界时,译码器可能失败,也可能发生误纠;真实系统还需考虑信道统计、标记可靠性、解码验证和更高层的错误处理。
下一章 · 第49章

《在无数条错误路径中寻找真相:维特比算法的诞生》

1967年,一位研究通信理论的年轻学者发表了一篇论文。他叫安德鲁·维特比(Andrew J. Viterbi)。当时,通信系统需要面对另一类特殊问题。数据不是被划分成一块一块独立编码。而是随着时间不断到来。发送端的编码状态,会随着之前输入的比特发生变化。接收端只看到一条受到噪声干扰的信号序列。它必须判断:这条信号背后,最有可能对应哪一条原始状态路径?如果暴力枚举全部可能路径,候选数量会随着序列长度指数增长。但是,许多不同的路径,可能到达相同的中间状态。能不能只保留到达该状态的最佳候选路径?然后不断向后递推?维特比提出了一项影响深远的动态规划算法。他的1967年论文发表于《IEEE Transactions on Information Theory》第13卷第2期,第260—269页。 [数字对象标识符]下一章,我们将认识维特比算法怎样在网格图(Trellis)中寻找最可能的路径。从卷积码译码出发,逐步推导路径度量、幸存路径、动态规划递推,以及为什么它后来也能够用于隐马尔可夫模型中的最优状态序列推断。里德—所罗门码利用多项式恢复受损符号;维特比算法则将教会我们,在充满噪声的时间序列里,寻找最有可能发生过的那条路径。
——《算法的故事》第二季 · 第48章 完