奇偶校验与海明码

数据是由一堆 01 串组成的. 要看这些 01 串在传输过程中有没有出现错误, 最简单的方法就是比较一下接收到的数据和发送的数据是否相同. 但是, 接收数据的人怎么知道发送的 “正确数据” 是多少呢? 所以这就很有意思了.

注意
这里的 “传输” 范围较广. 把数据存储进某一个地方, 然后再读取出来, 也算一种 “传输”. 而不仅限于 “使用互联网传输”.

数据在传输的过程中, 出错的数据一般来说比较少, 1 位以上出错的概率很低. 数据是 01 串, 如果一位出错, 那么发生错误之后, 1 或者 0 的数量的奇偶性将会改变. 检查数据的奇偶性, 就是 奇偶校验Parity Check 的思想.

奇偶校验的原理是, 事先约定好, 信息数据中 1 的个数一定是奇数. 如果这个数据的 1 的个数是偶数, 那就在数据开头加上一个 1. 如果本身就是奇数, 那就在开头加一个 0, 保持奇偶性不变. 偶校验就是在数据前加一个数 (也有可能是后? 无所谓, 估计考试加在哪会事先说, 不然没法做), 使得数据中 1 的个数为偶数. 加的这个数称为 校验位.

把数据分行, 然后垂直做奇偶校验.

数据
  10100101001101101100110010101011

按 8 位分行
  10100101
  00110110
  11001100
  10101011

垂直做奇校验
  00001011

再加个水平校验码

数据
  10100101001101101100110010101011

按 8 位分行, 前加上水平校验码
  1 10100101
  1 00110110
  1 11001100
  0 10101011

垂直做奇校验, 前加上水平校验码 (或者垂直也是一样的, 反正都是总和)
  0 00001011

奇偶校验只能检测出 (一位) 数据错误, 不知道哪一位发生错误, 无法纠正错误.

两个数据不同的位数叫码距. 一组合法的编码, 两两之间比较, 有 $\binom n m$ 个码距, 其中最小的一个叫最小码距.

直觉告诉我们, 添加更多的校验信息 (校验码的位数), 可以做到检测更多位数的数据错误, 甚至知道哪一位发生错误.

纠错原理说的就是, 最小码距越大, 检错能力和纠错能力就越强. 有一个公式:

$$L - 1 = D + C, D \ge C$$

$L$ 是最小码距, $D$ 是检错位数, $C$ 是纠错位数.

不会证明.

拿个例子感性理解一下, 1100, 1111, 0011, 0000 这组编码的最小码距 $L = 2$. 在传输的过程中, 如果接收到了这样的数据 1110, 那么它肯定发生了错误. 但是不知道是哪一位发生了错误 (有可能是 1111 的第 0 位错了, 也可能是 1100 的第 1 位错了). 同样, 如果接收到了 0010, 也只能知道发生了一位错误, 不能纠正. 通过枚举不难发现, 任何一个数据, 有且仅有某一位出错, 我一定知道, 但是完全无法知道是哪一位. 于是 $D = 1, C = 0$. $D = 2$. $L - 1 = D + C, D \ge C$ 成立.

如果只有 11110000 这样的编码, 最小码距 $L = 4$. 当接收到了 1110 这样的数据, 不仅能知道发生了一位错误, 还能纠正这一位错误. (当然如果是 0000 高 3 位出错那就无法检验了). 但是两位发生错误, 比如 0011, 只能检测, 并不能够纠正. 所以, $C = 1$. 而发生 3 位错误压根就检测不出来, 故 $D = 2$. $L - 1 = D + C, D \ge C$ 成立.

不懂纠错原理也没关系, 一开始压根就不想写, 看到作业里有一个题才写的.

海明码是根据纠错原理, 在数据中巧妙地添加若干个校验位 (合起来称为校验码), 使得 $L$ 变大, 从而提高检错和纠错的能力. 校验码应对数据的变化比较敏感, 才能够增大最小码距. (有点文件哈希校验的味道了哈哈.)

为了使编码具有 1 位纠错的能力, 可以这样考虑一下: 首先在原来 $n$ 位数据中加 $k$ 位校验码, 总共 $n + k$ 位的数据, 一共有 $n + k$ 种 1 位出错情况, 加上一种不出错情况, 一共是 $n + k + 1$ 种情况. 这些情况都要能够与校验码做一个映射 (不一定要一一对应, 但情况要映射到唯一的校验码). $k$ 位校验码能够储存的信息是 $2^k$. 所以就有如下关系式:

$$2^k \ge n + k + 1$$

下面说明具体如何做这个映射.

首先校验码第 $k$ 位应该插入数据的 $2^k$ 位置. 例如校验码为 $H_3H_2H_1H_0$, 数据为 $D_4D_3D_2D_1D_0$, 那么合起来传输的数据应该为:

