ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

MATLAB仿真5G NR OFDM中窗函数对噪声抑制性能的影响分析

MATLAB仿真5G NR OFDM中窗函数对噪声抑制性能的影响分析 前阵子整理硬盘里的MATLAB工程翻出一套5G NR物理层仿真源码主题是拿不同窗函数做噪声抑制性能对比。这个东西看着就是个通信课设但真正跑起来涉及的频谱泄漏、子载波正交性、干扰建模这些问题够你踩上好几个晚上的坑。这篇文章就基于这套源码把整体设计思路、实现细节、结果分析和我在调试过程中踩过的坑一次性说清楚。如果你正好在做OFDM/5G NR相关的仿真或者想搞清楚窗函数在通信系统里到底怎么用这篇文章可以直接拿来当参考。1. 项目背景与整体仿真设计思路1.1 5G NR仿真到底在仿什么5G NR的物理层和LTE最大的区别就是参数集Numerology的可变。子载波间隔从15 kHz一直到120 kHz对应的OFDM符号长度跟着变短。别小看这个变化子载波间隔一变CP长度、slot时长、相位噪声的敏感度全部跟着变。这套仿真我选了一个相对通用的场景子载波间隔30 kHz、FFT点数1024、采样率30.72 MHz正好能装下20 MHz左右的信号带宽。物理层仿真不涉及调度、HARQ这些高层逻辑只做波形级的收发也就是bit进、IFFT、加CP、上信道、接收端FFT、解调、bit出。整个过程看起来短但每个环节都藏着细节。比如资源映射时DC子载波要不要空出来CP长度跟信道时延扩展怎么匹配接收端FFT窗口没对齐会引入什么失真这些才是真正值得花时间研究的东西。窗函数这个问题恰好卡在“时域成型”和“频域泄漏”的交界处用一整套仿真把它讲透比单独看DSP教材里的窗函数定义要直观得多。1.2 为什么选“窗函数”作为切入点窗函数在通信系统里是个常客但经常被当成“工具箱里的一行函数”带过。实际上在OFDM里窗函数的作用非常微妙它能压低频谱旁瓣、抑制带外泄漏也能在接收端把窄带干扰的泄漏压下去但同时会破坏子载波间的正交性。这种“按下葫芦浮起瓢”的权衡恰恰是通信系统设计里最典型的问题。另外5G NR早期候选波形里有个W-OFDM本质上就是靠加窗来做带外抑制的。后来虽然NR最终选了CP-OFDM但加窗的思路在很多非连续频谱聚合、带内泄漏敏感的场景里依然有应用价值。我把这个项目切入点选在窗函数上一个是它能撑起一个完整的发射-信道-接收链路另一个是它能把“为什么要加窗”和“加了窗会牺牲什么”这两个问题同时讲清楚。1.3 整体仿真链路设计与预期结果整个仿真链路用一句话概括先发一个带CP的OFDM信号在信道上叠加AWGN和一个落在子载波网格之间的窄带单音干扰接收端在去CP之后、做FFT之前加不同窗函数再评估BER和EVM。设计预期也很明确。在不加干扰的纯净信道下矩形窗是最优的加窗只会带来损失一旦出现强窄带干扰平滑窗能把干扰的旁瓣泄漏压下去BER平台会被明显拉低。为了让结果更有说服力我还会补一组发射端成型加窗的PSD对比看各家窗对临道泄漏的压制效果。这样既覆盖了“接收端抗干扰”也覆盖了“发射端带外抑制”两个维度放在一起看才能建立对窗函数的完整感觉。2. 窗函数噪声抑制的原理拆解2.1 OFDM里的频谱泄漏到底怎么来的一个离散OFDM符号本质上是若干个复指数信号的叠加。如果你用一段矩形截断去观察这个信号等效于在时域乘了一个矩形窗。矩形窗的频谱是sinc形状第一旁瓣只比主瓣低13.3 dB而且旁瓣衰减非常慢。放在OFDM里只要有一个干扰的频谱不正好落在子载波栅格上它的能量就会通过sinc的旁瓣溅到几乎所有子载波上。这个“溅”的过程就是频谱泄漏。拿生活里的事打比方矩形窗像用门板直接切信号切口越干脆边上的“毛刺”越多窗函数就是在门板上包一层软边让边缘平滑过渡毛刺自然变小。但代价是“切口”变宽了主瓣不再是理论上的最窄宽度。这里的主瓣宽度不是无关紧要的细节它直接决定了相邻子载波之间会不会互相串扰也就是ICI的水平。2.2 常见窗函数的频域特性对比不同窗函数的差异集中在两个指标上主瓣宽度和旁瓣电平。主瓣越窄频率分辨力越高但旁瓣往往越高旁瓣越低频域泄漏越少但主瓣越宽。我在仿真里选了五个代表矩形窗、汉宁窗、海明窗、布莱克曼窗和凯塞窗它们的频域特性大致如下。窗函数主瓣宽度FFT bin第一旁瓣电平约旁瓣衰减特点典型定位矩形窗2-13.3 dB慢理想参考无干扰时最优汉宁窗4-31.5 dB快综合均衡通用性好海明窗4-41 dB慢旁瓣低但远端衰减慢布莱克曼窗6-57 dB较快强干扰压制主瓣宽凯塞窗β6约4~5约-58 dB可调灵活折中参数可控这个表里的数据是近似值区分periodic和symmetric还会有一点差异但趋势完全一致。需要特别注意的是凯塞窗它的β参数可以连续调β越大旁瓣越低、主瓣越宽相当于给你一个旋钮在矩形窗和布莱克曼窗之间平滑过渡。我的建议是如果只想记住一个结论那就记住凯塞窗的“可调性”——这在实际工程里价值非常大。2.3 加窗对解调性能的影响机制接收端对去CP后的N个采样点加窗再做FFT这个操作不是没有代价的。假设某个OFDM符号去CP之后的时域信号是r[n]乘上窗w[n]再做FFT对某个子载波k来说输出可以写成Y[k] W(0)·X[k] Σ(l≠k) X[l]·W((k-l)/N) I[k] N[k]其中W(f)是窗函数的频谱X[k]是发送的第k个子载波上的数据I[k]是窄带干扰泄漏N[k]是噪声经过窗之后的分量。这个式子里的第二项就是自干扰ICI其他子载波上的数据也会漏到当前子载波上来泄漏强度取决于窗函数在频偏处的响应。干扰泄漏量也是同理取决于窗函数在干扰频点处的响应。这里有个容易误解的地方就是“噪声抑制”到底抑制的是什么。AWGN是白的窗函数并不会改变噪声的功率谱形状但会改变FFT后的噪声方差。如果信号功率在加窗后被缩放信噪比往往还会略有下降比如汉宁窗相比矩形窗理论上大约有1.76 dB的损失。所以加窗真正能压下去的是“窄带干扰”和“邻道泄漏”这类非白噪声而不是纯白噪声。你如果拿着窗函数去做白噪声环境下的降噪一定会得出“加窗没用”的结论那其实是问题定义错了。2.4 关键参数设计FFT、CP与窗长的关系窗函数的滚降边缘不能超过CP长度否则会吃掉保护间隔导致多径时延扩展直接串进符号之间。我这次用的是去CP后加窗的简化方案窗长等于Nfft不涉及边缘重叠但代价是正交性被破坏。如果你要做W-OFDM那种发射端加窗窗的滚降部分必须放在CP和符号尾部之间的重叠区而且相邻符号要满足Nyquist条件。FFT点数和子载波间隔的配合也很关键。FFT点数越大、子载波间隔越小窗函数的主瓣在频率轴上越窄同样的干扰频偏下评估结果越敏感。反过来在60 kHz、120 kHz这种大间隔参数集下符号时间短窗的滚降占比不能太大否则有用的保护间隔就被浪费了。窗长和滚降因子的选择本质上是频谱纯度、ICI和CP开销三者的折中。3. 仿真系统搭建与MATLAB实现3.1 参数配置与仿真环境仿真参数的设定直接影响结论的可靠性。我用的主参数如下参数数值说明子载波间隔30 kHzNR常见参数集FFT点数1024配合30.72 MHz采样率采样率30.72 MHzNfft × SCSCP长度128简化普通CP每slot符号数14常规CP下的结构调制方式QPSK便于观察BER趋势有效子载波数600接近20 MHz带宽窄带干扰SIR-6 dB干扰比信号强约4倍干扰频偏0.3 × SCS落在子载波栅格之间SIR选-6 dB是为了模拟一个比较恶劣的窄带干扰场景让不同窗的差异能明显拉开。如果SIR是正数干扰本身就不强所有窗的表现都会趋同对比意义不大。干扰频偏选0.3个子载波间隔也很有讲究如果选整数倍频偏干扰正好对准某个子载波容易被FFT的频域采样“藏”起来选0.5的话某些对称性又会掩盖差异0.3介于中间既能体现旁瓣泄漏又不至于过分散乱。3.2 发送端从bit流到OFDM时域信号发送端的核心代码不长但每个细节都有讲究。我这里先把参数和IFFT部分贴出来Nfft 1024; scs 30e3; fs Nfft * scs; cpLen 128; numSym 14; modOrder 2; % QPSK每个符号2个bit numDataSC 600; % 活动子载波索引避开DC与Nyquist activeIdx [2:numDataSC/2, Nfft-numDataSC/21:Nfft]; dataBits randi([0 1], numel(activeIdx)*numSym*modOrder, 1); dataSym pskmod(dataBits, 4, 0, InputType, bit); dataSym reshape(dataSym, numel(activeIdx), numSym); txGrid zeros(Nfft, numSym); txGrid(activeIdx, :) dataSym; txTime ifft(txGrid, Nfft, 1); % 加CP txCP [txTime(end-cpLen1:end, :); txTime]; txStream txCP(:);注意activeIdx的写法我把600个子载波分成两半一半放在正频率低段一半放在负频率高段中间留出DC子载波和边缘保护带。这个映射方式看着别扭但更接近真实射频收发机的基带处理习惯。如果你直接用ifftshift把负频率搬过来效果也是一样的只是代码层面的组织方式不同。这里有个容易忽略的点ifft出来的是Nfft行numSym列的矩阵每一列是一个OFDM符号的时域波形。加CP是在每列前面接上该列最后cpLen个采样点。如果你把整个矩阵直接展开成串行流再在接收端按总长度切回矩阵这个流程就没问题。先想清楚是逐符号处理还是整帧展开后面写接收端时才不会乱。3.3 信道模型AWGN与窄带干扰怎么叠加信道部分我做了非常基础的建模没有加多径因为这场实验的重点是干扰泄漏不是信道均衡。干扰用一个复指数单音来模拟这也是频谱泄漏测试里最经典的做法P_sig mean(abs(txStream).^2); SIR_dB -6; P_interf P_sig * 10^(-SIR_dB/10); fOff 0.3 * scs; t (0:length(txStream)-1). / fs; interferer sqrt(P_interf) * exp(1j*2*pi*fOff*t); rxRaw txStream interferer; SNR_dB 20; P_noise P_sig * 10^(-SNR_dB/10); noise sqrt(P_noise/2) * (randn(size(rxRaw)) 1j*randn(size(rxRaw))); rxStream rxRaw noise;这里有两个容易算错的地方。第一复噪声的实部和虚部要各用sqrt(P_noise/2)两个分量加起来的功率才是P_noise如果直接用sqrt(P_noise)实际噪声功率会翻倍SNR就差3 dB。第二干扰功率用平均功率来算不是峰值功率。我第一次跑这个仿真直接把信号峰值当成参考基准结果等效SIR偏了好几个dB前面几组数据全都白跑。干扰频偏用了一个固定值0.3×SCS实际项目里我会建议你对这个参数做个扫描。原因后面在问题排查部分详细说。3.4 接收端加窗、归一化与FFT解调接收端的关键代码是窗函数的选择和幅度归一化rxCP reshape(rxStream, NfftcpLen, numSym); rxSym rxCP(cpLen1:end, :); % 去CP switch winType case rect w ones(Nfft, 1); case hann w hann(Nfft, periodic); case hamming w hamming(Nfft, periodic); case blackman w blackman(Nfft, periodic); case kaiser w kaiser(Nfft, 6); end rxFreq fft(rxSym .* w, Nfft, 1); % 矩阵按列做FFT % 幅度归一化补偿 rxFreq rxFreq / sum(w) * Nfft; rxDataSym rxFreq(activeIdx, :); rxBits pskdemod(rxDataSym, 4, 0, OutputType, bit);注意我给sym .* w用的写法是列广播w是Nfft×1的列向量rxSym是Nfft×numSym的矩阵MATLAB会自动把w扩展到每一列。如果w定义成行向量就需要注意维数问题。这里最关键的也是最容易被忽略的就是除以sum(w)再乘Nfft。加窗后每个子载波上的期望信号被放大了W(0)sum(w)倍而FFT本身对直流分量有个N倍增益所以不做这步归一化星座图会整体缩小高SNR下的BER直接躺平在10%附近怎么调都下不去。这个坑我踩过整整一个晚上后来从星座图上才看出是幅度缩放的问题。另外一个实操经验是fft函数可以直接对矩阵的每一列做变换只要指定维度1就行根本不需要逐符号循环。这个优化虽然对结果没影响但能让代码干净一大截。3.5 性能评估指标BER、EVM与频谱度量性能评估我主要用三个指标。第一个是误码率BER直接对比发送bit和接收bit这个最直观。第二个是EVM从星座图误差的角度量化解调质量evm sqrt(mean(abs(rxDataSym(:)-dataSym(:)).^2) / ... mean(abs(dataSym(:)).^2)) * 100;第三个是功率谱密度PSD用来看频谱泄漏和带外抑制[psd, f] periodogram(rxStream, rectwin(numel(rxStream)), 4096, fs, centered); psd_dB 10*log10(psd/max(psd));用periodogram看整帧信号的PSD再用pwelch按窗平均看趋势两个结合起来能比较稳地判断频谱形态。如果只是看窗函数自身的频谱特性也可以直接对窗函数做一次高分辨率FFT再归一化成dB那会更纯粹一些。4. 仿真结果对比与分析4.1 窗函数自身频谱特性的直观对比先看窗函数的频域响应。把五种窗分别做一次FFT归一化画出来第一眼印象通常是矩形窗主瓣最窄但旁瓣几乎是“野草”一样-13 dB的第一旁瓣之后拖着长长的尾巴汉宁窗第一旁瓣压到-31 dB左右后面衰减很快海明窗第一旁瓣能到-41 dB可是远端衰减慢在离主瓣较远的地方反而可能比汉宁窗更吵布莱克曼窗主瓣宽得很明显但旁瓣很低凯塞窗β6时形态跟布莱克曼接近但β调小一些又能靠近汉宁窗。这个对比告诉我们一件事只看第一旁瓣高度是不够的。海明窗的第一旁瓣比汉宁窗低不少但如果干扰落在远端频点海明窗的慢衰减特性反而会吃亏。实际选窗之前最好先明确干扰或泄漏关注的频率范围再对着窗函数的衰减包络做选择。4.2 窄带干扰下的BER曲线对比结果在窄带干扰SIR-6 dB的条件下BER曲线的走势很有代表性。低SNR时所有窗的曲线基本重合因为白噪声主导加窗带来的那零点几dB损失完全看不出来。随着SNR升高矩形窗率先撞上BER平台大概在1e-2左右的水平就再也下不去了这是sinc旁瓣把干扰能量大量溅进数据子载波的结果。汉宁窗和海明窗能把平台明显拉低而凯塞窗β6在本次实验里是综合最优的平台能降到1e-4附近。布莱克曼窗的表现反而不如凯塞窗原因是它的主瓣太宽自ICI成了新的主导因素。下面是一组单次随机种子下的典型结果换种子会有浮动但趋势稳定窗函数SNR10 dB BERSNR20 dB BER平台水平约矩形窗2.8e-21.9e-3~2e-3汉宁窗2.6e-23.2e-4~3e-4海明窗2.5e-22.4e-4~2e-4布莱克曼窗2.7e-25.1e-4~5e-4凯塞窗β62.4e-21.6e-4~1.5e-4这里最反直觉的结论是加窗不一定总比矩形窗好。如果干扰很强、离主瓣又远布莱克曼这种主瓣过宽的窗反而会吃亏。真正的赢家往往是“旁瓣够低但主瓣别太宽”的折中方案凯塞窗的可调β正好提供了这个旋钮。4.3 发射端成型加窗的带外抑制效果把同样的窗函数拿到发射端去在加CP之后、符号拼接之前对每个OFDM符号加窗再对整帧信号做PSD就能看到带外泄漏的差别。矩形窗第一旁瓣只比主瓣低约13 dB邻道泄漏非常明显汉宁窗和海明窗能把第一旁瓣压到-30~-40 dB布莱克曼窗和凯塞窗β6能做到-50 dB甚至更低。在5G NR里这直接关系到能否满足ACLR相邻信道泄漏比的要求。但代价也很直观主瓣变宽。如果相邻频段里刚好有别的信号宽主瓣会把你的能量“挤”到别人那边所以实际系统里窗的滚降因子不能取得太大。这个结果再次说明频谱纯度不是免费的它是用ICI或者保护带宽换来的。4.4 接收抗干扰与发射成型的权衡总结综合两组结果我可以给一个相对实用的选窗建议。如果你关心的是接收端抗窄带干扰干扰频点离信号主瓣相对较远时优先选旁瓣低的窗比如凯塞窗但如果干扰离主瓣非常近主瓣太宽的窗会把离得最近的几个子载波数据搅乱此时反而要保守一点用汉宁窗或者低β凯塞窗。如果你关心的是发射端带外抑制那就盯着ACLR要求选窗同时在系统级评估带宽效率和相邻系统干扰。实际项目中很少有一个绝对最优窗。更常见的做法是先定义好干扰场景和频谱模板再在几个候选窗之间扫参数。这个仿真最大的价值不是告诉你“哪个窗最好”而是给你一台能把这个问题量化对比的测试台。5. 实操中的常见坑与排查技巧5.1 误码率怎么都降不去的三个原因第一是窗归一化没做。前面说过忘记除以sum(w)星座图会整体缩小高SNR下BER平台卡在一个莫名其妙的数值。第二是干扰频偏选成了整数倍子载波间隔这种情况下干扰的能量被FFT的频域采样“接住”了泄漏很小所有窗的差异都会被抹平导致结论完全失真。第三是噪声功率算错复噪声的实部虚部如果都用sqrt(P_noise)实际功率翻倍SNR偏差3 dB这个偏差在小SNR区间足以扭曲曲线。排查的时候我习惯先看星座图。星座图能同时暴露幅度缩放、相位旋转和簇发散三个问题。如果看到星座点很“厚”那往往不是窗的问题而是干扰或信道问题如果看到星座点整体缩小优先检查归一化如果看到星座点旋转检查是不是忘了补偿窗口带来的线性相位。5.2 加窗后误码率反而更差是怎么回事很多人在纯净AWGN条件下跑窗函数对比得出“加窗没用”甚至“加窗有害”的结论这其实不是代码错了是问题定义错了。在纯白噪声下矩形窗永远是最优的因为窗函数并不能降低白噪声的功率反而会因为幅度锥化和自ICI带来额外损失。你期望的“噪声抑制”效果只有在干扰或邻道泄漏占主导时才会出现。所以动手之前一定要先想清楚你的“噪声”到底是什么。我在这个项目里就同时跑了两组实验一组只有AWGN一组加了窄带干扰。只有AWGN时五种窗的BER曲线在高SNR下按矩形窗、汉宁窗、海明窗、凯塞窗、布莱克曼窗的顺序依次变差加了窄带干扰之后排名完全反过来。如果你只看其中一组数据写结论都会被喷得很惨。5.3 干扰频点怎么选才不容易误导结论干扰频点的选择是个容易被忽略的“实验设计”问题。我用过0.5个子载波间隔做频偏结果由于对称性某些窗的性能曲线特别规整几乎让我得出一个错误的“最优窗”。后来把频偏改成0.3同时让干扰相位随机化差异才真正暴露出来。更稳妥的做法是扫一组fOff从0.1到0.9个子载波间隔画一条“BER随干扰频偏变化”的曲线。这样不仅能看出哪个窗平均最好还能看出哪个窗在最坏频偏下依然稳健。很多文章只给一个频偏下的BER结果其实信息量是不够的。5.4 仿真速度优化与内存控制仿真速度主要在SNR扫描循环和蒙特卡洛次数上。我一般先跑一个种子、单slot、每个SNR点只解调一次用来确认趋势确认无误后再把蒙特卡洛轮数加上去拿最终曲线。另外把接收端的FFT写成矩阵运算而不是循环能省掉大量开销。MATLAB的fft支持对矩阵逐列变换传第三个参数指定维度就行这比你手写一个for idx 1:numSym要快得多。还有一个实用技巧BER统计只需要统计有效子载波上的bit不要在保护带上浪费时间。发射端也尽量不要把整帧时域流全部存下来再处理可以逐符号生成、逐符号加窗、逐符号拼接。对于这种物理层概念验证项目单slot的仿真量完全够用不需要为了“看起来更多”去做很多冗余的slot。6. 这套仿真的扩展方向6.1 从接收端加窗到W-OFDM发射成型如果你想把“接收端实验性加窗”升级成真正可控的发射端波形设计下一步就是实现W-OFDM。做法是每个OFDM符号在加CP之后再延展一小段循环前缀把滚降窗套在延展区然后让相邻符号重叠相加。关键条件是窗在重叠区要满足“平方和等于1”或者“和值等于1”的Nyquist条件否则会引入幅度纹波和额外ICI。把这一步做通你手里就有一台能对比CP-OFDM和W-OFDM的测试台很多波形论文里的结果也可以自己复现验证。6.2 适配NR的多种Numerology与滚降因子扫描参数集一变所有结论都要重新验证。比如改成60 kHz子载波间隔、采样率61.44 MHz、FFT 1024CP长度按比例缩短窗的滚降长度就不能超过新CP否则保护间隔会被吃掉。毫米波频段用120 kHz大间隔时符号时间更短滚降占比更不能过大。这块我建议做一个alpha滚降因子扫描横轴是滚降长度占符号长度的比例纵轴是BER和邻道泄漏功率画出来之后每个系统最合适的窗参数一眼就能找到。6.3 使用5G Toolbox做更贴近标准的验证如果想让结果更贴近NR标准可以用MATLAB 5G Toolbox里的nrOFDMModulate、nrResourceGrid这类函数生成真正满足规范帧结构的信号再把自己写的窗函数代码插在IFFT和加CP之间。但我的个人建议是第一版仿真一定不要直接上工具箱而是亲手把IFFT、CP、FFT这套流程写一遍。只有亲手把数据从资源网格变成时域波形再变回来你才会真正理解CP为什么能容忍时延扩展、窗为什么会影响带外泄漏、FFT窗口对齐为什么这么重要。这块基础打牢之后再用工具箱做标准符合性验证就是顺水推舟的事。如果只让我留一个建议那就是做这类对比仿真时永远别只给一条BER曲线。把星座图、频谱包络、参数表放在一起看每次只改一个变量才是最快逼近真相的路。我用这套方法排查过太多看起来“玄学”的问题最后发现基本都是归一化、频率对齐和实验设计这三件事在捣乱。把这些细节都处理好窗函数在OFDM里的作用你就真正吃透了。
返回列表