Buck Blog · 博客正文

返回技术分享首页
前向纠错FEC

前向纠错FEC

> 目标:用一份文档快速建立 FEC(Forward Error Correction,前向纠错)的完整认知:

> 1)常见算法有哪些、各自优劣;

> 2)一种典型算法的纠错原理;

> 3)在 FPGA 中如何落地实现;

> 4)给出核心伪代码,便于工程实现。

---

1. FEC 是什么,为什么重要

FEC 的核心思想:

• 发送端在原始数据中加入冗余校验信息;

• 接收端不依赖重传,仅根据冗余信息检测并纠正部分错误。

FEC 的工程价值:

• 降低误码率(BER)

• 提升链路有效吞吐(减少重传)

• 提升系统鲁棒性(弱信道、长距离、高速链路)

典型应用:

• 光通信(400G/800G 以太网)

• 无线通信(4G/5G)

• 存储与传输(SSD、卫星链路)

• 高速 SerDes / Chiplet 互连

---

2. 常见 FEC 算法家族与优劣

2.1 奇偶校验(Parity)

• 特点:最简单,硬件开销极低

• 能力:只能检测奇数个 bit 错误,通常不能纠错

• 场景:低成本错误检测

优点:

• 逻辑极简、时延极低

缺点:

• 纠错能力几乎没有

2.2 汉明码(Hamming)

• 特点:典型线性分组码

• 能力:常见 SEC/DED(单错纠正,双错检测)

• 场景:存储保护(ECC 内存等)

优点:

• 编解码复杂度低

• 适合中小规模硬件

缺点:

• 强噪声信道能力不足

2.3 BCH 码

• 特点:强大的代数分组码,可配置纠错能力 t

• 场景:NAND Flash、存储控制器

优点:

• 多比特纠错能力强

• 理论体系成熟

缺点:

• t 增大时解码复杂度和时延明显上升

2.4 Reed-Solomon(RS)码

• 特点:符号级纠错(按 GF(2^m) 符号)

• 场景:光盘、广播、部分通信系统

优点:

• 对突发错误(burst error)效果好

• 工程成熟度高

缺点:

• 高速超大吞吐场景中,硬件开销与功耗压力较大

2.5 卷积码 + Viterbi

• 特点:序列码,经典最大似然解码

• 场景:早期无线通信

优点:

• 理论和实现成熟

缺点:

• 码长与约束长度上升时复杂度快速增加

2.6 Turbo 码

• 特点:迭代译码,接近香农极限(历史上)

• 场景:3G/4G 某些链路

优点:

• 误码性能好

缺点:

• 迭代译码时延较高、并行化复杂

2.7 LDPC(Low-Density Parity-Check)码

• 特点:稀疏校验矩阵 + 迭代译码

• 场景:5G、Wi-Fi、高速以太网/光通信等

优点:

• 性能强,接近香农极限

• 适合高并行硬件实现

缺点:

• 译码架构复杂,存储带宽和消息调度要求高

2.8 Polar 码

• 特点:信道极化理论,5G 控制信道常见

• 优点:理论优雅,某些场景表现好

• 缺点:实现和优化策略依赖具体码长与列表译码参数

---

3. 如何选择 FEC(工程视角)

选择维度建议:

1. 目标 BER / FER

2. 吞吐目标(Gbps)

3. 允许时延(ns/us/ms)

4. 资源预算(LUT/BRAM/DSP)

5. 功耗预算

6. 标准约束(协议规定了哪种码)

经验规则:

• 存储类多见 BCH/LDPC(取决于介质误码特性)

• 高速通信链路主流是 LDPC / RS-FEC(视协议)

• 控制信道、短码场景可见 Polar/其他专用码

---

4. 典型算法深讲:LDPC

> 这里选择 LDPC 作为典型算法,因为它在现代高速通信和网络中非常主流,且 FPGA 实现价值高。

4.1 基本定义

LDPC 是一种线性分组码,满足:

H · cT = 0

• H:稀疏校验矩阵(M x N)

• c:码字

译码本质:

• 给定信道软信息(LLR),通过 Tanner 图上的迭代消息传递,逼近最可能码字。

4.2 Tanner 图视角

图中有两类节点:

• 变量节点(VN,Variable Node)

• 校验节点(CN,Check Node)

边由校验矩阵 H 的 1 决定。译码迭代由两步交替:

1. VN -> CN 消息更新

2. CN -> VN 消息更新

4.3 译码算法(简化 Min-Sum)

在工程中常用 Min-Sum 及其修正版本(Normalized/Offset Min-Sum),原因是:

• 比 Sum-Product 更容易硬件化

• 复杂度低,性能接近可接受

