
简介这是一套基于MATLAB的无线通信系统仿真工程面向通信专业学生、研究人员及物理层算法工程师解决OFDM与OTFS在宽带多径衰落信道下的性能对比问题。压缩包共9个文件全部为m格式脚本整体大小11KB模块划分清晰主程序调度整体流程数据生成、多径信道建模、均衡器、收发端调制解调以及SFFT/ISFFT变换各自独立绘图脚本用于输出结果曲线便于二次开发信道模型覆盖瑞利、莱斯等典型衰落环境同时考虑多径时延与多普勒频移支持调整移动速度、子载波数、信噪比等参数各函数接口清晰参数集中在主程序顶部方便快速切换场景。运行仿真可直接获得误码率、符号误码率等指标直观比较两技术在高速移动场景下的差异体现OTFS的潜力。该工程目前已有468人学习可作为课题研究或论文验证的实用基线平台。1. 为什么要把OFDM和OTFS放在同一个多径衰落仿真里比很多人在评估6G候选波形时都想知道OTFS在时变多径信道里到底能不能比OFDM明显更抗衰落。答案不能靠论文里的理想曲线拍脑袋要自己搭一个公平的仿真框架同一个宽带无线通信系统参数、同一组信道抽头、同样的调制阶数和SNR定义把OFDM和OTFS两条收发链路各跑一遍用误码率曲线的交点说话。这套仿真做下来你会清楚地看到OFDM在低多普勒下依然可靠而OTFS的增益只在信道快速时变时才会兑现。适合刚接手物理层仿真的工程师、做波形对比的毕业生以及准备为立项报告补数据的预研人员。有了这个框架你可以把信道从静态一直扫到几百赫兹多普勒量化两者的真实差距。2. OFDM与OTFS的数学模型从时频域到时延-多普勒域的坐标迁移2.1 OFDM链路子载波间隔、循环前缀和频域均衡OFDM的核心思想是把高速串行数据拆成N路低速并行子流分别调制到N个正交子载波上。发射端先做QAM符号映射得到长度N的频域符号向量s再做IFFT得到时域信号x。为了对抗多径时延扩展在符号前面插入循环前缀也就是把IFFT输出的末尾一段复制到开头。接收端丢弃循环前缀后做FFT还原出频域符号。这套流程能work的前提是循环前缀长度要大于信道最大时延。只要这个条件满足原来的线性卷积就变成循环卷积信道矩阵在频域被对角化频域均衡退化为逐子载波除法。设信道频域响应为H_k接收频域符号为y_k那么估计值就是ŝ_k y_k / H_k。复杂度低、实现稳定这是OFDM统治4G和5G的原因。但OFDM有两个天生的短板。第一个是多径时延超过CP时符号间干扰直接进入FFT窗口频域均衡再怎么做也没用。第二个是子载波间干扰多普勒频移会破坏子载波之间的正交性造成能量泄漏到相邻子载波上。工程上有一个常用经验子载波间隔至少要大于最大多普勒频移的5到10倍否则ICI会明显抬高误码率地板。带宽20MHz配1024点FFT时Δf大约是19.5kHz支撑500Hz多普勒绰绰有余但如果你的系统带宽只有5MHz、FFT还是1024那么Δf就只有4.9kHz高铁场景下ICI就开始主导性能了。2.2 OTFS链路ISFFT如何把快变信道变慢变稀疏OTFS换了一个坐标系统来放置信息符号。它不把符号放在时频域而是放在时延-多普勒域上。这个域的横轴是时延τ纵轴是多普勒频移ν也就是信道在“哪条路径、多大频偏”这个维度上展开。物理直觉是时变多径信道在时频域看起来变化剧烈但在时延-多普勒域里是离散的、稀疏的而且在一帧时间内几乎不随时间变化。OTFS等于把信道从“快变黑匣子”变成了“稀疏静态图”接收机可以借用稀疏信号处理做检测。具体实现分两步。发射端把DD域的M×N符号矩阵先做逆辛傅里叶变换ISFFT映射成时频域的M×N网格再做海森堡变换本质上就是按列IFFT加循环前缀变成时域波形发出去。接收端顺序反过来时域去CP后做维格纳变换也就是按列FFT回到时频域再做辛傅里叶变换SFFT回到DD域然后做信道均衡和符号判决。这里最容易被绕晕的是ISFFT和SFFT的方向定义。不同文献里这两个变换的符号方向、归一化因子都有差异但有一个原则是死的你的发射端选了哪个约定接收端就必须严格用它的逆否则星座图不会收敛。我一般会把发射和接收的变换写在一对函数里保证互逆性测试通过再继续做别的。2.3 复现最小功能两种调制/解调的核心代码与参数先把OFDM调制的最简实现写出来。这个函数把频域QAM符号矩阵按列IFFT然后加CP是后面所有链路的地基。function tx ofdm_mod(symbols, params) % OFDM调制串并变换 IFFT 加循环前缀 % symbols: 频域QAM符号流长度 nfft * nsym % params.nfft: FFT点数 % params.ncp: 循环前缀采样点数 sym_mat reshape(symbols, params.nfft, []); ifft_out ifft(sym_mat, params.nfft, 1); % 沿子载波维IFFT tx [ifft_out(end-params.ncp1:end, :); ifft_out]; % 复制末尾到开头 tx tx(:); end逻辑说明sym_mat的每一列是一个OFDM符号按列做IFFT之后把每列的尾部ncp个采样复制到列首再按列展开为时域串行流。要注意这个函数默认QAM符号平均功率为1如果你的映射函数没有做归一化后续SNR定义会全部错位。OTFS调制器的核心是ISFFT它把DD域符号搬到时频域然后交给OFDM调制器处理。function tx otfs_mod(dd_sym, params) % OTFS调制ISFFT从时延-多普勒域映射到时频域再交给ofdm_mod % dd_sym: DD域符号矩阵维度 [params.m x params.n] % 常见约定先沿多普勒维做FFT再沿时延维做IFFT tf_grid ifft(fft(dd_sym, params.n, 2), params.m, 1) * sqrt(params.m * params.n); % tf_grid按列展开后就是OFDM调制器的频域输入 tx ofdm_mod(tf_grid(:), params); end参数说明m是时延维点数通常等于子载波数n是多普勒维点数对应一帧内的OTFS符号数。ISFFT的缩放因子sqrt(m*n)是为了保持变换前后的能量一致。如果你的帧结构是m256、n16那么一帧承载4096个QAM符号等价于16个OFDM符号周期。多普勒维点数要满足n大于等于2倍的最大归一化多普勒频移否则信道能量会泄漏到相邻多普勒格点上OTFS的性能优势直接被这个设计缺陷吃掉。对应接收端OFDM解调就是去CP加FFTOTFS解调则在FFT之后再补一次SFFT方向和发射端完全逆着来。这里不展开写完整函数了但验证方法很简单把调制输出直接接解调输入不加噪声和信道星座图应该和发送符号完全重合误差在浮点精度内。3. 多径衰落信道建模TDL抽头、时延扩展和多普勒谱怎么设3.1 TDL信道参数PDP、最大时延和抽头数怎么定多径衰落信道仿真几乎绕不开抽头延迟线模型。这个模型把物理环境中无数条反射路径近似为L个主要路径每条路径有独立的时延差、平均功率和多普勒谱。标准里的3GPP TDL-A、TDL-B、TDL-C以及ITU的城区模型都直接提供了这些参数表你的仿真可以先抄标准参数再按自己的场景改。我一般会关注三个量抽头数L、每径时延τ_l、每径平均功率P_l。抽头数的选择是个工程权衡5到10径足够刻画城区环境的主要衰落特征。标准表里有些30径的模型那是为了匹配实测信道的时间色散细节但落到你的链路仿真里每径都要在时域卷积一次帧长又长30径只会拖慢迭代速度并不显著改变误码率的相对关系。时延扩展的取值是最容易拍脑袋的地方。城区环境rms时延扩展一般在100ns到1us之间你的采样率20MHz对应采样周期50ns那么最大时延300ns只占6个采样点。PDP的形状常见是指数衰减也就是越晚到达的路径功率越小。设计PDP时务必做总功率归一化让所有路径功率加起来等于1这一步如果漏了整个仿真的SNR定义就没有意义了。抽头时延量化也要小心。标准参数表里的时延往往是纳秒级的精确值而你的采样周期是50ns直接取整会产生量化误差。常见做法是四舍五入到最近采样点或者用sinc插值把信道冲激响应重采样到整数时延网格。初版仿真优先用四舍五入因为分数时延的多了sinc插值那一步调试成本翻倍收益很小。3.2 时变信道模拟Jakes谱、多普勒频移与快照更新静态信道只跑通链路逻辑没有用多径衰落仿真的灵魂在于时变。最大多普勒频移fd由移动速度和载频决定公式是fd v × fc / c。车速120km/h、载频2GHz时fd约222Hz。这个值决定了信道在时间维上的变化快慢也决定了OFDM和OTFS的性能分水岭在哪里。经典的多普勒谱是Jakes谱对应各向同性散射环境下接收信号的功率谱呈现U型分布。仿真里生成满足Jakes谱的路径系数最实用方法是用正弦叠加每条路径用一组不同频率的正弦波叠加各个分量的频偏按fd×cos(2πk/n_osc)分布相位随机。分量数n_osc取8到16足够逼近理想谱取太少频谱会带纹波取太多只是增加计算量曲线几乎看不出差别。另一个工程决策是信道系数多长时间更新一次。最简单的做法是分块恒定也就是一个OFDM符号内信道不变符号间跳变。这个模型实现简单、跑得快但高多普勒下符号内的相位旋转被忽略结果会偏乐观。我一般的习惯是先分块恒定把整条链路跑通再改成按采样点更新对比两次结果的差距如果差距小于0.5dB说明你的场景还没到需要担心符号内时变的地步。3.3 信道系数生成一个可复现的MATLAB函数把上面的考虑收拢进一个函数里方便后面两条链路共用同一组信道系数。function [h, path_delays] gen_tdl_channel(npaths, rms_ds, fd, fs, nsamples) % 生成TDL多径信道系数PDP指数衰减时变特性按Jakes谱近似 % 输入 % npaths: 抽头数推荐5~10 % rms_ds: 均方根时延扩展单位秒 % fd: 最大多普勒频移单位Hz % fs: 采样率单位Hz % nsamples: 信道系数在时间维上的采样点数 % 输出 % h: npaths x nsamples 的复信道系数矩阵 % path_delays: 每条路径的时延单位采样点 % 时延按整数采样点量化路径间隔由rms_ds决定 path_delays (0:npaths-1) * round(rms_ds * fs * 2 / npaths); % 指数功率时延谱并做总功率归一化 pdp exp(-(0:npaths-1) * 2 / npaths); pdp pdp / sum(pdp); t (0:nsamples-1) / fs; h zeros(npaths, nsamples); rng(20240601); % 固定种子保证不同链路之间可比 n_osc 16; % 每径用16个正弦分量近似Jakes谱 for p 1:npaths coeff sqrt(pdp(p)); for k 1:n_osc fd_k fd * cos(2*pi*k/n_osc); % 频率分量按余弦分布 phase 2*pi*rand; % 每个分量随机相位 h(p,:) h(p,:) coeff * exp(1j*2*pi*fd_k*t 1j*phase); end end h h / sqrt(n_osc); % 除以sqrt(n_osc)保持总功率为pdp(p) end逻辑说明这段代码把时延量化成整数采样点PDP按指数衰减并归一化每径用16个正弦分量叠加出Jakes谱特性。使用时直接按path_delays索引做时域卷积或延迟叠加即可。这个函数的输出只做了一重归一化真正接入SNR定义时还要确保发射信号功率和噪声功率都以相同基准对齐这个坑在第5章会专门讲。如果你要模拟分数时延比如路径时延不是采样周期的整数倍需要在生成h之前对路径时延做sinc插值重采样。这个技术能精确刻画宽带系统中的时间色散但初版仿真不需要。先跑通整数时延版本再根据结果的收敛情况决定要不要升级。4. 搭一套完整的仿真链路从发射机到误码率曲线的可执行骨架4.1 仿真参数表先把带宽、FFT和帧结构定死仿真参数最忌讳自相矛盾。带宽、采样率、FFT点数、CP长度、子载波间隔和帧时长这些量是互相锁死的改一个就得连带检查其他几个。我通常开工前先把参数表填好落成表格贴在代码注释里。参数取值说明系统带宽BW20 MHz直接决定采样率采样率fs20 MHz等于带宽不做过采样FFT点数N1024全子载波使用不预留保护边带子载波间隔Δf19.53 kHz等于fs/NCP长度Ncp128约6.4us覆盖200ns时延扩展余量充足调制阶数16QAM后续可换64QAM观察高阶调制差距OFDM符号数/帧14一个时隙的长度便于对标5G帧结构最大多普勒fd0到500 Hz覆盖静止到300km/h范围蒙特卡洛帧数100到500每SNR点的统计帧数参数自洽性检查有两个不等式要过。第一个是CP长度乘以采样周期要大于信道最大时延第二个是子载波间隔要远大于最大多普勒频移。如果两个条件不能同时满足说明你的系统在带宽、速度和抗时延能力之间做了折中这个折中本身可能就是你做这个仿真想展示的结论之一但你要意识到它而不是让仿真在参数矛盾下跑出莫名其妙的曲线。4.2 发射机与接收机主循环OFDM与OTFS同框架实现主循环的关键在于让两条链路共用同一组信道系数。如果OFDM和OTFS各生成一套信道信道的随机性会掩盖调制方式的真实差距得到看似在波动实则没有统计意义的图。下面的骨架先建信道再分别跑两条链路最后汇总误码率。%% OFDM与OTFS对比仿真主脚本 clear; clc; params.bw 20e6; params.fs 20e6; params.nfft 1024; params.ncp 128; params.mcs 16; % 16QAM params.nsym 14; % 每帧OFDM符号数 params.fd 100; % 多普勒频移先从中低速开始 % 生成信道两条链路共用同一实现保证对比公平 npaths 6; rms_ds 100e-9; % 100ns rms时延扩展 nsamples params.nsym * (params.nfft params.ncp); [h, path_delays] gen_tdl_channel(npaths, rms_ds, params.fd, params.fs, nsamples); snr_db 0:2:20; ber_ofdm zeros(size(snr_db)); ber_otfs zeros(size(snr_db)); for s 1:length(snr_db) ber_ofdm(s) sim_ofdm_link(h, path_delays, snr_db(s), params); ber_otfs(s) sim_otfs_link(h, path_delays, snr_db(s), params); end % 画图 semilogy(snr_db, ber_ofdm, o-, snr_db, ber_otfs, s-); legend(OFDM,OTFS); xlabel(Eb/N0 (dB)); ylabel(BER); grid on;逻辑说明信道在循环外生成一次两个链路接收端拿到的都是同一组时变系数这样对比的只有调制方案本身。跑通这条主脚本后再扩展多个SNR点的并行计算也不难MATLAB的parfor可以直接套在这个for循环外面。OFDM链路接收机用一个简化版本重点展示去CP、FFT和频域均衡三个动作。function ber sim_ofdm_link(h, path_delays, snr_db, params) % OFDM链路QAM映射 - 调制 - 过信道 - 去CP/FFT/均衡 - 判决 nfft params.nfft; ncp params.ncp; nsym params.nsym; bits randi([0 1], nfft * nsym * log2(params.mcs), 1); symbols qammod(bits, params.mcs, InputType, bit); tx ofdm_mod(symbols, params); % 过信道每径延迟加权叠加长度对齐发射信号 rx zeros(size(tx)); for p 1:size(h,1) d path_delays(p); delayed circshift(tx, d); % 初版用循环移位近似正式仿真换成线性卷积 rx rx h(p, 1:length(tx)). .* delayed; end % 加高斯白噪声 rx awgn(rx, snr_db, measured); % 接收端去CP、FFT、理想频域均衡 rx_mat reshape(rx, nfft ncp, []); rx_mat rx_mat(ncp1:end, :); rx_fd fft(rx_mat, nfft, 1); % 理想信道均衡取信道第一径的频域响应做除法 h_fd fft(h(1, 1:nfft), nfft).; eq rx_fd ./ h_fd; rx_bits qamdemod(eq(:), params.mcs, OutputType, bit); ber mean(rx_bits ~ bits); end逻辑说明这里的circshift只是初版近似它在多径时延较大时会把符号尾部卷到前面产生非物理的混叠正式仿真应该改成延迟加零再叠加。h_fd用第一径做频域均衡也是简化实际中应该对完整CIR补零到nfft长度取FFT或者用LS信道估计从导频恢复。这两个简化不影响两条链路的相对比较但绝对误码率会和理论有些偏差。OTFS接收机则需要在去CP和FFT之后再逆变换回时延-多普勒域均衡。function ber sim_otfs_link(h, path_delays, snr_db, params) % OTFS链路DD域符号 - ISFFT - OFDM调制 - 信道 - 逆变换 - 判决 m params.nfft; n params.nsym; bits randi([0 1], m * n * log2(params.mcs), 1); dd_sym qammod(bits, params.mcs, InputType, bit); dd_sym reshape(dd_sym, m, n); tx otfs_mod(dd_sym, params); % 过信道这里和OFDM用同一个信道 rx zeros(size(tx)); for p 1:size(h,1) d path_delays(p); delayed circshift(tx, d); rx rx h(p, 1:length(tx)). .* delayed; end rx awgn(rx, snr_db, measured); % 接收端去CP、FFT回到时频域再SFFT回DD域 rx_mat reshape(rx, m params.ncp, []); rx_mat rx_mat(params.ncp1:end, :); tf_grid fft(rx_mat, m, 1); % SFFT方向与发射的ISFFT严格互逆 dd_grid ifft(fft(tf_grid, n, 2), m, 1) / sqrt(m * n); % 理想DD域均衡这里直接除以1径频响的近似正式用MMSE dd_eq dd_grid ./ mean(abs(dd_grid(:))); rx_bits qamdemod(dd_eq(:), params.mcs, OutputType, bit); ber mean(rx_bits ~ bits); end逻辑说明SFFT的乘法因子要和发射端的sqrt(m*n)匹配方向上用过转置之后先FFT多普勒维再IFFT时延维。DD域均衡这里用了最简单的平均幅度归一化性能上远不是最优但能验证链路是否连通。正式做OTFS检测需要实现消息传递或MMSE均衡这部分复杂度高很多放到后续优化。4.3 跑通最小闭环先单帧验证再扫SNR扫SNR曲线之前先固定一个SNR20dB跑单帧画接收星座图。OFDM的星座图应该能看到清晰的16个簇没有明显旋转或扩散OTFS的星座图同样要能分辨出16簇点。如果星座图是一团模糊先别急着调参数回去查收发变换是否互逆。单帧BER如果在0.1以下说明链路基本通了BER在0.5附近等于随机猜查代码比调信道参数更优先。单帧验证通过后再扫SNR。扫SNR时每次只改信噪比随机种子、信道实现都不变这样曲线是单调平滑的。如果曲线毛刺很多多半是信道随机种子没有固定或者帧数太少统计不够。每SNR点至少跑100帧BER才能稳定到可以下结论的程度。5. OFDM/OTFS仿真避坑五个让我翻过车的具体问题5.1 CP不够长误码率平台下不去的真凶现象SNR从0dB升到20dB误码率曲线下降一段后卡在某个平台再也不动。星座图上外层QAM点开始旋转散开。原因信道最大时延超过了循环前缀长度前一个符号的尾部串进当前符号的FFT窗口频域均衡完全失效。这个现象在宽带系统里尤其隐蔽因为时延扩展换算成采样点之后可能只有几个点容易被忽略。解决仿真前先打印path_delays的最大值换算成采样周期检查是否小于ncp。设计时保守一点让ncp至少是最大时延的2到4倍。如果最大时延本身接近OFDM符号长度说明这个场景根本不适合OFDM这时看OTFS反而能体现优势。5.2 信道没归一化OFDM和OTFS同差3dB现象两条BER曲线的相对走势正常但绝对位置整体偏向右侧无论怎么调SNR都对不上理论值。换抽头数之后整条曲线跟着漂移。原因信道PDP没有归一到总功率16径模型的总能量等于6相当于所有信号被放大了而噪声功率按接收信号功率比例添加SNR定义就全乱了。这是仿真里最玄学的一类问题因为曲线的形状看起来完全正常差点误判是均衡器的问题。解决在gen_tdl_channel里给pdp除以sum(pdp)给每径系数除以sqrt(n_osc)。然后在主脚本里用sum(abs(h(1,:)).^2)检查信道平均功率是否为1。这个归一化动作花五分钟做好能省掉后面一整天的排错时间。信道归一化是这类对比仿真里最容易翻车但最不值得翻车的地方。5.3 OTFS网格没对齐高多普勒下比OFDM还差现象fd超过300Hz后OTFS误码率反而高于OFDM和论文结论完全相反。原因DD域网格尺寸没有覆盖多普勒扩展。OTFS的多普勒分辨率等于1/帧时长如果多普勒维点数n太小或者帧时长太短fd对应的频率分量就会泄漏到相邻多普勒格点上干扰反而被放大。解决算一下fd_max乘以帧时长这个值必须小于n/2。比如fd500Hz、帧时长0.7ms乘积为0.35n至少取32才能留出余量。还要检查ISFFT的变换方向是否是论文定义的约定方向错了高多普勒下同样会恶化。先在小网格下验证逻辑再放大网格跑正式曲线。5.4 时变信道快照跳变曲线毛刺的来源现象BER曲线不光滑同一组SNR点重跑两次结果差异明显图看起来像锯齿。原因信道系数在符号边界直接跳变没有连续性或者每次蒙特卡洛迭代重新生成随机种子帧与帧之间信道统计不一致。理论上分块恒定模型在低多普勒下误差不大但高多普勒下跳变产生的额外频移会被接收机误判为多普勒扩散。解决固定主脚本的随机种子让信道生成可复现。如果要做多次统计平均则在每帧开始前用不同种子但要记录种子编号方便追溯。如果毛刺仍然存在就在符号间做线性插值或者缩短信道更新间隔。仿真发散这类问题大多和随机种子管理有关先查这个再查算法。5.5 仿真复杂度失控蒙特卡洛次数和检测迭代要收敛现象OTFS链路跑一次SNR扫描耗时几个小时甚至过夜换参数之后又要重跑。原因OTFS接收机的MP迭代检测在每一帧内要迭代20到30次每个SNR点再叠加几百帧复杂度直接爆炸。OFDM只做一次FFT加均衡自然快两者的时间差距很容易让人误以为OTFS工程上不可用。解决先用小网格如m128、n8验证逻辑再放大到256×16。每个SNR点先跑100帧看趋势确认无误再增加到300到500帧。MP迭代次数可以尝试10次和20次的差距如果性能不变就取10。框架跑通之后再考虑用parfor并行或者把信道预生成缓存下来避免每次重复计算信道系数。6. 想验证仿真没跑偏先用AWGN基准再上多径动手加多径之前先把信道替换成纯AWGN让OFDM和OTFS各跑一条曲线和16QAM的理论误码率叠加在一起画。理论曲线用经典公式就能算不用引入任何额外工具。实测曲线和理论差在0.5dB以内说明调制解调、功率归一化和SNR定义都没问题这时候再引入多径信道才有意义。如果AWGN下都对不上那多径结果也没法信先回去查代码。AWGN基准过了之后把信道从fd0逐步增加到50、100、300、500Hz每次只看相对性能。OFDM的BER会随fd升高逐渐抬升OTFS的曲线在高fd下应该比OFDM更平缓。注意一个容易被误读的现象fd很低时OTFS并不会比OFDM有明显的优势有时还会因为网格开销略差一点增益要等fd超过某个门限才出现。你在介绍里看到“OTFS全面碾压OFDM”的说法时先看一眼仿真条件里的多普勒频移和帧长大于号小于号一换结论就变。蒙特卡洛帧数也要讲策略。BER到10^-2量级100帧平均已经够稳想看到10^-4至少要1000帧以上。不要全部SNR点都跑5000帧那是极大的浪费。我做过一次最蠢的决定所有点平均跑满了5000帧结果过了一夜曲线和500帧的几乎重合。从那之后我的习惯是先单SNR点多帧跑出稳定性曲线找到帧数和BER波动的关系再决定整批次扫描用多少帧。仿真这种活时间要花在验证假设而不是反复跑同一张图上。希望帮到你。本文还有配套的精品资源点击获取