2、信道编码原理:Turbo码与LDPC码的演进、咬尾卷积码、速率匹配与HARQ机制

信道编码,说白了就是给数据加一层「防弹衣」。无线信道有多恶劣,做过物理层的人都懂——多径衰落、干扰、噪声,随便一个都能让比特翻个底朝天。我刚开始做3G芯片那会儿,Turbo码刚兴起,大家都觉得这东西复杂得离谱。后来做4G、5G,LDPC又成了新宠。今天咱们就把这几种编码的来龙去脉、实现细节,掰开了聊。

2.1 从卷积码到Turbo码:一场革命

早期的蜂窝通信,比如2G的GSM,用的都是卷积码。卷积码的原理很简单:把输入比特和几个移位寄存器里的历史比特做异或,生成编码输出。它的译码用Viterbi算法,说白了就是找一条最可能的路径。

但卷积码有个硬伤——性能离香农限差得远。我记得当年做项目时,为了在1%的误块率下多争取0.5dB增益,整个团队折腾了三个月。后来Turbo码的出现,彻底改变了局面。

Turbo码的核心思想:两个卷积编码器并行工作,中间加一个交织器。译码时两个译码器迭代交换软信息,像两个人互相纠正对方的错误。

Turbo码的编码结构其实不复杂。我画个图你就明白了:

Turbo码编码器结构 输入比特 系统比特 编码器1 (RSC) 交织器 编码器2 (RSC) 校验1 校验2 复用 +打孔 码流

Turbo码的译码是迭代的。每次迭代,两个译码器交换「外信息」——说白了就是我对你这比特的置信度,你参考一下。一般迭代4到8次就能收敛。我在项目中试过,迭代6次和8次性能差不到0.1dB,但延迟翻倍。所以实际芯片里,迭代次数是个需要权衡的参数。

经验之谈:Turbo译码器的硬件实现,最耗资源的是交织器地址生成和Log-MAP查表。我建议用滑动窗结构,把译码窗口切成小块,这样存储需求能降一半。

2.2 LDPC码:5G的新选择

LDPC码其实比Turbo码发明得更早,1960年代就有人提出来了。但那时候计算机能力太弱,根本玩不转。直到90年代末,大家发现LDPC码用迭代译码,性能可以逼近香农限,这才重新火起来。

5G为什么选LDPC而不是Turbo?说白了,两个原因:

  • 并行译码:LDPC的校验矩阵天然支持并行,吞吐量可以做得极高。Turbo码的SISO译码器是串行的,想提高吞吐量就得复制多个译码器,面积翻倍。
  • 灵活码率:LDPC通过打孔和缩短,可以很灵活地适配各种码率。Turbo码要改变码率,得改打孔模式,实现起来麻烦得多。

LDPC的译码算法,最常用的是和积算法(SPA)和最小和算法(MSA)。我给你们看个简化版的MSA实现:

