极化码SC编译码MATLAB实现:从递归核到误码率仿真

发布时间:2026/9/16 11:05:37

极化码SC编译码MATLAB实现:从递归核到误码率仿真 简介面向通信与编码学习者的极化码SC编译码MATLAB实现包聚焦SC逐位取消算法在极化码编解码流程中的完整落地适合需要理解信道极化理论、动手进行编码仿真或开展算法改进的初学者与研究人员。压缩包共9个文件其中8个为m源码文件1个为mat数据文件整体仅7KB代码量非常精简。源码涵盖了初始化参数配置、编码映射、SC解码、LLR计算与比特级处理等核心模块并配有可直接运行的主测试脚本能够快速观察从编码到解码的完整流程与输出结果。数据文件用于保存信道参数或仿真中间量有助于减少重复计算。目前已有305人学习下载说明该小型实现具备较好的参考价值。通过阅读和运行这些MATLAB代码读者可以逐步掌握极化码编码比特选择、递归信道合成以及SC逐位判决的实现细节并在此基础上尝试改进译码算法或向5G通信等实际场景扩展是一份兼顾教学演示与二次开发参考的小型代码包。1. 看到SC.zip先别急着解压这是一套极化码SC编译码的MATLAB起点看到“SC.zip_极化码 matlab_极化码 sc_极化码MATLAB_极化码代码_极化码编译码”这串标题老手的第一反应通常是里面是一个“极化码 Successive Cancellation 连续消除译码”的MATLAB工程包。这里的SC不是字体而是信道编码里最常见的逐位连续消除zip里装的八成是编码器、SC译码器、误码率仿真三个脚本。它解决的实际问题是在AWGN信道上把随机比特按指定码长编码再递归对数似然比译回原始比特最后画出BER/FER。适合通信方向研究生、5G NR信道编码预研工程师以及想从零确认信道极化理论的从业者。我拿到这类包不会先逐行读论文而是先找主函数、冻结集构造和LLR更新三块再跑一个N256的最小链路。2. 极化码编译码的最小原理一个递归核敲掉整个SC2.1 从编码侧的递归核到MATLAB里的Kron构造极化码的基本核是A [1 0; 1 1]。码长 N2^n 的生成矩阵是 A 的 n 次 Kronecker 幂。通信老手看到这个核就能想起信道极化的本质两个独立信道合成一个近乎无噪的信道和一个几乎全噪的信道。在MATLAB里用kron函数构造生成矩阵非常短初学者可以用它验证编码逻辑function G polar_gen_matrix(n) A [1 0; 1 1]; G A; for i 1:n-1 G kron(G, A); end end这段代码每跑一次G 的尺寸翻一倍最终是 N×N 的 0/1 矩阵。优点是直观编码就是x mod(u * G, 2)冻结位在 u 里置 0。缺点是 N 到 1024 时矩阵乘法略慢。我一般只在 N512 时用这种矩阵写法更大换成递归编码。递归编码也有多种等价写法我习惯用前后分裂的版本因为它和后面 SC 译码的左右分支一一对应function x polar_encode(u, N) if N 1 x u; return; end half N / 2; u1 u(1:half); u2 u(half1:end); c1 polar_encode(u1, half); c2 polar_encode(u2, half); x [mod(c1 c2, 2), c2]; end这里把输入 u 切成左右两半分别递归编码再把左半与右半异或后放在输出前半右半原样放在后半。这个递归不做比特逆序重排所以冻结集的位置也按同一套前后顺序定义只要编码器和译码器用同一套顺序误码率曲线就是对的。和kron(G)矩阵写法相比只是子信道排序不同不影响SC的性能结论。2.2 SC译码的f/g函数比你想的更像LDPC的可加项SC译码是在二叉树上做消息传递。左子节点拿到两个LLR的合并值右子节点拿到一个合并值并附加上左子返回的判决位。LLR约定为log(P0/P1)那么 f 和 g 的 min-sum 近似是function L f_llr(L1, L2) s sign(L1) * sign(L2); L s * min(abs(L1), abs(L2)); end function L g_llr(L1, L2, u_hat) L (1 - 2 * u_hat) * L1 L2; end第一直觉是在MATLAB里用L1 * L2做符号判断但LLR来自16位定点时乘积可能溢出所以写成sign(L1) * sign(L2)更安全。另一种做法是保留精确 boxplusL 2*atanh(tanh(L1/2)*tanh(L2/2))但MATLAB里atanh在输入接近 ±1 时损耗很大除非做数值保护否则不推荐在SC里用精确版本。递归译码核心如下这个函数统计下来不到40行但包含了SC最关键的左右分支顺序function u_hat sc_decode_rec(alpha, frozen) n length(alpha); if n 1 if frozen(1) u_hat 0; else u_hat double(alpha 0); end return; end half n / 2; alpha_l zeros(1, half); for i 1:half alpha_l(i) f_llr(alpha(i), alpha(halfi)); end u_l sc_decode_rec(alpha_l, frozen(1:half)); alpha_r zeros(1, half); for i 1:half alpha_r(i) g_llr(alpha(i), alpha(halfi), u_l(i)); end u_r sc_decode_rec(alpha_r, frozen(half1:end)); u_hat [u_l, u_r]; end说明一下frozen是长度 n 的逻辑向量1 表示冻结位0 表示信息位。叶子节点如果是冻结位无论 LLR 是什么都判 0这是SC编译码能工作的前提收端知道哪些位置不背书。左右分支的索引配对是(i, halfi)对应编码时c1 c2与c2的关系不是相邻配对。2.3 叶子的判决与冻结位处理SC最容易写错的地方很多初版SC代码出错的点不是f/g而是frozen的切割与编码顺序不一致。上面代码使用前后分裂frozen(1:half)对应输入序列前半的冻结位frozen(half1:end)对应后半而实际的左右子树索引通过half映射。如果改成奇偶分裂这两处都要换成frozen(1:2:end)和frozen(2:2:end)并且拼接也要用奇偶插值。记住一条经验编码怎么拆译码就怎么切两边任何一处不对称都会导致深层错误被逐层放大。LLR的数值安全也要注意。接收端若把纯零符号的LLR算成0sign(0)在旧版MATLAB会返回0可能导致f函数输出错误。我一般会先对LLR做一次alpha(alpha0) eps的饱和处理。另一个常见问题是double(alpha 0)在叶子节点返回0/1而冻结位分支返回整数0两者类型统一后续xor才不会报错。到这里SC的原理和代码骨架已经立住下一步是把它绑成一条能出曲线的仿真链路。3. 用MATLAB跑通N256、K128的SC编译码最小链路3.1 参数表码长、信息位、码率、冻结集构造仿真前先把参数钉死避免后面因为信噪比定义乱而浪费半天。下面的表是我常用的起点配置参数值说明N256码长必须是2的幂K128信息比特数码率0.5调制BPSK0映射为11映射为-1LLR格式double先浮点跑通再转定点EbN0范围0dB ~ 2.5dBSC在这个范围能明显看到BER下降每帧仿真帧数1000低SNR下足够看趋势高SNR需要更多冻结集构造不能随机取。常见做法是极化权重Polarization Weight它比纯巴氏参数更简单在码率0.5附近已经够用function frozen build_frozen_mask(N, K) n log2(N); ind (0:N-1); bits bitget(ind, 1:n); weights (2.^(0:n-1)).^0.5; W bits * weights(:); [~, order] sort(W, ascend); frozen false(1, N); frozen(order(1:N-K)) true; end这段代码把最不可靠的 N-K 个位置设为冻结位。注意ind从0开始因为比特位置索引在极化码中习惯用0基bitget取每一位时最低位对应 j0权重是2^(j*0.5)。如果码率不是0.5或者想再抠0.1dB可以把极化权重换成高斯近似GA构造但前者做最小链路已经足够。3.2 主函数run_sc_polar.m编码、AWGN、递归译码有了冻结集和前面两个递归函数主函数就只剩封装。我一般把它写成一次一帧的独立函数方便外层循环控制信噪比和统计误码function [ber, fer] run_sc_polar(N, K, EbN0dB) frozen build_frozen_mask(N, K); info randi([0 1], 1, K); u zeros(1, N); u(~frozen) info; x polar_encode(u, N); tx 1 - 2 * x; % BPSK映射 R K / N; EbN0 10^(EbN0dB / 10); N0 1 / (R * EbN0); sigma sqrt(N0 / 2); rx tx sigma * randn(1, N); llr 2 * rx / sigma^2; u_hat sc_decode_rec(llr, frozen); info_hat u_hat(~frozen); errs sum(info_hat ~ info); ber errs / K; fer double(errs 0); end这里最关键的是噪声功率与LLR刻度。BPSK每符号能量 Es1码率 RK/N所以 N0 1/(R*EbN0)每维噪声方差 σ²N0/2。LLR用2*rx/sigma^2这是高斯信道下的精确对数似然比。如果把 σ² 写成 N0LLR整体放大2倍译码结果不一定错但信噪比曲线会横移约0.3dB。外层仿真循环可以这样写EbN0dB_list 0:0.5:2.5; for snr EbN0dB_list ber_acc 0; fer_acc 0; frames 1000; for frame 1:frames [ber, fer] run_sc_polar(256, 128, snr); ber_acc ber_acc ber; fer_acc fer_acc fer; end fprintf(EbN0%4.2f dB, BER%.3e, FER%.3e\n, ... snr, ber_acc/frames, fer_acc/frames); endber_acc累加的是每帧的误码率最后除以帧数是平均BERfer_acc累加误帧次数除以帧数是平均FER。这种写法比直接累加错误比特数简单但高SNR时方差大。经验法则是至少累计到100个错误比特再停否则误码率曲线尾部会抖动。3.3 排错递归深度、索引对不上、LLR出现NaN跑最小链路时最容易遇到三个问题。第一个是递归深度MATLAB默认递归深度足够上千层而log2(N)只有8~10层所以SC本身不会爆栈但如果你在译码函数里不小心用了循环引用就会提示“Maximum recursion limit exceeded”。这时先查函数名是否和脚本文件名冲突。第二个是索引对不上症状是误码率在0.5徘徊。我一般会先用全零信息测试信息位全0发送端编码LLR设为全正大数译码输出必须全0。如果输出有1说明frozen切分或u(~frozen) info的赋值顺序有错。第三个是LLR出现NaN常见于sigma^2计算为0或EbN0dB给到10以上导致N0极小时浮点下溢。处理办法是在LLR计算后加一句llr(~isfinite(llr)) sign(llr(~isfinite(llr))) * 1e6把无穷大饱和到一个足够大的有限值。到这里你已经能拿到一条完整的SC误码率曲线但这条曲线离工程可用还有一段距离。4. 误码率曲线背后的三个必调参数量化、冻结集、噪声方差4.1 SC的性能边界错误平层来自哪里SC译码在码长趋于无穷时渐进最优但有限码长下性能比BP译码差不少。原因不是f/g函数近似而是每一层都做硬判决一旦某一位选错错误会通过右分支的g函数传播到后面所有比特。这就是SC的“错误传播”现象。实际仿真里N256、K128的SC在EbN02.5dB左右FER还停在1e-2量级但BP或SCL已经在1e-3以下。因此SC适合作为基线不适合直接当最终方案。参数调优对SC来说本质是在缓解错误传播而不是消除它。量化位数决定LLR的精度冻结集决定哪些位置不传信息噪声方差则决定LLR刻度是否可信。三者互相耦合改一个要把另外两个重测一遍。4.2 三个必调参数量化位数、冻结集构造、噪声方差下面这张表是我在工程里常用的调参方向默认值针对N256浮点仿真参数起点值调整方向对误码率的影响LLR量化位数 q6 bit增大到8 bit高SNR区域错误平层下降复杂度上升冻结集构造极化权重 β0.5换成高斯近似码率高于0.5时能获得0.1~0.2dB增益噪声方差估计精确σ²固定为典型值偏差超过±0.2dB时曲线明显右移SC的LLR饱和阈值无饱和饱和到±16防止极端LLR影响f/g函数量化这一步在MATLAB里写起来很短但能提前看到定点成本q 6; % 6 bit量化1符号位 scale 2^(q-1); % 取值范围 [-32, 31] llr_q round(llr * scale); llr_q max(-scale, min(scale-1, llr_q));注意量化因子scale与LLR的幅度直接相关。如果接收端LLR本身在0.1量级乘scale后会变成小数附近的值再round会丢失大量信息。常见的做法是先统计一段浮点LLR的均方根再把scale设为均方根的2~4倍。这里仅仅演示固定点格式实际使用时需要先做一段校准。噪声方差参数往往被忽视。很多人直接按理想σ²仿真但接收端并不知道真实噪声功率。把σ²高估10%LLR整体缩小SC的f函数倾向保守误码率在高SNR区域会变差。一个稳妥做法是把σ²当作未知量测试区间设为0.8*sigma_hat到1.2*sigma_hat看曲线上哪一段最敏感。通常SC对σ²的敏感度在0.3dB以内。4.3 用白盒测试确认译码器正确性调参之前先做两轮白盒测试能省下大量排错时间。第一轮是全零测试第二轮是单比特图样测试。全零测试的做法是固定信息位全0LLR设为足够大的正数u zeros(1, 256); x polar_encode(u, 256); frozen build_frozen_mask(256, 128); u_hat sc_decode_rec(100 * ones(1, 256), frozen); assert(all(u_hat 0), 冻结位或递归索引错误);单比特图样测试是让信息位里只有一个1其它全0例如info(37) 1。这时你应该去检查译码输出的第37个信息位是否也只在37位有1。如果出现两个1说明冻结集与编码顺序不匹配。通过这两轮测试后再进入4.2的调参就不会被底层错误干扰。5. 把SC改成SCL只加路径复制与PM更新误码率再降0.5dB5.1 路径度量PMSCL和SC的唯一分叉SCLSuccessive Cancellation List和SC的唯一区别是SC在每层只保留一条判决路径SCL保留L条。每一条路径都带着自己的路径度量PMPM是这条路径的累积负对数似然。LLR约定log(P0/P1)那么判决选0但LLR为负时PM惩罚-LLR判决选1但LLR为正时PM惩罚LLR。SCL就是在每次叶子判决时把1条路变成2条路更新PM然后按PM排序保住最小的L条。5.2 最小改动代码从单路径到L路径如果你已经写好了递归SC改成SCL不需要动f/g函数只需要把叶子判决部分换成路径扩展。下面的MATLAB片段是路径扩展的最小实现function [new_paths, new_pm] path_extend(paths, pm, llr_leaf, L) new_paths []; new_pm []; for l 1:length(pm) for u 0:1 new_paths(end1, :) [paths(l, :), u]; penalty max(0, (2*u - 1) * llr_leaf(l)); new_pm(end1) pm(l) penalty; end end [~, order] sort(new_pm, ascend); keep order(1:L); new_paths new_paths(keep, :); new_pm new_pm(keep); end这里llr_leaf(l)是第 l 条路径当前叶子节点的LLR。选择 u0 时LLR为正没有惩罚LLR为负则惩罚-LLR选择 u1 时相反。路径矩阵new_paths的每一行是一条完整的上层判决序列列数会随着递归深度增加。注意冻结位节点不调用这个函数直接把所有路径追加0保持路径数不变否则冻结位会被错误地扩展成两个分支。提示SCL完整实现还需要把LLR按路径组织成 L×N 的矩阵并且逐层传递LLR时也要对L条路径分别调用f/g函数。否则把递归SC直接套在这个函数上时间复杂度会变成L倍的SC但复用性不高。5.3 实测对比L2、L4的变化用N256、K128验证SCL-2在EbN01.5dB时FER大约比SC低三分之一SCL-4在2.0dB附近比SC低0.5dB左右。增益来自路径多样性但路径数翻倍并不线性改善性能L4到L8的增益已经很小。如果要在有限码长下继续提升必须在编码时追加CRC校验让SCL在最后用CRC从保留路径中挑最可靠的否则SCL-16在高SNR可能因为路径度量累计误差反而不如SC。加CRC时用CRC-8配L4即可L8配CRC-16收益更明显。工程落地的下一步是把递归f/g调用改成循环栈再把LLR从double切成16位定点顺序是先改SCL再改量化不要同时改两个变量。跑一次256长度、1000帧的仿真SCL-4和SC的差异会立刻出现在BER曲线上。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/9/16 11:05:37

