文章目录
-
- 摘要
- [1 研究背景](#1 研究背景)
- [2 译码算法](#2 译码算法)
-
- [2.1 SC](#2.1 SC)
- [2.2 SCL](#2.2 SCL)
- [2.3 BP](#2.3 BP)
- [2.4 SSC](#2.4 SSC)
- [2.5 SCAN](#2.5 SCAN)
- [3 仿真设置](#3 仿真设置)
- [4 总结](#4 总结)
摘要
极化码(Polar Code)是迄今唯一被严格数学证明能在二进制输入对称信道上达到香农极限的信道编码方案,并已广泛应用于5G控制信道标准。本文系统梳理了极化码译码领域五种核心算法------SC(串行抵消)、SCL(串行抵消列表)、BP(置信传播)、SCAN(软抵消)和SSC(简化串行抵消) 的数学原理、实现流程与工程特性,并基于matlab仿真分析了对应算法的误码率和误帧率。
1 研究背景
-
极化码(Polar Code)是2009年由Erdal Arıkan提出的编码方案,也是目前唯一被严格数学证明能够在二进制输入对称信道上达到香农极限的构造性编码。2016年,极化码被3GPP正式采纳为5G增强移动宽带场景中控制信道(PDCCH、PBCH)的编码标准。
-
极化码的译码算法历经多年发展,形成了从基础到优化的完整体系。本文将系统介绍四种主流译码算法的原理与实现步骤:SC(串行抵消)、SCL(串行抵消列表)、BP(置信传播)和SSC(简化串行抵消) 。
2 译码算法
2.1 SC
-
SC译码是极化码最基础的译码范式,本质是一种基于贝叶斯递归计算的逐比特判决过程。译码器从左至右依次估计每个比特,利用前序已确定比特的硬判决结果,递归计算当前比特在合成信道下的后验概率,再通过符号映射完成判决。
-
关键在于"串行"二字:译码器必须按顺序,从第一个比特u₁开始,先利用所有接收信号去"猜"u₁;猜完后假设自己猜对了,用这个值结合接收信号去猜u₂;再依次类推直到最后一个比特。这种"假设之前全对"的策略既是其计算简单的优点,也是性能瓶颈------一旦中间某个比特判错,错误会像多米诺骨牌一样传播下去。
SC译码的核心是两种基本运算:
-
f运算:用于计算当前比特的对数似然比(LLR)
-
g运算:在已知前序比特的条件下更新LLR
以N=2的极化码为例,编码关系为x₁=u₁⊕u₂,x₂=u₂。译码时先计算u₁的LLR(f运算),判决后再计算u₂的LLR(g运算)。
实现步骤为:
-
初始化:设置迭代次数N,初始化硬判决输出
-
逐比特译码:从接收码字中依次取出比特,进行LLR计算和硬判决
-
迭代处理:重复步骤2直到处理完所有比特
-
输出结果:输出最终的硬判决序列
2.2 SCL
SCL译码引入宽度为L的候选路径列表(L为列表大小)。在每一信息比特位置,算法保留L个最优LLR路径分支,通过路径度量进行剪枝。
当设置L=1时,SCL退化为标准的SC译码。
步骤为
-
初始化:创建L条译码路径,每条路径初始度量值为0
-
逐比特译码:对每个信息比特,每条路径分裂为0和1两个分支
-
路径度量更新:计算每条新路径的累积度量值
-
剪枝:从2L条候选路径中保留度量最优的L条
-
冻结比特处理:冻结比特不分裂,直接设置为固定值
-
输出:选择度量最优的路径作为译码结果
实际工程中常采用CA-SCL(CRC辅助SCL) 方案,在译码结束后对所有幸存路径进行CRC校验,选择通过校验且度量最优的路径作为输出
2.3 BP
BP译码将极化码视为一种特殊的因子图,利用消息传递机制进行迭代译码。图中每个节点关联两种类型的概率消息:
-
左到右消息(L→R) :从因子图左侧向右侧传播
-
右到左消息(R→L) :从因子图右侧向左侧传播
在每次迭代中,变量节点将信念传递给校验节点,校验节点处理后再将信念传回变量节点。消息在相邻节点间反复传递,直到收敛或达到最大迭代次数。
步骤为:
-
初始化:将信道接收值初始化为右到左消息(R→L),左到右消息(L→R)初始化为0或均匀分布
-
消息更新:按因子图结构,交替更新所有节点的L→R和R→L消息
-
迭代判断:检查是否达到最大迭代次数或消息是否收敛
-
硬判决:根据最终LLR进行硬判决输出译码结果
2.4 SSC
SSC译码是SC译码的重大优化,由Alamdar-Yazdi和Kschischang提出,利用极化码的分形结构------冻结比特与信息比特在码树中的规律性分布,将整棵长度为N的码树划分为若干独立可解的子树:
-
全冻结子树(Rate-0节点) :所有比特均为冻结比特,直接输出0,无需任何LLR计算
-
全信息子树(Rate-1节点) :所有比特均为信息比特,调用快速SC或查表法直接译码
-
混合子树:同时包含冻结和信息比特,才启动标准SC流程
算法步骤为:
-
配置译码参数:确定码长、信息位集合等
-
构建码树:将极化码表示为二叉树结构
-
节点分类:递归判断每个节点的类型(Rate-0、Rate-1或混合)
-
快速处理:Rate-0节点直接输出全0;Rate-1节点调用快速译码
-
标准SC处理:仅对混合节点执行标准SC译码
-
输出结果:合并所有节点的译码结果
2.5 SCAN
可以视为SC算法与BP算法之间的桥梁------它继承了SC的调度顺序以降低复杂度,同时保留了BP的软信息输出能力,算法的核心在于在SC的串行调度框架下运行软信息迭代传递。译码器在极化码的因子图上,按特定顺序(通常从左至右再反向)循环更新两类消息:
-
L→R消息(左到右) :从因子图左侧节点向右侧传播
-
R→L消息(右到左) :从因子图右侧节点向左侧传播
与BP不同,SCAN不对所有节点同时更新------而是按照SC的串行调度顺序逐节点更新消息。这种设计使得SCAN在保持软输出的同时,显著降低了BP的计算复杂度。
算法步骤:
-
初始化:将接收信号的信道LLR初始化为因子图右侧的R→L消息,左侧L→R消息初始化为0或均匀分布
-
迭代译码:按SC调度顺序(从左至右再反向),逐节点更新L→R和R→L两类消息
-
迭代判断:检查是否达到最大迭代次数(通常为1-4次)
-
软输出:输出所有比特的软信息LLR,供后续迭代或联合检测使用
3 仿真设置

仿真流程如上图所示。




在这里插入图片描述
c
function u_hat = polar_SSC_decode(decoder_tree_initial, G, B, LLR)
%======================================
%============遍历树开始===================
global PCparams;
n=PCparams.n;
u_hat = zeros(1,2^(n+1)-1);%初始化译码比特
node_index = 1; %取第一个节点,即根节点
decoder_tree = decoder_tree_initial;
decoder_tree{node_index}{2} = LLR; %初始化根节点的LLR
while decoder_tree{1}{7}~=2
if decoder_tree{node_index}{7} == 0 && decoder_tree{node_index}{4} ~=-1 %节点未激活,且不是叶节点
%1. 计算左子节点的LLR,节点状态=1
node_llr = decoder_tree{node_index}{2};
left_node_llr = fFunction( node_llr(1:2:end), node_llr(2:2:end) );
decoder_tree{node_index}{7} = 1;
%2. 并取左子节点
node_index = decoder_tree{node_index}{4};
decoder_tree{node_index}{2} = left_node_llr;
continue;
elseif decoder_tree{node_index}{7} == 0 && decoder_tree{node_index}{4} ==-1 %节点未激活,但是叶节点(叶节点只能是0节点或者1节点)
% 计算节点的B,节点状态=2
%判断节点类型,计算信息比特;
layer = floor( log2(node_index) ); %该节点位于哪一层
layer_num = 2^(n-layer); %该层对应L和B的维度
if decoder_tree{node_index}{1} == 0 %节点类型为0节点
decoder_tree{node_index}{3} = zeros( 1, layer_num );
elseif decoder_tree{node_index}{1} == 1 %节点类型为1节点
decoder_tree{node_index}{3} = ( decoder_tree{node_index}{2}<0 );
u_temp = decoder_tree{node_index}{3};
u_temp = u_temp( B{layer+1}+1 );
u_hat( node_index*layer_num:(node_index+1)*layer_num-1 ) = mod( u_temp*G{layer+1}, 2 );
end
decoder_tree{node_index}{7} = 2;
% 取父节点
node_index = decoder_tree{node_index}{6};
continue;
elseif decoder_tree{node_index}{7} == 1 && decoder_tree{ decoder_tree{node_index}{5} }{7} ==0 %节点激活过一次(肯定不是叶节点),并且右子节点未激活过
%计算右子节点L
right_node_index = decoder_tree{node_index}{5};
left_node_index = decoder_tree{node_index}{4};
node_llr = decoder_tree{node_index}{2};
right_node_llr = node_llr(1:2:end).*( 1-2* decoder_tree{left_node_index}{3} ) + node_llr(2:2:end);
decoder_tree{right_node_index}{2} = right_node_llr;
%取右子节点
node_index = right_node_index;
continue;
elseif decoder_tree{node_index}{7} == 1 && decoder_tree{ decoder_tree{node_index}{5} }{7} ==2 %节点激活过一次(肯定不是叶节点),并且右子节点激活过两次
%计算该节点的B, 节点状态=2;
right_node_index = decoder_tree{node_index}{5};
left_node_index = decoder_tree{node_index}{4};
decoder_tree{node_index}{3}(1:2:end) = xor( decoder_tree{left_node_index}{3}, decoder_tree{right_node_index}{3} );
decoder_tree{node_index}{3}(2:2:end) = decoder_tree{right_node_index}{3};
decoder_tree{node_index}{7} = 2;
%取父节点
node_index = decoder_tree{node_index}{6};
continue;
end
end
u_hat = u_hat(2^n:end);
end
4 总结
实现了5种主流的polar码译码算法,较为全面。
- 源代码 出图所见即所得,代码获取方式见VX公众号