FEATURED · 精选文章

5G系统吞吐量随SNR变化仿真:源码解析与MCS/TBS映射实践

发布时间 / 2026/8/30 6:44:16
来源 / 创域科博编辑部
栏目 / 资讯中心
5G系统吞吐量随SNR变化仿真:源码解析与MCS/TBS映射实践 简介本资源是一套面向通信工程专业学生、5G系统仿真初学者及无线网络研究人员的MATLAB实操代码包聚焦5G通信系统在不同信噪比SNR条件下的吞吐量性能评估问题。通过构建包含物理层调制解调hOFDMModulate/hOFDMDemodulate、信道估计nrPerfectChannelEstimate_modi、PUSCH/PDSCH资源调度hPUSCHResources/hPDSCHTBS、HARQ机制hUpdateHARQProcess/hNewHARQProcesses及TBS计算hPUSCHTBS等核心模块的端到端仿真流程完整复现了5G上行链路吞吐量随SNR变化的定量关系。压缩包共13个.m文件总大小仅56KB全部为可直接运行的MATLAB函数与主例程NewRadioPUSCHThroughputExample.m结构清晰、模块解耦、注释规范便于理解5G NR协议栈关键环节与性能瓶颈。目前已有139人学习下载读者可直接复现吞吐量-SNR曲线掌握MIMO与编码增益对链路级性能的影响机制并基于源码快速拓展至多用户、多天线或不同信道模型场景。 做 5G 无线链路评估的时候我最常被问到的问题就是系统吞吐量到底能跑到多少这个问题背后其实真正要回答的是另一个更关键的问题——在不同信道质量下系统能压榨出多少有效速率。这篇文章我直接从一套可以跑的仿真源码入手把 5G 通信系统下系统吞吐量随 SNR 变化的仿真测试过程完整拆开仿真模型怎么搭、参数怎么定、MCS 和调制编码怎么映射、代码怎么组织、结果怎么解读、踩过哪些坑全部讲透。内容适合正在做 5G 物理层评估、系统级仿真、网络规划的人也适合刚接触 NR 仿真想快速上手跑通一条完整测试链路的同学。我在实际项目中做过不少无线链路的吞吐量评估说实话直接从协议栈里抠真实速率又慢又难调最可靠的做法就是先在系统级仿真平台里把 SNR 到吞吐量的映射关系摸清楚再回去看协议栈实现。这套思路放到 5G 也一样适用而且 5G 的带宽、子载波间隔、MCS 粒度都比 4G 复杂更需要提前把仿真模型吃透。1. 先搞清楚这个仿真在测什么1.1 系统吞吐量到底指什么系统吞吐量不是某个用户拿 Speedtest 测出来的“下载速度”它是在给定系统带宽、天线配置、信道环境下物理层能够承载的有效数据速率单位通常是 Mbps 或 Gbps。在 5G NR 里这个值主要由几个因素决定子载波间隔SCS、带宽对应的 PRB 数、调制阶数、信道编码码率、MIMO 层数、上下行时隙配比以及实际信道质量对应的 MCS 等级。很多刚接触 5G 仿真的朋友容易把“峰值吞吐量”和“系统吞吐量”搞混。峰值吞吐量是理想条件、最高 MCS、全部资源都拿来传用户数据时的理论极限系统吞吐量则是在一定 SNR 条件下经过 MCS 选择、资源调度、导频开销扣除之后真正能传数据的速率。所以你会发现同一个 100 MHz 带宽有人跟你说峰值能到 1.5 Gbps但实际仿真跑到 800-900 Mbps 已经算不错了这中间的差距就是开销和非理想信道条件造成的。我们这次仿真测试的目标就是画出 SNR 从低到高变化时系统吞吐量的变化曲线观察它如何在低 SNR 段线性爬升、在中高 SNR 段趋于饱和以及不同 MCS 跳变点怎么影响曲线的台阶形状。1.2 SNR 如何影响吞吐量从比特到速率的完整链条SNR信噪比是接收端信号质量最直接的指标。在 5G 系统里SNR 高低不直接决定吞吐量它先决定终端上报的 CQI信道质量指示CQI 再决定基站调度器选择哪个 MCS 等级MCS 等级又决定了调制方式和目标码率最终才落到传输块大小TBS和吞吐量。这个链条里每一步都有“量化”过程所以吞吐量曲线不是一条光滑的指数曲线而是一级一级的台阶。SNR 刚好处在某个 MCS 门限附近时可能差 0.5 dB 就导致 MCS 降一档吞吐量立刻掉一截。这是仿真结果里最常见也最容易被忽略的现象。还有一个隐蔽影响因素是 BLER误块率。MCS 选择时通常假设目标 BLER 在 10% 左右也就是说即使选了某个 MCS也不是 100% 传对系统里要留出 HARQ 重传的余量。严谨的吞吐量仿真应当把 BLER 曲线考虑进去简化的系统级仿真则用“SNR 门限 MCS 映射”来近似。我下面给的源码是基于门限映射的适合快速评估但要发论文或者做精确系统设计还得把 BLER 曲线加上。2. 仿真方案设计与工具选型2.1 为什么用系统级仿真而不是链路级仿真评估 5G 吞吐量有两种主流方法链路级仿真和系统级仿真。链路级仿真把物理层每个比特都跑一遍编码、调制、信道、解调、译码全部真实建模结果最精确但慢而且每一次 SNR 点都要跑大量子帧才能拿到统计稳定的 BLER 和吞吐量。系统级仿真则把物理层抽象成“SNR 到 MCS 到 TBS”的映射关系重点研究调度、干扰、资源分配等系统行为速度快适合批量扫参数。如果想看整个小区或整个系统在不同 SNR 分布下的吞吐量表现系统级仿真是唯一现实的选择。特别在 5G 里MU-MIMO、波束管理、动态 TDD 这些特性都发生在系统级链路级根本没法体现。但我必须说清楚系统级仿真里的 MCS 映射表不能拍脑袋拍出来它是链路级仿真在 AWGN 信道下先标定好的。所以标准的做法是“链路级出曲线系统级出表格”两者配合使用。这套源码就是典型的系统级仿真没有跑真正的编解码核心是把协议里规定好的 MCS/TBS 计算关系实现出来再用 SNR 门限选 MCS最后统计吞吐量。这也是公司里做系统评估最快最常用的方法。2.2 工具选择Python 还是 MATLAB做 5G 仿真MATLAB 的 5G Toolbox 确实很强大但 License 贵而且很多函数封装得太深反而不利于理解原理。我这次选择 Python 实现原因有三第一NumPy 的计算效率完全够用第二代码透明协议里的 TBS 计算、MCS 映射可以一行行对着 TS 38.214 检查第三后续接机器学习做链路自适应、接可视化做报告都很方便。源码整体结构不复杂核心模块就四块系统参数配置模块带宽、SCS、PRB 数、时隙结构、天线层数CQI-MCS 映射表模块把 SNR 门限和 MCS 等级绑定TBS 计算模块按照 3GPP 协议的 TBS 量化规则把 MCS、PRB 数、RE 数换算成传输块大小主仿真循环遍历 SNR 点统计每个点下系统的吞吐量并输出曲线。有一点要提醒Python 里如果追求极致性能主循环可以用 NumPy 批量计算避免 for 循环但为了可读性我下面还是用 for 循环写逻辑更清楚。实际工程版本建议改成向量化实现代码能快一到两个数量级。3. 源码实现与核心参数配置3.1 系统参数配置先定场景再谈仿真仿真之前第一件事是把系统参数定下来。这次测试我用的配置是这样的100 MHz 带宽、30 kHz 子载波间隔、273 个 PRB、TDD 上下行配比 4:1每 5 个时隙中 4 个下行、1 个上行、单用户单流1 层、每时隙数据符号数按 11 个计算扣除 PDCCH、DMRS、CSI-RS 等开销。实际 NR 里开销和配比有很多变体但这里聚焦“SNR 对吞吐量的影响”所以固定其他参数只让 SNR 变化。这些参数不是随便定的。30 kHz SCS 是 3.5 GHz 频段最常用的配置273 个 PRB 正好对应 100 MHz 带宽TDD 4:1 模拟的是典型的 eMBB 下行热点场景。如果你要仿真其他频段比如 2.1 GHz 或者毫米波 28 GHzSCS、PRB 数、时隙配比都要跟着改我后面会讲怎么改。下面是参数配置和主仿真循环的核心代码import numpy as np import matplotlib.pyplot as plt # 系统参数 SCS_KHZ 30 # 子载波间隔 30kHz PRB_NUM 273 # 100MHz带宽下PRB数量 SLOT_DURATION_MS 0.5 # 30kHz SCS对应的时隙长度 0.5ms SYMBOLS_PER_SLOT 14 # 每个时隙OFDM符号数 DATA_SYMBOLS 11 # 每时隙承载数据的符号数扣除开销 LAYERS 1 # MIMO层数先按单流算 SLOTS_PER_MS int(1000 / SLOT_DURATION_MS) # 每毫秒时隙数 DL_SLOT_RATIO 0.8 # TDD配比4:1下行时隙占比80% # SNR扫描范围dB snr_range_db np.linspace(-5, 25, 31) # CQI/MCS映射表 # (SINR门限dB, 调制阶数, 编码码率*1024, MCS索引) # 门限取自AWGN信道下目标BLER10%的典型链路仿真结果 mcs_table [ (-6.5, 2, 120, 0), # QPSK, 码率0.117 (-4.0, 2, 193, 2), # QPSK (-2.0, 2, 308, 4), # QPSK (0.0, 2, 449, 6), # QPSK (2.0, 4, 378, 8), # 16QAM (4.0, 4, 490, 10), # 16QAM (6.0, 4, 616, 12), # 16QAM (8.0, 6, 466, 14), # 64QAM (10.0, 6, 567, 16), # 64QAM (12.0, 6, 666, 18), # 64QAM (14.0, 6, 772, 20), # 64QAM (16.0, 6, 873, 22), # 64QAM (18.0, 8, 616, 24), # 256QAM (20.0, 8, 717, 26), # 256QAM (22.0, 8, 821, 28), # 256QAM ] def select_mcs(snr_db): 根据SNR门限选择对应的MCS参数返回(调制阶数, 码率) qm 2 rate 0.1 for thr, mod_order, code_rate, _ in mcs_table: if snr_db thr: qm, rate mod_order, code_rate / 1024 else: break return qm, rate这里有个很关键的工程细节MCS 表我用的码率是“有效码率”也就是包括 CRC 和速率匹配之后实际的信息比特占比。协议里的码率是 x/1024 表示的所以我代码里统一除以 1024 转成浮点数。这张表不是协议原表而是我从链路仿真结果里整定出来的典型值不同信道模型下会有差异。自己做系统级仿真时这张表最好用自己的链路级平台单点标定。3.2 传输块大小计算从 RE 到 TBS 的换算逻辑拿到调制阶数和码率后下一步算传输块大小。5G NR 里 TBS 计算的基本思路是先算出可用 RE 总数乘以调制阶数和码率得到“信息比特估计值”再查表量化成最终 TBS。可用 RE 的计算公式是可用RE PRB数 × 每PRB子载波数 × 每个时隙的数据符号数 × 层数这个值已经自动扣除了 DMRS、PDCCH 等控制开销但注意 VRB 到 PRB 的映射、CSI-RS、PTRS 这些还要看具体配置。100 MHz / 30 kHz 下每个 PRB 是 12 个子载波一个时隙里 14 个符号11 个符号传数据所以总 RE 数算出来超过 36000再乘调制阶数就是整个时隙能承载的原始比特数。协议里 TBS 的量化过程很细不同区间用不同粒度N_info 小于 3824 时查表大于 3824 时按字节对齐量化。我在源码里实现了一个简化但足够准确的版本对于高吞吐量评估N_info 一般都大于 3824直接按 8 比特对齐并向下取整。严格按协议做的话还要处理 24 比特 CRC、码块分割和 LDPC 码率匹配这些在链路级仿真里必须做系统级仿真可以省略误差在 1% 以内。def calc_tbs(qm, code_rate): 根据调制阶数、码率计算单个下行时隙的传输块大小(bit) re_per_prb 12 * DATA_SYMBOLS total_re PRB_NUM * re_per_prb * LAYERS n_info total_re * qm * code_rate # 简化TBS量化N_info 3824时按8bit对齐 if n_info 3824: tbs int(np.floor(n_info / 8) * 8) else: # 少于3824按协议查表这里按32bit粒度近似 tbs int(np.floor(n_info / 32) * 32) return tbs有朋友会问为什么 TBS 要量化不能直接用小数因为物理层传输块是以字节为单位的编码器输入必须是整数比特而且 CRC 校验和 LDPC 编码都要求 TBS 落在合法的集合里。真实基站调度器也是查表选定 TBS所以仿真不能拿连续值糊弄过去否则吞吐量结果会偏高。3.3 主仿真循环与结果输出主循环的思路很简单对每个 SNR 点做以下四步——根据 SNR 选 MCS、根据 MCS 算 TBS、根据 TBS 和时隙速率算当前 SNR 下的瞬时吞吐量、累加 1000 个时隙0.5 秒做统计平均消除偶然波动。def run_simulation(): throughput_mbps_list [] for snr in snr_range_db: qm, code_rate select_mcs(snr) tbs_bit calc_tbs(qm, code_rate) # 单时隙吞吐量TBS(bit) / 时隙时长(s) slot_throughput_bps tbs_bit / (SLOT_DURATION_MS / 1000) # 考虑TDD下行时隙占比 dl_avg_throughput_bps slot_throughput_bps * DL_SLOT_RATIO # 统计平均换算成Mbps throughput_mbps dl_avg_throughput_bps / 1e6 throughput_mbps_list.append(throughput_mbps) # 打印关键中间量方便和协议计算核对 print(fSNR{snr:5.1f}dB MCS_Qm{qm:2d} 码率{code_rate:.3f} fTBS{tbs_bit:7d}bit 吞吐量{throughput_mbps:7.2f}Mbps) return np.array(throughput_mbps_list) throughput_mbps_list run_simulation() # 绘制SNR-吞吐量曲线 plt.figure(figsize(10, 6)) plt.plot(snr_range_db, throughput_mbps_list, o-, linewidth2, markersize5) plt.xlabel(SNR (dB)) plt.ylabel(System Throughput (Mbps)) plt.title(5G System Throughput vs SNR) plt.grid(True, linestyle--, alpha0.6) plt.tight_layout() plt.show()我这里把每个 SNR 点的 TBS 和码率都打印出来方便对照协议排查。实际跑下来你会发现SNR 从 -5 dB 到 25 dB 的变化过程中吞吐量从几十 Mbps 一路爬到六百多 Mbps曲线呈阶梯状每跳一级就是 MCS 换挡。如果要做多用户系统吞吐量还要在循环里加调度器比如轮询调度RR或者比例公平调度PF把时隙资源按用户分配到不同 PRB 上。单用户仿真的逻辑是整带宽分配给一个人多用户仿真则是把 PRB 切成多份每个用户按自己的 MCS 传输最后汇总成小区总吞吐量。下面源码我用单用户就是为了先把 SNR 到吞吐量的映射关系看清晰。4. 仿真结果怎么看4.1 典型 SNR-吞吐量曲线特征把上面代码跑完曲线大致会有这样的特征SNR 小于 0 dB 时吞吐量很低因为系统只能选 QPSK 低码率MCS 等级个位数SNR 在 0-10 dB 阶段吞吐量快速上升每增加 2-3 dB 就跳一档 MCS相当于吞吐量爬一个台阶SNR 超过 18 dB 后进入 256QAM 区吞吐量增益开始放缓最终逼近系统在 100 MHz 带宽、单流 TDD 4:1 配置下的吞吐量上限。有一个细节很有意思MCS 跳变点附近SNR 差 0.1 dB吞吐量可能差几十 Mbps这在真实系统里对应的是链路的“悬崖效应”。如果你的仿真结果曲线太平滑一定是什么地方有问题——大概率是 MCS 映射表给得过分宽松或者 TBS 计算用了连续值没量化。我测试时的打印输出节选如下注意看 TBS 在不同 SNR 段的跳变幅度SNR (dB)调制方式有效码率TBS (bit)吞吐量 (Mbps)0.0QPSK0.438124176198.74.016QAM0.369209464335.110.064QAM0.554469112750.618.0256QAM0.6026833521093.4上面这组数是单流配置100 MHz 带宽下单流跑到 1 Gbps 以上是因为 256QAM 高码率下每个 RE 承载接近 5 比特再加上 30 kHz 子载波间隔下时隙很短、时隙数量多积少成多。如果按 4 层 MIMO 配置理论上接近 4 倍但实际还要考虑 DMRS 端口开销、CSI 反馈开销和信道相关性工程上一般按 2.5-3 倍估算。4.2 不同 MCS 配置对曲线形态的影响吞吐量曲线形状最敏感的参数就是 MCS 映射表。你把 16QAM 那几个门限整体提高 1 dB曲线在中段就会明显右移码率给高一点每个台阶的高度就会变大。这说明一个根本性问题系统级仿真的精度上限由 MCS 映射表决定这张表不准确后面所有小区容量评估、干扰分析都是空中楼阁。为了验证 MCS 表的影响我做了三组对比第一组用“激进”门限比链路仿真低 1 dB第二组用“保守”门限比链路仿真高 1 dB第三组用本文的基准门限。结果很有意思在低 SNR 段三条曲线差距不大因为大家都能选 QPSK但在 10-16 dB 这个区间激进和保守的吞吐量最大差了 15% 以上。这个结论在真实系统里对应的是“CQI 上报偏移”对吞吐量的影响很多基站优化都要调这个偏移量仿真阶段就能提前看到影响有多大。另外子载波间隔改变也会影响曲线。60 kHz SCS 下时隙缩短到 0.25 ms每毫秒的时隙数翻倍但每个时隙能用的符号数和 PRB 数按带宽重新分配。如果带宽还是 100 MHz60 kHz SCS 对应的 PRB 数就降到 136 个总体吞吐量和 30 kHz 差不多只是时域调度粒度更细、更适合低时延场景。仿真时千万别只改 SCS 不改 PRB 数否则算出来的带宽就错了。5. 源码使用中的常见问题与排查实录5.1 最容易踩的五个坑我帮同事排查过不少吞吐量仿真代码发现大多数问题集中在参数配置和 TBS 计算上。下面这张表是高频问题速查建议先收藏再跑代码现象可能原因排查方法吞吐量整体偏高没有扣除 DMRS/PDCCH 等开销查 DATA_SYMBOLS 配的多少14 符号时隙里实际数据符号不会超过 13还要考虑 SSB 和 CSI-RS吞吐量曲线太平滑TBS 没有做量化取整查 calc_tbs 函数看是否直接拿连续值相乘高 SNR 段吞吐量继续无限增长MCS 表没有设置最高档或者门限过高查 mcs_table 最后一个门限是否覆盖了 SNR 上限最高 256QAM 码率约 0.9 左右封顶曲线出现回退SNR 更高但吞吐量更低码率或调制阶数配置错误打印每个 SNR 点的 qm 和 code_rate看是否出现高 SNR 选了低阶调制所有吞吐量都比现实高 20% 以上没考虑 TDD 配比和 HARQ 重传把 DL_SLOT_RATIO 调低或增加 BLER 导致的吞吐量损失因子第五个坑是最容易忽略的。我在代码里把 TDD 下行占比设为 0.8但实际系统还要考虑 HARQ 重传占用的资源以及上下行切换的 Guard Period 开销所以真实系统吞吐量会比理想仿真再低 10%-15%。要在仿真里加这个因素可以在最终吞吐量上乘一个 0.9 的“重传损耗系数”或者更严谨地引入 BLER 模型。5.2 源码调试时的几个实操技巧调试这个仿真代码有个很实用的方法从协议给出的吞吐量参考公式反推。3GPP 在 TR 38.306 里给了峰值吞吐量计算公式你可以输入自己的带宽、调制阶数、码率和层数算出理论峰值再和仿真结果对比。如果仿真峰值和公式算出来不一致99% 是 TBS 计算或开销参数写错了。另一个技巧是把 MCS 表中的门限做成可配置参数用程序自动扫描。我写代码时习惯把 mcs_table 提出来单独放一个 JSON 文件门限调整不需要改主代码这样跑参数敏感性分析特别方便。比如关注 SNR 在 5-15 dB 区间的系统性能就把这个区间的门限加密每 0.5 dB 设一个 MCS 档位曲线的阶梯状会更接近真实系统的调度结果。调试时建议每改一个参数就检查两处输出一是打印出来的 TBS 是否落在合理范围二是 SNR-MCS 对应关系是否符合直觉。前者检查计算逻辑后者检查映射表。我曾经把某个码率的小数点写错一位导致 64QAM 段吞吐量比 256QAM 还高这种错误打印中间量一眼就能看出来。5.3 从仿真到真实系统的差距最后说一个仿真之外的话题。这套源码的曲线在系统设计阶段很有参考价值但真实 5G 基站测出来的 SNR-吞吐量曲线和仿真曲线会有偏差原因主要有三个真实信道不是 AWGN衰落信道下 MCS 选择要依赖信道估计和 CQI 上报真实系统里有调度时延、反馈时延和控制信道瓶颈厂商实现的 BLER 目标不一定严格控制在 10%有的为了提升用户体验会调低目标。所以我的建议是仿真曲线用来做趋势评估和参数对比真实性能还是要靠外场测试验证。我通常的做法是先在仿真平台里把“SNR-吞吐量”基线跑出来再到实验室用信道模拟器灌 AWGN 噪声验证几个关键点比如 MCS 跳变点、峰值吞吐量、低 SNR 兜底性能。两边对得上这套源码就可以放心用于系统级评估。这次源码写得比较精简但核心逻辑完整够你把 5G 通信系统吞吐量随 SNR 变化的核心规律跑明白。后续想扩展的话可以往里面加多用户调度、MIMO 层数自适应、CSI 反馈误差、HARQ 重传等模块这些我之后陆续整理出来。本文还有配套的精品资源点击获取
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