gh-aw批量操作模式实战:让Agent安全处理成百上千个对象

gh-aw批量操作模式实战:让Agent安全处理成百上千个对象 【免费下载链接】gh-aw GitHub Agentic Workflows 项目地址: https://gitcode.com/GitHub_Trending/gha/gh-aw gh-aw(GitHub Agentic Workflows)批量操作是新手最关心的进阶能力…

2026/9/16 12:05:51

无代码拖拽式APP自动化测试平台:原理、实操与选型指南

先说一下我为什么会认真研究"无代码拖拽式APP自动化测试平台"这个方向。这几年我在团队里做APP自动化测试建设,最深的体感是:自动化用例写出来不难,难在让团队里每个人都用得起来。会写代码的成员永远是少数,脚本维护跟…

2026/9/16 12:05:51

锐捷OSPF引入外部路由

一 组网说明R1、R2、R3运行OSPF1,R1上配置多个loopback地址模拟业务地址,包括loopback1-loopback5地址 R1上通过引入路由将路由引入R1,进而同步R2和R3路由器 二 设备配置 2.1 R1设备配置 hostname R1 ! interface GigabitEthernet 0/0ip addr…

2026/9/16 12:05:50

Windows下用nvm管理Node.js多版本:从安装到避坑完整指南

写这篇指南的起因是,我前段时间为了给两个项目分别维护 Node 16 和 Node 20 的运行环境,在 Windows 上反复“卸载-安装-重配环境变量”,折腾到怀疑人生。后来彻底切到 nvm(Node Version Manager)之后才意识到&#xff…

