0. 前言
CRC(Cyclic Redundancy Check,循环冗余校验),是一种数字编码技术,广泛应用于数字通信的传输差错检测,或数字存储的数据完整性检测,最早由W. Wesley Peterson于1961年发表的论文《Cyclic Codes for Error Detection》中提出。
众所周知,CRC校验码需要预先确定一个生成多项式,且该多项式有一个最低要求(条件):最高位和最低位必须是1。Peterson教授的论文和所有的《信息论与编码理论》教材都对此条件有详细解释及证明。
笔者之前在一篇以Peterson教授的论文之理解性翻译的博文中,也直接以结论的方式列出。后来参阅网友文章过程中,时不时会看到一些不是那么完美的解释,也时不时的看到网友在博文评论区询问为什么?有感而作此文。当然,如果你对为什么不感兴趣,那这就是一个规定(或定义)。
文中公式较多,若显示不正常,请刷新重试。
1. CRC校验码咋个都不能简化的原理
要回答或真正理解此问题的答案,是绕不开CRC校验的基本数学原理的,所以,这段内容必须有。
CRC校验的编码是一种线性分组码的编码方法,将待编码的 \(k\) 位二进制序列 \(D[d_{k-1},...,d_{0}]\) 看作 \(GF(2)\) 域多项式 \(D(x)\) 的系数,将 \(D(x)\) 乘以 \(x^r\)(对二进制序列而言,即左移 \(r\) 位并右侧补0)后得到一个新的多项式 \(x^rD(x)\),将其除以一个预先选定的 \(r\) 次生成多项式 \(G(x)\),将得到一个次数小于 \(r\) 的余式 \(S(x)\),求余过程中得到的次数 \(\leq k-1\) 的商式 \(Q(x)\) 未使用。此过程的数学描述为:
\[ x^{r}D(x)=Q(x)G(x)+S(x) \]
求出余式 \(S(x)\) 后,将其系数对应的 \(r\) 位二进制序列 \(S[s_{r-1},...,s_{0}]\) 附加于原信息位之后,即获得编码完成的 \( n = k + r \) 位待发送码字 \(M[d_{k-1},...,d_{0},s_{r-1},...,s_{0}]\),这一过程的数学描述为:
\[ M(x)=x^{r}D(x)+S(x) \]
对于 \(GF(2)\) 域的多项式,其系数的加、减定义为模二加、减,依模二算术的定义,模二减和模二加是相同的操作,故上式可写为:
\[ M(x)=x^{r}D(x)-S(x)=Q(x)G(x) \]
可以看到,CRC校验编码完成的码字有两个显著特点:
-
信息位原样不变的出现在编码后码字的高 \(k\) 位,意味着接收端不需要任何的信息恢复译码电路;
-
\(2^k\) 个许用码字,其码多项式 \(M(x)\) 都是生成多项式 \(G(x)\) 的倍式,自然可以被相同的 \(G(x)\) 整除(余式为0)。接收方可以此方法判断收到的消息是否出错:整除(余数为0)认为无错;余数不为0认为有错。当然,也有设计是在接收方只对信息位进行相同的校验码计算,并与收到的校验位比较是否一致来判断是否出错。
2. CRC校验码生成多项式的最高位和最低位为什么必须是1
2.1 生成多项式的最高位为什么必须是1?
答案就在问题中!这是多项式的定义。考虑到CRC校验中的多项式是在有限域定义的,引用文献2的截图:
看到了吗,就是“叫作”、“规定”。多项式最高的(系数)非零项的幂次,叫作它的次数。这与我们中学所学的多项式阶次的定义是一样的。在一个多项式的非零最高次项的前面,无论我们再写多少幂次更高但系数为零的项,都不影响该多项式参与运算的结果,而这样写下去,有无穷多个运算性质相同的多项式,只会造成沟通不畅,于是,人们就给多项式规定了一个次数。
因为CRC校验生成多项式的系数是\( GF(2) \)有限域的,只有0和1两个取值可能,最高次系数不允许是0(否则多项式的次数变了,是另一个多项式了),那就只能是1了!谜底就在谜面!
2.2 生成多项式的最低位为什么必须是1?
这个需要再看看前文关于CRC编码的原理:依据CRC的编码原理编码所得的码字\( M(x) \),一定是其生成多项式\( G(x) \)的倍式!
同时,我们还需要澄清一个概念,通常人们(包括本文)说CRC生成多项式最低位时特指多项式的常数(或零次)项。
那我们假设最低位、甚至最低几位都为零,看看编码出来的码字有什么现象?比如最低\( a \)位为0,则\( G(x)= x^aG'(x) \),其中\( G'(x) \)是一个最低位为1的多项式。用\( G(x) \)生成的CRC校验码的码字将满足:
\[M(x)=Q(x)G(x)=x^a Q(x)G'(x) = \color{red}{ x^a M'(x) } \]
上式的数学意义是:用\( G'(x) \)对原信息码编码得到\( M'(x) \),然后把\( M'(x) \)左移\( a \)位,右侧补\( a \)个0!
如果我们选定的CRC校验码生成多项式的最低位有几个0,那么我们编码出来的码字,最低位就始终有固定的几个0,而这几个固定的0不传输任何有用信息,也不能进行差错检测,唯一的作用就是浪费我们几位传输位时或存储空间!(备注:Peterson教授论文\( ^{[1]} \)中即如此解释。)
CRC校验生成多项式:首一(是定义)、尾一(是避免浪费)!当然,实际还隐含一个要求,首尾不同位,就是你不能用常数1(\( x^0 \))或者\( x^i \)作为生成多项式,非要用的结果就是没有余数,没有校验码,输入啥子信息就发啥子信息出去,没附加任何校验位(或者愣补几个常数0)。
以CRC-8/MAXIM的生成多项式\( G(x) = x^8 + x^5 + x^4 + 1 \)为例,如果我们将其“首一尾一”改成0,然后还是规定我们这个是CRC-8,那么我们提供的生成多项式 是:
\[ G'(x) = 0 \cdot x^8 + x^5 + x^4 + 0, POL=0b000110000 \]
我们用这个\( (x^5 + x^4)=x^4(x+1) \)的多项式,按照CRC校验的编码方法,能正确实现编码,只不过我们最后用8位校验码,得到的是CRC-1(单比特偶校验码)的性能,余式可写为:
\[S(x)=0\cdot x^7 + 0\cdot x^6 + 0\cdot x^5 + s_4 \cdot x^4 + 0\cdot x^3 + 0\cdot x^2 + 0\cdot x^1 + 0\cdot x^0\]
我们虽然规定校验位是8位的,但实际只有比特4这一位是有效的。无论待校验数据怎么变化,其余的7个比特保持0不变,是无效的校验比特!为获得更直观的感受,我们给定一个待校验数据0b1101,用去掉了“首一尾一”约束条件的多项式POL = 0b000110000,硬性规定为8个校验位,基于长除法实现发送端编码和接收端检错译码的结果如下图:
可以看到,我们能实现正确的编解码计算,校验码仅比特4的值为1,是待校验数据0b1101的偶校验。待校验数据中1的个数为偶数时,按分析,获得的校验码为全0。待校验数据0b1001、0b1010的计算过程和结果如下图(其它数据,请读者自行验算):
违背CRC校验码生成多项式“首一尾一”的约束条件,会导致有效校验位数减小,进一步可能导致实际的差错检测性能下降:
- CRC-8/MAXIM去掉“首一”的约束,性能退化为CRC-5(\( G(x)=x^5 + x^4 +1 \)),硬规定校验位长度为8,则高3位保持0不变(无效);
- CRC-8/MAXIM去掉“尾一”的约束,性能退化为CRC-4/ITU(\( G(x)=x^4 + x +1 \)),硬规定校验位长度为8,则低4位保持0不变(无效)。
2.3 CRC校验码与循环码的关系
循环码属于线性分组码,循环码有着看似随意但事实上严格的定义\( ^{[3][4]} \):
若\( (n,k) \)线性分组码中任意码字为\( C=(c_{n-1},c_{n-2},\cdots ,c_{1},c_{0}) \),将码字\( C \)中的码元向右或向左移动一位后得到码字\( C=(c_{0},c_{n-1},c_{n-2},\cdots ,c_{1}) \)或\( C=(c_{n-2},\cdots ,c_{1},c_{0},c_{n-1}) \)仍是\( (n,k) \)的一个码字,则称此\( (n,k) \)码为循环码。
依循环码的定义可知,它的一个码字的任意多次循环移位仍是它的码字。
一个\( (n,k) \)循环码可由一个\( (n-k) \)次,常数项不为0的生成多项式\( G(x) \)构造,而且\( G(x) \)还必须是\( (x^n - 1) \)的因式。因为\( (x^n - 1) \)并不一定具有\( (n-k) \)次的因式,所以,我们并不能构造\( n \) 、\( k \)任意取值的循环码,事实上\( ^{[3]} \),大多数的\( (n,k) \)线性分组码并不是循环码。
我们要正向设计一个\( (n,k) \)循环码的方法就是:
-
(查表或利用工具软件)对\( (x^n - 1) \)因式分解,选取次数为\( (n-k) \)的因式作为生成多项式\( G(x) \),若找不到,我们就只有增加码长\( n \)(或者说增加校验位长度\( r \),通常来说,信息位长度\( k \)是不允许减小的),直到找到满足要求的\( G(x) \);
-
与CRC校验码相同的编码方法实现\( 2^k \)个码字的编码。
从循环码定义及构造的角度来看,生成多项式“首一尾一”是构造循环码的必要条件!(证明过程请参考《信息论与编码理论》教材)
仔细思考循环码定义和生成多项式之间的关系,不难发现,严格意义的循环码不但数量不多,尤其值得注意的是,生成多项式一选定,则码字长度\( n \)(也即信息位长度\( k \))不能变化。
我们实际应用中大多数通讯协议的信息位长度\( k \)都会在一个相当大的范围内变化,而生成多项式\( G(x) \)保持不变,所以,我们实际用到或实现的CRC校验码大都不是严格意义的循环码。当然,除了搞起耍的,正规通讯协议的\( G(x) \)都确保了“首一尾一”的最低原则,一般还会以协议允许的最大信息位长度,采用蒙特卡洛仿真或重量枚举的方法,参考目标信道典型误比特率,完成对选用\( G(x) \)的漏检概率分析。
3. 总结
本文从编码效率、实际检错性能、循环码原理等三个方面研究了CRC校验码生成多项式的约束条件,可总结为一句话:“首一尾一,且首尾不同位”。或者:“次数大于等于1,且常数项为1”。
生成多项式“首一尾一”的条件与严格意义的循环码之间有着定义级别的数学约束关系,意味着约束条件的违背会导致生成的码字在循环码定义层面的失效。
CRC校验码是循环码在工程中的具象应用,实施(实现)过程中通常因码字长度的灵活性而在事实上违背循环码的严格定义,因此本文讨论生成多项式“首一尾一”约束条件对CRC校验码实现时的影响主要从两个方面切入:
- 违背约束条件不会导致CRC编码和检错译码的计算方法失效;
- 违背约束条件会导致有效校验位数减少,导致编码效率降低,进一步大概率会降低检错性能。
备注:
- 未特别说明的情况下,本文描述的编码特指二进制编码;
- 笔者阅读的多本《信息论与编码理论》教材中,有两本以“对码组中的码字循环移动多位(i)所得的码字仍是码组中码字”这一特性来定义循环码。但这两本教材后续讲解循环码的构造,或循环码与生成多项式间的关系时,仍然是\( (x^n - 1) \)的一个\( (n - k) \)次且常数项为1的因式是\( (n,k) \)循环码的生成多项式\( G(x) \),而满足此条件的\( G(x) \)与“码组中的码字循环一位所得码字仍是码组中码字”这一循环特性一一对应,即二者互为充要条件。满足“循环一位所得码字仍是有效码字”的循环码,可简单递推得到“循环移位多位(i)仍为有效码字”的一般特性。因此,笔者建议读者将“一位循环移位的特性”作为循环码的严格定义,“多位循环移位特性”作为定义的推论而不是定义本身。
- 至于多本《计算机组成原理》教材将“CRC校验码的余数循环现象”作为循环码的定义,笔者建议按照《信息论与编码理论》教材的定义来理解循环码。毕竟:《计算机组成原理》仅将CRC校验码作为一个应用手段的小知识点,而循环码可是作为《信息论与编码理论》的一个重点理论研究来讨论。更重要的是,世界公认的CRC校验码的发明(提出)者W. Wesley Peterson教授在其论文《Cyclic Codes for Error Detection》中,明确阐明了和《信息论与编码理论》教材中一致的循环码定义。
4. 参考
- W. W. Peterson and D. T. Brown, "Cyclic Codes for Error Detection," in Proceedings of the IRE, vol. 49, no. 1, pp. 228-235, Jan. 1961.
- 冯克勤. 纠错码的代数理论[M]. 北京: 清华大学出版社, 2005.
- Robert J.McEliece. 信息论与编码理论[M]. 第2版. 北京:电子工业出版社, 2004.
- 傅祖芸. 信息论—基础理论与应用[M]. 第4版. 北京: 电子工业出版社, 2015.