CN 更新核心:

• 符号取邻居符号异或(或乘积)

• 幅值取最小值(或修正后的最小值)

VN 更新核心:

• 先验 LLR + 来自所有 CN 的外信息求和

判决:

• LLR < 0 判 1,否则判 0

• 满足全部校验方程可提前停止

---

5. LDPC 在 FPGA 中的实现方案

5.1 顶层模块划分建议

LLR Input Buffer
    -> VN Update Engine
    -> CN Update Engine
    -> Hard Decision + Syndrome Check
    -> Iteration Controller
    -> Output Buffer

建议再加:

• 配置寄存器(码型/迭代上限/早停开关)

• 统计模块(迭代次数、失败计数、吞吐)

5.2 数据通路与存储组织

关键数据:

• 信道先验 LLR

• VN->CN 消息

• CN->VN 消息

• 硬判决比特

存储建议:

• 消息 RAM 双缓冲(ping-pong)

• 按校验层(layer)分块存储,适配 Layered Decoding

• 量化位宽固定点(如 6~8 bit)

5.3 调度策略

两种主流:

1. Flooding:全局轮次更新

2. Layered:分层更新(收敛更快,常更优)

工程上 Layered 常见优势:

• 同等性能下迭代次数更少

• 总时延更低

5.4 关键优化点

1. 定点量化优化:

• 位宽太小性能损失,太大资源/功耗上升

2. 早停(Early Stop):

• syndrome=0 时提前结束迭代

3. 并行度折中:

• 并行越高吞吐越高,但 BRAM 带宽和布线压力更大

4. 消息裁剪与饱和:

• 防止数值溢出,提高稳定性

---

6. 核心算法伪代码(LDPC Min-Sum)

6.1 解码主流程伪代码

input: llr_channel[N], H_structure, iter_max
state:
  msg_v2c[edge_num]
  msg_c2v[edge_num]
  llr_apost[N]

init:
  for each edge (v,c):
    msg_v2c[v,c] = llr_channel[v]

for iter in 1..iter_max:

  // CN update
  for each check node c:
    gather all incoming msg_v2c[* ,c]
    sign_all = product(sign(msg_v2c))
    min1, min2 = two_smallest(abs(msg_v2c))
    for each neighbor v of c:
      sign_out = sign_all * sign(msg_v2c[v,c])
      mag_out  = (abs(msg_v2c[v,c]) == min1) ? min2 : min1
      msg_c2v[c,v] = sign_out * scale_or_offset(mag_out)

  // VN update
  for each variable node v:
    sum_llr = llr_channel[v]
    for each neighbor c of v:
      sum_llr += msg_c2v[c,v]
    llr_apost[v] = saturate(sum_llr)

    for each neighbor c of v:
      extrinsic = llr_apost[v] - msg_c2v[c,v]
      msg_v2c[v,c] = saturate(extrinsic)

  // hard decision + syndrome check
  for v in 0..N-1:
    hard[v] = (llr_apost[v] < 0) ? 1 : 0

  if syndrome_ok(hard, H_structure):
    return hard, iter, SUCCESS

return hard, iter_max, FAIL

6.2 Syndrome 检查伪代码

function syndrome_ok(hard_bits, H):
  for each check node c:
    parity = 0
    for each v connected to c:
      parity ^= hard_bits[v]
    if parity != 0:
      return false
  return true

---

7. 性能、资源、功耗三者折中

7.1 吞吐估算(简化)

可粗估:

Throughput ≈ frac{N · R · fclₖ · P}{Iavg · C}

其中:

• N:码长

• R:码率

• fclₖ:时钟频率

• P:并行度

• Iavg:平均迭代次数

• C:每次迭代等效周期因子

结论:

• 降低平均迭代次数(如早停、layered)通常收益很大。

7.2 常见“看起来快、其实不优”的设计

1. 并行度盲目拉高:

• BRAM 端口不够,最终频率下降

2. 位宽盲目加大:

• 误码性能提升有限,资源与功耗显著增加

3. 不做早停:

• 平均时延和功耗都偏高

---

8. 测试与验证建议

8.1 功能验证

• 与软件黄金模型(Python/C)逐向量对比

• 覆盖不同 SNR、码率、码长

• 注入随机 bit 错误与 burst 错误

8.2 性能验证

• 吞吐(Gbps)

• 平均/最大迭代次数

• 时延分布

8.3 误码性能验证

• BER/FER 曲线

• 与浮点参考模型差距

• 不同量化位宽下性能对比

8.4 硬件实现验证

• 时序收敛(WNS/TNS)

• 资源占用(LUT/FF/BRAM/DSP)

• 功耗分析(动态/静态)

---

