news 2026/9/11 18:15:22

Polar编解码与PSS-SSS联合检测:MATLAB物理层仿真实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Polar编解码与PSS-SSS联合检测:MATLAB物理层仿真实现

简介:面向5G通信研究者与通信工程学生的MATLAB仿真源码包,专注于Polar编解码与PSS/SSS联合检测技术,通过仿真输出同步成功率以及误比特率(BER)、块误码率(BLER),可用于评估物理层同步与信道编码性能,适合深度学习5G NR同步机制和Polar码应用的读者。资源共包含68个文件,以56个.m源码文件为主体,另有.mat数据、.bin信道文件、头文件及mexw64插件,分别用于保存信道响应、导入真实信道参数、提供C接口加速等,整体压缩包仅2.63MB。目前已有146人学习下载。源码工程目录清晰,涵盖系统参数、发端、信道、收端、常用函数等模块,内置TU信道和DMRS相关数据,可直接运行Runme.m复现仿真流程。借助该资源可快速上手Polar码编解码与联合检测的工程实现,也可基于现有框架修改参数、替换信道模型,是通信仿真实践和5G算法研究的高价值参考资料。

1. 一个MATLAB工程,把两件物理层难事放在同一条链路上

“基于Polar编解码的联合检测”这个标题,第一眼看像是两个独立仿真拼在一个工程里:一边是Polar码的收发链路,一边是PSS-SSS的小区搜索检测。实际做下来会发现,标题里的“联合”不只是一个文件夹装多份脚本,而是让同步检测的结果直接参与Polar译码过程——典型做法是先靠PSS-SSS盲检拿到物理小区标识和粗定时,再把这些参数用于PBCH信道的解扰、解速率匹配和Polar译码,最终统一用检测成功率、BER、BLER三条曲线交代整条链路的性能。这篇文章面对的读者是看过Polar码论文但没亲手搭过接收端的人,以及写过LTE同步但没碰过NR同步序列的人。我不会去依赖5G Toolbox里的封装黑盒,而是把从序列生成到统计误码的最小闭环一步步展开,让你能在自己的数据上复现并看清每个门限和参数在结果里的作用。

2. Polar编解码的最小MATLAB实现:从生成矩阵到SCL译码

2.1 为什么控制信道场景选Polar而不是Turbo或LDPC

5G NR在物理下行共享信道用LDPC做数据信道编码,在物理广播信道和控制信道用Polar,这个分工本身就是工程权衡的结果。LDPC在中长码长上有接近香农限的性能,但在PBCH这种只有几百比特的小净荷上,码块分段带来的开销会明显吃掉编码增益,延时也受迭代次数限制。Polar码的优势恰恰是短码和中等码长下表现稳定,且速率匹配非常灵活——它通过打孔和缩短从母码长度适应各种调度尺寸,这让它适合承载DCI和MIB这类结构不对称的小包。

另一个常被忽略的点是Polar补码的构建方式明确。Arikan极化码的结构基于信道极化的递归变换,信息位集合生成后,编码器是一个固定矩阵的乘法,复杂度O(N log N)。这个确定性使得控制信道可在严格时延预算内完成一次SCL译码,而Turbo码在短码时的错误平层和LDPC在低信噪比下的高迭代代价都是实际顾虑。因此后面仿真链路里我会把Polar放在PBCH信道模型下验证,而不是把它塞进高速数据业务场景。

2.2 极化构造:参数表与矩阵递归生成

要动手写Polar编解码,先要确定一组构造函数需要的参数。下表是我常用的默认配置,也方便后续调参对比:

参数符号含义默认值调参方向
N母码码长,必须为2的幂512增大提升性能,缩短则降低时延
K信息位长度,不含CRC32由MIB实际比特决定
CRC位数CRC级联,用于SCL路径选择8增加可降低误检,但有效信息率下降
冻结位集合信道容量最低的N-K个位置高斯近似生成直接影响早期译码错误传播
SCL列表L译码路径数8L增大BLER下降,复杂度线性上升

