最近和朋友的聊天涉及到了海明码纠错,先来康康海明纠错码到底是什么
海明码
Hamming Code,电信领域的一种线性调试码,由于编码简单,广泛应用于内存(RAM)。
编码原理
若海明码长为n,信息位数为k,则需要插入r个监督位校验码。如果想要r个校验码能构成r个关系式来指示出错码的n个可能位置,则需要
即为
比如说我们有8位二进制数需要编码,那么应该有
信息码位数 | 1 | 2 ~ 4 | 5 ~11 | 12 ~ 26 |
---|---|---|---|---|
校验码位数 | 2 | 3 | 4 | 5 |
校验码位置
海明码的校验码都在2的整数次幂处,也就是第1、2、4....等位
注意这不是数组索引,没有第0位数。
第n个校验码 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
所在位置 | 1 | 2 | 4 | 8 | 16 |
如果用pn表示第n个校验码
dk表示第k个数据
所以我们的8位二进制数编码结果应该是
位数 | 1(0001) | 2(0010) | 3(0011) | 4(0100) | 5(0101) | 6(0110) | 7(0111) | 8(1000) | 9(1001) | 10(1010) | 11(1011) | 12(1100) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
数据 | p1 | p2 | d1 | p3 | d2 | d3 | d4 | p4 | d5 | d6 | d7 | d8 |
校验码计算
校验位1 的校验规则是从当前位数起,校验一位,跳过一位,再校验一位,再跳过一位.......也就是说校验了所有数据位位置序号的二进制表示的最后一位是1的数据,即 0001,0011,0101,0111,1001,1011
同理,第k个校验位的校验规则是从当前位开始连续校验位然后跳过位......也就是说,第k位校验位应该校验数据位位置序号的二进制表示的倒数第k位是1的数据
其实就是二进制数的第k位表示
那到底咋算嘞?
之前学过奇校验和偶校验,可以排上用场了
奇校验是要求整个被校验的位中“1”的个数为奇数,偶校验则是要求整个被校验的位中“1”的个数为偶数
我们用偶校验来试算一下。
比如我们输入的数据是10111011
插入后应该是
位数 | 1(0001) | 2(0010) | 3(0011) | 4(0100) | 5(0101) | 6(0110) | 7(0111) | 8(1000) | 9(1001) | 10(1010) | 11(1011) | 12(1100) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
数据 | p1 | p2 | 1 | p3 | 0 | 1 | 1 | p4 | 1 | 0 | 1 | 1 |
计算p1, 第0001,0011,0101,0111,1001,1011位中除了p1本身共有4个1,所有p1为0可以使“1”的总数为0
同理p2为0
p3为1
p4为1
所得数据为
海明码纠错
比起普通的奇校验偶校验而言,海明码非常强大的一点就在于它不仅可以实现校验,还能实现1bit的纠错。
依然以我们的偶校验为例
p1 | p2 | d1 | p3 | d2 | d3 | d4 | p4 | d5 | d6 | d7 | d8 | ||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
p1 | √ | √ | √ | √ | √ | √ | |||||||||
p2 | √ | √ | √ | √ | √ | √ | |||||||||
p3 | √ | √ | √ | √ | √ | ||||||||||
p4 | √ | √ | √ | √ | √ | ||||||||||
数 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 |
可以看出来的是,所有的校验码位都不会被其他校验码影响,仅由自己校验自己,这就保证了如果我们的某位校验码出错的话不会影响其他校验码的校验结果,我们可以轻易的找到这个出错的校验码。
所以说,我们的四个校验组计算出来如果只有一个校验组的结果是错误的,那么说明是该位校验码出错,取反即可。
再来看看数据位。
因为每个数据都被校验了2-3次,所以出错的校验组数肯定大于1
如果是两个校验组出错的话,有d1、d2、d3、d5、d6、d8,每个数据位都和校验组的组合形式一一对应,因此我们知道哪两个校验组出错就知道了哪一位出错。
如果是三个校验组出错的话同理也可以找出是哪一位。
写写代码
本来应该用FPGA写verilog的,不过我现在电脑里就只能写python
就用python做了一个hamming码的编码与校验纠错
class Hamming():
def __init__(self,data):
self.data = data
def hammingEncode(self):
self.dataLen = len(self.data)
self.r = 0
while pow(2,self.r) - self.r < self.dataLen + 1:
self.r += 1
self.HammingLen = self.r + self.dataLen #求出插入校验码后的总长
self.HammingData = [0] * self.HammingLen
for i in range(self.r):
self.HammingData[pow(2,i)-1] = 1#先默认校验位都设置为1
dataIndex = 0
for i in range(self.HammingLen):#插入数据
if self.HammingData[i] == 0:
self.HammingData[i] = self.data[dataIndex]
dataIndex += 1
print(self.HammingData)
for pn in range(1,self.r+1):#逐个计算校验位
#pn所在位置
pos = pow(2,(pn-1)) - 1
temp = 0
for pr in range(pos,self.HammingLen+1,pow(2,pn)):
for i in range(pr,min(pr+pow(2,(pn-1)),self.HammingLen)):#疯狂异或
temp ^= self.HammingData[i]
if temp == 1:
self.HammingData[pos] = 0
print(self.HammingData)
def makeMistake(self,k):
if self.HammingData[k] == 0:
self.HammingData[k] = 1
else:
self.HammingData[k] = 0
print(self.HammingData)
def hammingDecode(self):
wrongList = []
for pn in range(1,self.r+1):#逐个计算校验组
#pn所在位置
pos = pow(2,(pn-1)) - 1
temp = 0
for pr in range(pos,self.HammingLen+1,pow(2,pn)):
for i in range(pr,min(pr+pow(2,(pn-1)),self.HammingLen)):#疯狂异或
temp ^= self.HammingData[i]
print(temp)
if temp == 1:
wrongList.append(pn)#记下哪个校验组错了
if wrongList:
print("原数据",self.HammingData)
if len(wrongList) == 1:
self.HammingData[pow(2,wrongList[0]-1)-1] ^= 1
elif len(wrongList) == 2:
if 1 in wrongList and 2 in wrongList:
self.HammingData[2] ^= 1
elif 1 in wrongList and 3 in wrongList:
self.HammingData[4] ^= 1
elif 1 in wrongList and 4 in wrongList:
self.HammingData[8] ^= 1
elif 2 in wrongList and 3 in wrongList:
self.HammingData[5] ^= 1
elif 2 in wrongList and 4 in wrongList:
self.HammingData[9] ^= 1
elif 4 in wrongList and 3 in wrongList:
self.HammingData[11] ^= 1
elif len(wrongList) == 3:
if 1 in wrongList and 2 in wrongList and 3 in wrongList:
self.HammingData[6] ^= 1
elif 1 in wrongList and 2 in wrongList and 4 in wrongList:
self.HammingData[10] ^= 1
print("现数据",self.HammingData)
return False
else:
return True
a = Hamming([1,0,1,1,1,0,1,1])
a.hammingEncode()
a.hammingDecode()
a.makeMistake(4)
a.hammingDecode()