2、信道编码原理:Turbo码与LDPC码的演进、咬尾卷积码、速率匹配与HARQ机制
信道编码,说白了就是给数据加一层「防弹衣」。无线信道有多恶劣,做过物理层的人都懂——多径衰落、干扰、噪声,随便一个都能让比特翻个底朝天。我刚开始做3G芯片那会儿,Turbo码刚兴起,大家都觉得这东西复杂得离谱。后来做4G、5G,LDPC又成了新宠。今天咱们就把这几种编码的来龙去脉、实现细节,掰开了聊。
2.1 从卷积码到Turbo码:一场革命
早期的蜂窝通信,比如2G的GSM,用的都是卷积码。卷积码的原理很简单:把输入比特和几个移位寄存器里的历史比特做异或,生成编码输出。它的译码用Viterbi算法,说白了就是找一条最可能的路径。
但卷积码有个硬伤——性能离香农限差得远。我记得当年做项目时,为了在1%的误块率下多争取0.5dB增益,整个团队折腾了三个月。后来Turbo码的出现,彻底改变了局面。
Turbo码的核心思想:两个卷积编码器并行工作,中间加一个交织器。译码时两个译码器迭代交换软信息,像两个人互相纠正对方的错误。
Turbo码的编码结构其实不复杂。我画个图你就明白了:
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算法,因为不知道初始状态。常用的方法是:
- 环绕Viterbi算法:把接收序列复制一遍,做两倍长度的Viterbi译码,取中间一段。
- 循环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