生成矩阵是Polar编码的根基。核矩阵F为[[1,0],[1,1]],N阶生成矩阵是F的n次Kronecker幂再乘以比特反转置换矩阵。Kronecker幂可以直接用MATLAB的kron函数迭代得到,但N=1024时矩阵膨胀得很厉害,更稳的做法是用递归结构隐式完成极化变换。下面给出一个不显式展开生成矩阵的编码思路,它把输入重排后做蝶形异或操作,对应的是编码的快速实现。

2.2.1 极化变换的MATLAB操作
function x = polar_encode(u, n) % u: 长度为2^n的逻辑比特向量,已含冻结位置 x = u; for s = 1:n % 逐级蝶形 step = 2^s; idx = reshape(1:length(u), step, []); % 每组的后一半与前半部分异或后更新前半段 for blk = 1:size(idx, 2) i1 = idx(1:step/2, blk); i2 = idx(step/2+1:step, blk); x(i1) = xor(x(i1), x(i2)); end end x = bitrevorder(x); % 比特反转,等效于在接收端做同样的反转 end

这段代码的关键是蝶形运算的循环结构:每一级把向量按2的幂拆分,前半部分异或后半部分后写回,级间顺序从s=1到s=n。这里我用bitrevorder做比特反转,它和5G标准中的位置映射方式一致,解码端需要在软信息送入译码器前做同样的反置换。用循环而不是矩阵乘法,好处是省内存,坏处是MATLAB循环在N较大时有性能损失,后续优化可改用实部虚部重排的算法。

2.3 SC与SCL的工程取舍:列表长度的实际影响

SC译码本质上是沿二叉树逐比特递归地判断似然比,判定错误后会不可逆转地传播。SCL则是维护L条候选路径,在每比特扩展后保留度量最高的L条,直到结尾用CRC校验挑出正确路径。下面给一个框架性的SCL实现片段,只截取最核心的剪枝逻辑,便于解释参数含义。

function [bits, path_metric] = scl_decode_llr(llr, info_idx, crc_bits, L) % llr: 接收符号的对数似然比,长度N % info_idx: 信息位索引,冻结位在该框架中被硬置为0 paths = zeros(L, numel(llr)); metrics = zeros(1, L); for i = 1:numel(llr) % 扩充路径:每路径分裂为候选0和1 expanded = zeros(2*L, i); expanded(1:2:2*L-1, :) = paths(:, 1:i); expanded(1:2:2*L-1, i) = 0; expanded(2:2:2*L, :) = paths(:, 1:i); expanded(2:2:2*L, i) = 1; % 用llr累加度量,这里简化使用硬判决近似 new_metric = repmat(metrics, 1, 2)' + expanded(:, i) .* llr(i); [~, ord] = sort(new_metric, 'descend'); paths = expanded(ord(1:L), :); metrics = new_metric(ord(1:L)); end % 最后用CRC做最优路径选择 for p = 1:L if crc_check(paths(p, :), crc_bits) bits = paths(p, info_idx); path_metric = metrics(p); return; end end bits = paths(1, info_idx); % 全部失败时退回度量最大路径 end

以上实现做了两处简化:一是路径度量直接用硬判决似然累加,简化了标准SCL中的对数似然比递推;二是每个比特都做全路径分裂,没有按冻结位优化分支数。实际工程中应当在第i步只对信息位做扩展,冻结位直接追加0且不分裂,否则复杂度会翻倍。SCL的关键参数L决定性能拐点:L从1增到4时,BER和BLER下降最明显,L超过16后增益趋饱和,而每个L值的复杂度近似线性增长。

提示:在没有5G Toolbox的情况下,CRC校验可以自己实现,但需要用matlab的comm.CRCGenerator配合comm.CRCDetector验证过再接入SCL,否则路径选择错误会表现为中高信噪比下BLER依旧平层。

