ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

宽带瑞利衰落信道下OFDM与OTFS误码率对比:循环前缀的关键作用

宽带瑞利衰落信道下OFDM与OTFS误码率对比:循环前缀的关键作用 简介针对宽带瑞丽衰减信道下不同调制波形的误码率对比需求这份MATLAB仿真包提供了OFDM、OTFS、C-OFDM、C-OTFS四种方案在16QAM调制下的完整实现适合本硕博学生及科研人员作为通信课程设计与算法验证的参考。压缩包共10个文件含9个m脚本和1个avi操作录屏涵盖数据生成、调制、多径信道、均衡解调与误码率绘图等功能模块整体仅327KB轻量便捷。这套代码已有1256人学习下载配套操作录像可帮助读者快速复现仿真流程。通过运行主脚本读者既能对比各方案在宽带瑞丽信道下的性能差异也能理解不同波形的调制解调与均衡思路为后续研究提供可复用的工程脚本。1. 宽带瑞利衰落信道下的误码率对比先搞清楚这四条曲线在比什么宽带瑞利衰落信道下做误码率对比把 OFDM、OTFS、C-OFDM、C-OTFS 四套波形都设为 16QAM 调制这几乎是所有物理层波形评估里最早会碰到的对照实验。单载波系统在这种多径信道下会直接崩盘而 OFDM 和 OTFS 谁更扛得住很多人第一反应是“OTFS 一定更好”但实际跑出来往往不是这么回事——循环前缀够不够长、符号放在时频域还是时延-多普勒域、接收机做到什么程度都会让结论反转。标题里的“瑞丽”其实就是瑞利Rayleigh正文里我统一按瑞利处理。这篇文章从信道建模、四路波形接入、误码率主循环一直写到结果验证适合正在做基带预研、课程设计或者想从 OFDM 向 OTFS 迁移的工程师照着复现。2. 宽带瑞利衰落信道建模为什么 16QAM 在这里最容易翻车2.1 频率选择性衰落对 16QAM 意味着什么宽带瑞利衰落的本质是多径时延扩展和符号周期在同一量级甚至更大。信号经过不同长度的路径到达接收端在频域上就表现为频率选择性衰落——某些子载波被深衰落压到接近零点另一些子载波却基本完好。这种信道对 16QAM 尤其不友好因为 16QAM 同时携带幅度和相位信息星座点之间的欧氏距离比 QPSK 小得多深衰落下符号可能直接被压到原点附近判决出错几乎是必然的。OFDM 的思路是把宽带信道切成大量窄带子载波每个子载波近似经历平坦衰落再用均衡把每个子载波上的相位和幅度补偿回来。OTFS 则换了个坐标系把 QAM 符号铺在时延-多普勒网格上让每个符号在传输过程中经历整段信道的平均增益而不是被某一个频点上的凹口单独毁掉。这里有个容易被忽略的角色循环前缀CP。CP 的作用是把多径产生的符号间干扰ISI挡在有用信号之外如果 CP 短于最大时延扩展OFDM 和 OTFS 都会出现无论怎么加大信噪比也压不下去的误差地板。这个项目的对比核心其实就是把 CP 当作一个隔离变量普通方案用短 CPC-方案用足以覆盖多径时延的完整 CP。这样四条曲线放在一起能直接看出 CP 对误码率的贡献有多大也能看出在相同保护条件下 OFDM 和 OTFS 的差异。2.2 最小信道生成函数每帧一个瑞利冲激响应我一般不会一上来就上完整的抽头延时线信道模型而是先用一个最简单、可复现的帧级信道函数把链路跑通。下面这个函数生成一帧宽带瑞利信道的冲激响应每径一个独立复高斯增益按抽头延迟摆到冲激响应里最后做总功率归一化。function hImp gen_frame_channel(pathDelays, pathPowers) % 生成一帧信道冲激响应每个径独立复高斯增益 % pathDelays : 整数采样点延迟例如 [0 3 6 10 15] % pathPowers : 线性功率例如 [1 0.5 0.25 0.125 0.0625] maxDelay max(pathDelays); hImp zeros(1, maxDelay 1); for tap 1:length(pathDelays) g (randn 1j*randn) / sqrt(2); % 每径瑞利增益 hImp(pathDelays(tap) 1) hImp(pathDelays(tap) 1) ... g * sqrt(pathPowers(tap)); end hImp hImp / sqrt(sum(pathPowers)); % 总功率归一化到 1 end这里每帧只生成一次信道也就是块衰落模型。这样做有两个好处一是四条曲线可以在完全相同的信道实例上对比随机性不会干扰结论二是帧与帧之间独立变化已经足够模拟“宽带瑞利衰落”的多径特征。如果你要的是符号级时变信道可以在外面对每径增益做多普勒滤波每帧内部再按符号数插值更新但对本项目的误码率对比来说块衰落已经够用。参数上要注意两点。pathDelays的单位是采样点假设采样率 10 MHz延迟 15 个采样点就是 1.5 us 的时延扩展这已经是典型的宽带场景。pathPowers决定频域凹口的深度和位置建议用递减功率谱比如[1 0.5 0.25 0.125 0.0625]总功率归一化后接收端噪声方差可以直接由信噪比推出不用再额外折算信道增益。2.3 关键参数表CP、子载波间隔、时延扩展怎么配仿真参数必须在一开始就定死否则后面换方案时很容易顾此失彼。下面这套参数是我在这个对比项目里常用的配置参数取值说明nfft64子载波数也是 FFT 点数OTFS 的时延轴长度N8每帧 OFDM 符号数OTFS 的多普勒轴长度cpShort4普通方案的 CP 长度故意小于最大时延cpLong16C-方案的 CP 长度覆盖最大时延 15pathDelays[0 3 6 10 15]多径位置单位采样点pathPowers[1 0.5 0.25 0.125 0.0625]每径线性功率snrDb0:3:24信噪比扫描范围numFrames30每个信噪比点的蒙特卡洛帧数modOrder1616QAM注意这里cpShort4小于max(pathDelays)15意味着普通方案必然存在符号间干扰cpLong16则完全覆盖多径。这样做的目的是让普通 OFDM/OTFS 与 C-OFDM/C-OTFS 之间只有一个变量——保护间隔是否足够。如果你把 CP 设得足够长四条曲线在高信噪比下会全部收敛到理论 16QAM 曲线附近对比就没有意义了。提示信道归一化千万别省。hImp总功率不归一化的话不同帧之间的信号幅度差异会被误当成信噪比波动曲线抖到你怀疑人生。3. 把 OFDM、OTFS、C-OFDM、C-OTFS 塞进同一套收发框架3.1 C- 到底指什么这里按循环前缀配置实现C-OFDM 和 C-OTFS 里的 C- 在不同项目里有不同解释常见的有 Cyclic Prefix、Coded、Chaotic 三种。在这个工程里我按 Cyclic Prefix 实现OFDM 和 OTFS 使用短 CPC-OFDM 和 C-OTFS 使用完整 CP。这样四条曲线的差异完全由保护间隔决定最容易解释也最容易复现。如果你的 C- 指的是 Coded信道编码或者 Chaotic混沌置乱对比逻辑是一样的——把普通方案的处理链替换成对应模块然后保持其他参数不变。但第一次做这个对比时我建议先从 CP 差异入手因为它的代码改动量最小而且结果非常直观高信噪比下短 CP 方案出现地板C-方案继续下降。先跑通这组曲线再往里面加编码或置乱后续排错会轻松很多。3.2 OFDM 与 C-OFDM 的收发核心函数OFDM 的收发核心就是 IFFT 加 CP、去 CP 加 FFT。C-OFDM 和 OFDM 的唯一区别是 CP 长度参数所以我用一个函数同时覆盖两个方案function tx tx_ofdm(modSyms, nfft, cpLen) % modSyms : nfft 行、nCols 列的频域 QAM 符号矩阵 % cpLen : 循环前缀长度普通方案传 cpShortC-方案传 cpLong nCols size(modSyms, 2); tx []; for col 1:nCols sym ifft(modSyms(:, col), nfft); txSym [sym(end-cpLen1:end); sym]; % 复制尾部到开头 tx [tx; txSym]; end end function rxSyms rx_ofdm(rxIn, nfft, cpLen, nCols) % 按帧长切分去 CP 后 FFT返回频域符号矩阵 frameLen nfft cpLen; rxSyms zeros(nfft, nCols); for col 1:nCols seg rxIn((col-1)*frameLen1 : col*frameLen); seg seg(cpLen1:end); % 丢弃循环前缀 rxSyms(:, col) fft(seg, nfft); end endmodSyms每一列是一个 OFDM 符号行索引对应子载波。发射端先对每列做 IFFT把频域符号变回时域波形然后复制末尾cpLen个采样点拼到开头。接收端按nfft cpLen的长度切帧丢掉 CP再做 FFT 回到频域。这里有个细节卷积信道后接收信号长度会变成len(tx) maxDelay我在主循环里会直接截断到numel(tx)。因为 CP 已经把前导干扰吸收掉了尾部多出来的径不需要参与后续处理。如果你发现均衡后符号有明显的固定偏移先检查截断位置对不对。3.3 OTFS 与 C-OTFS 的 DD 域映射OTFS 的发射端先把 QAM 符号放在时延-多普勒DD域矩阵里然后通过辛有限傅里叶变换ISFFT变成时频TF域符号再走一遍 OFDM 的 IFFT 加 CP 流程。接收端反过来先 TF 域均衡再做 SFFT 回到 DD 域判决。function tx tx_otfs(Xdd, nfft, N, cpLen) % Xdd : nfft×N 的 DD 域符号矩阵行时延列多普勒 % 时延维 DFTISFFT 前半 Xtf fft(Xdd, nfft, 1) / sqrt(nfft); % 多普勒维 IDFTISFFT 后半 Xtf ifft(Xtf, N, 2) * sqrt(N); % 落到时域发射复用 OFDM 的加 CP 逻辑 tx tx_ofdm(Xtf, nfft, cpLen); end function XddHat rx_otfs(rx, nfft, N, cpLen, Htf, varNoise) % 得到 TF 域接收符号 Xtf rx_ofdm(rx, nfft, cpLen, N); % TF 域 MMSE 均衡Htf 是信道频响在 TF 网格上的扩展 XtfEq conj(Htf) .* Xtf ./ (abs(Htf).^2 varNoise); % 时延维 IDFTSFFT 后半 XddHat ifft(XtfEq, nfft, 1) * sqrt(nfft); % 多普勒维 DFTSFFT 前半 XddHat fft(XddHat, N, 2) / sqrt(N); end这段代码里最容易搞错的是 FFT 沿哪个维度。Xdd 的行是时延轴列是多普勒轴所以 ISFFT 的时延维 DFT 必须用fft(Xdd, nfft, 1)也就是沿第一维多普勒维 IDFT 用ifft(Xtf, N, 2)沿第二维。接收端 SFFT 是反向操作先沿时延维 IDFT再沿多普勒维 DFT顺序不能反。调不出来的时候先做个无噪声回环把单位阵放进去看能不能原样收回来。需要说明的是这里用的是 TF 域逐点 MMSE 均衡不是 DD 域联合检测。这意味着在块衰落信道下OTFS 和 OFDM 的误码率会非常接近因为信道在帧内不变时DD 域和 TF 域本质上是同一组线性变换。要让 OTFS 真正拉开差距需要把信道抽头改成符号级时变并换成 DD 域的消息传递或 MMSE 均衡器。这个我会在最后一章展开。3.4 16QAM 的格雷映射与功率归一化16QAM 在 MATLAB 里直接用qammod很方便但默认星座功率不是 1而是 10。如果不做归一化后面噪声方差和信噪比的定义全都会偏移四路曲线的相对关系虽然可能不变但绝对位置对不上理论值。const qammod(0:15, 16, gray); const const / sqrt(mean(abs(const).^2)); % 平均功率归一为 1 % 发送端symIdx 是 0~15 的符号索引 X const(symIdx 1); % 接收端先乘回 sqrt(10) 恢复 MATLAB 默认星座幅度再硬判决 rxBits qamdemod(Xhat(:) * sqrt(10), 16, gray, OutputType, bit); txBits qamdemod(X(:) * sqrt(10), 16, gray, OutputType, bit); err sum(rxBits ~ txBits);qamdemod(..., OutputType, bit)会把每个符号直接映射成 4 个比特而且走的是格雷编码相邻星座点之间只差 1 个比特。这样统计误码率时不用自己维护比特到符号的映射表代码干净很多。用同样的方式处理发送星座可以保证对比双方的比特序列完全同源。注意发送端符号矩阵X的平均功率已经被归一化成 1所以后面主循环里的varNoise 10^(-snrDb/10)直接就是噪声方差不需要再乘任何信号功率因子。4. 误码率对比主循环参数表、代码与曲线的判读方法4.1 仿真主流程设计主循环的逻辑不复杂每个信噪比点跑若干帧每一帧生成一个信道冲激响应然后 OFDM、OTFS、C-OFDM、C-OTFS 四个方案依次用同一份信道、同一份发送符号、同一份噪声种子过链路统计各自的比特错误数。关键在于四条曲线必须共用hImp、X和随机噪声的生成状态。如果每个方案各自重新生成信道曲线之间的差异会被随机性淹没尤其是 OFDM 和 OTFS 性能接近时你会看到两条曲线交错到无法下结论。共用信道之后差异就只来自波形和 CP 配置本身。信噪比定义统一用符号信噪比 Es/N0因为 16QAM 是 4 比特/符号符号能量和比特能量之间差 4 倍这个换算关系在判读曲线时要记住。短 CP 方案节省了开销但这里先不折算信息速率差异等对比框架稳定后再按(nfft / (nfft cpLen))的速率比去修正 Eb/N0 也不迟。4.2 主循环代码同一套信道跑四个方案rng(1); % 固定随机种子保证可复现 nfft 64; N 8; cpShort 4; cpLong 16; pathDelays [0 3 6 10 15]; pathPowers [1 0.5 0.25 0.125 0.0625]; snrDb 0:3:24; numFrames 30; const qammod(0:15, 16, gray); const const / sqrt(mean(abs(const).^2)); % 16QAM 星座平均功率归一为 1 ber zeros(4, length(snrDb)); % 行OFDM, OTFS, C-OFDM, C-OTFS for s 1:length(snrDb) varNoise 10^(-snrDb(s) / 10); errCount zeros(4, 1); bitCount 0; for f 1:numFrames % 每帧生成一次信道四个方案共用 hImp gen_frame_channel(pathDelays, pathPowers); Hf fft(hImp, nfft).; Htf repmat(Hf, 1, N); % 扩展到 nfft×N 的 TF 网格 % 随机 16QAM 符号索引每个符号对应 4 bit symIdx randi([0 15], nfft, N); X const(symIdx 1); % ---- OFDM短 CP ---- tx tx_ofdm(X, nfft, cpShort); rx conv(tx, hImp); rx rx(1:numel(tx)); rx rx sqrt(varNoise/2) * (randn(size(rx)) 1j*randn(size(rx))); Xhat rx_ofdm(rx, nfft, cpShort, N); Xhat conj(Htf) .* Xhat ./ (abs(Htf).^2 varNoise); % MMSE 均衡 txBits qamdemod(X(:) * sqrt(10), 16, gray, OutputType, bit); rxBits qamdemod(Xhat(:) * sqrt(10), 16, gray, OutputType, bit); errCount(1) errCount(1) sum(rxBits ~ txBits); % ---- OTFS短 CP ---- tx tx_otfs(X, nfft, N, cpShort); rx conv(tx, hImp); rx rx(1:numel(tx)); rx rx sqrt(varNoise/2) * (randn(size(rx)) 1j*randn(size(rx))); Xhat rx_otfs(rx, nfft, N, cpShort, Htf, varNoise); rxBits qamdemod(Xhat(:) * sqrt(10), 16, gray, OutputType, bit); errCount(2) errCount(2) sum(rxBits ~ txBits); % ---- C-OFDM长 CP ---- tx tx_ofdm(X, nfft, cpLong); rx conv(tx, hImp); rx rx(1:numel(tx)); rx rx sqrt(varNoise/2) * (randn(size(rx)) 1j*randn(size(rx))); Xhat rx_ofdm(rx, nfft, cpLong, N); Xhat conj(Htf) .* Xhat ./ (abs(Htf).^2 varNoise); rxBits qamdemod(Xhat(:) * sqrt(10), 16, gray, OutputType, bit); errCount(3) errCount(3) sum(rxBits ~ txBits); % ---- C-OTFS长 CP ---- tx tx_otfs(X, nfft, N, cpLong); rx conv(tx, hImp); rx rx(1:numel(tx)); rx rx sqrt(varNoise/2) * (randn(size(rx)) 1j*randn(size(rx))); Xhat rx_otfs(rx, nfft, N, cpLong, Htf, varNoise); rxBits qamdemod(Xhat(:) * sqrt(10), 16, gray, OutputType, bit); errCount(4) errCount(4) sum(rxBits ~ txBits); bitCount bitCount numel(txBits); end ber(:, s) errCount / bitCount; end semilogy(snrDb, ber(1,:), o-, snrDb, ber(2,:), s-, ... snrDb, ber(3,:), ^-, snrDb, ber(4,:), d-); grid on; xlabel(Es/N0 (dB)); ylabel(BER); legend(OFDM, OTFS, C-OFDM, C-OTFS);这段代码的节奏是每帧先gen_frame_channel生成信道然后四个方案依次走发射、卷积、加噪、接收、均衡、比特比对。conv之后直接截断是因为 CP 已经吸收了多径扩展保留前numel(tx)个采样点即可。均衡用的是 MMSE 而不是 ZF分母里加了varNoise这样深衰落子载波上的噪声不会被无限放大。OFDM 与 OTFS 共用同一个Htf但 OTFS 的均衡发生在 TF 域均衡完才 SFFT 回 DD 域两者处理顺序不同这是 OTFS 和 OFDM 在代码层面最本质的区别。如果你发现代码跑得很慢优先检查是不是在循环里反复调用tx_ofdm导致频繁拼接矩阵。tx [tx; txSym]这种写法在符号数多时会越来越慢可以把预分配打开。本例帧规模和numFrames30的配置MATLAB 一般在十几秒内能跑完。4.3 曲线怎么读不要把结果解读成“OTFS 一定更好”跑完后的典型走势是这样的低信噪比段四条线几乎重合因为 AWGN 主导波形差异体现不出来中高信噪比段短 CP 的 OFDM 和 OTFS 出现明显的地板效应无论怎么增加信噪比误码率都不再下降长 CP 的 C-OFDM 和 C-OTFS 则继续向下走逼近 16QAM 在瑞利衰落下的理论曲线。这里最容易犯的解读错误是看到 OTFS 不比 OFDM 好就认为代码错了。在块衰落模型加 TF 域逐点均衡的条件下OTFS 和 OFDM 性能接近是正常的因为信道在帧内没有时变DD 域和 TF 域本质上是在描述同一个线性系统。OTFS 的真正优势要在高多普勒场景下才明显那时候 OFDM 的子载波正交性被多普勒破坏而 DD 域符号受多普勒扩展的影响是散布而非突变。如果你想要 OTFS 胜出的曲线需要把信道改成符号级时变再把 OTFS 接收机换成 DD 域 MMSE 或消息传递。5. 避坑清单误码率曲线对不上的五个常见原因5.1 四条曲线完全重叠看不出任何差异现象OFDM、OTFS、C-OFDM、C-OTFS 四条线几乎贴在一起只有细微抖动。原因每帧里四个方案各用各的信道或者随机噪声没有对齐。比如你在循环里调用了四次gen_frame_channel每次返回的hImp都不同曲线差异被随机性抹平。解决把hImp的生成挪到帧循环最前面四个方案共用同一个冲激响应。噪声也可以先randn一次存下来四个方案直接用同一份噪声向量这样 SNR 相同时唯一变量就是波形本身。5.2 高信噪比下短 CP 方案没有地板误码率持续下降现象cpShort和cpLong跑出来的曲线在高信噪比下基本重合没有出现预期中的误差地板。原因信道多径的最大时延其实小于cpShort。比如pathDelays最大值是 3而cpShort4CP 已经完全覆盖多径短 CP 方案并不“短”自然没有 ISI。解决让max(pathDelays)明显大于cpShort我常用[0 3 6 10 15]配合cpShort4。跑完打印一下max(pathDelays)和两个 CP 长度确认差距存在。另外卷积后截断位置错了也可能让长 CP 方案的性能看起来和短 CP 一样差检查接收信号是否从正确位置开始切帧。5.3 短 CP 方案误码率反而更低结论和理论相反现象CP 短的方案性能优于 CP 长的方案尤其在低信噪比段。原因CP 短意味着每帧开销小在固定总时长下能放更多有效数据。如果你按信息速率折算 Eb/N0短 CP 方案会有“省下的开销”带来的增益但更常见的原因是代码里把噪声方差按符号总功率扣了却没有扣 CP 部分等效于给短 CP 方案多送了能量。解决先把横轴统一为符号信噪比 Es/N0确保信号平均功率归一化为 1varNoise 10^(-snrDb/10)直接使用。等曲线形状稳定后再按nfft / (nfft cpLen)把短 CP 方案的开销增益折算进 Eb/N0这时候结论才会公平。5.4 OTFS 解调后星座整体旋转或者错位现象OFDM 曲线正常OTFS 误码率在无噪声时也不是 0星座图看起来像被转了一下或者行列顺序不对。原因ISFFT 和 SFFT 的 FFT 维度搞反了。fft沿时延轴还是沿多普勒轴决定了 DD 域矩阵的行列物理含义一旦反了收端符号矩阵相当于做了转置误码率自然崩。解决做无噪声回环自检。发送一个只有单个非零元素的 DD 域矩阵接收后看非零元素是否回到了原位。检查fft(Xdd, nfft, 1)和ifft(Xtf, N, 2)的维度参数以及接收端ifft(XtfEq, nfft, 1)、fft(XddHat, N, 2)的顺序。另外rx_ofdm返回的 TF 矩阵行是子载波列是符号这个约定和Htf的构造必须一致。5.5 曲线抖动剧烈加帧数也压不下来现象同一套代码多跑几次同一信噪比点的 BER 差别很大曲线锯齿明显。原因随机数种子没固定或者numFrames太少。误码率是统计量16QAM 在高信噪比下每帧可能只有几个比特错误帧数不够时统计涨落很大。还有一个隐蔽原因每个方案独立调用randn导致四个方案的噪声序列长度不同抽样的随机过程也不同步。解决脚本开头加rng(1)固定种子每个信噪比点增加帧数或者设置“累计错误比特数达到 100 就停止”的循环条件这样高信噪比下也能保证统计精度。更简单的做法是先把某几帧的误码情况打印出来人工看一下是不是集中在个别深衰落帧里。6. 结果验证比跑通更重要时延-多普勒观测与仿真提速四条曲线跑出来后先别急着下结论。我习惯做三件事来验证结果是否可信。第一无噪声回环自检。把主循环里的噪声去掉snrDb100近似无噪声发送一个稀疏 DD 域符号矩阵接收端把abs(XddHat)用imagesc画出来。如果非零元素的位置、行列数量和发送端一致说明 ISFFT/SFFT 链路方向正确如果出现了转置那你后面所有 OTFS 曲线都是无效的。这个检查花不了十秒钟却能避免最隐蔽的方向性错误。第二用同一帧信道多次加噪代替每帧重新生成信道。块衰落模型下误码率是信道样本和噪声样本的双重平均。如果你固定hImp不变只改变噪声就能单独观察噪声对误码的影响方差会小很多。做法是把numFrames拆成numChannels * numNoise外层循环生成信道内层循环加噪声。这样不仅曲线更平滑调试时也更容易定位问题是出在信道还是出在均衡器。第三把 16QAM 在瑞利衰落下的理论误码率曲线画进来当基准线。MATLAB 里用berawgn(..., qam, 16)只能给出 AWGN 基准瑞利衰落的理论 BER 是0.5 * (1 - sqrt(gamma/(1gamma)))再按比特修正。把理论线画上之后如果长 CP 方案的曲线还差理论线 3 dB 以上说明系统里有额外损耗要么是信道估计没做要么是均衡器把 MMSE 写成了 ZF。这一步能帮你判断“还能不能再优化”而不是停在“四条线出来了”就收工。我最早跑 OTFS 对比时犯过最蠢的错误就是只在 TF 域做均衡然后发现 OTFS 跟 OFDM 曲线完全重合一度以为是 ISFFT 写反了。后来把信道改成符号级时变OTFS 的优势才真正显现出来。这个过程让我养成了一个习惯对比仿真里永远先确认每条曲线的“理论极限”是什么再谈谁优谁劣。希望帮到你。本文还有配套的精品资源点击获取
返回列表