87 lines
7.2 KiB
Markdown
87 lines
7.2 KiB
Markdown
+++
|
||
author = "FlintyLemming"
|
||
title = "海明校验码"
|
||
slug = "126cc71ce5234e699042036798edcf66"
|
||
date = "2020-06-01"
|
||
description = ""
|
||
categories = ["Coding"]
|
||
+++
|
||
|
||
在了解海明校验码之前,需要知道一个重要的概念——码距。
|
||
|
||
## 概念介绍-码距
|
||
码距是指是两个码字中不相同的二进制位的个数,举个例子,有两个编码,分别是01101101和01000101,可以发现,这两个编码有两位值不相同,所以他们的码距为2。
|
||
那么,你还有可能听到这么一个说法:“8421码码距d=1”,这里的码距指的是“该数据编码的最小码距”,是整个编码系统中中任意两个码字的码距的最小值。还有一个问题,使用四位二进制的编码系统,码距一定是1吗?显然不是,虽然用的是四位二进制编码系统,但是没有限定编写什么码字。如果我用这个编码系统只编写0000、0011、0101这三个码字,那么这个编码系统的码距就是2,因为这三个码子互相之间的码距最小值为2。
|
||
|
||
## 码字的结构
|
||
接下来,我还要介绍一下添加校验码后,整个码字的结构。码字包括信息位和校验位,这里设信息位的位数为k,校验位的位数为r,那么整个码字的长度就是k+r。
|
||
|
||
## 所需校验位的计算
|
||
对于校验位来说,需要有足够的位数来表示信息位中发生的错误,而海明校验码只表示信息位中一位的错误。
|
||
举个例子(并不是海明码的结构,不严谨,仅作理解),现在有信息位0110,那么,校验位就需要有四个状态分别表示信息位的第一、二、三或者第四位有误。那么校验位如果只有一位,0和1,并不能表示四种状态。我们试试两位:比如校验位我用00表示信息位第一位发生错误,01表示第二位发生错误,用10表示第三位发生错误,11表示第四位发生错误。看似没有问题,但是忘了一点:校验位如何表示信息位没有错误呢?所以其实我们需要4+1=5种情况来表示信息位的校验信息,即需要3位的校验位。
|
||
而对于海明码来说,数据位和校验位穿插,存在校验位可以“我 查 我 自 己”的情况,需要检查的位数就是k+r。所以对于k位的信息位,r位的校验位,需要满足2^r-1>k+r才能检查出1个位的错误。
|
||
|
||
## 确定校验码和数据的位置
|
||
上节提到,海明码的校验位和信息位是穿插的,所以我们需要确定校验位的各个位置。为了方便说明,我们给校验码定义为P1、P2、P3…;数据为定义为D1、D2、D3…;最终整个码字的编码依次为M1、M2、M3……那对于校验码Pi来说,它的位置是M[2^(i-1)],比如P1的位置是M1、P2的位置是M2,P3的位置是M4,P4的位置是M8……那么剩下的就是数据的位置
|
||
M1 M2 M3 M4 M5 M6 M7 M8 M9
|
||
P1 P2 D1 P3 D2 D3 D4 P4 D5
|
||
|
||
## 求出校验位的值(规律法)
|
||
这里以一个例子讲解,比如我们现在掌握如下信息
|
||
|
||
M1 M2 M3 M4 M5 M6 M7 M8 M9 M10
|
||
|
||
P1 P2 D1 P3 D2 D3 D4 P4 D5 D6
|
||
|
||
(空) (空) 1 (空) 0 1 1 (空) 0 1
|
||
|
||
表里可以看出已经给定了一组信息位的值,现在,我们先计算P1的值:
|
||
我们从**P1开始,连续1个,中间间隔1个,再连续1个**,组合成一个串:
|
||
【为了方便理解,我详细说一下上方加粗的过程:从P1(也就是对应的M1)开始,连续一个,就还是P1;然后间隔一个,就跳过M2;再连续一个,取M3的值;然后间隔一个,也就是跳过M4;再连续一个,取M5的值…以此类推,我们取了P1、3、5、7…的值,把它放在一个串里】
|
||
然后对这个串进行偶校验,也就是说,保证这个串中1的个数为偶数个,可以看到,已经有两个1了,所以我们在第一位补0:
|
||
这也就是我们得到的P1的值
|
||
|
||
为了加强理解,我们再计算一下P2的值:
|
||
我们**从P2开始,连续2个,中间间隔2个,再连续2个**,组合成一个串:
|
||
|
||
【为了方便理解,我再详细说一下加粗部分的过程:从P2(也就是对应的M2)开始,连续两个,就是M2、M3,取M3的值;然后间隔2个,跳过M4、M5;再连续两个,取M6、M7的值;再间隔两个,跳过M8、M9;再连续两个,取M10、M11…以此类推,我们取了M3、6、7、10的值】
|
||
然后同样进行偶校验,发现已经有4个1,所以补0:
|
||
这也就是我们得到的P2的值
|
||
|
||
同理,计算P3的过程中,我们**从P3开始,连续3个,中间间隔3个,再连续3个**,也就是取M4、5、6;跳过M7、8、9;取M10、11、12
|
||
然后进行偶校验,补0:
|
||
|
||
P4同理,最后补的是1:
|
||
这样,我们就依次获得了校验位的数据,P1-4依次为0、0、0、1
|
||
|
||
## 求出校验位的值(数学法)
|
||
还是用这一题:
|
||
第一步,我们要列出整个码字的编码对应的二进制。比如M1,1对应的就是0001;M2,就是0010;M3就是0011
|
||
观察这个二进制编码,以M3为例,0011,第一位和第二位都是1,那么我们称M3和P1、P2有关
|
||
第二步,我们要找到还有哪些和P1有关,可以发现,M1、3、5、7、9都和P1有关
|
||
第三步,以此类推,找出哪些和P2有关(可以找到M2、3、6、7、10),哪些和P3有关……
|
||
第四步,去掉第一位(因为比如对于P1来说,M1、3、5、7、9中,M1并没有值),列出如下方程式:
|
||
P1 = M3 ⊕ M5 ⊕ M7 ⊕ M9 = 1 ⊕ 0 ⊕ 1 ⊕ 0 = 0
|
||
P2 = M3 ⊕ M6 ⊕ M7 ⊕ M10 = 1 ⊕ 1 ⊕ 1 ⊕ 1 = 0
|
||
P3 = M5 ⊕ M6 ⊕ M7 = 0 ⊕ 1 ⊕ 1 ⊕ = 0
|
||
P4 = M9 ⊕ M10 = 0 ⊕ 1 = 1
|
||
便可以算出校验位的值
|
||
|
||
## 接收端校验
|
||
参考上一节求出校验位的值(数学法)中求P的过程,我们需要把P,和其相关的数据位相加,比如上面我们计算了P1 = M3 ⊕ M5 ⊕ M7 ⊕ M9 = 1 ⊕ 0 ⊕ 1 ⊕ 0 = 0,这里我们就校验P1 ⊕ M3 ⊕ M5 ⊕ M7 ⊕ M9 是否等于 0,接着,依次计算P2 ⊕ M3 ⊕ M6 ⊕ M7 ⊕ M10、P3 ⊕ M5 ⊕ M6 ⊕ M7、P4 ⊕ M9 ⊕ M10是否都等于0,如果都是0,说明这个数据没有问题。
|
||
如果出问题了呢?下面举个例子:
|
||
还是上面那一题,如果M5在传输中发生错误,0变成了1
|
||
那么计算中就会发现:
|
||
P1 ⊕ M3 ⊕ M5 ⊕ M7 ⊕ M9 = 1
|
||
P2 ⊕ M3 ⊕ M6 ⊕ M7 ⊕ M10 = 0
|
||
P3 ⊕ M5 ⊕ M6 ⊕ M7 = 1
|
||
P4 ⊕ M9 ⊕ M10 = 0
|
||
得出出错位为:0101(2)位,即第五位,那么,只要把M5的值反转,即可得到正确的字串。
|
||
|
||
## 海明码的码距
|
||
回到一开始说的码距问题,有题目会问,海明码的码距是多少?答案是3。为什么呢,其实我们不妨再观察一下用数学法计算校验位的过程:
|
||
P1 = M3 ⊕ M5 ⊕ M7 ⊕ M9 = 1 ⊕ 0 ⊕ 1 ⊕ 0 = 0
|
||
P2 = M3 ⊕ M6 ⊕ M7 ⊕ M10 = 1 ⊕ 1 ⊕ 1 ⊕ 1 = 0
|
||
P3 = M5 ⊕ M6 ⊕ M7 = 0 ⊕ 1 ⊕ 1 ⊕ = 0
|
||
P4 = M9 ⊕ M10 = 0 ⊕ 1 = 1
|
||
不难发现,即使是靠前的数据位,比如M3、M5,都至少与两个校验位有关,所以变了一个数据位,会更改两个校验位,一共改变三个值。即可得出海明码的码距为3。 |