3. PSS-SSS联合检测:序列生成、滑动相关与PCI盲检

3.1 PSS和SSS的M序列基础

5G NR的PSS和SSS都是m序列,即最长线性反馈移位寄存器序列,区别在于PSS基于多项式x7+x4+1,SSS基于x7+x6+1。物理小区标识PCI由两部分组成:PCI = 3*NID1 + NID2,其中NID2取0、1、2,对应PSS的三种循环移位;NID1取0到335,对应SSS序列的循环移位组合。联合检测的目标就是在接收信号里同时找到这两个移位量,拼出完整的PCI。下面这段代码生成标准的PSS序列,采用频域定义,方便后续直接映射到子载波。

3.1.1 PSS频域序列的MATLAB生成
function pss_seq = generate_pss(NID2, Nfft) % NID2: 0, 1, 2 % Nfft: Nfft主要用于占位,标准长度固定为127 x = zeros(1, 127); x(1:7) = [0 0 0 0 0 0 1]; % 初始状态 m = 1:7; for i = 8:127 x(i) = mod(x(i-7) + x(i-4), 2); % 由多项式 x^7 + x^4 + 1 导出 end seq = 1 - 2*x; % BPSK映射 pss_seq = zeros(1, 127); for n = 0:126 pss_seq(n+1) = seq(mod(n + 43*NID2, 127) + 1); end % 频域直接适用,做归一化以便相关 pss_seq = pss_seq / sqrt(mean(abs(pss_seq).^2)); end

频域PSS序列长度固定127,不需要用Nfft参数生成序列本身,但接收端做相关前要先做OFDM解调得到频域符号,才能把收到的127个子载波和本地序列做相关。43这个移位常数来自5G标准中的循环移位定义,NID2为0、1、2时分别对应移位0、43、86。归一化步骤很重要,它会直接影响后续相关峰和门限的比较,不归一化时功率差异会覆盖门限判断的结果。

3.2 滑动相关与定时同步:从粗同步到联合判决

接收端最直接的做法是取同步信号所在OFDM符号的解调输出,在频域对所有可能的NID2和NID1组合做相关。但在多径信道下,窄带干扰或频偏可能使单个PSS相关峰不够稳定,所以工程上常先用PSS做一次粗对齐,确定OFDM符号边界后,再联合SSS做二次判决。下面给出频域联合检测的代码,输入是接收OFDM符号解调后的资源网格。

function [pci, timing, strength] = joint_pss_sss_detect(rx_grid, n_id2_range, n_id1_range) % rx_grid: 接收端OFDM解调后的频域资源网格,大小为 Nfft x Nsym max_corr = -inf; for nid2 = n_id2_range pss_loc = generate_pss(nid2, size(rx_grid, 1)); corr = sum(conj(pss_loc) .* rx_grid(pss_indices, pss_symbol), 1); [val, sym_off] = max(abs(corr)); if val > max_corr max_corr = val; best_nid2 = nid2; timing = sym_off; end end % 基于PSS找到的最佳NID2和定时位置,再在SSS位置做联合判决 sss_corrs = zeros(1, length(n_id1_range)); for nid1 = n_id1_range sss_loc = generate_sss(best_nid2, nid1, size(rx_grid, 1)); sss_corrs(nid1+1) = sum(conj(sss_loc) .* rx_grid(sss_indices, pss_symbol + 1)); end [~, best_nid1] = max(abs(sss_corrs)); pci = 3 * best_nid1 + best_nid2; strength = abs(sss_corrs(best_nid1+1)); end

这里用两个步骤避免联合暴搜的复杂度:先对NID2做三路相关,取最大者确定粗定时;再固定NID2后对336个SSS候选做一轮相关。总相关次数从3×337次降为3+337次,在MATLAB for循环下能快一个数量级。timing输出用于后续OFDM符号对齐,而strength可以保存下来用于成功率判决——工程中常把strength除以噪声功率得到检测度量,比直接用绝对相关值更公平。

