漢明碼 (39,32)是一個用于錯誤檢測和糾正的編碼算法,特別適合于嵌入式領(lǐng)域的32bit CPU,數(shù)據(jù)位寬正好與總線位寬一致。
1. 基本結(jié)構(gòu)
數(shù)據(jù)位(k):32 位
編碼總長(n):39 位
校驗(yàn)位(r):n - k = 7 位
數(shù)據(jù)位與校驗(yàn)位的排列規(guī)則:
1. 數(shù)據(jù)位和校驗(yàn)位一起組成 39 位編碼。
2. 索引為2的冪次方(1, 2, 4, 8, 16, 32)的位為各分組的奇偶校驗(yàn)位(p1,p2,p3,p4,p5,p6),39位為總的奇偶校驗(yàn)位(p7),其余位置為數(shù)據(jù)位(d0-d31),本文以偶校驗(yàn)為例。
2. 編碼過程
2.1 基本布局
索引: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
排布: p1 p2 d0 p3 d1 d2 d3 p4 d4 d5 d6 d7 d8 d9 d10 p5 d11 d12 d13 d14 d15 d16 d17 d18 d19 d20 d21 d22 d23 d24 d25 p26 d26 d27 d28 d29 d30 d31 p7
2.2 校驗(yàn)碼計(jì)算
p1 校驗(yàn)的位是索引中二進(jìn)制bit0位為1的位置,全部列舉如下:
0b000001(1)->p1
0b000011(3)->d0
0b000101(5)->d1
0b000111(7)->d3
0b001001(9)->d4
0b001011(11)->d6
0b001101(13)->d8
0b001111(15)->d10
0b010001(17)->d11
0b010011(19)->d13
0b010101(21)->d15
0b010111(23)->d17
0b011001(25)->d19
0b011011(27)->d21
0b011101(29)->d23
0b011111(31)->d25
0b100001(33)->d26
0b100011(35)->d28
0b100101(37)->d30
0b100111(39)->p7
由此可得,p1 = d0 ^ d1 ^ d3 ^ d4 ^ d6 ^ d8 ^ d10 ^ d11 ^ d13 ^ d15 ^ d17 ^ d19 ^ d21 ^ d23 ^ d25 ^ d26 ^ d28 ^ d30
p2 校驗(yàn)的位是索引中二進(jìn)制bit1位為1的位置,全部列舉如下:
0b000001(2)->p2
0b000011(3)->d0
0b000110(6)->d2
0b000111(7)->d3
0b001010(10)->d5
0b001011(11)->d6
0b001110(14)->d9
0b001111(15)->d10
0b010010(18)->d12
0b010011(19)->d13
0b010110(22)->d16
0b010111(23)->d17
0b011010(26)->d20
0b011011(27)->d21
0b011110(30)->d24
0b011111(31)->d25
0b100010(34)->d27
0b100011(35)->d28
0b100110(38)->d31
0b100111(39)->p7
由此可得,p2 = d0 ^ d2 ^ d3 ^ d5 ^ d6 ^ d9 ^ d10 ^ d12 ^ d13 ^ d16 ^ d17 ^ d20 ^ d21 ^ d24 ^ d25 ^ d27 ^ d28 ^ d31
以此類推,
p3 校驗(yàn)的位是索引中二進(jìn)制bit2位為1的位置;
p4 校驗(yàn)的位是索引中二進(jìn)制bit3位為1的位置;
p5 校驗(yàn)的位是索引中二進(jìn)制bit4位為1的位置;
p6 校驗(yàn)的位是索引中二進(jìn)制bit5位為1的位置;
p7是可選校驗(yàn)位,主要用于檢測大于1bit的錯誤,屬于漢明碼的拓展選項(xiàng),p7是所有位異或得到,如果只需要檢測1bit的錯誤,p7位可以不用;
整理如下:
p1 = d0 ^ d1 ^ d3 ^ d4 ^ d6 ^ d8 ^ d10 ^ d11 ^ d13 ^ d15 ^ d17 ^ d19 ^ d21 ^ d23 ^ d25 ^ d26 ^ d28 ^ d30
p2 = d0 ^ d2 ^ d3 ^ d5 ^ d6 ^ d9 ^ d10 ^ d12 ^ d13 ^ d16 ^ d17 ^ d20 ^ d21 ^ d24 ^ d25 ^ d27 ^ d28 ^ d31
p3 = d1 ^ d2 ^ d3 ^ d7 ^ d8 ^ d9 ^ d10 ^ d14 ^ d15 ^ d16 ^ d17 ^ d22 ^ d23 ^ d24 ^ d25 ^ d29 ^ d30 ^ d31
p4 = d4 ^ d5 ^ d6 ^ d7 ^ d8 ^ d9 ^ d10 ^ d18 ^ d19 ^ d20 ^ d21 ^ d22 ^ d23 ^ d24 ^ d25
p5 = d11 ^ d12 ^ d13 ^ d14 ^ d15 ^ d16 ^ d17 ^ d18 ^ d19 ^ d20 ^ d21 ^ d22 ^ d23 ^ d24 ^ d25
p6 = d26 ^ d27 ^ d28 ^ d29 ^ d30 ^ d31
p7 = p1 ^ p2 ^ p3 ^ p4 ^ p5 ^ p6 ^ d0 ^ d1 ^ d2 ^ d3 ^ d4 ^ d5 ^ d6 ^ d7 ^ d8 ^ d9 ^ d10 ^ d11 ^ d12 ^ d13 ^ d14 ^ d15 ^ d16 ^ d17 ^ d18 ^ d19 ^ d20 ^ d21 ^ d22 ^ d23 ^ d24 ^ d25 ^ d26 ^ d27 ^ d28 ^ d29 ^ d30 ^ d31
由此可得,漢明碼 (39,32)編碼后的7位校驗(yàn)碼p1-p7和32bit原始數(shù)據(jù)d0-d31。
3. 解碼過程
解碼過程需要用到編碼生成的7位校驗(yàn)碼和32bit原始數(shù)據(jù)組成的39bit的數(shù)據(jù),由于p1-p6都是各組數(shù)據(jù)異或而得的,故理論上在數(shù)據(jù)沒有出錯的情況下,以下p1' p2' p3' p4' p5' p6' p7' (可選)的值應(yīng)該都等于0 :
p1' = p1 ^ d0 ^ d1 ^ d3 ^ d4 ^ d6 ^ d8 ^ d10 ^ d11 ^ d13 ^ d15 ^ d17 ^ d19 ^ d21 ^ d23 ^ d25 ^ d26 ^ d28 ^ d30
p2' = p2 ^ d0 ^ d2 ^ d3 ^ d5 ^ d6 ^ d9 ^ d10 ^ d12 ^ d13 ^ d16 ^ d17 ^ d20 ^ d21 ^ d24 ^ d25 ^ d27 ^ d28 ^ d31
p3' = p3 ^ d1 ^ d2 ^ d3 ^ d7 ^ d8 ^ d9 ^ d10 ^ d14 ^ d15 ^ d16 ^ d17 ^ d22 ^ d23 ^ d24 ^ d25 ^ d29 ^ d30 ^ d31
p4' = p4 ^ d4 ^ d5 ^ d6 ^ d7 ^ d8 ^ d9 ^ d10 ^ d18 ^ d19 ^ d20 ^ d21 ^ d22 ^ d23 ^ d24 ^ d25
p5' = p5 ^ d11 ^ d12 ^ d13 ^ d14 ^ d15 ^ d16 ^ d17 ^ d18 ^ d19 ^ d20 ^ d21 ^ d22 ^ d23 ^ d24 ^ d25
p6' = p6 ^ d26 ^ d27 ^ d28 ^ d29 ^ d30 ^ d31
p7' = p7 ^ p1 ^ p2 ^ p3 ^ p4 ^ p5 ^ p6 ^ d0 ^ d1 ^ d2 ^ d3 ^ d4 ^ d5 ^ d6 ^ d7 ^ d8 ^ d9 ^ d10 ^ d11 ^ d12 ^ d13 ^ d14 ^ d15 ^ d16 ^ d17 ^ d18 ^ d19 ^ d20 ^ d21 ^ d22 ^ d23 ^ d24 ^ d25 ^ d26 ^ d27 ^ d28 ^ d29 ^ d30 ^ d31
如果有一個不等于0,說明必然發(fā)生了bit跳變,跳變位可能是校驗(yàn)位也可能是數(shù)據(jù)位。
- 如果只有一個bit發(fā)生了跳變,我們可以通過以下公式找到出錯位置的索引號,并將里面的bit位翻轉(zhuǎn)即可糾正該bit位的錯誤:
索引 = (p6'<<5) | (p5'<<4) | (p4'<<3) | (p3'<<2) | (p2'<<1) | p1'
比如:算出來索引為3,我們根據(jù)前面的基本布局,知道索引為3的位置存的是d0的值,故只要把d0位翻轉(zhuǎn)即可; - 如果存在大于1bit的位置發(fā)生跳變,則需要用到p7'和上面計(jì)算的索引共同來判斷。
4. 算法實(shí)現(xiàn)
def hamming_39_32_encode(data):
# get data bits
d = [(data >> i) & 1 for i in range(32)]
# calculate parity
p1 = d[0] ^ d[1] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[10] ^ d[11] ^ d[13] ^ d[15] ^ d[17] ^ d[19] ^ d[21] ^ d[23] ^ d[25] ^ d[26] ^ d[28] ^ d[30]
p2 = d[0] ^ d[2] ^ d[3] ^ d[5] ^ d[6] ^ d[9] ^ d[10] ^ d[12] ^ d[13] ^ d[16] ^ d[17] ^ d[20] ^ d[21] ^ d[24] ^ d[25] ^ d[27] ^ d[28] ^ d[31]
p3 = d[1] ^ d[2] ^ d[3] ^ d[7] ^ d[8] ^ d[9] ^ d[10] ^ d[14] ^ d[15] ^ d[16] ^ d[17] ^ d[22] ^ d[23] ^ d[24] ^ d[25] ^ d[29] ^ d[30] ^ d[31]
p4 = d[4] ^ d[5] ^ d[6] ^ d[7] ^ d[8] ^ d[9] ^ d[10] ^ d[18] ^ d[19] ^ d[20] ^ d[21] ^ d[22] ^ d[23] ^ d[24] ^ d[25]
p5 = d[11] ^ d[12] ^ d[13] ^ d[14] ^ d[15] ^ d[16] ^ d[17] ^ d[18] ^ d[19] ^ d[20] ^ d[21] ^ d[22] ^ d[23] ^ d[24] ^ d[25]
p6 = d[26] ^ d[27] ^ d[28] ^ d[29] ^ d[30] ^ d[31]
p7 = p1 ^ p2 ^ p3 ^ p4 ^ p5 ^ p6 ^ d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6] ^ d[7] ^ d[8] ^ d[9] ^ d[10] ^ d[11] ^ d[12] ^ d[13] ^ d[14] ^ d[15] ^ d[16] ^ d[17] ^ d[18] ^ d[19] ^ d[20] ^ d[21] ^ d[22] ^ d[23] ^ d[24] ^ d[25] ^ d[26] ^ d[27] ^ d[28] ^ d[29] ^ d[30] ^ d[31]
parity = (p7<<6) | (p6<<5) | (p5<<4) | (p4<<3) | (p3<<2) | (p2<<1) | p1
return parity
def hamming_39_32_decode(parity, data):
# get data bits
d = [(data >> i) & 1 for i in range(32)]
# get parity bits
p = [(parity >> i) & 1 for i in range(7)]
# calculate syndrome
p1 = p[0] ^ d[0] ^ d[1] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[10] ^ d[11] ^ d[13] ^ d[15] ^ d[17] ^ d[19] ^ d[21] ^ d[23] ^ d[25] ^ d[26] ^ d[28] ^ d[30]
p2 = p[1] ^ d[0] ^ d[2] ^ d[3] ^ d[5] ^ d[6] ^ d[9] ^ d[10] ^ d[12] ^ d[13] ^ d[16] ^ d[17] ^ d[20] ^ d[21] ^ d[24] ^ d[25] ^ d[27] ^ d[28] ^ d[31]
p3 = p[2] ^ d[1] ^ d[2] ^ d[3] ^ d[7] ^ d[8] ^ d[9] ^ d[10] ^ d[14] ^ d[15] ^ d[16] ^ d[17] ^ d[22] ^ d[23] ^ d[24] ^ d[25] ^ d[29] ^ d[30] ^ d[31]
p4 = p[3] ^ d[4] ^ d[5] ^ d[6] ^ d[7] ^ d[8] ^ d[9] ^ d[10] ^ d[18] ^ d[19] ^ d[20] ^ d[21] ^ d[22] ^ d[23] ^ d[24] ^ d[25]
p5 = p[4] ^ d[11] ^ d[12] ^ d[13] ^ d[14] ^ d[15] ^ d[16] ^ d[17] ^ d[18] ^ d[19] ^ d[20] ^ d[21] ^ d[22] ^ d[23] ^ d[24] ^ d[25]
p6 = p[5] ^ d[26] ^ d[27] ^ d[28] ^ d[29] ^ d[30] ^ d[31]
p7 = p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4] ^ p[5] ^ p[6] ^ d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6] ^ d[7] ^ d[8] ^ d[9] ^ d[10] ^ d[11] ^ d[12] ^ d[13] ^ d[14] ^ d[15] ^ d[16] ^ d[17] ^ d[18] ^ d[19] ^ d[20] ^ d[21] ^ d[22] ^ d[23] ^ d[24] ^ d[25] ^ d[26] ^ d[27] ^ d[28] ^ d[29] ^ d[30] ^ d[31]
syndrome = (p6<<5) | (p5<<4) | (p4<<3) | (p3<<2) | (p2<<1) | p1
if syndrome == 0 and p7 == 0 :
print("hamming decode success")
return data
else:
if syndrome !=0 and p7 != 0:
print(f"1 bit error at positon {syndrome}")
# correct 1bit error
index = 0
decode = data
for i in range(39):
if (i & (i + 1)) == 0:
continue
if i == 38:
continue
if (i == syndrome-1):
decode &= (~(1 << index))
decode |= ((d[index] ^ 1) << index) #flip
index += 1
print("correct success decode origin data is 0x%x" %decode)
return decode
else:
print("more than 1 bit error")
return -1
##test code
data = 0x0ff0000e
parity = hamming_39_32_encode(data)
print(f"parity:{parity:07b}")
decode = hamming_39_32_decode(parity, 0x0ff0000e)
print("decode:%x"%decode)