拓冰建站拓冰建站
首页 / 资讯中心 / 正文

IEEE 802.11a/g ERP-OFDM物理层链路级仿真:从原理到MATLAB实现

做 WLAN 物理层的同学应该都有过这种经历课本上 OFDM 的原理图画得干干净净从 IFFT 到加循环前缀每一步都有公式可真到了 MATLAB 里发端一个点没归一化收端整个星座图就开始旋转。你查半天发现不过是因为 IFFT 用了 1/64 而不是 1/sqrt(64)。这套 IEEE 802.11a/g ERP-OFDM 物理层链路级仿真教学/研究代码编号在 n24 到 n28 这一段的就是专门解决这类问题的。这套代码不是那种“能用就行”的黑盒工程包而是按教学和研究需求拆开的模块化链路发射端从加扰、卷积编码、交织、星座映射一直到 OFDM 调制和组帧接收端从同步、FFT、信道估计、均衡、译码一直到误码统计。n24 到 n28 正好覆盖整条物理层基带链路里最核心的收发闭环适合拿来理解 802.11a/g 信号格式、验证自己的接收机算法或者直接作为毕业设计和论文仿真的起点。1. 链路整体设计与参数选型思路1.1 802.11a/g 核心参数为什么这么定IEEE 802.11a 工作在 5GHz802.11g 的 ERP-OFDM 模式工作在 2.4GHz但两者的 OFDM 基带参数几乎完全一样。看到这套参数你就能明白为什么这个标准过了二十多年还在大规模商用它的设计非常务实。信道带宽 20MHzFFT 点数为 64子载波间隔 20MHz/64 312.5kHz。这个数值不是随便拍的它跟室内多径信道的相干带宽是匹配的。室内环境时延扩展通常在 50ns 到 300ns 之间对应的相干带宽大约在几百 kHz 到几 MHz 量级312.5kHz 的子载波间隔能保证每个子载波上的信道是平坦衰落的接收端只要做一次一阶均衡就能解出来。循环前缀 0.8μs对应 16 个采样点能容纳大概 240 米以内的多径时延差在室内场景里是够用的。有效子载波是 52 个其中有 48 个数据子载波和 4 个导频子载波。为什么空掉边缘子载波和直流子载波边缘子载波是为了留出频谱滚降的过渡带直流子载波是避免收发本振泄漏直接落在信号正中间干扰数据。这些都是工程上非常实际的考量。1.2 ERP-OFDM 与 802.11a 的差别没有想象中大很多人以为 802.11g 的 ERP-OFDM 和 802.11a 差别很大实际上 OFDM 符号级别几乎一样区别主要在两个方面。第一是工作频段802.11g 在 2.4GHz所以物理层仿真时信道模型要偏向 2.4GHz 的室内传播特性但基带算法部分一套代码两边通用。第二是协议层面的兼容性要求802.11g 需要向下兼容 802.11b 的 DSSS/CCK 设备所以在实际帧格式里有保护机制和混合前导的概念。不过做链路级基带仿真这些协议层的处理通常可以放到 MAC 层去考虑物理层我们更关心的是 STF、LTF、SIGNAL、DATA 这四个部分的构成和信号处理流程。还有一点要注意ERP-OFDM 引入了可选短保护间隔Short GI选项把 0.8μs 的循环前缀缩短到 0.4μs能提升约 10% 的吞吐量。在教学代码里我建议先把标准 0.8μs 跑通再扩展短 GI不然定时偏差一上来短 GI 的符号间干扰会非常难排查。1.3 收发链路的整体信号流发射端数据流的顺序是二进制数据比特 → 加扰 → 卷积编码 → 删余打孔如果需要 2/3 或 3/4 码率→ 块交织 → 星座映射 → 插入导频和空子载波 → 64 点 IFFT → 加循环前缀 → 组帧STF LTF SIGNAL DATA→ 加窗前导发送。接收端是反过来的接收采样信号 → 粗定时和频率同步 → 去循环前缀 → FFT → 提取有效子载波 → 信道估计与均衡 → 导频相位跟踪 → 软/硬解映射 → 去交织 → 删除插入恢复 → Viterbi 译码 → 解扰 → 输出比特流。整个链路里最容易出问题的点是各模块的接口参数尤其是每个模块之间传递的到底是频域数据还是时域数据、是码片级数据还是比特级数据这个必须在代码注释里写得清楚否则调试起来会非常痛苦。2. n24 到 n28 代码模块的核心逻辑拆解2.1 n24PLCP 前导与帧结构生成n24 这一段代码负责的是物理层帧的前导生成。802.11a/g 的 PLCP 前导包含短训练序列STF和长训练序列LTF两部分加起来 16μs。STF 由 10 个重复的短符号组成总时长 8μs。每个短符号只有 12 个非零子载波分布在每隔 4 个子载波的位置。这种稀疏结构让时域波形呈现严格的周期性周期是 0.8μs、16 个采样点。收端利用这种周期重复特性做自相关就能完成自动增益控制AGC和粗频率偏移估计。这就是为什么 STF 的子载波一定要留空一半以上重复周期越短频率捕获范围越大这是给粗同步用的。LTF 由 1 个 1.6μs 的循环前缀加两个 3.2μs 的长训练符号组成总时长 8μs。长训练序列在全部 52 个有效子载波上都有值接收端拿本地已知的 LTF 频域序列和接收到的 LTF 做除法就能得到每个子载波上的信道响应估计。n24 模块里除了生成 STF 和 LTF还要把 SIGNAL 域组好。SIGNAL 域承载速率和长度信息只用 BPSK 1/2 卷积编码确保所有设备都能解出来。教学仿真里可以简化 SIGNAL 域的处理只传速率和长度两个量但帧结构里必须把它的位置留出来。2.2 n25OFDM 调制解调与子载波映射n25 是整条链路的“数据管道”核心做的事情就是把频域的星座符号变成时域波形再从时域波形还原回频域符号。发射端映射规则是 64 个子载波中索引 -26 到 -22、-20 到 -8、-6 到 -1、1 到 6、8 到 20、22 到 26 这 48 个位置放数据符号索引 -21、-7、7、21 这 4 个位置放导频符号索引 0 的位置置零其余边缘子载波全部填零。在 MATLAB 里把 64 个频域值排好直接 ifft 就行。这里关键的坑在于 IFFT 归一化。MATLAB 的 ifft 默认除以 Nfft 不除如果你发射端用 ifft 之后不乘 sqrt(N)接收端 fft 之后也不除以 sqrt(N)星座图的模值就不对。我建议在参数文件里统一定义一个 norm_factor 1/sqrt(64)发射端 ifft 后乘 norm_factor接收端 fft 后乘 norm_factor这样收发端能量是守恒的而且和理论分析里常用的归一化方式一致。星座映射的归一化同样重要。BPSK 用 ±1QPSK 用 (±1±j)/sqrt(2)16QAM 用 (1j)、(-13j) 等除以 sqrt(10)64QAM 除以 sqrt(42)。这些归一化因子保证各种调制阶数下的平均符号能量都是 1否则对比不同速率下的 BER 曲线时信噪比口径会对不上。2.3 n26信道估计与均衡n26 模块是接收端算法最集中的地方主要包括信道估计、均衡和导频相位跟踪。先用两个 LTF 符号的频域接收值取平均再点除本地已知 LTF 序列得到每个有效子载波上的信道估计 H_est。如果只做 AWGN 仿真H_est 基本接近 1但一旦上了多径信道H_est 会是一个随频率变化的复数响应必须逐子载波均衡。均衡最简单的是迫零ZF均衡X_eq X_rx * conj(H) / |H|^2。这个方案在噪声比较小的时候效果挺好但信道深度衰落时会把噪声放大。更稳一点是 MMSE 均衡X_eq X_rx * conj(H) / (|H|^2 sigma2)其中 sigma2 是噪声方差和信号功率的比值。教学代码里两个都实现一遍对比一下曲线能直观看到在高阶调制下 MMSE 的增益。导频相位跟踪很多人会漏掉。实际系统中收发本振不是理想锁定的每个 OFDM 符号都会有一个公共相位误差CPE。好在 4 个导频子载波一直在那里而且收发双方都知道导频的取值所以每解出一个数据符号就用 4 个导频的相位误差平均一下把整个符号的星座点旋转回去。不少教材把这个步骤省略掉但工程代码里必须有。2.4 n27定时同步与频偏估计n27 处理的是接收机前端最脏最累的活找到信号从哪里开始把频偏掰回来。定时同步一般分粗同步和细同步。粗同步利用 STF 的周期自相关特性在滑动窗口里计算 r(n) 和 r(n16) 的相关值相关峰会出现一个平台平台起始点大致就是 STF 的开始。细同步用 LTF 和本地参考做互相关找到峰值精确锁定 FFT 窗口起点。这个两级方案的好处是计算量小且鲁棒低信噪比下也不会崩。频偏估计用的原理是自相关相位。短训练序列的周期是 16 个采样点相邻短符号之间的相位差是 2πΔf * 16/fs所以用粗同步位置处的自相关值求幅角就能估算出频偏。注意捕获范围用 STF 估频偏Δf 的范围是 ±fs/(2*16)也就是 ±0.625MHz捕获范围很宽但精度一般用 LTF 估频偏周期是 64 个采样点捕获范围收窄到 ±156.25kHz但精度高。所以标准做法是粗同步用 STF 估一次补偿完再用 LTF 估一次细频偏。n27 里必须把两步都写出来只做一步的话大频偏场景下链路是跑不起来的。2.5 n28完整链路集成与误码率统计n28 是把前面所有模块装起来的仿真工作台。它做的事情是外层循环扫描 SNR内层循环做蒙特卡洛仿真每个 SNR 点统计误码率和误包率最后画出 BER/PER 曲线。我在这个模块里习惯加一个参数控制继续运行的条件统计到至少 100 个误码才停止当前 SNR 点这样测出来的 BER 曲线尾部不会因为样本太少抖动太大。对于 10 的负 4 次方量级的误码率至少要跑几百个包这个计算量和精度之间要有个取舍。n28 还可以扩展出两个有用的功能一个是和理论曲线对比另一个是不同算法之间的对比。理论曲线可以用无编码的 BPSK 误码率 Q(sqrt(2*Eb/N0)) 做参考也可以用 MATLAB 自带的 berawgn 和 berfading 函数。对比的目的是验证链路实现的正确性而不是追求完全重合。3. 实操环节从参数文件到跑通整套仿真3.1 仿真环境与代码组织建议这套代码是基于 MATLAB 实现的R2018b 以上版本都能跑不需要额外的通信工具箱也可以因为核心的加扰、卷积编码、交织、IFFT 这些操作都可以用基础函数完成。如果用了 comm.Scrambler、convenc、vitdec那就需要 Communications Toolbox。教学场景里我建议自己手动实现加扰和交织部分这部分代码量不大但能极大加深对标准的理解。工程代码的目录结构我是这样组织的wlan_sim/ 00_params.m 全局参数设置 10_tx_data.m 发射端比特级处理加扰、编码、交织、映射 20_tx_ofdm.m OFDM 调制与组帧 30_channel.m 信道模型AWGN、多径 40_rx_sync.m 同步 50_rx_ofdm.m OFDM 解调 60_rx_est.m 信道估计与均衡 70_rx_data.m 解映射、去交织、维特比译码 90_run_ber.m 主仿真脚本对应到 n24 到 n28 这套编号n24 对应前导生成相关函数n25 对应 20_tx_ofdm 和 50_rx_ofdmn26 对应 60_rx_estn27 对应 40_rx_syncn28 对应 90_run_ber。当然每个人手里的代码编号方式不一定一样但核心的数据流是相同的。3.2 关键参数表与仿真脚本全局参数文件里我会放这么一张表参数数值说明fs20MHz采样率Nfft64FFT 点数Ncp16循环前缀采样点数Nsd48数据子载波数Nsp4导频子载波数Nst52有效子载波数preamble_len320STFLTF 总采样点数16μsrate_code1/2、2/3、3/4卷积编码码率mod_order1、2、4、6BPSK、QPSK、16QAM、64QAM主仿真脚本的核心循环大概是这个结构for snr_idx 1:length(snr_list) snr_db snr_list(snr_idx); total_bits 0; total_errors 0; while total_errors min_errors total_bits max_bits tx_bits randi([0 1], 1000, 1); tx_signal wlan_tx_packet(tx_bits, params); rx_signal channel_sim(tx_signal, snr_db, params); rx_bits wlan_rx_packet(rx_signal, params); [n_error, n_bit] biterr(tx_bits, rx_bits); total_errors total_errors n_error; total_bits total_bits n_bit; end ber(snr_idx) total_errors / total_bits; endwlan_tx_packet 是发射端入口函数内部调用 n24、n25 对应的模块wlan_rx_packet 是接收端入口函数内部调用 n26、n27 对应的模块。把接口设计成输入比特、输出比特这样主脚本非常干净调试的时候也可以逐级断点检查中间信号。3.3 SNR 与 Eb/N0 的换算口径这个坑值得单独拿出来说一遍。很多同学把仿真里设置的 SNR 直接当成 Eb/N0 画曲线结果曲线整体偏了好几个 dB根本对不上理论值然后开始怀疑自己的链路写错了。问题出在 OFDM 的开销上64 个子载波里只有 48 个传数据还有循环前缀、前导、编码冗余。仿真里常用的做法是对时域发射信号直接加特定功率的噪声此时 SNR 可以理解为时域信号功率和噪声功率之比。要换算成 Eb/N0必须把一个 OFDM 符号承载的实际信息比特数算清楚。每个 OFDM 符号的信息比特数是 48数据子载波数乘以每个子载波的比特数乘以编码码率。比如 64QAM、码率 3/4每个符号携带 48×6×0.75 216 个信息比特。而每个 OFDM 符号的时域长度是 80 个采样点6416对应 4μs。所以一个符号的时域采样点总能量和实际信息比特数之间的关系决定了 Eb/N0 和 SNR 之间的换算系数。每个 SNR 点想精确互换建议在代码里写一个换算函数先通过满功率信号测量接收信号平均能量再按噪声功率谱密度推导。工程经验是先在无编码 QPSK 下把 BER 曲线和理论值对齐确认换算系数无误后再切换到高阶调制和编码模式。4. 调试实录与常见问题排查4.1 星座图不收敛或者整体旋转这是最常见的问题。现象是接收端解调出来的星座点形状对了但整体有固定角度偏移或者随 OFDM 符号序号逐渐旋转。固定角度偏移一般是信道估计没对准或者频偏没完全补偿逐步旋转几乎可以肯定是导频相位跟踪没做。我的排查顺序是第一步打印接收端 FFT 窗口提取是否正确第二步看导频相位差是否随符号序号线性变化第三步检查频偏估计算法里用到的延迟周期 D 和采样率 fs 是否匹配。曾经有个学生把粗频偏估计的公式写成了 angle(R) / (2piD) * fs结果量纲错了频偏补偿之后反而把信号推到边缘星座图散成一片。正确的量纲是 Δf angle(R) * fs / (2piD)D 是相关延迟的采样点数不是符号数。4.2 BER 曲线出现“地板效应”误码率降到一定程度后不再往下掉形成一个平台。这种情况十有八九是存在不可消除的系统误差源最常见的是残余频偏或者定时偏差。残余频偏会导致星座图在符号间旋转即使导频能估计出公共相位误差但如果频偏过大符号内相位变化也会导致星座点扭曲。排查方法是把仿真里的频偏设为 0看曲线是否恢复。如果设 0 之后曲线正常说明频偏估计算法有偏差如果还是平台那就要怀疑循环前缀长度和信道时延扩展是否匹配。另一个隐蔽原因是信道估计用的 LTF 位置和实际 FFT 窗口起点错了一个采样点导致估计出的信道相位是错的并且这个错误对每个符号都一样。这种误差在接收端完全无法通过均衡消除BER 就会卡在一个下界。4.3 高阶调制完全解不出来64QAM 对幅度和相位的精度要求远高于 BPSK如果接收链路在高阶调制下星座图糊成一团首先检查星座映射归一化是否用对了因子其次检查均衡后星座点的幅度是否整体缩放。我在调试 64QAM 时习惯先做无信道编码、无同步偏差的理想测试发射信号经过纯 AWGN 信道接收端理想已知起始点直接解调。如果这种情况下 64QAM 在 SNR 25dB 附近能压到 1e-3 误码率说明链路基本正常。然后再逐步加入编码、定时同步、频偏估计每一步都验证一次定位问题的边界。4.4 常用调试技巧速查表问题现象可能原因排查手段星座点整体偏转信道估计相位误差使用导频相位校正对比校正前后星座图星座点呈同心圆状幅度归一化错误检查 QAM 归一化因子误码率曲线不降频偏或定时偏差关闭频偏/定时模块测试Viterbi 译码后比特全错交织/去交织索引不匹配编码后不调制直接逆交织验证多径信道下噪声地板高均衡算法放大噪声改用 MMSE 均衡检查信道抽头能量归一化BER 曲线整体偏 2-3dBSNR 和 Eb/N0 换算系数错误用 BPSK 无编码理论曲线校验还有一个小技巧在每个模块出口打印信号的能量或者星座图看起来像多此一举但能极大加速问题定位。比如发射端 IFFT 之前和之后的信号能量应该基本一致如果按归一化设计接收端 FFT 之前的功率和 FFT 之后的功率也有确定的比例关系。一旦能量关系不对前面模块一定有问题。5. 后续扩展与个人实操心得这套代码跑通 BER 曲线之后往下面扩展的方向非常多。一个是加真实的频率偏移和采样时钟偏移模型看接收机同步算法的鲁棒性另一个是替换成更接近实际的多径信道模型比如带指数功率延时谱的 5 抽头信道对比不同均衡和信道估计算法的表现。如果做研究还可以在导频位置优化和信道估计插值算法上做文章。我个人在实际调试过程中的体会是链路级仿真最忌讳的就是一上来追求“一步到位全链路跑通”。先把无编码 BPSK 在 AWGN 下跑通再逐步加 QPSK、16QAM、64QAM然后加卷积编码和交织最后才加多径信道和同步算法。每一步都保留对应的实验曲线和关键中间变量截图后面出了问题往回查会非常高效。n24 到 n28 这套代码的价值恰恰就体现在这种“可拆解、可验证、可回归”的结构上它不只是一个能出图的黑盒子而是一个能帮你各种“折腾”的实验台。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门