汉明码(Hamming Code)是由理查德·汉明(Richard Hamming)于1950年提出的错误检测与纠正码,广泛应用于计算机内存(如ECC内存)、通信系统等领域。其核心目标是通过冗余位实现单比特错误纠正和双比特错误检测。
核心原理
-
冗余位(校验位):
- 在原始数据中插入
r
个校验位,满足不等式:
2ʳ ≥ m + r + 1(m
为数据位长度)。 - 例如:7位数据(m=7)需要4个校验位(r=4),形成11位汉明码(7+4=11)。
- 在原始数据中插入
-
校验位位置:
- 校验位位于2的幂次方位(即第1、2、4、8…位),其余位为数据位。
-
编码过程:
- 每个校验位覆盖特定位置的比特,其值为偶校验(或奇校验)结果。
- 校验位计算规则:
第i
个校验位覆盖所有二进制表示中第i
位为1的位置。
例如:- P1(第1位)覆盖所有位置号二进制第1位为1的位(1,3,5,7,9…)。
- P2(第2位)覆盖位置号二进制第2位为1的位(2,3,6,7,10…)。
-
错误检测与纠正:
- 接收端重新计算校验位,生成校验子(Syndrome)。
- 校验子为0表示无错误;非0时,其值直接指出错误位置(二进制转十进制)。
示例:7位数据编码为汉明码
原始数据:1011001
(7位,D7-D1)
校验位:需4位(P1,P2,P4,P8),满足2⁴≥7+4+1→16≥12。
步骤:
- 排列数据与校验位(
_
为校验位):
P1 P2 D3 P4 D5 D6 D7 P8
填入数据:P1 P2 1 P4 0 0 1 P8
- 计算校验位(偶校验):
- P1(覆盖1,3,5,7,9…):
P1 ⊕ 1 ⊕ 0 ⊕ 1 = 0
→ P1=0 - P2(覆盖2,3,6,7,10…):
P2 ⊕ 1 ⊕ 0 ⊕ 1 = 0
→ P2=0 - P4(覆盖4,5,6,7,12…):
P4 ⊕ 0 ⊕ 0 ⊕ 1 = 0
→ P4=1 - P8(覆盖8,9,10,11…):
P8 ⊕ 1 = 0
→ P8=1
- P1(覆盖1,3,5,7,9…):
- 最终汉明码:
0 0 1 1 0 0 1 1 1
(共11位)。
错误纠正示例
假设第5位(D5)出错:0 0 1 1 1 0 1 1 1
(原应为0,现为1)。
接收端校验:
- 重新计算校验子:
- S1(P1覆盖位:1,3,5,7,9…):
0 ⊕ 1 ⊕ 1 ⊕ 1 ⊕ 1 = 0
→ 0 - S2(P2覆盖位:2,3,6,7,10…):
0 ⊕ 1 ⊕ 0 ⊕ 1 ⊕ 1 = 1
→ 1 - S4(P4覆盖位:4,5,6,7,12…):
1 ⊕ 1 ⊕ 0 ⊕ 1 = 1
→ 1 - S8(P8覆盖位:8,9,10,11…):
1 ⊕ 1 = 0
→ 0
- S1(P1覆盖位:1,3,5,7,9…):
- 校验子:
S8S4S2S1 = 0110
(二进制)= 6 → 第6位(D5)出错,翻转即可纠正。
关键特性
- 单比特错误纠正:可定位并修复任意1位错误。
- 双比特错误检测:通过扩展汉明码(如SEC-DED)可检测2位错误,但无法纠正。
- 效率:冗余位占比随数据位增加而降低(如7位数据需4位校验,1024位数据仅需11位校验)。
应用场景
- ECC内存(如服务器、航天器)。
- 网络通信(如卫星传输)。
- 存储系统(如RAID磁盘阵列)。
如需更深入的细节(如扩展汉明码、奇偶校验选择),可进一步探讨!
import numpy as np
class HammingCode:
def __init__(self, r=3):
self.r = r
self.n = 2 ** r - 1
self.k = self.n - r
# 生成矩阵 (系统码形式:前k位为信息位)
self.gen_matrix = np.array([
[1, 0, 0, 0, 1, 1, 0],
[0, 1, 0, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 1, 1],
[0, 0, 0, 1, 1, 1, 1]
], dtype=int)
# 校验矩阵 (与生成矩阵配对)
self.parity_matrix = np.array([
[1, 1, 0, 1, 1, 0, 0],
[1, 0, 1, 1, 0, 1, 0],
[0, 1, 1, 1, 0, 0, 1]
], dtype=int)
# 错误位置映射表 (伴随式元组 → 错误位置索引)
self.error_table = {
(0, 0, 0): -1, # 无错误
(0, 0, 1): 6, # p3错误
(0, 1, 0): 5, # p2错误
(0, 1, 1): 2, # d3错误
(1, 0, 0): 4, # p1错误
(1, 0, 1): 1, # d2错误
(1, 1, 0): 0, # d1错误
(1, 1, 1): 3 # d4错误
}
def encode(self, bits):
"""(7,4)汉明码编码"""
# 补零使长度为4的倍数
padding_len = (4 - len(bits) % 4) % 4
padded_bits = np.concatenate((bits, np.zeros(padding_len, dtype=int)))
# 输出长度 = 输入长度 * 7/4
encoded = np.zeros(len(padded_bits) * 7 // 4, dtype=int)
# 分组处理每个4位信息组
for i in range(0, len(padded_bits), 4):
message = padded_bits[i:i + 4]
codeword = (np.dot(message, self.gen_matrix) % 2)
start_idx = i * 7 // 4
encoded[start_idx:start_idx + 7] = codeword
# 存储补零长度用于解码
self.last_padding = padding_len
return encoded
def decode(self, encoded_bits):
"""(7,4)汉明码解码(自动纠单比特错误)"""
decoded_list = []
# 处理每个7位码字组
for i in range(0, len(encoded_bits), 7):
codeword = encoded_bits[i:i + 7]
# 计算伴随式(校验子)
syndrom = np.dot(self.parity_matrix, codeword) % 2
syndrom_tuple = tuple(syndrom)
# 检测错误位置
error_index = self.error_table.get(syndrom_tuple, -1)
# 自动纠正单比特错误
if error_index >= 0 and error_index < len(codeword):
codeword[error_index] = 1 - codeword[error_index]
# 提取信息位(前4位)
decoded_list.extend(codeword[:4])
# 去除编码时添加的填充位
decoded = np.array(decoded_list[:-self.last_padding]) if self.last_padding > 0 else np.array(decoded_list)
return decoded
# 测试验证
if __name__ == "__main__":
encoder = HammingCode()
# 测试1: 单码字无错误
data1 = np.array([1, 0, 1, 0])
encoded1 = encoder.encode(data1)
decoded1 = encoder.decode(encoded1)
assert np.array_equal(data1, decoded1), "测试1失败"
# 测试2: 单码字错误纠正
data2 = np.array([1, 0, 0, 0])
encoded2 = encoder.encode(data2)
# 引入错误 (d3位置)
corrupted2 = encoded2.copy()
corrupted2[2] = 1 - corrupted2[2] # 翻转d3位
decoded2 = encoder.decode(corrupted2)
assert np.array_equal(data2, decoded2), "测试2失败"
# 测试3: 多码字连续解码
data3 = np.array([1, 0, 1, 0, 1, 1, 0, 0])
encoded3 = encoder.encode(data3)
decoded3 = encoder.decode(encoded3)
assert np.array_equal(data3, decoded3), "测试3失败"
# 测试4: 多码字错误纠正
data4 = np.array([1, 1, 0, 0, 1, 0, 1, 0])
encoded4 = encoder.encode(data4)
corrupted4 = encoded4.copy()
# 第一个码字d1错误
corrupted4[0] = 1 - corrupted4[0]
# 第二个码字d4错误
corrupted4[3 + 7] = 1 - corrupted4[3 + 7]
decoded4 = encoder.decode(corrupted4)
assert np.array_equal(data4, decoded4), "测试4失败"
# 测试5: 边界情况 - 单码字p位错误
data5 = np.array([0, 1, 0, 1])
encoded5 = encoder.encode(data5)
corrupted5 = encoded5.copy()
# 引入p1错误
corrupted5[4] = 1 - corrupted5[4]
decoded5 = encoder.decode(corrupted5)
assert np.array_equal(data5, decoded5), "测试5失败"
print("所有测试通过!")