9. RS-FEC 编码/解码伪代码(工程补充)

> 这里给出通用 RS(n,k) 框架伪代码,便于对照硬件实现。不同标准(如 RS(544,514))参数不同,但流程一致。

9.1 RS-FEC 编码伪代码(系统码)

思路:

• 原始数据作为前 k 个符号;

• 用生成多项式对消息多项式做模运算得到 parity;

• 码字 = data || parity。

input:
  data_sym[0..k-1]      // GF(2^m) 符号
  gen_poly[0..2t]       // 生成多项式

state:
  parity[0..2t-1] = 0

for i in 0..k-1:
  feedback = data_sym[i] XOR parity[2t-1]

  // LFSR 形式更新 parity 寄存器
  for j in (2t-1) downto 1:
    if feedback != 0:
      parity[j] = parity[j-1] XOR gf_mul(feedback, gen_poly[j])
    else:
      parity[j] = parity[j-1]

  if feedback != 0:
    parity[0] = gf_mul(feedback, gen_poly[0])
  else:
    parity[0] = 0

codeword = concat(data_sym[0..k-1], parity[2t-1..0])
return codeword

9.2 RS-FEC 解码伪代码(硬判决,经典流程)

标准步骤:

1) 计算综合(Syndrome)

2) Berlekamp-Massey 求误差定位多项式

3) Chien 搜索找错误位置

4) Forney 算法求错误值

5) 修正码字

input:
  recv[0..n-1]

// Step1: syndrome
for i in 1..2t:
  S[i] = poly_eval(recv, alpha^i)

if all S[i] == 0:
  return recv, NO_ERROR

// Step2: error locator polynomial
Lambda = berlekamp_massey(S)

// Step3: find error locations
err_pos = []
for p in 0..n-1:
  if poly_eval(Lambda, alpha^(-p)) == 0:
    err_pos.append(p)

if len(err_pos) > t:
  return recv, DECODE_FAIL

// Step4: error magnitude
Omega = syndrome_to_omega(S, Lambda)
for each p in err_pos:
  e = forney_eval(Omega, Lambda, p)
  recv[p] = recv[p] XOR e

// Step5: optional re-check
recompute syndrome S2
if any S2 != 0:
  return recv, DECODE_FAIL

return recv, DECODE_OK

9.3 FPGA 实现提示(RS-FEC)

• gf_mul/gf_inv 建议查表(LUT)或对数表(log/antilog)实现。

• Syndrome 计算可流水化,按符号流并行处理。

• Chien 搜索天然适合并行展开。

• Forney 可做时分复用降低资源。

---

10. 其他相关信息补充

10.1 标准与协议关联

不同协议会规定特定 FEC:

• 高速以太网常见 RS-FEC

• 5G 数据信道广泛使用 LDPC

工程上要先看标准,再定算法,不可反过来。

10.2 FEC 与系统架构关系

• FEC 放在 PHY/PCS 附近时,接口延迟与带宽规划要提前做

• FEC 与重传机制(ARQ/HARQ)是互补关系

• FEC 参数会影响整机功耗与热设计

10.3 何时不该上“重型 FEC”

• 链路本身误码很低且时延极敏感

• 资源预算极其紧张

• 协议并不要求该级别纠错

---

11. 初学者快速上手路径(建议)

1. 先实现 Hamming/BCH 小例子,理解编码-译码闭环

2. 再做 LDPC 简化版本(短码长、低并行)

3. 加入早停和量化优化

4. 最后做高吞吐流水与并行扩展

---

12. 一页总结

• FEC 的本质是“冗余换可靠性”。

• 常见算法各有适配场景:

• 简单检测:Parity

• 轻量纠错:Hamming

• 存储强纠错:BCH

• 突发错误友好:RS

• 现代高速通信主力:LDPC

• 以 LDPC 为例,FPGA 落地关键在:

• 消息存储组织

• 迭代调度(尤其 layered)

• 量化与早停策略

• 真正工程可用的 FEC 方案,需要同时满足:

• 误码性能目标

• 吞吐/时延目标

• 资源与功耗预算

---

附录A:FEC 方案选型速查表

| 场景 | 推荐算法 | 关注点 |

| ------------- | ---------------- | -------------------- |

| 低复杂度检测 | Parity/Hamming | 低开销、低时延 |

| NAND/存储控制 | BCH/LDPC | 多比特纠错能力 |

| 高速链路 | RS/LDPC | 吞吐、并行与标准兼容 |

| 无线数据面 | LDPC/Turbo/Polar | 性能与时延折中 |

---

> 注:不同标准版本和器件平台会影响最终算法选择与参数,请结合目标协议规范和 FPGA 资源报告做最终定型。