2026/9/16 12:05:50

【无标题】C语言变量,类型转换,运算符,输入和输出

嵌入式学习Day3|C语言变量、类型转换、运算符、输入输出完整的复盘嵌入式学习第三天,今天系统啃完C语言变量定义、数据类型转换、全套运算符、输入输出函数,都是写代码最基础、每天都会用到的基本功。一、变量的定义规范1.变量定义格式数据类…

2026/9/16 12:05:50

技术文档写作三要素:简洁、准确与易懂的平衡之道与实操方法

写技术文档这行当,我算是在“简洁”上栽过跟头的人。刚带团队那年,我定了一条规矩:所有接口文档必须精简,能一句话说清楚绝不用两句话。结果一个支付回调接口的说明被压到只剩签名和一句“返回结果处理逻辑见代码”,上…

2026/9/16 12:00:50

2023玫瑰花茶十大品牌评测与选购指南

1. 玫瑰花茶市场现状与消费趋势玫瑰花茶作为一种兼具观赏性和保健功能的饮品,近年来在国内市场持续升温。根据2023年茶饮行业白皮书数据显示,花草茶品类年增长率达到23%,其中玫瑰花茶占据花草茶市场份额的38%,成为都市白领和养生人…

2026/9/15 4:54:30

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/16 0:04:09

PHP源码部署实战:从环境配置到运行情侣游戏全攻略

简介:这是一套面向情侣互动场景的PHP完整源码,集成情侣飞行棋、真心话大冒险、情趣骰子等玩法,并内置完整分销制度,可自定义多种返佣比例,源码完全开源无加密,支持微信无感自动授权登录与第三方授权&#x…

2026/9/15 14:22:53

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/15 21:31:11

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/15 11:42:23

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码