3.3 检测门限的设置:不只看相关峰

很多初版仿真在检测成功率上虚高,原因不是算法坏,而是判决标准只剩“是否找到全局最大峰”。实际系统中,即使完全随机的噪声,也总能找到一个最大峰来强制判决,因此必须设置一个有效峰与噪声底的比例门限。常用方式是取相关结果的均值作为噪声估计,期望峰值的旁瓣水平大约在均值的4到6倍之间。跳进仿真后,先跑几万个纯噪声符号记录最大值分布,再取PFA目标来反推门限,比任何经验常数都靠谱。

4. 联合仿真链路搭建:从发射端到成功率、BER、BLER统计

4.1 帧结构与联合检测的配合方式

联合仿真需要一个完整的收发链路。发送端在每帧第一个时隙放PSS和SSS,同时在同一SSB块内把MIB比特经过Polar编码、QPSK调制后映射到PBCH资源。接收端先做PSS-SSS检测获取PCI和定时,随后按PCI指定的扰码和速率匹配参数解调PBCH,最后执行Polar译码。整个仿真脚本结构如下:

  • 外层循环遍历信噪比点
  • 中层循环遍历仿真帧数,每个SNR点运行2000帧以上
  • 内层调用PSS-SSS检测函数、PBCH解调函数、Polar SCL译码函数
  • 统计量在每帧结束时更新

4.2 误码统计单元:BER、BLER、成功率的正确计数方法

% 主仿真循环核心片段 for snr_idx = 1:length(snr_db) ber_count = 0; bler_count = 0; block_total = 0; sync_success = 0; for frame = 1:num_frames tx_bits = randi([0 1], K, 1); [pss_sym, sss_sym, pbch_grid] = tx_chain(tx_bits, PCI); rx_signal = awgn_channel(pbch_grid, snr_db(snr_idx)); [est_pci, timing, strength] = joint_pss_sss_detect(rx_signal); if est_pci == PCI && strength > threshold sync_success = sync_success + 1; rx_bits = rx_pbch_chain(rx_signal, est_pci, timing); block_total = block_total + 1; err_bits = sum(rx_bits ~= tx_bits); ber_count = ber_count + err_bits; if err_bits > 0 bler_count = bler_count + 1; end end end ber(snr_idx) = ber_count / (block_total * K); bler(snr_idx) = bler_count / block_total; sync_rate(snr_idx) = sync_success / num_frames; end

这里有一个容易混淆的统计口径:BER的分母是所有译码后解码块的比特总和,而不是全部发射比特总和。如果PSS-SSS检测失败,那一帧的译码直接就丢了,因此它的错误比特不该进BER分母。BLER同理,只统计成功同步后的块集。实际做下来你会发现,在低信噪比区域检测成功率下降导致block_total偏小,BER曲线会出现在低信噪比下剧烈跳动的现象——这不是代码bug,而是有效样本量变小导致的统计方差,解决方法是加大num_frames或者至少固定随机数种子。

4.2.1 统计口径速查表
统计量分子分母易错点
PSS-SSS检测成功率正确PCI且强度超门限的帧数总仿真帧数正确PCI但强度不足应算失败
BER错误比特总数参与译码的总信息比特数不要用整帧比特数做分母
BLER译码后含任意错误比特的块数成功译码尝试的总块数未同步的帧不计作译码块

4.3 性能曲线绘制:semilogy配合置信区间的Monte Carlo

MATLAB画BER和BLER曲线时,数值可能跨越几个数量级,线性坐标根本看不出差异,所以统一用semilogy。此外很多仿真曲线在低信噪比处右端翘起来,其实是同步丢失导致统计样本收缩,画图前先看线性坐标下的成功率曲线,能解释BER的反常上升。

