简介:5GLLSimulator_v1.1 是一款面向通信工程研究人员、高校师生及5G算法开发者的链路级仿真平台,聚焦物理层与数据链路层关键过程的建模与验证,可用于分析信号传播、编解码、多用户调度、波束赋形与功率控制等性能指标。资源包共76个文件,以60个m脚本为核心,辅以4个cpp源码、4个mexw64编译组件、3个mat数据文件及5个pdf文档,压缩包约7.76MB,涵盖信道建模、调制解调、MIMO处理、信道编码与场景配置等模块,并附用户手册与功能说明。目前已有2295人学习下载。读者可借助预定义场景快速复现标准链路性能,也可通过自定义参数搭建城市、农村或室内等传播环境,结合参考曲线与结果绘图脚本完成吞吐量、误码率等对比分析,适合作为教学演示、算法验证与系统设计优化的实践工具。
1. 链路级仿真到底在算什么:从一条误块率曲线说起
做无线算法的人迟早会撞上一件事:链路预算表算得再漂亮,到了外场还是掉链子。原因不复杂,链路预算只告诉你「信号够不够强」,但真正决定业务能不能跑起来的,是「在这个信噪比下,误块率到底是多少」。5G链路级仿真平台要回答的就是这个问题——它把物理层从调制编码、层映射、预编码到信道估计、解调译码的整条链路在软件里搭出来,逐帧跑,最后给你一条 BLER 对 SNR 的曲线。有了这条曲线,链路自适应选什么 MCS、HARQ 重传几次能收敛、不同信道模型下性能差多少,才有据可依。
5GLLSimulator 这类平台的价值在于把「链路级」这件事做完整:不是只算个香农限,也不是只跑个理想 AWGN,而是把 TDL/CDL 信道、相位噪声、定时偏差这些非理想因素都塞进去。适合谁用?做物理层算法验证的、做系统级仿真需要链路抽象模型的、以及想搞明白 5G NR 物理层各模块怎么串起来的人。下面按「先跑通最小闭环,再逐个模块抠参数,最后避坑」的顺序讲。
2. 把 5GLLSimulator 跑起来:环境、目录与最小闭环
2.1 先看清平台在仿真链路里的位置
链路级仿真夹在链路预算和系统级仿真中间。链路预算给你一个粗略的 SNR 估计,系统级仿真需要知道「给定 SNR 和 MCS,误块率是多少」才能做调度和资源分配,而这个映射关系就是链路级仿真产出的。5GLLSimulator 的定位就是产出这张映射表,或者更直接地说,产出 BLER-SNR 曲线。
它的内部结构通常分四层:波形与参数配置层( numerology、带宽、子载波间隔)、发射机层(CRC、LDPC 编码、调制、层映射、预编码、OFDM 调制)、信道层(TDL/CDL、AWGN、多普勒)、接收机层(同步、信道估计、均衡、解调、LDPC 译码)。每一层都有可配参数,跑一次仿真就是把这四层串起来循环。
常见做法是先用理想信道跑通,确认发射接收链路自洽,再逐步加非理想因素。我一般会先跑一个 SISO、QPSK、1/3 码率、AWGN 的最小配置,看 BLER 在 0dB 附近是不是从 1 掉到 0.1 左右,如果曲线形状不对,说明链路里有模块没对齐。
2.2 环境依赖与目录结构
平台一般依赖 MATLAB 或 Python 科学计算栈。以 Python 为例,核心依赖是 numpy、scipy、matplotlib,如果带 GPU 加速可能还要 cupy。建议用虚拟环境隔离,避免和系统里的老版本 numpy 打架。
# 创建独立环境,Python 3.9 以上 python -m venv venv_5gll source venv_5gll/bin/activate # Windows 用 venv_5gll\Scripts\activate # 安装核心依赖,版本按平台 requirements 来,不要盲目追新 pip install numpy==1.24 scipy==1.10 matplotlib==3.7目录结构通常长这样,先认准几个关键文件再动手:
5GLLSimulator/ ├── config/ # 仿真配置文件,numerology、信道、MCS 都在这里 │ ├── default.yaml │ └── tdl_cdl_profiles.yaml ├── src/ │ ├── transmitter/ # 编码、调制、层映射、预编码 │ ├── channel/ # TDL/CDL、AWGN、相位噪声 │ ├── receiver/ # 同步、估计、均衡、译码 │ └── metrics/ # BLER、吞吐量、EVM 统计 ├── run_sim.py # 主入口 └── results/ # 曲线和日志输出config/default.yaml是你要改的第一个文件。里面通常有numerology、bandwidth、mcs_table、channel_model、snr_range这几段。不要一上来就改代码,先把配置读明白。
2.3 跑通第一个 BLER 曲线
最小闭环就是固定 MCS、扫 SNR、统计 BLER。下面是一个典型的调用方式,不同平台函数名可能不同,但参数含义一致。
# run_minimal_bler.py from src.simulator import LinkSimulator from src.config import load_config # 加载配置,指定用默认 numerology 和 AWGN 信道 cfg = load_config("config/default.yaml") cfg.numerology = 1 # 30 kHz SCS cfg.bandwidth_mhz = 20 cfg.mcs = 4 # QPSK, 约 1/3 码率 cfg.channel_model = "AWGN" cfg.snr_db = list(range(-2, 8, 1)) # -2 到 7 dB,步长 1 cfg.num_frames = 2000 # 每个 SNR 点跑 2000 帧,保证统计量 sim = LinkSimulator(cfg) results = sim.run() # 返回每个 SNR 点的 BLER 和吞吐量 for snr, bler in zip(cfg.snr_db, results.bler): print(f"SNR={snr:>3} dB BLER={bler:.4f}")逻辑说明:LinkSimulator内部对每个 SNR 点循环num_frames次,每次生成随机传输块、过发射机、过信道、过接收机,最后比对 CRC 是否通过。BLER 就是失败帧数除以总帧数。
参数说明:num_frames是关键。BLER 在 0.1 量级时,2000 帧的统计误差大约在 1% 左右,够用;如果要看 1e-3 量级的瀑布区,至少得 1e5 帧,否则曲线尾部全是噪声。snr_db的步长建议 1dB,太密浪费算力,太疏看不出拐点。mcs要跟mcs_table对应,填错会直接报索引越界。
跑完你会得到一条从 1 降到 0.01 的曲线,拐点位置和理论值差 1dB 以内就算链路自洽。差太多,先查信道估计和均衡,这两个模块最容易出问题。
3. 抠参数:numerology、信道模型与 MCS 怎么配才不翻车
3.1 numerology 和带宽的联动关系
5G NR 的 numerology 由子载波间隔定义,μ=0 是 15kHz,μ=1 是 30kHz,μ=2 是 60kHz。子载波间隔变了,每帧的时隙数、每时隙的符号数、CP 长度全跟着变。5GLLSimulator 里通常用numerology一个参数控制这一串。
配置时最容易翻车的地方是带宽和 numerology 不匹配。比如 20MHz 带宽配 μ=2(60kHz),可用 RB 数会变得很少,因为保护带占比变大。常见做法是查平台自带的bandwidth_rb_map,或者直接看配置注释。
# config/default.yaml 片段 numerology: 1 # 30 kHz SCS bandwidth_mhz: 20 # 对应可用 RB 数由平台内部查表,不要手填 # μ=1, 20MHz -> 51 RB,这是协议定义的参数说明:numerology影响的不只是符号长度,还影响相位噪声敏感度。μ 越大,子载波间隔越宽,对相位噪声越不敏感,但 CP 开销越大。做 FR1 场景一般用 μ=0 或 1,FR2 用 μ=2 或 3。仿真时如果发现高频段性能异常好,先确认相位噪声模型有没有打开。
3.2 TDL 和 CDL 信道模型的选择
TDL(抽头延迟线)和 CDL(簇延迟线)是 3GPP 定义的两类信道模型。TDL 用于 SISO 和简单的 MIMO 场景,CDL 用于带空间相关性的 MIMO 场景。5GLLSimulator 的tdl_cdl_profiles.yaml里通常预置了 TDL-A/B/C 和 CDL-A/B/C/E。
选哪个?看你的场景。TDL-A 是非视距、低时延扩展,适合室内;TDL-C 时延扩展大,适合室外宏站。CDL 则要配合天线配置用,CDL-A 是视距主导,CDL-B 是非视距。
# 切换信道模型 cfg.channel_model = "TDL-C" cfg.delay_spread_ns = 300 # 时延扩展,TDL-C 典型值 cfg.doppler_hz = 5 # 多普勒频移,对应低速移动 cfg.tx_ant = 1 cfg.rx_ant = 1逻辑说明:平台会根据channel_model加载对应的抽头功率和时延,再根据doppler_hz生成时变信道。delay_spread_ns要和模型匹配,TDL-C 填 30ns 就失去意义了。
参数说明:doppler_hz决定信道变化快慢。5Hz 对应大约 3km/h(2.6GHz 载波),高速场景要调到几百 Hz。多普勒一高,信道估计的插值间隔就得加密,否则性能断崖式下跌。这是新手最容易忽略的参数。
3.3 MCS 表和 SNR 范围的匹配
MCS 表决定了每个 MCS 索引对应的调制阶数和码率。5GLLSimulator 一般支持 QPSK、16QAM、64QAM、256QAM 四档调制。配置 MCS 时要注意:低 SNR 用高阶调制等于自杀,高 SNR 用低阶调制浪费频谱效率。
# 扫 MCS 找拐点 for mcs in [2, 4, 7, 10, 13, 16]: cfg.mcs = mcs cfg.snr_db = list(range(-5, 25, 1)) cfg.num_frames = 5000 res = LinkSimulator(cfg).run() # 记录 BLER=0.1 对应的 SNR,就是该 MCS 的工作点逻辑说明:每个 MCS 都有自己的 BLER 曲线,拐点 SNR 不同。把各 MCS 的 0.1 BLER 点连起来,就是链路自适应的工作曲线。
参数说明:num_frames在扫 MCS 时要加大,因为高阶 MCS 的瀑布区更陡,统计量不够会看到曲线抖动。我一般用 5000 帧起步,看 1e-2 量级够用。如果要看 1e-3,得上 5e4 帧,算力不够就上 GPU 或者减少 SNR 点数。
4. 避坑与排查:链路级仿真里最容易翻车的五件事
4.1 BLER 曲线尾部不收敛,全是毛刺
现象:高 SNR 段 BLER 本该掉到 1e-3 以下,但曲线在 1e-2 附近来回跳。
原因:统计量不足。BLER 是二项分布,方差和帧数成反比。1e-3 的 BLER 用 1000 帧去测,期望只有 1 个错误帧,方差比均值还大。
解决:按目标 BLER 倒推帧数。经验公式是num_frames >= 100 / target_bler。要看 1e-3,至少 1e5 帧。算力不够就只跑关键 SNR 点,不要全扫。
4.2 信道估计性能比理论差一大截
现象:加了 TDL-C 信道后,BLER 比 AWGN 差 5dB 以上,远超预期。
原因:信道估计的插值间隔没跟着多普勒调。平台默认可能是每 4 个符号插一次,多普勒一高,信道在插值间隔内已经变了,估计值过期。
解决:查channel_estimation配置里的interp_interval,多普勒大于 50Hz 时改成 2 或 1。代价是参考信号开销变大,吞吐量会降,这是必要 trade-off。
4.3 LDPC 译码迭代次数不够,误码平台下不去
现象:BLER 曲线在 1e-2 附近出现平台,再加大 SNR 也不降。
原因:LDPC 译码迭代次数设太小,比如默认 10 次,高码率下收敛不了。
解决:把ldpc_max_iter调到 25 或 50。注意迭代次数翻倍,译码耗时也翻倍。如果平台支持 early termination,打开它,大部分帧几次迭代就收敛了,平均耗时不会涨太多。
4.4 相位噪声模型没开,FR2 场景性能虚高
现象:60kHz SCS、28GHz 载波下,256QAM 的 BLER 曲线好得不真实。
原因:相位噪声模型默认关闭。FR2 的相位噪声是主要损伤,不开的话等于在理想条件下仿真。
解决:在配置里打开phase_noise,设置pn_model和pn_level。常见做法是查 3GPP 的相位噪声模型,按载波频率和 SCS 填参数。开了之后 256QAM 的性能会明显下降,这才是真实情况。
4.5 多线程跑仿真结果不可复现
现象:同样的配置跑两次,BLER 差 10% 以上。
原因:随机数种子没固定,或者多线程下各线程的随机流互相干扰。
解决:在配置里设random_seed,并且确保每个 SNR 点的随机流独立。如果平台用多进程,给每个进程分配不同的种子段。我一般会在结果目录里存一份配置快照,方便回溯。
5. 进阶:用链路抽象模型把仿真结果喂给系统级
链路级仿真的产出如果只是几张曲线图,价值就浪费了。真正有用的是把 BLER-SNR 映射做成链路抽象模型,供系统级仿真调用。常见做法是拟合一个 S 型函数,或者直接查表加插值。
# 把 BLER 曲线拟合成可查询的映射 import numpy as np from scipy.interpolate import interp1d # 假设已有 snr_list 和 bler_list snr_arr = np.array(snr_list) bler_arr = np.array(bler_list) # 对数域插值,避免尾部失真 log_bler = np.log10(np.maximum(bler_arr, 1e-5)) f = interp1d(snr_arr, log_bler, kind='linear', fill_value='extrapolate') def get_bler(snr, mcs): # 实际使用时按 mcs 索引到对应的插值函数 return 10 ** float(f(snr))逻辑说明:对数域插值比线性域更稳,因为 BLER 跨越几个数量级。fill_value='extrapolate'让超出范围的点也能返回估计值,但外推不可靠,系统级仿真里要限制查询范围。
参数说明:1e-5是下限,防止 log 报错。如果平台支持,最好存原始 BLER 和帧数,系统级仿真可以按置信区间加权。
一个更工程化的做法是生成 AWGN 和 TDL 两套映射表,系统级仿真根据用户信道条件切换。TDL 的曲线比 AWGN 差 2-4dB,具体差值取决于时延扩展和多普勒。这个差值就是链路抽象模型里的「信道补偿因子」,调准了系统级仿真才可信。
我自己的习惯是每换一次 numerology 或信道模型,就重新跑一遍映射表,绝不复用旧数据。链路级仿真没有后悔药,配置变了结果就变了,老老实实重跑最省心。希望帮到你。
本文还有配套的精品资源,点击获取