$$\begin{array}{ccccccccc} D_4 & H_3 & D_3 & D_2 & D_1 & H_2 & D_0 & H_1 & H_0 \\ 9 & 8 & 7 & 6 & 5 & 4 & 3 & 2 & 1 \\ \color{yellow}1\color{none}00\color{red}1 & \color{yellow}1\color{none}000 & 0\color{green}1\color{#6495ED}1\color{red}1 & 0\color{green}1\color{#6495ED}1\color{none}0 & 0\color{green}1\color{none}0\color{red}1 & 0\color{green}1\color{none}00 & 00\color{#6495ED}1\color{red}1 & 00\color{#6495ED}1\color{none}0 & 000\color{red}1 \end{array}$$

表中第一行是传输的数据, 第二行是数据的下标, 第三行是下标的二进制表示.

信息
这里的数据位置从 1 开始. 像树状数组那样, 二者都是通过下标的二进制表示来达到某些效果.

如上图所示, $H_0$ 的下标为 $(0001)_2$, 它负责检测下标形如 $\texttt{xxx}1$ 的数据有没有出现错误. 上表红色标记的地方, 就是它负责校验的数据. 有 $H_0$, $D_0$, $D_1$, $D_3$, $D_4$. 校验的方法采用 偶校验. 即 $H_0$ 的取值要使得表达式 $H_0 \oplus D_0 \oplus D_1 \oplus D_3 \oplus D_4 = 0$ 成立. 换句话说, $H_0 = D_0 \oplus D_1 \oplus D_3 \oplus D_4$. 同理, $H_1$ 负责校验的数据在表中用蓝色标出, $H_2$ 负责校验的数据用绿色标出, $H_3$ 负责的数据用黄色标出.

形式化地,

$$H_k = \bigoplus_{i \wedge k = k, i \ne k} Q_i$$

其中, $Q$ 是插入了校验码的数据.

比如有数据 $D = 01011$, 那么 $Q = 0H_3101H_21H_1H_0$. 根据上述公式 (其实算的时候得手拆二进制, 毕竟人不是计算机), 得 $H_0 = 1$, $H_1 = 0$, $H_2 = 0$ $H_3 = 0$, 校验码 $H = 0001$, 传输的数据 $Q = 001010101$.

接收到数据后, 对所有 $H_k$ 负责的数据进行偶校验, 如果校验失败, 即出现了 1, 则说明数据出现错误. 比如, 上述数据在传输的过程中, $Q_9(D_4)$ 出现了错误, 那么 $\bigoplus\limits_{i \wedge (1000)_2 = (1000)_2} Q_i = 1$ ($H_3$ 负责校验的位), 且 $\bigoplus\limits_{i \wedge (0001)_2 = (0001)_2} Q_i = 1$ ($H_0$ 负责校验的位).

为方便表示, 设 $P_k$ 为校验位所负责的位数据的异或和. 即:

$$P_k = \bigoplus_{i \wedge k = k} Q_i$$

这个等式在书上被称为校验方程 (西电的书, 不知道是不是自己造的概念).

如果数据不出错 (不考虑一位以上的错误), 则 $P_k = 0$. 如果出错, 则至少有一个 $P_k = 1$.

很容易发现, 一个数据位被多个校验位负责校验. 仔细观察还可以得知, 该位下标二进制表示下的 1 分别被不同的校验位负责. 于是, 如果某一位出错, 通过判断校验信息, 就能立即知道是哪一位出错, 然后纠正 (取反). 比如 $P_3 = 1$, $P_0 = 1$, 其他都为 $0$, 那么就是 $Q_9$ 出错 ($9 = (1001)_2$). 更一般地, 二进制数 $P = P_3P_2P_1P_0$ 如果不为 $0$, 那 $P$ 就是出错的数据位置, 即 $Q_P$ 出错. ($P = 0$ 当然就是没有出错啦.)

所以, 海明码具有 一位纠错 能力.

从上面可以看到, 海明码具有 一位检错 + 一位纠错 能力, 即 $D = C = 1$.

下面来证明一下海明码的最小码距 $L = 3$.

证明
任意给一个数据 $D$, 在其中下标为 $2^k$ 的位置插入了 $H_k$, 占据了所有二进制表示下只有一个 1 的下标的位置. 于是任意一个 $Q_i = D_k$ 的位置 $i$ 的二进制表示下 1 的个数大于 $1$. 那么, 任取一个合法的编码, 改变其中的一位 $D_k$, 至少有三位 $Q$ 会被改变, 其中一个是 $D_k$, 其余是相应的校验位. 所以最小码距 $L = 3$

由纠错原理, $L - 1 = D + C$, 即 $3 - 1 = 1 + 1$ 成立.

拓展
若要使海明码具有两位检错能力, 则可以对 $Q$ 加上一个奇偶校验码, 这样和上面的证明过程类似, 改变一个 $D_k$, 至少会改变编码的 4 位 (原先的 3 位加上新加入奇/偶校验码), 由纠错原理得检错位数为 2.