极化码MATLAB实现指南:从压缩包到可信BER曲线

发布时间:2026/9/23 23:54:37
极化码MATLAB实现指南:从压缩包到可信BER曲线
简介本资源为极化码基础仿真代码包面向通信工程、信息论方向的学生与研究者以及希望理解信道极化原理并动手验证编码性能的开发者。包内共23个文件以20个Matlab脚本.m为核心涵盖编码、SC与SCL解码、噪声添加、调制、蝶形运算及冻结比特初始化等模块另含1份PDF学位论文、1份README说明和1个mat数据文件压缩包约6MB便于直接运行与二次修改。已有225人学习下载说明其在极化码入门与仿真练习中具有一定参考价值。读者可借助这些脚本复现从码率转换、编码到误码率计算的全流程结合外文论文理解信道极化与逐比特迭代解码的理论细节并在此基础上调整参数、优化解码算法或探索5G控制信道等应用场景。1. 从 Polar-Codes-Software-Matlab 压缩包说起极化码到底在 MATLAB 里怎么跑起来如果你手里正好有一个叫Polar-Codes-Software-Matlab--master.zip的压缩包解压后大概率是一堆.m文件和几个示例脚本而不是一个能双击运行的 App。这就是极化码Polar Codes在 MATLAB 生态里的典型形态它是一套算法实现不是一个成品软件。极化码本身是 5G 控制信道 eMBB 场景采用的编码方案核心思想是信道极化——把 N 个独立信道经过线性变换后一部分变成近乎无噪的“好信道”另一部分变成近乎全噪的“坏信道”信息只放在好信道上坏信道上放冻结比特。这个思路听起来简单但落到 MATLAB 里从构造、编码、译码到误码率仿真每一步都有具体的参数和坑。这篇文章面向的是想用 MATLAB 把极化码跑通、跑对、跑出可信 BER 曲线的人不管你是通信专业的学生还是刚接触 5G 物理层实现的工程师下面这些步骤和参数你都能直接抄。2. 极化码在 MATLAB 里的最小可运行链路构造、编码、译码2.1 先搞清楚压缩包里通常有什么一个典型的 Polar Codes MATLAB 实现包目录结构不会太复杂常见的是按功能分文件夹Construction/放信道构造和可靠度排序Encoder/放编码函数Decoder/放 SC、SCL 译码器Simulation/放 BER 仿真脚本Utils/放一些辅助函数比如 CRC 校验、调制映射。你解压后第一件事不是急着跑main.m而是先看README或者脚本开头的注释确认它依赖的 MATLAB 版本和工具箱。很多极化码实现只依赖基础 MATLAB 和 Communications Toolbox但有些会用到comm.PolarEncoder和comm.PolarDecoder这两个系统对象——那是 MATLAB R2018b 之后才有的内置极化码支持。如果你手里的包是纯自研实现那就不依赖这两个对象但需要自己检查函数签名。我一般会先做一件事在 MATLAB 命令窗口里addpath(genpath(解压目录))然后which polar_encode或者which polarConstruct看看能不能找到函数。如果找不到说明路径没加对或者函数名和你想的不一样。这一步花不了两分钟但能避免后面“函数未定义”的低级报错。2.2 信道构造可靠度排序怎么选、参数怎么设极化码的构造就是决定哪些比特位置放信息、哪些放冻结比特。MATLAB 里常见的构造方法有三种巴氏参数法Bhattacharyya parameter、密度进化Density Evolution、高斯近似Gaussian Approximation。对于 AWGN 信道最常用的是高斯近似因为它在性能和复杂度之间平衡得最好。压缩包里的构造函数通常长这样% 高斯近似构造极化码信息位集合 % N: 码长, K: 信息比特数, SNR_dB: 设计信噪比 function infoIdx polarConstructGA(N, K, SNR_dB) % 将 SNR 从 dB 转为线性值 snr 10^(SNR_dB/10); % 设计信噪比下的噪声方差假设 BPSK 调制信号功率归一化 sigma2 1/(2*snr); % 初始化高斯近似下的均值数组 L zeros(N, 1); L(1) 2/sigma2; % 根节点的 LLR 均值 % 递归计算各节点的可靠度度量 for level 1:log2(N) step 2^level; for i 1:step:N % 左子节点均值减半 L(i) L(i) / 2; % 右子节点均值不变但需要处理 % 这里简化处理实际实现会用更精确的递归 end end % 按可靠度从高到低排序取前 K 个作为信息位 [~, sortedIdx] sort(L, descend); infoIdx sort(sortedIdx(1:K)); end这段代码是简化版真实的高斯近似构造会用到递归的phi函数和更精细的节点更新。但你要关注的是参数N必须是 2 的幂K是信息比特数SNR_dB是设计信噪比。这个设计信噪比很关键——它决定了构造时假设的信道质量如果设得太低信息位会偏向那些在低信噪比下更可靠的位设得太高则偏向高信噪比下的可靠位。实际仿真中我一般会把设计 SNR 设成目标工作点附近的值比如你要看 2dB 下的 BER就用 2dB 来构造。如果压缩包里的构造函数没有暴露SNR_dB参数那它可能用的是固定值或者巴氏参数法你需要看代码确认。注意不同构造方法得到的可靠度排序可能不一样尤其是短码长N256 以下时差异更明显。如果你发现跑出来的 BER 曲线和论文对不上先检查构造方法是否一致。2.3 编码从信息比特到码字编码本身不复杂极化码的编码就是矩阵乘法x u * F^⊗n其中F [1 0; 1 1]⊗n是 n 次克罗内克积。但 MATLAB 里直接算克罗内克积再乘向量对于 N1024 或更大内存和速度都会有问题。常见的做法是用蝶形运算或者递归实现。压缩包里的编码函数通常有两种写法一种是直接生成生成矩阵G然后mod(u * G, 2)另一种是递归的polar_encode逐层合并。我建议你用第二种因为 N 大了之后第一种会非常慢。% 递归极化码编码 % u: 输入比特序列已包含冻结比特长度为 N % N: 码长 function x polarEncode(u, N) if N 1 x u; else % 将输入分为前后两半 u1 u(1:N/2); u2 u(N/21:N); % 递归编码前半部分 x1 polarEncode(mod(u1 u2, 2), N/2); % 递归编码后半部分 x2 polarEncode(u2, N/2); % 合并 x [x1, x2]; end end这个递归写法很直观但要注意输入u必须是已经排好序的完整序列信息位和冻结比特的位置已经确定。冻结比特通常置 0。如果你拿到的压缩包里编码函数要求输入的是信息比特和索引那它内部会先做插入冻结比特的操作。参数上N必须是 2 的幂u的长度必须等于N。编码后的x是 BPSK 调制前的比特序列通常 0 映射为 11 映射为 -1。2.4 译码SC 和 SCL 怎么选、怎么调译码是极化码最核心也最容易翻车的部分。SCSuccessive Cancellation译码是基础复杂度 O(N log N)但性能一般。SCLSuccessive Cancellation List译码通过保留 L 条候选路径性能接近最大似然但复杂度乘以 L。压缩包里一般两种都有SCL 还会带 CRC 辅助。我建议你先跑通 SC确认编码和构造没问题再上 SCL。% SC 译码简化版仅示意流程 % llr: 接收到的对数似然比序列长度为 N % infoIdx: 信息位索引 % frozenBits: 冻结比特值通常全 0 function u_hat polarSCDecode(llr, infoIdx, frozenBits) N length(llr); u_hat zeros(1, N); % 递归译码这里省略递归细节 % 关键按索引顺序逐个判决 for i 1:N if ismember(i, infoIdx) % 信息位根据当前 LLR 判决 u_hat(i) llr(i) 0; % LLR 0 判为 1 else % 冻结位直接置为冻结值 u_hat(i) frozenBits(i); end end endSCL 译码的代码会长很多核心是维护一个路径列表每条路径有对应的路径度量PM在信息位处分裂路径在冻结位处不分裂最后选 PM 最小的路径。参数上L通常取 8、16、32CRC 长度常见的是 24 位5G 标准里 CRC24C 用于 Polar。如果你发现 SCL 译码结果比 SC 还差大概率是路径度量更新写错了或者 CRC 校验没加上。提示MATLAB 内置的comm.PolarDecoder支持 SCL 和 CRC 辅助如果你不打算自己实现可以直接用系统对象。但要注意它的参数名和自研实现不一样比如ListLength对应 LCRCLength对应 CRC 长度。3. 用 MATLAB 跑出可信的 BER 曲线仿真参数、调制与并行加速3.1 仿真框架怎么搭才不浪费时间跑 BER 曲线最怕的是仿真时间太长。N1024、K512、SCL L8 的极化码在普通笔记本上跑 1e-4 的 BER 可能需要几个小时。所以仿真框架的设计很关键。我一般会写一个主脚本外层循环 SNR内层循环帧数每帧生成随机信息比特、编码、加噪、译码、统计误比特。关键参数是每 SNR 点的帧数——不要固定帧数而是固定最少错误数比如每个 SNR 点至少收集 100 个错误比特或者 100 帧无错误就停。这样在高 SNR 区不会浪费太多时间。% 极化码 BER 仿真主循环简化框架 N 1024; K 512; L 8; % 码长、信息位、SCL 列表长度 snrRange 0:0.5:3; % SNR 范围 maxFrames 1e5; % 最大帧数 minErrors 100; % 最少错误数 ber zeros(size(snrRange)); for s 1:length(snrRange) snr snrRange(s); errors 0; bits 0; frames 0; while errors minErrors frames maxFrames % 生成随机信息比特 infoBits randi([0 1], 1, K); % 构造完整输入序列插入冻结比特 u zeros(1, N); u(infoIdx) infoBits; % 编码 x polarEncode(u, N); % BPSK 调制 tx 1 - 2*x; % AWGN 加噪 sigma sqrt(1/(2*10^(snr/10))); rx tx sigma*randn(1, N); % 计算 LLR llr 2*rx/(sigma^2); % SCL 译码 u_hat polarSCLDecode(llr, infoIdx, L); % 统计误比特 errors errors sum(u_hat(infoIdx) ~ infoBits); bits bits K; frames frames 1; end ber(s) errors / bits; fprintf(SNR %.1f dB, BER %.2e, frames %d\n, snr, ber(s), frames); end这段框架里infoIdx是构造阶段得到的polarSCLDecode需要你自己实现或者从压缩包里调用。注意sigma的计算BPSK 下符号能量为 1噪声方差是1/(2*10^(SNR/10))LLR 是2*rx/sigma^2。这个换算如果搞错BER 曲线会整体平移看起来像是译码器有问题其实是噪声功率算错了。3.2 调制方式与信道模型的选择极化码本身是二进制编码调制方式可以是 BPSK、QPSK甚至更高阶。但 5G 里 Polar 主要用于控制信道调制阶数不高。仿真时我建议先用 BPSK 把链路跑通再换 QPSK 验证。QPSK 下每个符号携带 2 比特LLR 计算要按比特分别算不能直接套 BPSK 的公式。信道模型方面AWGN 是最基础的但如果你要模拟衰落信道需要加瑞利或者莱斯衰落并且要在接收端做信道估计和均衡。压缩包里如果有channel相关的函数先看它支持哪些模型。注意MATLAB 的awgn函数默认假设信号功率为 0 dBW如果你自己算噪声方差不要混用。我一般直接手算sigma避免函数内部假设不一致。3.3 用 parfor 加速哪些地方能并行、哪些不能MATLAB 的parfor可以加速 SNR 循环因为不同 SNR 点之间是独立的。但要注意parfor里不能有依赖顺序的变量比如你不能在循环里累加全局错误数。正确的做法是把每个 SNR 点的结果存成数组循环结束后再汇总。另外parfor启动并行池有开销如果每个 SNR 点的仿真时间很短并行反而更慢。我一般会在 SNR 点超过 6 个、且每个点预计超过 1 分钟时才开parfor。% 用 parfor 并行跑 SNR 循环 ber zeros(size(snrRange)); parfor s 1:length(snrRange) % 每个 worker 独立跑仿真 [ber(s), ~] simulateOneSNR(N, K, L, snrRange(s), minErrors, maxFrames); endsimulateOneSNR是你自己封装的函数输入参数和输出 BER 以及帧数。这样每个 worker 独立工作不会互相干扰。如果你没有 Parallel Computing Toolbox那就老老实实串行跑或者用backgroundPoolR2021b 之后支持。4. 极化码 MATLAB 实现里最容易翻车的几个地方4.1 现象BER 曲线在高 SNR 下不降反升原因SCL 译码的路径度量更新用了错误的符号或者 CRC 校验的生成多项式不对。极化码的 SCL 译码里路径度量是累加的每次分裂时选 PM 小的路径但 PM 的更新公式和 LLR 的符号强相关。如果符号搞反高 SNR 下错误路径反而被保留。解决检查 PM 更新代码确保在信息位处PM 增加的是-log(1exp(-|LLR|))或者类似的形式并且路径选择时选 PM 最小的 L 条。CRC 多项式要和标准一致5G 里 Polar 用的 CRC24C 多项式是0x1864CFB。4.2 现象编码后码字和预期不符原因克罗内克积的顺序搞反了。极化码的生成矩阵是F^⊗n但有些实现会写成F^⊗n的转置或者逆序。另外比特反转bit-reversal操作容易漏掉。解决用 N2 或 N4 的小码长手动验证。N2 时F [1 0; 1 1]输入u [u1 u2]编码后x [u1u2, u2]模 2。如果你跑出来是[u1, u1u2]那就是顺序反了。4.3 现象构造出来的信息位索引和论文对不上原因高斯近似里的phi函数实现有偏差或者设计 SNR 设得不一样。不同论文用的phi函数近似公式可能不同导致可靠度排序有差异。解决先确认你用的构造方法和论文一致。如果论文用的是巴氏参数法你就不要用高斯近似去对比。另外设计 SNR 要明确很多论文默认用 0 dB 或者 2 dB你不设成一样的排序自然不同。4.4 现象MATLAB 报错“Out of memory”原因N 太大比如 8192 或 16384SCL 的 L 又设得很大比如 32路径列表占用的内存是N * L的矩阵再加上中间变量很容易爆内存。解决减小 N 或 L或者用single类型代替double存储 LLR 和路径度量。如果必须跑大 N考虑分段处理或者用 MATLAB 的tall数组但极化码的递归结构不太适合 tall。4.5 现象仿真跑了一晚上BER 曲线还是不平滑原因每个 SNR 点的错误数不够统计涨落太大。尤其是高 SNR 区错误事件稀疏固定帧数会导致 BER 估计方差很大。解决用最少错误数作为停止条件而不是固定帧数。我一般设minErrors 100如果跑 1e5 帧还没到 100 个错误就停但要在图上标注这个点的置信区间。5. 从能跑到好用极化码 MATLAB 仿真的进阶技巧5.1 用 CRC 辅助 SCL 把性能再提一截SCL 译码本身已经比 SC 好很多但加上 CRC 之后性能还能再提升 0.2~0.5 dB。做法是在信息比特后面附加 CRC 校验位译码时 SCL 输出 L 条候选路径然后用 CRC 筛选选第一条通过 CRC 的路径。如果都没有通过就选 PM 最小的。CRC 长度常见的是 6、11、24 位5G 里 Polar 用 24 位 CRC24C。实现时要注意CRC 校验位也参与极化码编码它们放在信息位集合里但不是真正的“信息”译码后要先提取再校验。% CRC 辅助 SCL 译码的路径选择 % paths: SCL 输出的 L 条候选路径每条是一个比特序列 % crcPoly: CRC 生成多项式 function u_hat crcAidedSelect(paths, crcPoly) for i 1:length(paths) u paths{i}; % 提取信息位和 CRC 位 infoWithCRC u(infoIdx); % 计算 CRC 并校验 if checkCRC(infoWithCRC, crcPoly) u_hat u; return; end end % 如果没有路径通过 CRC选第一条PM 最小 u_hat paths{1}; endcheckCRC需要你自己实现或者用 MATLAB 的comm.CRCGenerator和comm.CRCDetector。注意 CRC 的输入是信息位加 CRC 位校验时要把 CRC 位也包含进去。5.2 用 MATLAB 内置极化码对象做交叉验证如果你不确定自研实现对不对可以用 MATLAB 内置的comm.PolarEncoder和comm.PolarDecoder做交叉验证。内置对象支持 SC 和 SCL还能指定 CRC。你只需要把相同的输入比特和参数喂进去对比输出码字和译码结果。如果自研实现和内置对象在相同参数下结果一致那基本可以放心。但要注意内置对象的构造方法可能和你用的不一样所以信息位索引可能不同对比时要确保构造方式一致。% 用内置对象交叉验证 polarEnc comm.PolarEncoder(N, K, ConstructionMethod, GA); polarDec comm.PolarDecoder(N, K, ListLength, L, CRCLength, 24); % 编码 encoded polarEnc(infoBits); % 译码 decoded polarDec(llr);内置对象的ConstructionMethod可以选GA高斯近似或者DE密度进化你要和自研实现对齐。如果内置对象跑出来的 BER 和自研实现差很多先检查构造方法是否一致再检查译码器参数。5.3 画图与数据保存别让仿真结果丢了跑完仿真一定要把数据存下来不然重跑一次可能又是几个小时。我习惯用save(ber_results.mat, snrRange, ber, N, K, L)把关键变量存成 MAT 文件。画图时用semilogy(snrRange, ber, o-)加上网格和标签。如果要在论文里用导出成 EPS 或者 PDFMATLAB 的exportgraphics函数比print更好用尤其是 R2020a 之后。% 保存并画图 save(ber_results.mat, snrRange, ber, N, K, L); figure; semilogy(snrRange, ber, o-, LineWidth, 1.5); grid on; xlabel(SNR (dB)); ylabel(BER); title(sprintf(Polar Code (N%d, K%d, L%d), N, K, L)); exportgraphics(gcf, ber_curve.pdf, ContentType, vector);5.4 我踩过的一个血泪坑MATLAB 版本差异不同 MATLAB 版本对comm.PolarEncoder和comm.PolarDecoder的支持不一样。R2018b 刚引入时只支持 SC后来才加了 SCL 和 CRC。如果你在 R2018b 上跑 SCL会直接报错。另外R2023a 之后comm.PolarDecoder的参数名有变化比如ListLength变成了ListLength没变但有些参数被弃用了。我一般会在脚本开头检查ver(comm)的版本号然后根据版本走不同的分支。如果你手里的压缩包是在老版本上写的在新版本上跑之前先看有没有弃用警告。提示MATLAB 的comm工具箱版本号可以用ver(comm)查看输出里的Version字段就是。如果版本低于 7.0极化码对象可能不存在。5.5 最后一句实在话极化码的 MATLAB 实现跑通不难跑对不容易。我自己的习惯是先用 N8 或 N16 的小码长手动验证编码和译码确认每一步的中间结果都对再放大到 N1024。每次改构造方法或者译码器参数都重新跑一遍小码长验证。这样虽然前期慢一点但后面省下的调试时间远不止这一点。希望帮到你。本文还有配套的精品资源点击获取