文章目录
BCH码是循环码的一个重要子类。其名称来源于三位独立发现者博斯(Bose)、查德胡里(Chaudhuri)和霍昆格姆(Hocquenghem)。汉明码(仅能纠1个错误)可视为BCH码的一个特例(t=1)。
BCH码的核心思想,是通过在传输的数据中加入精心设计的冗余信息,让接收端不仅能检测出错误,还能自动修正。这一过程建立在严谨的有限域(伽罗瓦域) 数学理论之上。
数学基础:BCH码的构造和运算都在一个名为GF(2m)的有限域中进行。这个域里的所有元素都可以用m位的二进制数来表示,并遵循一套特定的加法和乘法规则。例如,在GF(23)中,元素可以是{0, 1, α, α², α³, ..., α⁶}。
2、生成多项式:这是BCH码编码的核心。对于一个能纠t个错误的BCH码,其生成多项式 g(x) 是通过在有限域中选取特定的2t个连续元素作为根,并求其最小多项式的最小公倍式(LCM) 得到的。通过这个精心构造的多项式,可以保证码字的最小距离d_min ≥ 2t+1,从而具备纠正t个错误的能力。
3、编码与解码流程:
编码:将待发送的k位信息看作一个多项式u(x)。用x^(n-k)乘以u(x)后,除以生成多项式g(x),得到的余数r(x) 就是校验位。最终的码字c(x)就是信息位与校验位的组合。
解码:接收端收到可能出错的码字r'(x)后,首先计算伴随式(Syndrome)来判断是否有误。如果有误,则通过伯利坎普-梅西(Berlekamp-Massey)迭代算法和钱天闻(Chien)搜索等关键步骤,精确定位错误位置并予以纠正。
应用:从太空到口袋的可靠保障
BCH码凭借其强大的纠错能力,已成为保障数据可靠性的关键技术,应用范围极广。
深空通信:在极其微弱的信号和巨大的噪声下,可靠性至关重要。NASA在火星探测器通信中就采用了RS-BCH级联码,在0.1dB信噪比下,将误码率从10⁻³降至10⁻⁶,数据传输成功率从82%提升至99.7%。
5G移动通信:在5G新空口(NR)标准中,BCH码与Polar码级联,用于保护至关重要的控制信道信息,共同提升了系统的整体性能。
数据存储:无论是NAND闪存(如SSD)还是光盘,BCH码都是对抗数据损坏的核心技术。例如,企业级SSD采用BCH码后,可将原始误码率从10⁻⁵显著降低至10⁻¹⁰,有效延长了设备寿命。
其他关键领域:BCH码还广泛用于卫星通信、光纤通信、无线传感网络等。其缩短码型(n-s, k-s)更提供了极大的灵活性,能适配各种字节长度的信息编码需求。
C语言实现
编码
bash
#include <stdio.h>
#include <stdint.h>
#include <string.h>
// BCH(15,7) 参数定义
#define BCH_N 15 // 总码长
#define BCH_K 7 // 信息位长度
#define BCH_M (BCH_N - BCH_K) // 校验位长度 8
// 生成多项式 g(x) = x^8 + x^7 + x^6 + x^4 + 1
// 二进制: 1 1101 0001 = 0x1D1
#define BCH_POLY 0x1D1
/**
* BCH编码函数
* @param data 输入7位信息数据 (仅低7位有效)
* @return 15位编码后的码字
*/
uint16_t bch_encode(uint8_t data) {
uint16_t code = (uint16_t)data << BCH_M; // 信息位左移8位,留出校验位空间
// 循环移位除法,计算校验位
for (int i = 0; i < BCH_K; i++) {
if (code & 0x4000) { // 检查最高位 (第14位)
code ^= (BCH_POLY << 7); // 异或生成多项式(对齐最高位)
}
code <<= 1; // 左移一位
}
// 此时code的高8位是余数(校验位),低7位是0
// 将校验位与原始信息位组合成最终码字
uint16_t encoded = ((uint16_t)data << BCH_M) | ((code >> 7) & 0xFF);
return encoded;
}
解码
bash
// 有限域GF(2^4)下的数据表
static const uint8_t gf_exp[16] = {
1, 2, 4, 8, 3, 6, 12, 11, 5, 10, 7, 14, 15, 13, 9, 0
};
static const uint8_t gf_log[16] = {
0, 0, 1, 4, 2, 8, 5, 10, 3, 14, 9, 7, 6, 13, 11, 12
};
// 有限域乘法
static uint8_t gf_mul(uint8_t a, uint8_t b) {
if (a == 0 || b == 0) return 0;
return gf_exp[(gf_log[a] + gf_log[b]) % 15];
}
// 有限域除法
static uint8_t gf_div(uint8_t a, uint8_t b) {
if (a == 0) return 0;
if (b == 0) return 0; // 错误处理
return gf_exp[(gf_log[a] - gf_log[b] + 15) % 15];
}
/**
* BCH译码函数 (使用BM算法,纠正最多2个错误)
* @param rx 接收到的15位码字
* @param data 输出纠正后的7位信息数据
* @return 返回检测到的错误个数,-1表示不可纠正
*/
int bch_decode(uint16_t rx, uint8_t *data) {
uint8_t s[4] = {0}; // 伴随式 S1, S2, S3, S4 (t=2需要2t=4个)
// 1. 计算伴随式 S_i = rx(alpha^i)
for (int i = 1; i <= 4; i++) {
uint16_t poly = rx;
uint8_t sum = 0;
// 使用霍纳法则计算多项式在 alpha^i 的值
for (int j = BCH_N - 1; j >= 0; j--) {
sum = gf_mul(sum, gf_exp[i % 15]);
if (poly & (1 << j)) {
sum ^= 1;
}
}
s[i-1] = sum;
}
// 如果没有错误,所有伴随式应为0
if (s[0] == 0 && s[1] == 0 && s[2] == 0 && s[3] == 0) {
*data = rx >> BCH_M;
return 0;
}
// 2. BM算法求错误位置多项式 sigma(x)
uint8_t sigma[3] = {1, 0, 0}; // sigma[0]=1, sigma[1]=sigma1, sigma[2]=sigma2
uint8_t b[3] = {1, 0, 0};
uint8_t delta, delta_prev = 1;
int L = 0;
for (int r = 1; r <= 4; r++) {
// 计算差值 delta
delta = 0;
for (int i = 0; i <= L; i++) {
delta ^= gf_mul(sigma[i], s[r-1-i]);
}
if (delta == 0) {
// 更新b
for (int i = L; i >= 1; i--) {
b[i] = b[i-1];
}
b[0] = 0;
} else {
uint8_t t[3];
memcpy(t, sigma, sizeof(t));
// sigma = sigma - delta * x^r * b
for (int i = 0; i <= L; i++) {
sigma[i+r] ^= gf_mul(delta, b[i]);
}
if (2*L <= r-1) {
L = r - L;
for (int i = 0; i <= L; i++) {
b[i] = gf_div(t[i], delta);
}
} else {
for (int i = L; i >= 1; i--) {
b[i] = b[i-1];
}
b[0] = 0;
}
}
}
// 3. 钱搜索找到错误位置
int err_count = 0;
uint16_t error_pos = 0;
for (int i = 0; i < BCH_N; i++) {
uint8_t eval = sigma[0];
uint8_t x = gf_exp[i % 15];
eval ^= gf_mul(sigma[1], x);
eval ^= gf_mul(sigma[2], gf_mul(x, x));
if (eval == 0) {
error_pos |= (1 << i);
err_count++;
}
}
// 检查错误个数是否超出纠错能力
if (err_count > 2) {
return -1; // 不可纠正
}
// 4. 纠正错误
uint16_t corrected = rx ^ error_pos;
*data = corrected >> BCH_M;
return err_count;
}