figure; semilogy(snr_db, ber, 'b-o', 'LineWidth', 1.5); hold on; semilogy(snr_db, bler, 'r-s', 'LineWidth', 1.5); grid on; xlabel('Eb/N0 (dB)'); ylabel('Error Rate'); legend('BER', 'BLER', 'Location', 'southwest'); % 对成功率单独用plot而非semilogy yyaxis right; plot(snr_db, sync_rate, 'g--^'); ylabel('Detection Success Rate');

注意这里我用yyaxis把成功率和误码率画在同一张图的不同纵轴上,成功率是0到1的量级,放左轴会把曲线压缩在顶部,放右轴更合理。x轴标签用Eb/N0而非SNR,因为Polar译码后的性能对比要考虑速率匹配和CRC开销,统一为每信息比特的噪声功率密度才可复现。

5. 验证仿真正确性的三个关键技巧

5.1 用纯噪声标定相关门限,而不是拍脑袋定阈值

联合检测成功率曲线对门限非常敏感,门限高了低信噪比下检测不到,门限低了高信噪比下误检。标准做法是先把PSS-SSS发射机关闭,让接收端只收到复高斯噪声,重复执行数千次检测,记录相关度量的分布,选取满足目标虚警概率的那一点。这个经验值可以作为仿真中threshold的初始值,后续再微调。我在实际项目中通常用噪声场景下第99.9百分位的度量值作为门限,效果比固定乘噪声均值更稳定。

5.2 验证SCL译码的正确性:固定L=1先对比SC

SCL译码比SC复杂,出问题时往往是路径度量计算或CRC选择逻辑有bug。一个稳妥的验证路径是先把L固定为1,让它退化为SC译码,然后对照一个从零实现的SC译码器或对比论文中的性能曲线。两者输出完全一致后,再把L提升到4、8,观察BLER是否单调下降。如果L=2比L=1差,基本可以断定路径度量或剪枝算法存在符号错误。此外,要在CRC级联前先只跑无CRC的场景,确认Polar译码本身没错,再加CRC做终选。

5.3 固定随机种子复现高信噪比区域的“错误平层”

Polar码在高信噪比下的错误平层通常由两个因素导致:冻结位选择不佳或SCL路径数不足。若BER曲线在中高信噪比出现拐点不再下降,先检查冻结位集合是否用了巴氏参数而非随机选取。MATLAB的bhattacharyya函数可以计算每个比特信道的容量,按容量从大到小排序后,把最小的一部分做冻结位。随机冻结位在高信噪比下会残留固定数量的错误比特,表现就是BER曲线平台,出现这种现象时不要急着加信噪比点数,先去换冻结位生成方案,再考虑增大L。最后还可以跑一组不同随机种子,观察曲线波动幅度是否在几个dB内,如果相同信噪比下BER差异超过一个数量级,说明仿真帧数不足,BLER置信区间过大。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 18:14:11

双容水箱模糊控制MATLAB仿真与PID对比分析

简介:这是一份基于MATLAB的双容水箱模糊控制仿真资源,面向自动化、控制工程等专业的学生及需要实现液位控制的工程技术人员,可用于课程设计、毕业设计或技术预研。资源以两个相互串联的水箱为被控对象,围绕水位恒定控制目标&#…

作者头像 李华
网站建设 2026/9/11 18:14:02

源代码论文分享|Spring Boot就业管理系统,做校园类毕设很实用!

如果你最近在找一个业务逻辑比较清楚、数据库不难设计、答辩也容易讲明白的毕业设计题目,可以看看就业管理系统这一类项目。 它不像一些算法题目那样上手门槛高,也不只是简单的信息录入。就业本身就是一个很完整的业务场景,围绕学生、就业信…

作者头像 李华
网站建设 2026/9/11 18:12:07

Prompt 事故档案(七):你以为你在和AI聊天,其实AI在审判你

(本篇为「Prompt 事故档案」系列第(七)篇。没看过前几篇也没关系——这个系列的核心只有一句话:Prompt 是「自然语言编写的代码」,却在绝大多数团队里被允许「裸奔」上线,没有 Code Review、没有三审三校。…

作者头像 李华