超级无敌简单易懂的海明码的校验和纠错原理与实现

最近和朋友的聊天涉及到了海明码纠错,先来康康海明纠错码到底是什么

海明码

Hamming Code,电信领域的一种线性调试码,由于编码简单,广泛应用于内存(RAM)。

编码原理

若海明码长为n,信息位数为k,则需要插入r个监督位校验码。如果想要r个校验码能构成r个关系式来指示出错码的n个可能位置,则需要
2 r − 1 ≥ n 2^r - 1 \geq n 2r1n
即为
2 r − r ≥ k + 1 2^r - r \geq k+1 2rrk+1
比如说我们有8位二进制数需要编码,那么应该有
k = 8 k=8 k=8
r ≥ 4 r \ge 4 r4

信息码位数12 ~ 45 ~1112 ~ 26
校验码位数2345

校验码位置

海明码的校验码都在2的整数次幂处,也就是第1、2、4…等位
注意这不是数组索引,没有第0位数。

第n个校验码12345
所在位置124816

如果用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)
数据p1p2d1p3d2d3d4p4d5d6d7d8

校验码计算

校验位1 的校验规则是从当前位数起,校验一位,跳过一位,再校验一位,再跳过一位…也就是说校验了所有数据位位置序号的二进制表示的最后一位是1的数据,即 0001,0011,0101,0111,1001,1011

同理,第k个校验位的校验规则是从当前位开始连续校验 2 ( k − 1 ) 2^(k-1) 2(k1)位然后跳过 2 ( k − 1 ) 2^(k-1) 2(k1)位…也就是说,第k位校验位应该校验数据位位置序号的二进制表示的倒数第k位是1的数据

其实就是二进制数的第k位表示 2 ( k − 1 ) 2^(k-1) 2(k1)

那到底咋算嘞?
之前学过奇校验和偶校验,可以排上用场了
奇校验是要求整个被校验的位中“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)
数据p1p21p3011p41011

计算p1, 第0001,0011,0101,0111,1001,1011位中除了p1本身共有4个1,所有p1为0可以使“1”的总数为0
同理p2为0
p3为1
p4为1
所得数据为
[ 0 , 0 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ] [0, 0 ,1, 1, 0, 1, 1, 1, 1, 0, 1, 1] [0,0,1,1,0,1,1,1,1,0,1,1]

海明码纠错

比起普通的奇校验偶校验而言,海明码非常强大的一点就在于它不仅可以实现校验,还能实现1bit的纠错。
依然以我们的偶校验为例
p 1 ⨁ d 1 ⨁ d 2 ⨁ d 4 ⨁ d 5 ⨁ d 7 = 0 p1 \bigoplus d1 \bigoplus d2 \bigoplus d 4 \bigoplus d 5 \bigoplus d7= 0 p1d1d2d4d5d7=0
p 2 ⨁ d 1 ⨁ d 3 ⨁ d 4 ⨁ d 6 ⨁ d 7 = 0 p2 \bigoplus d1 \bigoplus d3 \bigoplus d 4 \bigoplus d 6 \bigoplus d7= 0 p2d1d3d4d6d7=0
p 3 ⨁ d 2 ⨁ d 3 ⨁ d 4 ⨁ d 8 = 0 p3 \bigoplus d2 \bigoplus d3 \bigoplus d 4 \bigoplus d 8 = 0 p3d2d3d4d8=0
p 4 ⨁ d 5 ⨁ d 6 ⨁ d 7 ⨁ d 8 = 0 p4 \bigoplus d5 \bigoplus d6 \bigoplus d 7 \bigoplus d 8= 0 p4d5d6d7d8=0

p1p2d1p3d2d3d4p4d5d6d7d8
p1
p2
p3
p4
001101111011

可以看出来的是,所有的校验码位都不会被其他校验码影响,仅由自己校验自己,这就保证了如果我们的某位校验码出错的话不会影响其他校验码的校验结果,我们可以轻易的找到这个出错的校验码。
所以说,我们的四个校验组计算出来如果只有一个校验组的结果是错误的,那么说明是该位校验码出错,取反即可。
再来看看数据位。
因为每个数据都被校验了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()
  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

豆沙粽子好吃嘛!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值