// 最小和算法核心步骤(简化版)
for (int iter = 0; iter < MAX_ITER; iter++) {
    // 变量节点到校验节点
    for (每个变量节点 v) {
        for (每个相连的校验节点 c) {
            LLR[v][c] = LLR_ch[v] + sum(LLR[c'][v] for c' != c);
        }
    }
    // 校验节点到变量节点
    for (每个校验节点 c) {
        for (每个相连的变量节点 v) {
            min1 = 最小绝对值, min2 = 第二小绝对值;
            sign = 符号乘积;
            LLR[c][v] = sign * (v == min1_idx ? min2 : min1);
        }
    }
    // 硬判决 + 校验
    if (所有校验方程满足) break;
}

嗯,这里要注意。MSA比SPA性能差大概0.2-0.3dB,但硬件实现简单太多了。我在5G芯片项目里,最后选的就是MSA加一个归一化因子修正,性能和SPA几乎一样,面积却小了40%。

避坑指南:我曾经在LDPC译码器的定点化上栽过跟头。LLR的量化位数,少了性能差,多了面积大。我的经验是:8比特量化,符号位1比特,整数部分3比特,小数部分4比特,这个配置在大多数场景下都够用。

2.3 咬尾卷积码:LTE的控制信道主力

咬尾卷积码(Tail-biting Convolutional Code)是LTE控制信道用的编码。它和普通卷积码的区别在于:编码器的初始状态不是0,而是输入的最后几个比特。这样编码完,编码器的结束状态和初始状态一样,就像咬住了自己的尾巴。

为什么要这么设计?因为控制信道的传输块很小,比如就几十个比特。如果用普通卷积码,末尾要加几个0来复位编码器,浪费了宝贵的码率。咬尾卷积码没有这个开销。

译码时,咬尾卷积码不能用标准的Viterbi算法,因为不知道初始状态。常用的方法是:

  1. 环绕Viterbi算法:把接收序列复制一遍,做两倍长度的Viterbi译码,取中间一段。
  2. 循环MAP算法:用BCJR算法,在网格图上绕一圈,迭代收敛到正确的初始状态。

我在LTE芯片里用的是环绕Viterbi,实现简单,性能也够用。但要注意,环绕Viterbi的译码深度要选好,太浅了性能差,太深了延迟大。我一般选5倍约束长度。

2.4 速率匹配:把码流塞进资源格

速率匹配,说白了就是让编码后的比特数和物理资源能承载的比特数对上。LTE和5G的速率匹配都包含三个步骤:

步骤 操作 说明
1. 子块交织 把编码比特按行写入、按列读出 打散连续错误,提高译码性能
2. 比特收集 把系统比特和校验比特按顺序排列 形成循环缓冲区
3. 比特选择 从缓冲区中选取需要的比特数 冗余版本(RV)决定起始位置

5G的速率匹配比LTE多了一个LDPC特有的步骤——比特填充。因为LDPC的校验矩阵有固定的结构,有些比特位置是固定的填充比特,速率匹配时要跳过它们。

实现技巧:速率匹配的硬件实现,我建议用地址映射的方式,不要真的去搬移数据。维护一个地址生成器,直接从循环缓冲区里读对应位置的比特,这样省存储、省功耗。

2.5 HARQ机制:错了就重传

HARQ(混合自动重传请求)是物理层和MAC层之间的桥梁。它把FEC和ARQ结合起来:第一次传错了,不直接丢弃,而是存下来。重传时,把新旧数据合并起来译码,成功率更高。

HARQ有两种类型:

  • Chase合并(CC):重传和第一次传的完全一样。接收端把两次的LLR相加,再做译码。实现简单,但增益有限。
  • 增量冗余(IR):每次重传发不同的校验比特。接收端把多次传输的比特拼起来,等效于一个更低码率的码。增益大,但实现复杂。

5G用的是IR-HARQ。每次重传的冗余版本(RV)不同,从循环缓冲区的不同位置开始读。我给你们看个典型的RV定义:

// 5G LDPC的冗余版本起始位置
// 循环缓冲区大小: N_cb
// RV0: 0
// RV1: floor(N_cb * 17/66)
// RV2: floor(N_cb * 33/66)
// RV3: floor(N_cb * 50/66)

为什么选这些位置?因为要保证不同RV之间的码字尽可能不重叠,最大化编码增益。我在调试HARQ时发现,RV顺序对性能影响很大。一般推荐RV0→RV2→RV3→RV1的顺序,这样每次重传都能提供最大的新信息。

避坑指南:我曾经在HARQ的软合并上踩过坑。接收端要存储每次传输的LLR,但LLR的量化精度不能太低。我建议用6比特存LLR,合并时用饱和加法,防止溢出。另外,HARQ进程的管理要小心,每个进程的软buffer是独立的,不能搞混。

嗯,信道编码这块内容很多,但核心就这几个点。Turbo码和LDPC码各有千秋,咬尾卷积码在短码场景下依然有用,速率匹配和HARQ则是把编码和实际传输连接起来的关键。做物理层芯片,这些算法都得吃透,才能在面积、功耗、性能之间找到最优解。


公众号:蓝海资料掘金营,微信deep3321