BCH码介绍

文章目录

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;
}