前言:海明编码这一块在刚开始的时候没有弄懂,后面通过做实验、复习慢慢摸清了门道。在学习计算机组成原理的过程中,实验实践是很重要的,它会让你去搞清楚事情背后的原理,逼着你学会你没听懂的东西。这篇文章会从海明码的理论部分和实验部分进行阐述。
海明码
奇偶校验码
为什么要谈到奇偶校验码呢?因为它和海明码一样,都属于校验码。所谓校验码,就是数据位和校验位的合并,通过校验位的信息,你能知道数据是不是出错了,哪里出错了,它本应是多少。
注:后文均用 k k k 表示原式数据位数, r r r 表示校验位位数(也同时是校验组的组数), n n n 表示校验码(数据位 + 校验位)的总位数。
正如上图所示,校验码主要是用于数据发送方和接收方通信用的,通过校验位可以检查传过来的数据是否准确。
偶校验码通过设置
r
=
1
r=1
r=1 位校验位
P
P
P,使得校验码
P
D
k
⋯
D
2
D
1
PD_k\cdots D_2D_1
PDk⋯D2D1 所有位共有偶数个
1
1
1。计算公式是
P
=
D
1
⊕
D
2
⊕
⋯
⊕
D
k
(1)
P=D_1\oplus D_2\oplus\cdots\oplus D_k\tag 1
P=D1⊕D2⊕⋯⊕Dk(1)
比如发送方需要传输
k
=
5
k=5
k=5 位数据
11001
11001
11001,会生成一位校验位
1
1
1,打包成校验码
1
11001
\red{1}11001
111001 送给接收方。如果传输过程没有发生错误,接收方收到的就是
111001
111001
111001,看一下有
1
1
1 的个数是偶数,应该是没问题。如果传输过程中有一位出错了,比如
111001
→
11
0
001
111001\rightarrow 11\red 0001
111001→110001,接收方收到的数据就有奇数个
1
1
1,所以就能够判断传过来的数据出错了(但是不能分辨是哪一位错了)。
奇偶校验码的缺点也是显而易见的,对偶校验码来说,如果传输过程中出现了
2
2
2 位错误,接收方就会认为是正确的,这说明奇偶校验码最多检错
1
1
1 位。
码距
定长编码中任意两个合法编码最少有多少位不同,这个编码的码距就是多少。比如上面的奇偶校验码码距就是 2 2 2。海明码的码距是 3 3 3。
海明码
有多种类型的海明码校验,这里只介绍能纠一位错的海明码。
多校验组
前面提到,奇偶校验码可以检测
1
1
1 位错,但是不具备纠错能力。并且所有数据位于
1
1
1 个校验组中,即
r
=
1
r=1
r=1。
海明码在
k
k
k 位数据位中插入
r
r
r 个校验位,使得每个数据至少位于
2
2
2 个校验组中(为什么?后面会解释)。也就意味着对于某个
D
s
D_s
Ds 而言,它至少要参与
P
i
P_i
Pi 和
P
j
(
i
≠
j
)
P_j(i\neq j)
Pj(i=j) 的生成。同样的,
P
i
P_i
Pi 是由某一些数据位异或得到的,
P
i
P_i
Pi 和这些数据位共同构成
1
1
1 个校验组(偶校验组)。
P
i
=
D
i
1
⊕
D
i
2
⊕
⋯
⊕
D
i
t
(2)
P_i=D_{i1}\oplus D_{i2}\oplus \cdots\oplus D_{it}\tag 2
Pi=Di1⊕Di2⊕⋯⊕Dit(2)
式 ( 2 ) (2) (2) 描述了第二个第 i i i 个校验位的生成。
省流:每个校验组都是由一个 P P P 和若干 D D D 构成的, P P P 是这些 D D D 的异或结果。
接收方会生成一种叫检错码的东西,每个校验位生成
1
1
1 个检错码,所以一共有
r
r
r 个检错码,用
G
i
(
i
=
1
,
2
,
⋯
,
r
)
G_{i}(i=1,2,\cdots,r)
Gi(i=1,2,⋯,r) 来表示。 接收方会干这样的事情:
G
i
=
P
i
′
⊕
D
i
1
′
⊕
D
i
2
′
⊕
⋯
⊕
D
i
t
′
(3)
G_i=P_i'\oplus D_{i1}'\oplus D_{i2}'\oplus\cdots\oplus D_{it}'\tag 3
Gi=Pi′⊕Di1′⊕Di2′⊕⋯⊕Dit′(3)
其中加一个 ′ ' ′ 表示数据传输后的结果,比如发送方的 D 4 D_4 D4 在接收方变成了 D 4 ′ D_4' D4′。
注意 G i G_i Gi(检错码) 和 P i P_i Pi (校验码)是不同的东西, P i P_i Pi 是发送方根据 D D D 生成的; G i G_i Gi 是接收方根据 P i ′ P_i' Pi′ 和 D ′ D' D′ 生成的,用于检错。海明码的实现中结合了偶校验的思想。
显然,如果接收方发现 G i = 1 G_i=1 Gi=1,就说明第 i i i 个校验组有数据出错了。但是到底是谁出错了?是 P i P_i Pi 还是对应的 D i t D_{it} Dit 呢?
海明码原理
海明码致力于制定一套规则回答上面的问题。它将
k
k
k 个数据位
D
D
D 和
r
r
r 个校验位
P
P
P 以某种方式组合成
n
n
n 位校验码
H
H
H,以某种方式划分校验组,以期达到这样的目标:
G
r
⋯
G
1
G_r\cdots G_1
Gr⋯G1 直接指示出错的位置。比如
G
3
G
2
G
1
=
011
G_3G_2G_1=011
G3G2G1=011,代表海明码的
H
3
H_3
H3 出错了。其中,预留
G
3
G
2
G
1
=
000
G_3G_2G_1=000
G3G2G1=000 代表没有错误。
因此,对于海明码
n
=
k
+
r
n=k+r
n=k+r 位来说,
1
1
1 位错一共有
k
+
r
k+r
k+r 种可能,但是
G
r
⋯
G
1
G_r\cdots G_1
Gr⋯G1 只能指示
2
r
−
1
2^r-1
2r−1 种错误。所以应该有:
k
+
r
≤
2
r
−
1
(4)
k+r\leq 2^r-1\tag4
k+r≤2r−1(4)
并且,由于海明码要实现纠错功能,码距就不能是 2 2 2,至少要是 3 3 3,否则就会像奇偶校验码一样只能检错、不能纠错。为了减少冗余,海明码的码距设定为 3 3 3。这就意味着每个数据位 D s D_s Ds 至少要出现在 2 2 2 个校验组中。
假设数据位 D s D_s Ds 只出现在校验组 P i P_i Pi 中。当 D s = 0 D_s=0 Ds=0 时,记 P i = k P_i=k Pi=k,得到的海明码是 H \boldsymbol H H;当 D s = 1 D_s=1 Ds=1 时,根据异或的性质,有 P i = k ‾ P_i=\overline k Pi=k,得到的海明码是 H ′ \boldsymbol {H'} H′。你会发现 H \boldsymbol H H 和 H ′ \boldsymbol{H'} H′ 只有 D s D_s Ds 和 P i P_i Pi 两位是不一样的,那么海明码的码距就是 2 2 2。但是我们海明码的码距是 3 3 3,所以 D s D_s Ds 只出现在一个校验组是不够的。
现在我们来看海明码是怎么编码的。假设
r
=
3
r=3
r=3 的海明码,检错位是
G
3
G
2
G
1
=
001
G_3G_2G_1=001
G3G2G1=001——这说明只有校验组
1
1
1 出错了。那可能是生成
P
1
P_1
P1 的那些
D
D
D 出错了吗?不可能,因为一旦
D
D
D 出错,
G
3
G
2
G
1
G_3G_2G_1
G3G2G1 就至少有两个
1
1
1(至少两个校验组出错)了,因为每个数据位都至少要出现在
2
2
2 个校验组中。
所以,对于
G
3
G
2
G
1
G_3G_2G_1
G3G2G1 只有一位
1
1
1 的情况,只能是校验组所对应的检错位出错了。
那么
G
3
G
2
G
1
=
001
/
010
/
100
G_3G_2G_1=001/010/100
G3G2G1=001/010/100 分别对应检错位
P
1
,
P
2
,
P
3
P_1,P_2,P_3
P1,P2,P3 出错,根据海明码的目标“
G
r
⋯
G
1
G_r\cdots G_1
Gr⋯G1 直接指示出错的位置”,应该把
P
1
P_1
P1 放在
H
1
H_1
H1,
P
2
P_2
P2 放在
H
2
H_2
H2,
P
3
P_3
P3 放在
H
4
H_4
H4。且看下面的表格:
海明码 | H 1 H_1 H1 | H 2 H_2 H2 | H 3 H_3 H3 | H 4 H_4 H4 | H 5 H_5 H5 | H 6 H_6 H6 | H 7 H_7 H7 |
---|---|---|---|---|---|---|---|
检错码/位置 G 3 G 2 G 1 G_3G_2G_1 G3G2G1 | 001 001 001 | 010 010 010 | 011 011 011 | 100 100 100 | 101 101 101 | 110 110 110 | 111 111 111 |
映射关系 (这一位 H H H 放什么) | P 1 P_1 P1 | P 2 P_2 P2 | D 1 D_1 D1 | P 3 P_3 P3 | D 2 D_2 D2 | D 3 D_3 D3 | D 4 D_4 D4 |
属于 G 1 G_1 G1 校验组 | √ | √ | √ | √ | |||
属于 G 2 G_2 G2 校验组 | √ | √ | √ | √ | |||
属于 G 3 G_3 G3 校验组 | √ | √ | √ | √ |
这个表格是对应海明码在
(
n
,
k
)
=
(
7
,
4
)
(n,k)=(7,4)
(n,k)=(7,4) 时的分组规则。预留了
G
3
G
2
G
1
=
000
G_3G_2G_1=000
G3G2G1=000 ,对应海明码没有出错。其实上面
D
D
D 的位置是可以随便放的,这个只影响后面校验位
P
P
P 的生成表达式。按照上面的
D
D
D 的放置方式,有:
{
P
1
=
D
1
⊕
D
2
⊕
D
4
P
2
=
D
1
⊕
D
3
⊕
D
4
P
3
=
D
2
⊕
D
3
⊕
D
4
(5)
\begin{cases}P_1=D_1\oplus D_2\oplus D_4\\P_2=D_1\oplus D_3\oplus D_4\\P_3=D_2\oplus D_3\oplus D_4\end{cases}\tag 5
⎩
⎨
⎧P1=D1⊕D2⊕D4P2=D1⊕D3⊕D4P3=D2⊕D3⊕D4(5)
式
(
5
)
(5)
(5) 是发送方要干的事情。给发送方一个
D
4
D
3
D
2
D
1
D_4D_3D_2D_1
D4D3D2D1,发送方需要按照
(
5
)
(5)
(5) 生成
P
3
P
2
P
1
P_3P_2P_1
P3P2P1,然后打包成
H
7
H
6
H
5
H
4
H
3
H
2
H
1
=
D
4
D
3
D
2
P
3
D
1
P
2
P
1
H_7H_6H_5H_4H_3H_2H_1=D_4D_3D_2P_3D_1P_2P_1
H7H6H5H4H3H2H1=D4D3D2P3D1P2P1,发送给接收方。
根据式
(
2
)
(
3
)
(2)(3)
(2)(3),接收方需要按照下面的方式生成检错位:
{
G
1
=
P
1
′
⊕
D
1
′
⊕
D
2
′
⊕
D
4
′
G
2
=
P
2
′
⊕
D
1
′
⊕
D
3
′
⊕
D
4
′
G
3
=
P
3
′
⊕
D
2
′
⊕
D
3
′
⊕
D
4
′
(6)
\begin{cases}G_1=P_1'\oplus D_1'\oplus D_2'\oplus D_4'\\ G_2=P_2'\oplus D_1'\oplus D_3'\oplus D_4'\\ G_3=P_3'\oplus D_2'\oplus D_3'\oplus D_4'\end{cases}\tag 6
⎩
⎨
⎧G1=P1′⊕D1′⊕D2′⊕D4′G2=P2′⊕D1′⊕D3′⊕D4′G3=P3′⊕D2′⊕D3′⊕D4′(6)
根据生成的 G 3 G 2 G 1 G_3G_2G_1 G3G2G1,接收方能够判断有没有出错,是谁出错了。
海明码的检错与纠错
海明码的检错、纠错能力是有限的。由于码距是 3 3 3,因此它最多能够检测 2 2 2 位错;但是它不能区分 1 1 1 位错和 2 2 2 位错。同时,它只能够纠正 1 1 1 位错。
检测 2 2 2 位错的含义是,编码在传输过程中有 2 2 2 位出错,接收方拿到之后能够识别到异常;而不是接收方拿到数据,说我发现你发送过来的数据里面有 2 2 2 位错。
举个例子,数据传输过程中 D 1 D_1 D1 出错,接收方得到的是 G 3 G 2 G 1 = 011 G_3G_2G_1=011 G3G2G1=011;但是如果 D 2 , D 3 D_2,D_3 D2,D3 同时出错,那么接收方得到的还是 G 3 G 2 G 1 = 011 G_3G_2G_1=011 G3G2G1=011。所以只有在假定最多发生 1 1 1 位错的前提条件下,海明码才能够正确地检错并纠错。
拓展海明码
前面说了海明码不能区分
1
1
1 位错和
2
2
2 位错。如果再引入一个总偶校验位
P
a
l
l
P_{all}
Pall,就能够分辨一位错和两位错。
P
a
l
l
=
H
n
⊕
⋯
⊕
H
2
⊕
H
1
(7)
P_{all}=H_n\oplus \cdots\oplus H_2\oplus H_1\tag7
Pall=Hn⊕⋯⊕H2⊕H1(7)
G
a
l
l
=
P
a
l
l
′
⊕
H
n
′
⊕
⋯
⊕
H
2
′
⊕
H
1
′
(8)
G_{all}=P_{all}'\oplus H_n'\oplus \cdots\oplus H_2'\oplus H_1'\tag8
Gall=Pall′⊕Hn′⊕⋯⊕H2′⊕H1′(8)
( 7 ) (7) (7) 是发送方做的事情, ( 8 ) (8) (8) 是接收方做的事情。假设没有 3 3 3 位错,接收方在发现 G 3 G 2 G 1 ≠ 000 G_3G_2G_1\neq 000 G3G2G1=000 即有错的条件下,可利用 G a l l G_{all} Gall 判断是一位错 ( G a l l = 1 ) (G_{all}=1) (Gall=1) 还是两位错 ( G a l l = 0 ) (G_{all}=0) (Gall=0)。
海明码实验
海明编码
实际上就是填写分组规则表,像前文的那个表格一样。这里原始数据有
k
=
16
k=16
k=16 位,检错位有
r
=
5
r=5
r=5 位加上
1
1
1 位
P
a
l
l
(
P
6
)
P_{all}(P_6)
Pall(P6)。
P
1
P_1
P1~
P
5
P_5
P5 的线路连接参考式
(
2
)
(
5
)
(2)(5)
(2)(5),
P
6
P_{6}
P6 的线路连接参考式
(
7
)
(7)
(7)。
海明解码实验
参考
(
3
)
(
6
)
(3)(6)
(3)(6),根据分组规则表生成
G
1
G_1
G1~
G
5
G_5
G5。
G
6
G_6
G6 根据
(
8
)
(8)
(8) 式生成。这里面多路选择器根据检错码
G
\boldsymbol G
G 的情况,选择一个数与原来的数据
D
\boldsymbol D
D 异或一下,使得异或的数据能够恢复成正确的数据。
资源获取
华中科技大学计算机组成原理实验
华中科技大学计算机组成原理实验——数据表示实验