漢明碼、海明校驗碼(Hamming Code)


基礎知識

  1. 碼距:又叫海明距離,是在信息編碼中,兩個編碼之間對應位上編碼不同的位數。例如編碼100110和010101,第1、2、5、6位都不相同,所以這兩個編碼的碼距就是4,並且可以通過異或的方式求出(異或后計算零的個數)

  2. 奇偶校驗(Parity Check):一種校驗代碼傳輸正確性的方法,分為奇校驗和偶校驗兩種方式,目的都是在一字節(8位二進制數)后面加上一個校驗位(0或1),奇校驗下前面8位和校驗碼的1的個數應為奇數個,偶校驗為偶數個。公式表示為:

    \[奇校驗:G=\overline{C\oplus X_1\oplus X_2\oplus X_3\oplus ... \oplus X_n}\\ 偶校驗:G=C\oplus X_1\oplus X_2\oplus X_3\oplus ... \oplus X_n\\ G等於0表示數據正常,否則表示出錯 \]

    在實際中奇偶校驗的選擇是事先選擇的。

    奇偶校驗的特點

    1. 編碼檢錯簡單
    2. 編碼效率高
    3. 不能檢測偶數位錯誤,無錯結論不可靠,是一種錯誤檢測碼
    4. 也沒法識別錯誤,更不能糾正錯誤,出錯只能重新傳

漢明碼/海明校驗碼

海明碼的構成方法是在數據位之間的確定位置上插入k個校驗位,通過擴大碼距來實現檢錯和糾錯。

漢明碼跟其它的錯誤校驗碼類似,也利用了奇偶校驗位的概念。不過與奇偶校驗碼不同的是,它並不是指定長度字節后面加一位,而是通過計算關系:

\[2^k-1\ge n+k(在指定n的情況下,找到滿足式子的最小的k) \]

計算出指定數據位對應的校驗位長度。其中n為數據位,k為校驗位長度。

計算

設數據位是8位,那么通過式子\(2^4-1=15>8+4=12\),則校驗位為4位

設信息位為:D7,D6,D5,D4,D3,D2,D1,D0,校驗位P3,P2,P1,P0,先計算校驗位在總共12位的海明碼中占據的位數:

  • \(P0=2^0=1\)
  • \(P1=2^1=2\)
  • \(P2=2^2=4\)
  • \(P3=2^3=8\)

所以校驗位P3,P2,P1,P0分別占據第8、4、2、1位,而信息碼從左到右占據剩下的位數,如表:

位數 12 11 10 9 8 7 6 5 4 3 2 1
信息位 D7 D6 D5 D4 D3 D2 D1 D0
校驗位 P3 P2 P1 P0

注:這個表很多資料中其實是左右倒過來的,如果是倒過來的話就不用最后在倒置了

而信息位與校驗位的關系為:信息位的位數=位數相加等於信息位位數的校驗位組。例如D7的位數為12,所以D7的校驗位組為P3和P2。

信息位 信息位檢驗計算 校驗位組
D7 12=8+4 P3,P2
D6 11=8+2+1 P3,P1,P0
D5 10=8+2 P3,P1
D4 9=8+1 P3,P0
D3 7=4+2+1 P2,P1,P0
D2 6=4+2 P2,P1
D1 5=4+1 P2,P0
D0 3=2+1 P1,P0

所以,P0參與了D0,D1,D3,D4,D6的檢驗,其他由此類推:

\(P0=D0\oplus D1\oplus D3\oplus D4\oplus D6\)
\(P1=D0\oplus D2\oplus D3\oplus D5\oplus D6\)
\(P2=D1\oplus D2\oplus D3\oplus D7\)
\(P3=D4\oplus D5\oplus D6\oplus D7\)

注意:海明碼是由高位到低位進行排序(高位先放,低位后方),所以得到的海明碼是:P0 P1 D0 P2 D1 D2 D3 P3 D4 D5 D6 D7

而校驗的方式則是算出信息的校驗碼,然后與得到的校驗碼對應,相同標0,不同標1(讓01串異或成原來的樣子),得到錯誤的位置為\(P3^*P2^*P1^*P0^*\)\(Pn^*\)是標記)

python代碼實現校驗(這代碼摸了快三天,代碼水平還是得提高)

# -*- coding: utf-8 -*-
"""
Created on Fri Dec  3 21:59:38 2021
海明碼解碼糾錯(默認只有一個錯誤)
@author: 01am
"""
#返回將列表里面的元素全部異或的值
def xor1(lista):
    j=lista[0]
    for i in range(1,len(lista)):
        j=j^lista[i]
    return j

a = input("請輸入海明碼:")
len_a = len(a)
k=0

#確定k的值
for i in range(1,len_a):
    tmp = pow(2,i)
    if tmp > len_a :
        k=i
        break

#循環創建校驗位變量和校驗位對應的數據位列表
for i in range(k):
    exec('P'+str(i)+'='+str(a[pow(2,i)-1]))
    exec('D'+str(i)+'=[]')

#循環創建數據位變量並確定是否與校驗位有關
for i in range(len_a):
    #如果按照位數的二進制情況下查找1只有1個的情況下,那么一定是校驗位
    if bin(i+1).count('1')==1:#加一是為了解決range從0開始而海明碼從1開始的矛盾
        continue
    else:
        tmp1=bin(i+1)[-1:1:-1]#將二進制數翻轉並且去掉0b,方便后面循環尋找相關的校驗位
        for j in range(len(tmp1)):
            if tmp1[j]=='1' :#這里無需加一,因為校驗位是從0開始的
                exec('D'+str(j)+'.append('+str(a[i])+')')

#新計算的糾錯位和原校驗位對比后的標志不准確
#判斷校驗位和計算出來的校驗位是否一致
K=''
for i in range(k):
    exec('tmp2 = D'+str(i))  #這里的問題,不能寫成tmp2 = exec('D'+str(i)),這樣會讓tmp2成為NoneType
    exec('tmp3 = P'+str(i))
    tmp4 = xor1(tmp2)  #這里可能會提示有變量未定義,不用理
    if tmp4 == tmp3 :  #這里可能會提示有變量未定義,不用理
        K+='0'
    else:
        K+='1'
tmp5 = K[::-1]#校驗位的位置,如果全為零就不存在

#判斷校驗碼是否存在,存在就把對應的位置修改
a=list(a)
if tmp5.find('1')!=-1:
    int1 = int(tmp5,2)-1
    a[int1]=str(int(a[int1])^1)
    print("已經自動糾錯一位\n")

#輸出不帶校驗碼的字符串
b=''
c=[pow(2,i) for i in range(k)]
for i in range(len_a):
    if i+1 not in c:
        b+=a[i]
a=''.join(a)
print(a)
print(b)

參考:

  1. 海明碼的計算步驟
  2. 百度百科-奇偶校驗
  3. 百度百科-海明校驗碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM