SC-FDE完整链路MATLAB仿真:UW序列、定时同步与频域均衡
发布时间:2026/10/7 10:52:03 作者:尧图编辑部 阅读量:1,286

做通信仿真的人几乎都会被OFDM的峰均比问题折磨过功放要回退好几个dB频偏稍微大一点子载波间干扰就开始抬头想让它和单载波一样好分数阶傅里叶变换、加窗、削波一通操作下来复杂度一点没少。如果你也在这个坑里待过SC-FDE是值得认真看的一条路线。单载波频域均衡名字听起来绕其实思路很简单——把单载波信号按块处理在频域做均衡保留OFDM抗多径能力的同时把PAPR压得很低。我最近在MATLAB里把一整套SC-FDE通信链路从零搭了一遍包含UW序列生成、QPSK调制、帧结构拼接、定时同步、载波频偏估计和频域均衡这几个核心模块。这篇文章就把链路设计、关键代码和踩坑过程完整写出来适合正在做SC-FDE课题、或者想用MATLAB做完整通信链路仿真的同学作为参考。标题里提到的载...其实是载波频偏估计我会在同步部分重点展开。1. 为什么是SC-FDE单载波与频域处理的一次握手1.1 OFDM的甜头与代价都不小OFDM最大的贡献是把一个频率选择性信道拆成了若干平坦子信道。在接收端每个子载波上用一个复数除法就能完成均衡多径带来的符号间干扰ISI通过循环前缀CP直接消化掉。这个设计干净利落所以在4G/5G的物理层下行得到了广泛应用。但OFDM的问题同样清晰。第一是高峰均比多路子载波叠加时域波形幅度起伏很大对功放的线性度要求很高终端侧尤其难受。第二是对频偏敏感子载波间隔一旦被频偏破坏正交性就没了会带来严重的载波间干扰。第三是OFDM要求子载波间严格同步这在很多非合作或者突发通信场景里并不容易满足。这些痛点在我做上行链路仿真时体会特别深。发射端是电池供电的终端功放效率上不去信号质量再怎么优化都白搭。1.2 SC-FDE怎么实现既要又要SC-FDE的出发点很简单信号还是单载波但把符号流切成固定长度的块每块末尾插入一段已知序列接收时对整个块做FFT到频域在频域逐点计算均衡系数再IFFT回时域进行判决。这里的关键在于为什么单载波信号也能在频域均衡因为频域均衡要求信道卷积是循环卷积。线性卷积无法直接通过频域点除来逆操作但如果我们把数据块看成是循环延拓的信道对块的影响就等价于频域相乘。插入UW序列正是为了构造这种循环特性——它既承担保护间隔的职责又让数据块在频域上具备可处理的边界条件。跟OFDM相比SC-FDE不需要在发射端做IFFTPAPR天然等于单载波的水平功放效率可以拉高很多。抗频偏能力也远强于OFDM因为不存在子载波正交性可以被破坏的问题。接收端复杂度跟OFDM几乎一样都是一次FFT频域点除一次IFFT代价是多了一个UW开销。1.3 UW序列在链路里的多重身份UW全称是Unique Word也叫独特字。它跟CP最大的区别在于CP是未知数据的循环拷贝接收端一般直接丢弃而UW是收发双方都知道的固定序列接收端可以拿它做很多事情。在我这套链路里UW至少承担三个任务。保护间隔和CP一样避免块间干扰保证数据块在频域上近似循环卷积。定时同步锚点接收端用本地UW与接收信号做滑动相关相关峰的位置就是块边界。信道估计与频偏估计的参考信号因为UW内容已知接收端能够从接收到的UW反推信道频响也能利用相邻块UW之间的相位差估算残余频偏。用一份开销同时换三样功能这是UW方案比CP方案更划算的地方也是标题里把UW序列单独拎出来的原因。2. 发射链路搭建帧结构、QPSK映射与UW生成2.1 仿真参数先定下来动手写代码之前我习惯先把参数表列好。很多新手上来就写循环参数改来改去最后结果对不上问题多半出在这里。我这次用的核心参数如下。参数取值说明数据块长度M256每块承载的数据符号数也是FFT点数UW长度L32插在数据块末尾的已知序列长度调制方式QPSK每个符号携带2比特块数numBlocks2000蒙特卡洛仿真用的总块数过采样倍数ovs4工程化脉冲成形时的采样倍数滚降系数alpha0.22根升余弦成形滤波器滚降系数归一化频偏0.02每符号相位旋转增量单位rad/symbol等效信道抽头3径幅度衰减多径信道数据块长度M定在256是性能和复杂度之间的平衡。FFT点数太小频域分辨率不够均衡后残留ISI明显太大则UW开销和仿真时间都上升。UW长度取32约为数据长度的1/8这个比例在大多数SC-FDE文献里都算常见。2.2 QPSK映射与符号分块QPSK映射代码非常简单关键点是能量归一化。每个符号从两比特映射到±1±1j再除以根号2让每个符号的平均功率为1。这一步很多人会漏漏掉之后SNR计算全乱。M 256; % 每块数据符号数 L 32; % UW长度 numBlocks 2000; % 仿真块数 dataBits randi([0 1], numBlocks, 2*M); % QPSK映射能量归一化 qpskSym (1 - 2*dataBits(:,1:2:end)) 1i*(1 - 2*dataBits(:,2:2:end)); qpskSym qpskSym / sqrt(2);每个块由256个QPSK数据符号和32个UW符号组成实际发送块长度为288个符号。多个块按顺序拼接成一条完整的发射符号流。2.3 UW序列用Chu序列而不是随便填一段伪随机数UW序列的选取有讲究。最简单的是用m序列或者PN序列但它们的周期自相关特性一般在做频偏估计和定时同步时旁瓣不够低会影响精度。我选用的是Chu序列它的幅度恒定、周期自相关特性理想——做定时同步时旁瓣接近于零做频偏估计时相位信息干净。Chu序列的生成公式比ZC序列更灵活长度L为偶数时能用q取任意整数。我用的是最基础的形式n (0:L-1).; uwSeq exp(1i*pi*q*n.^2/L); % 这里q取1也可以换成其他与L互质的整数 uwSeq uwSeq / norm(uwSeq) * sqrt(L);最后一步归一化让UW的平均功率和数据符号保持一致。UW内容在收发两端都是已知的这个条件在后面信道估计和同步计算中会被反复用到。块拼接的代码也很直白txBlocks zeros(numBlocks, M L); for k 1:numBlocks txBlocks(k, :) [qpskSym(k, :), uwSeq.]; end txSignal reshape(txBlocks., [], 1);注意reshape之前要转置否则块内顺序会乱。这是一个很低级但很容易错的点。2.4 如果要工程化还得加脉冲成形前面这套符号率模型适合快速验证算法但真实系统里信号必须经过脉冲成形和数模转换。我在完整链路里也加了根升余弦成形把符号流插值到4倍过采样滤波器滚降系数0.22。ovs 4; span 8; rrcFilter rcosdesign(0.22, span, ovs, sqrt); txUp upsample(txSignal, ovs); txFiltered conv(txUp, rrcFilter, same);加了脉冲成形之后UW序列在采样域中的相关特性仍然成立但峰值会被成形滤波器稍微抹平定时同步的窗口会变宽。这在第3节的同步实现里需要处理。3. 接收端第一关定时同步与载波频偏估计3.1 接收信号模型与前端预处理接收信号在等效基带可以写成r[n] e^(j2πf_off n) * (s[n] * h[n]) w[n]其中f_off是归一化频偏h[n]是多径信道冲激响应w[n]是复高斯白噪声。在仿真里我们先加多径、再叠频偏、最后加噪声顺序不要搞反。我常用的信道模型是3径等效基带抽头hChan [1; 0.35*exp(1i*0.6); 0.18*exp(-1i*0.9)]; rxSignal filter(hChan, 1, txSignal); freqOffset 0.02; nIdx (0:length(rxSignal)-1).; rxSignal rxSignal .* exp(1i*2*pi*freqOffset*nIdx); rxSignal rxSignal awgn(rxSignal, snr, measured);归一化频偏0.02表示每隔一个符号相位旋转2*pi*0.02弧度。这个量级已经足够让QPSK星座图转成花环如果不补偿后面的误码率会惨不忍睹。3.2 用UW做定时同步滑动相关与归一化度量定时同步的目标是找到每个块的起点。因为UW是已知序列接收端可以用本地UW和接收信号做滑动互相关相关峰值对应UW位置。归一化相关度量定义如下metric(d) |Σ r[dk] * conj(uw[k])|² / Σ |r[dk]|²分母做能量归一化是为了避免信号幅度起伏造成误判。MATLAB里用conv一步实现滑动相关corrSeq conv(rxSignal, conj(fliplr(uwSeq)), same); metric abs(corrSeq).^2; % 简单归一化用滑动能量窗 winEnergy movsum(abs(rxSignal).^2, L, endpoints, discard); metricNorm metric(ceil(L/2):end-ceil(L/2)1) ./ (winEnergy eps); [~, peakPos] max(metricNorm); startIdx peakPos; % 近似UW起点实际使用可加修正量滑动相关窗长度等于UW长度L。由于本地UW和接收UW在正确对齐时才会真正相干累加所以相关峰明显错位时近似噪声水平。movsum滑动能量窗的作用是避免接收信号本身幅度波动影响峰值判断这在突发通信里尤其重要。3.3 载波频偏估计相邻块UW相位差定时同步完成后载波频偏估计就顺手了。思路是UW在每个块中相同位置重复出现两个相邻块的UW内容完全相同它们之间的相位差只由频偏和时间间隔决定。设块长为D M L相邻UW的时间间隔就是D个符号。对两个UW做相关corrUW Σ rxUw2[k] * conj(rxUw1[k])这个相关值的相位角等于2*pi*f_off*D于是频偏估计为f_off_est angle(corrUW) / (2*pi*D)代码实现如下uwPos1 startIdx; uwPos2 startIdx M L; uwRx1 rxSignal(uwPos1 : uwPos1 L - 1); uwRx2 rxSignal(uwPos2 : uwPos2 L - 1); corrVal sum(uwRx2 .* conj(uwRx1)); freqOffEst angle(corrVal) / (2*pi*(M L));这个估计算法的频率捕获范围受相位模糊限制最大可估频偏约为±1/(2D)每符号。在我们参数下D288范围大约是±0.0017每符号远小于我仿真的0.02。所以实际链路里需要先做粗频偏估计再用这个UW相关法做细估计。粗频偏可以用帧同步阶段的大范围搜索或者基于FFT的频偏估计实现我后面会提一句。得到频偏估计后对整个接收信号做相位补偿nIdxAll (0:length(rxSignal)-1).; rxComp rxSignal .* exp(-1i*2*pi*freqOffEst*nIdxAll);补偿之后星座图会从旋转状态稳定下来但可能还残留很小的相位偏转这属于残余频偏可以在均衡之后用判决辅助相位跟踪再消掉。4. 频域均衡信道估计与均衡系数计算4.1 频域均衡为什么需要循环频域均衡的理论基础是时域循环卷积等价于频域相乘。如果数据块通过信道的效果是循环卷积那么接收端就能对块做FFT用频域信道响应逐点相除把信道的影响逆回去。线性卷积和循环卷积的区别是新人最容易绕晕的地方。用一个生活类比循环卷积就像一条环形跑道数据块头尾相接前面冲出去的部分会从后面绕回来线性卷积则是一条直线跑道前面的符号冲出去就没了。UW的作用就是在数据块后面垫一段已知序列人为制造头尾相接的效果让信道看起来像循环卷积。4.2 基于UW的信道估计由于UW序列内容已知接收端可以利用收到的UW和本地UW的频谱比值来估计信道频响。设U[k] FFT(uwSeq, M)Ruw[k] FFT(rxUw, M)则信道频响估计为H_est[k] Ruw[k] / U[k]这里的FFT点数是M也就是数据块长度。UW长度L只有32补零到256点。单块估计噪声大实际中用多个块的UW估计取平均uwR zeros(L, numBlocks); for k 1:numBlocks idx startIdx (k-1)*(ML); uwR(:,k) rxComp(idx : idxL-1); end Uf fft(uwSeq, M); H_est mean(fft(uwR, M, 1) ./ repmat(Uf, 1, numBlocks), 2);取平均能把噪声压低多块平均后信道估计精度明显提升这是SC-FDE里很实用的技巧。需要注意的是UW和数据块在同一信道下传输信道估计的时效性要跟上信道变化速度。如果信道快变就得缩短估计块窗口不能为了平均增益盲目用很多块。4.3 MMSE与ZF均衡器怎么选信道频响估计出来后常用的均衡系数有两种。Zero-ForcingZF均衡就是直接取倒数W_zf[k] 1 / H_est[k]实现简单但在信道频响接近零点的子载波上噪声被剧烈放大星座图上会出现炸开的现象。我一般不推荐单独用ZF。MMSE均衡在计算均衡系数的同时把噪声功率也考虑进去W_mmse[k] conj(H_est[k]) / (|H_est[k]|² 1/SNR)这里SNR是每符号信噪比。从公式可以看出当某点子载波信噪比很高时MMSE系数趋近ZF当信道处于深衰落、|H|²很小而噪声不可忽略时MMSE会自动压低该点的增益而不是把噪声无限放大。代价是引入了少量残余ISI但总体误码率远好于ZF。实际计算代码如下noiseVar 10^(-snr_dB/10); W conj(H_est) ./ (abs(H_est).^2 noiseVar); % 提取一个完整数据块 rxBlock rxComp(startIdx - M : startIdx - 1); R fft(rxBlock, M); Y W .* R; xHat ifft(Y, M); % 判决QPSK符号 detSym sign(real(xHat)) / sqrt(2) 1i * sign(imag(xHat)) / sqrt(2);注意这里取的两级sign判决实际中如果数据块包含的是符号率抽取后的QPSK符号直接按实虚部判象限即可。4.4 频域均衡完整流程串一遍从接收信号到判决输出整个过程按顺序是定时同步找UW起点。频偏估计并补偿。利用多块UW估计信道频响。计算MMSE均衡系数。对每个数据块做FFT - 频域点乘 - IFFT。逐符号硬判决并统计误比特。这个流程里块起点startIdx - M这个偏移经常让人迷糊。因为startIdx是UW的起点UW前面紧挨着的是当前块的数据所以当前块数据起始位置是startIdx - M。画一帧结构图就能避免出错[data(256个) | uw(32个)] [data(256个) | uw(32个)] ...UW起点往前数256个符号就是本块数据起点。5. 链路仿真结果与参数敏感性分析5.1 蒙特卡洛仿真怎么组织完整误码率曲线需要跑蒙特卡洛仿真。外层循环控制信噪比Eb/N0内层生成大量随机数据块统计总比特数和误比特数。我通常把发送链路和接收链路各写成一个函数避免在信噪比循环里大量复制粘贴代码。仿真流程大致是EbN0dB 0:2:12; ber zeros(size(EbN0dB)); for i 1:length(EbN0dB) % 转为每符号信噪比 snr_dB EbN0dB(i) 10*log10(2); % QPSK每符号2比特 [ber(i)] run_SCFDE_Link(M, L, numBlocks, snr_dB); endQPSK的Es/N0比Eb/N0高3dB这个换算关系必须写对。另外如果发送端做了根升余弦成形实际噪声带宽还要考虑滚降因子工程仿真里经常在成形前后用信号功率归一化来规避换算错误。5.2 均衡前后对比星座图和误码率我跑下来的典型结果是在3径信道、无频偏补偿的情况下QPSK星座图完全转成一圈误码率接近0.5基本等于随机猜测。加上频偏补偿和MMSE均衡之后星座图恢复到四个清晰的象限误码率在Eb/N08dB附近能压到10^-3以下。MMSE和ZF的对比也很有意思。在信道频响较平坦的归一化频偏环境下两者的差距不是很大但一旦多径信道在某个频点形成深衰落ZF那条BER曲线会出现明显的平台SNR再高也压不下去MMSE则能继续下降。这就是我之前强调噪声增强问题的实际体现。5.3 参数影响分析UW长度、频偏残留和信道抽头几个参数的影响我可以直接给结论都是实测后的经验。UW长度LL过短循环保护不充分块间干扰会抬底L过长开销增大相同频谱效率下数据速率下降。32在M256时是甜点L/M1/8左右。残余频偏即使频偏估计补偿后仍可能有0.001量级的残留。这个残留会在多个块之间累积相位旋转导致MMSE均衡后星座图整体旋转。解决方法是每个块内再做一次判决辅助相位跟踪或者用块内UW做二次相位校正。多径时延当多径时延超过UW长度时循环卷积条件被破坏均衡性能急剧恶化。做仿真时要把信道最大时延控制在L个符号以内否则UW设计本身就不合理。6. 填坑实录仿真总跑不出理想曲线的几个原因6.1 FFT缩放因子把能量搞没了MATLAB的fft不除点数ifft除点数。很多人在计算频域信道响应时直接fft(rx)/fft(tx)做完MMSE均衡后ifft回来发现信号幅度整体变小了。原因是这里涉及两次FFT和一次IFFT缩放因子已经变化但QPSK判决是看象限的幅度变化不影响相位判决所以误码率不一定崩。真正坑人的是SNR计算。如果接收端信号在做FFT之前已经归一化功率而均衡后IFFT又引入1/M因子你统计的噪声方差就跟理论SNR对不上。我的习惯是全程用measured让awgn函数按实际信号功率加噪避免自己手写功率归一化出错。6.2 定时偏差会引入频域相位斜坡定时同步只要偏差一个符号频域就会产生固定的线性相位斜坡导致均衡判决时星座图整体旋转。这是SC-FDE比OFDM更敏感的地方因为OFDM载波间有循环前缀保护同步偏差1个小采样影响不大。解决方法有两个一是在定时同步后用插值精确定位UW峰值的分数倍偏移而不是只取整数抽头二是干脆放弃对每个块分别定时只做一次帧定时之后按固定块长顺延。帧定时一旦稳定块间定时偏差几乎是恒定的对频域均衡的影响可以通过信道估计吸收掉一部分。6.3 频偏估计范围限制与二次补偿第3.3节的UW相关法估计范围是±1/(2D)在我们参数下只有±0.0017每符号。所以整个链路里必须有粗频偏估计环节。粗频偏可以用接收信号的自相关FFT谱峰搜索来做也可以在帧前插入一段较长的已知训练序列用重复结构的相位差扩大捕获范围。如果偷懒不做粗估计直接拿UW相关法去估0.02的频偏相关值会落在模糊区间估出来完全不对。这是我最早踩过的一个大坑一度以为是信道估计写错了。6.4 Eb/N0换算错误导致BER曲线整体平移QPSK的Es/N0 Eb/N0 3dB这条公式我至少看到五个帖子的代码写错过。写错了BER曲线会整体左右平移3dB看起来形状正确但横坐标不对。另外一个容易忽略的点是如果发射端用了根升余弦成形滚降因子0.22不会改变Es/N0但会让信号带宽变大实际需要的传输带宽更大频谱效率下降。在做系统设计对比时要把这个开销算进去建议以Eb/N0做横轴对比不同方案。我在实际跑这套链路时最深的体会是SC-FDE的算法框架不复杂但完整链路四个字意味着每一步都要自洽。UW序列设计、定时同步、频偏估计、信道估计、频域均衡、SNR换算任何一环错位结果都会离理论曲线十万八千里。把简化符号率模型跑通再逐步加上脉冲成形、过采样和更多信道环境是比直接硬啃完整系统代码更稳的路。希望这篇记录能帮你少走我走过的那些弯路。