简介这是一份面向LTE下行链路系统级仿真的MATLAB源码工程采用SISO单入单出配置覆盖从物理层信道处理到系统级资源调度的完整仿真闭环适合通信专业学生、算法工程师以及正在学习LTE物理层与无线资源管理的读者。资源共40个文件全部为.m脚本压缩包仅35KB代码模块化程度高包含主控仿真脚本、参数预配置、信道估计、信道编码与解码、OFDM收发、均衡解调、资源映射及CRC校验等子模块可支撑从链路级到系统级的灵活配置与二次开发。已有330人学习下载。借助该工程读者可以直观理解eNodeB到UE的下行数据流掌握路径损耗、多径衰落、资源块分配、多用户调度及邻小区干扰处理等核心环节通过运行commlteSISO主脚本并结合可视化与误码率测试能快速验证不同信道条件下的算法性能为后续扩展MIMO或系统级性能评估提供基础。1. 拿到 SISO.zip 之后先搞清楚这套 LTE 仿真到底能干什么A同学把压缩包解压出来看到一堆.m文件和config文件夹第一反应是直接跑main结果要么报错、要么跑一晚上没结果。这不是代码有问题而是这套东西和“点一下出图”的链路级仿真完全是两个物种。SISO.zip指向的是一套 LTE 系统级仿真工程场景聚焦在下行链路、单发单收天线配置它评估的不是一条链路的误码率而是一张网里几十个用户互相抢资源时的吞吐量、时延和干扰状况。系统级仿真和链路级仿真最大的区别在于链路级关心的是“给定信道和 SINR这条链路能跑到什么 BLER”系统级关心的是“基站调度器给每个用户分配资源之后整网的 SINR 分布长什么样”。所以这套工程里你看到的不是星座图、不是误码率曲线而是用户吞吐量 CDF、小区平均频谱效率、边缘用户性能这类指标。适合拿它做方案验证的人是已经学过 LTE 物理层、想评估调度算法或干扰协调方案但又不想从头搭信道模型的从业者或学生。下文我会按“先理解仿真框架再改参数跑通最后把坑填平”的顺序把这套下行链路系统级仿真讲透。中间会给到可改的配置项、可复现的运行流程以及在真实跑仿真时最容易翻车的地方。这套代码不复杂但它的调试逻辑和链路级仿真完全不同用链路级的思路去调系统级参数基本都会踩坑。2. LTE系统级仿真与链路仿真分工SISO下行链路在评估什么2.1 系统级和链路级到底差在哪评估对象、时间粒度和信道模型很多第一次接触 LTE 仿真的人会把系统级和链路级混为一谈。我一般用一个简单粗暴的标准去区分链路级仿真假设只有一条链路信道是给定的、干扰是给定的仿真器只负责把发射端的比特经过编码、调制、信道、解调、解码最后算出 BLER 或吞吐量。系统级仿真不碰比特级处理它把物理层抽象成一张 SINR 到 BLER 的映射表仿真器把精力花在用户移动、调度、功率分配、干扰计算、HARQ 重传这些“网络行为”上。对比维度链路级仿真系统级仿真评估对象单条链路的传输质量整网多用户多小区的资源分配结果时间粒度子帧级甚至符号级处理TTI 级1 ms循环推进信道模型精确的衰落实现逐符号卷积大尺度衰落抽样快衰按 RB 粒度给 SINR物理层处理完整的编解码、调制解调用 BLER 曲线或互信息映射代替典型输出BLER、吞吐量、星座图、EVM用户吞吐量 CDF、频谱效率、边缘用户性能运行成本单链路跑一次几十分钟多小区多用户跑一次几小时SISO.zip 里的代码属于后者。它的输入是基站布局、用户分布、调度策略输出是整个仿真周期内每个用户的吞吐量、每个 RB 上的 SINR以及最终聚合出来的小区平均频谱效率。要理解这个工程的代码结构必须先接受一个观点系统级仿真里“信道”不是一个波形而是一张张 SINR 矩阵每个 TTI 更新一次。2.2 SISO 建模在下行链路中的角色从天线端口到 CQI 上报标题里特意提到 SISO很多人觉得这是“退而求其次”的天线配置。实际上在系统级仿真里SISO 和 MIMO 的差距不只是天线数量而是整套反馈和资源映射规则都不一样。SISO 下行链路只有一个发射天线端口对应 LTE 里端口 0 的 CRS小区专用参考信号。在系统级仿真中这意味着预编码矩阵不用考虑传输模式固定在 TM1 或等效的发射分集场景CQI 上报的计算也简化成单流映射。下行链路的信号链是这样的基站给用户分配 RB每个 RB 上的参考信号位置是固定的UE 测量 CRS 得到信道估计再换算成 SINRUE 把这个 SINR 映射成 CQI 上报给基站基站根据 CQI 选择 MCS决定这个 TTI 的数据块大小。系统级仿真把这条链路的中间步骤全部用查表实现。SISO 场景下SINR 计算简化成信号功率除以干扰加噪声不用考虑秩指示和预编码矩阵的迭代这对初学者理解整条反馈链路非常友好。SISO.zip 里的下行链路仿真核心代码集中在三个环节信道系数生成、RB 粒度 SINR 计算、CQI/MCS 映射。信道系数生成用的是大尺度衰落加多径快衰模型常见的做法是每 10 个 RB 粒度或者每 TTI 更新一次快衰因子。CQI 映射部分工程里一般配一张 15 级 CQI 到 MCS 的表格SINR 落在哪个区间就选哪个 CQI再根据目标 BLER通常 0.1去查 MCS 和 TBS。2.3 下行链路仿真骨架小区布局、用户接入和调度器怎么协作系统级仿真的运行逻辑可以被拆成四层场景配置层、信道更新层、调度传输层、统计收集层。场景配置层定义小区数、扇区数、用户数、天线模型、频率和带宽信道更新层在每个 TTI 计算用户的路径损耗、阴影、快衰和来自邻小区的干扰调度传输层决定这个 TTI 哪些用户被调度、分到多少 RB、用哪个 MCS统计收集层把每个 TTI 的结果累加起来仿真结束后做平均和 CDF 分布统计。仿真推进的粒度固定是 1 个 TTI也就是 LTE 里一个 1 ms 的子帧调度器每个 TTI 都做一次决策。有人第一次跑这套代码时觉得慢得离谱原因多半是没搞清楚“用户数 x 小区数 x 仿真 TTI 数”这个复杂度。比如 7 个小区、每小区 10 个用户、仿真 2000 个 TTI就是 14 万次用户级 SINR 计算每次计算还要遍历所有邻区干扰源。所以系统级仿真的性能瓶颈几乎都在信道更新和干扰计算上而不是调度器本身。工程里通常会对复杂度做两个简化。第一个是快衰更新间隔不需要每个 TTI 都更新多径快衰UE 低速移动时 20 个 TTI 更新一次也能接受代价是时间分集效果被弱化。第二个是干扰源截断SINR 计算只考虑最强的前 6 个相邻小区更远的小区信号弱到对 SINR 的影响远小于噪声。这两个简化能极大压缩仿真时间而且对最终统计指标的影响在工程容差范围内。理解了这个骨架改动配置和定位性能瓶颈就有方向了。3. 把 SISO.zip 在本地跑通目录结构、配置修改和最小运行流程3.1 先花十分钟把代码结构读明白再谈跑仿真拿到压缩包先别双击 main.m。大多数 LTE 系统级仿真工程的目录结构都类似先花十分钟把每个文件的作用定位清楚比反复跑报错日志快得多。常见的目录拆分是这样的路径内容职责config/params.m全局参数定义小区数、带宽、用户数、仿真时长等main.m仿真入口读配置、初始化场景、进入 TTI 循环channel/信道模型函数路径损耗、阴影、快衰生成和更新scheduler/资源调度算法RR、PF、Max C/I 等调度器实现phy/物理层抽象SINR 计算、CQI 映射、MCS 查表harq/HARQ 实体ACK/NACK 判定、重传管理report/数据统计吞吐量收集、SINR 记录、结果导出如果压缩包里目录名不一样可以按函数名的关键字去匹配以上职责比如schedul开头的文件就是调度器cqi或mcs开头的就是物理层映射。一个重要的检查点确认params.m里是否有lte_dl_bw或num_rb这类带宽参数。没有的话可能这套代码的带宽写死在某个函数里后续调参数时要去改函数签名。检查完目录后在运行完整仿真之前先做一次“冒烟测试”把仿真 TTI 数临时改成 10用户数改成 2小区数改成 1。这样做的目的是验证整条数据链路有没有断点而不是直接投入几小时的算力去跑一个注定报错的完整配置。冒烟测试通过后再逐步恢复到目标参数。3.2 改配置文件把场景切到你真正想验证的目标配置文件的重点参数通常集中在文件头部我一般会按“仿真规模、信道模型、调度策略、输出选项”四组分批调整。以下是一个典型的params.m配置片段模拟了 19 个小区、每小区 10 个用户的下行满载场景% 仿真规模 sim_cell_num 19; % 小区个数采用 19 小区 3 扇区布局 sim_ue_per_cell 10; % 每个小区的用户数 sim_tti_total 1000; % 仿真总 TTI 数1 TTI 1ms sim_tti_fastfading 20; % 快衰更新间隔TTI % 下行物理层 lte_bw_hz 10e6; % 系统带宽 10MHz lte_num_rb 50; % 对应 RB 数10MHz 固定为 50 个 RB lte_carrier_hz 2.0e9; % 载波频率 2GHz lte_subframe_ms 1; % 子帧时长固定 1ms tx_power_dbm 46; % 基站发射功率 46dBm约 40W tx_antenna_num 1; % SISO基站 1 根发射天线 rx_antenna_num 1; % SISOUE 1 根接收天线 % 信道模型 ch_model eutra_epi; % 可选: eutra_epa/eutra_eva/eutra_epi ue_speed_kmh 30; % UE 移动速度 30km/h对应典型低速车载 ch_large_scale_update 100; % 大尺度衰落更新时间间隔TTI % 调度器 sched_type pf; % rr 轮询 / pf 比例公平 / mc 最大载干比 sched_target_bler 0.1; % 目标 BLER用于 CQI 修正 % 输出选项 save_dl_sinr true; % 导出每个 RB 的 SINR save_ue_throughput true; % 导出每个用户的吞吐量每个 TTI 的时长固定 1 mssim_tti_total 1000意味着模拟 1 秒的物理时间。1 秒的真实网络行为在单机上通常要跑几十分钟到几小时这取决于小区数和用户数。快衰更新间隔sim_tti_fastfading是调仿真速度最关键的参数之一30 km/h 的移动速度下20 个 TTI 更新一次快衰只会引入可接受的统计误差但计算量直接降到原来的 1/20。如果是为了赶方案周期可以适当调大这个值到 50结果趋势不会反转。带宽参数要和 RB 数对应上1.4 MHz 对应 6 个 RB3 MHz 是 15 个 RB5 MHz 是 25 个 RB10 MHz 是 50 个 RB20 MHz 是 100 个 RB。改带宽时只改lte_bw_hz不改lte_num_rb会导致 RB 配置和带宽不匹配后面 SINR 计算和 TBS 查表全都错位。另外要留意发射功率和小区布局的匹配19 小区场景下 46 dBm 是常见配置但如果用的是 7 小区或者单小区功率不变会导致 SINR 整体偏高统计结果没有参考价值。3.3 跑主循环理解 TTI 推进里每个步骤的发生顺序配置文件准备好之后主循环的结构基本是固定的。下面的代码是main.m里最核心的 TTI 循环骨架它体现了系统级仿真的典型流程每 1 个 TTI 依次做信道更新、调度决策、传输判定、HARQ 处理和统计收集% 主循环逐 TTI 推进 for tti 1 : sim_tti_total % 更新信道每隔若干 TTI 更新一次快衰和大尺度参数 if mod(tti, sim_tti_fastfading) 0 || tti 1 [h_channel, h_pathloss] update_channel(tti, ue_list, cell_list, ch_model); end % 计算每个用户在所有小区下的宽带 SINR含邻区干扰 [sinr_wideband, sinr_per_rb] compute_dl_sinr(... h_channel, h_pathloss, tx_power_dbm, cell_list, ue_list); % UE 侧 CQI 上报根据 SINR 查 CQI 表支持 BLER 目标修正 cqi_report wideband_sinr_to_cqi(sinr_wideband, sched_target_bler); % 调度器根据 CQI 和调度策略分配 RB 和 MCS [schedule_result] scheduler(tti, sched_type, cqi_report, ... ue_list.ue_buffer, cell_list, lte_num_rb); % 传输判定模拟下行数据发送按 MCS 查 BLER 决定 ACK/NACK [ack, rv] simulate_transmission(schedule_result, sinr_per_rb, ... ch_model, sched_target_bler); % HARQ 实体处理重传队列更新 UE 缓冲 [harq_buf, retrans_cnt] harq_process(ack, rv, schedule_result, harq_buf); % 统计记录该 TTI 的吞吐量和 RB 利用率 collect_report(tti, schedule_result, ack, sinr_per_rb, report); end % 仿真结束聚合统计画 CDF 曲线 finalize_report(report);整个循环里调度器的输入依赖 CQI 上报而 CQI 上报依赖 SINR 计算SINR 计算依赖信道更新。所以信道的更新频率直接决定了调度器的输入信息新鲜度。如果快衰更新间隔设得过大比如 100 个 TTI调度器看到的 SINR 是过期的比例公平调度器的频选增益会明显下降用户吞吐量统计偏低。反之更新太频繁计算开销大。经验值是低速用户 20 TTI、高速用户 10 TTI。simulate_transmission这一步是系统级仿真和链路级仿真的关键分界这里没有去做真正的编解码而是用一张 BLER 曲线查表判断传输是否成功。代码里传入的sinr_per_rb是 RB 级 SINR如果整套代码用的是宽带 CQI 调度这里通常会把 RB 级 SINR 做 EESM 合并变成一个等效 SINR再拿这个值去查 BLER。如果 SISO.zip 里的代码没有 EESM 合并而是直接平均那它在频率选择性信道下的结果会偏乐观这一点在解读数据时要心里有数。3.4 数据收集与保存不要为了省事把中间结果丢掉仿真跑完之后最尴尬的事情是指标维度不够前面几小时白跑。所以collect_report这一步要提前设计好收集哪些中间变量。我通常建议至少保留三类数据每 TTI 的用户级吞吐量、每 TTI 的宽带 SINR、每个用户最终的平均吞吐量和 RB 占用数。这三类数据可以支撑吞吐量 CDF、SINR CDF、边缘用户性能、RB 利用率四条分析线。% 数据收集示例记录 TTI 级用户吞吐量和宽带 SINR report.tti_throughput(:, tti) schedule_result.ue_tbs_bits / 1e3; % Kbps report.tti_sinr_db(:, tti) sinr_wideband; % dB report.tti_rb_num(:, tti) schedule_result.ue_rb_count; % 分配的 RB 数这里有个易错点如果 TTI 内某个用户没被调度它的ue_tbs_bits是 0吞吐量记录 0 是正确行为但统计平均时不能把一个只被调度了 10% 的用户的“平均吞吐量”直接按所有 TTI 平均否则它的平均吞吐量会被稀释成看起来调度很少的用户。正确做法是按用户被调度的 TTI 数做条件平均或者直接统计“累计传输比特数 / 仿真总时长”。两种口径给出的结论不同建议在报告里标注清楚采用的是哪种口径。数据保存格式上save成.mat文件比逐行写 CSV 更稳因为 MATLAB 崩溃后.mat至少能保住已经写入的部分。我一般每个 TTI 往内存数组里写一行仿真结束后统一存盘避免在 TTI 循环里频繁打开文件句柄拖慢速度。如果内存不够可以每 100 个 TTI 刷一次盘把report结构切片存储。4. 下行链路仿真结果怎么看从吞吐量 CDF 到参数敏感性分析4.1 先看全局分布再看单用户行为系统级仿真的第一张图应该是用户平均吞吐量 CDF而不是某个用户的吞吐量时间曲线。CDF 能直观告诉你这个仿真场景下 50% 用户能跑多少、边缘用户通常取 5% 分位跑多少。边缘用户性能是评估资源公平性的核心指标如果你的调度方案把边缘用户吞吐量从 200 Kbps 拉到了 400 Kbps但代价是平均吞吐量下降 10%这个交换是否值得取决于你验证的目标。画 CDF 的代码很简单但要注意样本口径。下面这段代码假设report.ue_avg_tput是每个用户在仿真周期内的平均吞吐量单位 Kbps直接对所有用户做 CDF% 画用户平均吞吐量 CDF figure; cdfplot(report.ue_avg_tput); xlabel(用户平均吞吐量 (Kbps)); ylabel(CDF); grid on; % 标注 5% 分位点边缘用户吞吐量 edge_tput prctile(report.ue_avg_tput, 5); line([edge_tput edge_tput], [0 1], Color, r, LineStyle, --); text(edge_tput, 0.1, sprintf(5%% %.1f Kbps, edge_tput));CDF 图出现“长尾左拖”时不需要太担心这是多用户抢资源的正常表现。真正需要警惕的是 CDF 曲线“平台化”也就是 20% 到 80% 的用户吞吐量挤在一个很窄的区间这通常说明调度器的频选增益没有发挥出来或者 CQI 上报的量化阶距太大MCS 选择跳变剧烈。这种情况下要先检查信道更新频率再检查 CQI 映射表是否合理而不是怀疑代码算错了。4.2 三个必调参数组合调度策略、用户数和信道种子我在实际跑仿真时发现改动这三个参数的排列组合能覆盖绝大多数“结果不合理”的排查场景。调度策略、用户数、随机种子三者共同决定了系统级仿真结果的统计特性排查时优先调它们确认仿真平台本身没跑偏再回到自己的算法指标上。三个参数的说明用表格整理如下参数可选值对结果的影响排查时的作用调度策略rr / pf / mc决定用户间资源分配的公平性和频谱效率上限用 rr 做基准验证平台基本功能正常用户数5 / 10 / 20直接决定小区负载和干扰环境负载高时若边缘用户性能不下降说明调度器没在干活随机种子任意整数影响用户位置和信道衰落的复现性固定种子可确保对比实验条件一致调度策略中rr轮询是最容易验证正确性的它每个 TTI 给用户循环分配 RB不参考信道质量。如果rr策略下所有用户吞吐量应该趋于一致但仿真结果里却出现了 10 倍差距那说明调度器的 RB 分配代码存在问题或者 RB 分配权重受到某个未初始化的变量干扰。用rr做基准平台校验是系统级仿真里最常用也最有效的冒烟验证手段。信道种子的问题在对比实验时尤其容易踩坑如果你改动了调度器代码但没有固定随机种子那么两次仿真结果之间的差异是“调度器改动 用户位置变化”的混合效应结论不可信。正确做法是对基线方案和新方案各跑 5 个不同的随机种子取平均和方差做对比。只跑一次、只用一个种子的对比数据在方案评审时说服力很差。4.3 定位吞吐量瓶颈一个实际的排查案例模拟项目 X 的开发者曾遇到过一个问题PF 调度器跑出来的小区平均吞吐量比 RR 还低 20%从理论上说不通。当时我先看了全网的宽带 SINR 分布发现 SINR 在 0 到 5 dB 之间堆积这是典型的干扰受限场景。在这个区间内PF 调度的频选增益本来就比 RR 有限因为用户的信道质量差异不够大。接着检查 CQI 上报的时间线发现 CQI 更新周期被配置成了 100 个 TTI。在 30 km/h 的移动速度下100 ms 的 CQI 时延意味着用户上报的 CQI 严重过期PF 调度器基于过期 CQI 做频选实际分配和当前信道质量脱节。把 CQI 更新周期改到 10 个 TTI 后PF 的吞吐量优势恢复到了预期的 15% 左右。这个案例说明一个排查顺序先看 SINR 分布判断场景是噪声受限还是干扰受限再看 CQI 新鲜度判断调度输入是否可靠最后才去怀疑调度算法本身的问题。这个顺序能避免在错误的方向上反复调参。5. 常见问题与排查把 SISO.zip 真的稳定跑起来这六个坑绕不开5.1 MATLAB 老版本报“未定义函数或变量”现象运行main.m时提示某个函数名未定义但这个函数明明在目录里能看到。原因MATLAB 的当前文件夹没有包含该函数所在目录或者工具箱函数名和自定义函数重名。解决在main.m文件头部加上addpath(genpath(pwd))把当前目录及所有子目录加入搜索路径。如果是在并行计算池里跑还需要对每个 worker 也执行addpath否则parfor内部会找不到自定义函数。这个操作要放在代码最开始执行靠 MATLAB 菜单栏的“设置路径”在换机器时会失效。5.2 仿真速度慢到无法接受一个 TTI 要好几秒现象TTI 循环推进速度极慢按当前规模估算要跑好几天。原因绝大多数情况是信道更新和干扰计算没有做简化。常见的有两个快衰每个 TTI 都重新生成或者 SINR 计算遍历了所有小区而不是最强干扰小区集合。解决先检查sim_tti_fastfading是否设置成了 1改成 20 到 50。再检查计算干扰时是否有小区截断逻辑。如果已经截断到 6 个小区还是很慢把用户数减少一半做性能摸底确认性能瓶颈在用户循环还是小区循环。找到瓶颈函数后用profile on定位热点行通常是大矩阵逐元素运算没有向量化。系统级仿真的性能优化从向量化开始从不用for循环遍历全部用户开始。5.3 吞吐量结果异常低甚至全为 0现象仿真正常跑完画出来的吞吐量 CDF 全是零或者低到几百 bps。原因最常见的两个原因是 CQI 映射表配置错误导致 MCS 全部落在最低档以及 HARQ 重传逻辑死循环导致数据永远传不出去。解决先看报告的 SINR 分布。如果 SINR 在 15 dB 以上但吞吐量极低说明问题在 CQI 映射侧如果 SINR 本身就低到 -5 dB 以下说明信道模型或功率配置有问题。检查 HARQ打印每个 TTI 的 ACK/NACK 比例如果 NACK 比例超过 80%说明目标 BLER 设置或 BLER 查表有问题。还有一种情况是sched_target_bler被设置成 0.01 甚至更小导致 MCS 选择极端保守吞吐量大幅下降目标 BLER 一般取 0.1 而不是越低越好。5.4 两次相同配置的仿真结果对不上现象一套参数跑了两遍吞吐量 CDF 曲线明显不同但你又没动过代码。原因随机种子没有被固定。用户位置、信道衰落、干扰的生成默认使用了当前时间作为随机种子导致每次运行的结果都有统计波动。解决在params.m里加一个sim_rand_seed 202xxxxx;参数并在main.m初始化场景之前调用rng(sim_rand_seed)。做对比实验时不同方案之间固定相同的种子等于给所有方案放了同一批用户、同一套信道差值才来自方案本身。要评估方案真实增益时再更换多个种子取统计平均。5.5 改了参数但结果完全不变现象把用户数从 10 改成 50吞吐量 CDF 居然和一帧没变化。怀疑代码没有重新加载配置。原因配置读取的时机不对。如果params.m里的变量被主脚本加载一次后后续循环引用的是某个函数的局部缓存副本修改配置文件不会生效。解决确认main.m是否真的调用了params.m还是压根没引用。很多系统级工程里配置清洗和默认值填充写在单独的load_params.m里只改params.m而load_params.m里又做了二次覆盖等于白改。排查方法是把sim_tti_total改成 1 跑一遍看运行时间和原来一致那就是没加载新配置。把改动的参数在main.m开头直接赋值打印可以快速定位是读取问题还是作用域问题。5.6 内存不足跑了一半被强制中断现象仿真跑到一半MATLAB 弹出“内存不足”的错误之前算好的数据全部丢失。原因收集上报数据的矩阵是预分配了全量大小的但某个维度算错导致矩阵异常膨胀或者中间变量没有及时清理累积了巨大内存占用。解决在 TTI 循环内用whos检查最大占用变量。常见的膨胀点是 SINR 矩阵如果把所有用户在所有 RB 的 SINR 都记录到一个n_users x n_rb x n_tti的三维数组里1000 TTI 数据量很容易突破几个 GB。正确做法是按需记录只需要吞吐量指标就不存 RB 级 SINR需要做 SINR 分布分析就只记录宽带 SINR。另一个建议是每个 TTI 结束时用clear清掉信道矩阵等临时大变量MATLAB 的for循环里变量会一直被引用不清掉就占着内存不放。6. 进阶验证方向把系统级仿真结果和链路级接口对齐系统级仿真做出来的结果如果只用于方案对比问题不大但如果想拿去做链路级联调或者出报告就需要验证系统级仿真里的 SINR 到 BLER 映射是否和真实链路级仿真结果一致。这个验证过程通常叫“校准”在相同的 SINR 输入下系统级仿真查表出来的 BLER 要和链路级仿真跑出来的 BLER 对齐。校准的目标是把 EESM 的等效 SINR 计算参数 β 调到匹配特定信道模型。公式上EESM 等效 SINR 是每个子载波 SINR 的指数加权平均β 是这个加权平均的缩放指数不同 MCS 档位需要不同的 β 值。校准的具体步骤是先用链路级仿真跑一组 MCS/BLER 曲线再用系统级仿真在同一组 MCS 下反推 β。更实用的验证手段是让系统级仿真输出“调制编码效率”而不是直接输出吞吐量。调制编码效率等于 TBS 除以分配的 RB 数和符号数用这个指标做对比可以消除不同调度器分配 RB 数差异的干扰直接看物理层传输效率。如果调制编码效率和理论上限比如 64QAM 的 4.4 bit/symbol 效率差得太远说明 CQI 映射或者信道质量反馈有压缩损耗值得回头检查实现细节。另外一块验证方向是定点化系统级仿真里用的浮点信道矩阵换成定点格式后CQI 上报会不会偏移。移动端实际跑协议栈的人会特别关心这步因为定点 CQI 计算在芯片实现里很常见浮点仿真的结果偏乐观。常见的做法是把信道估计后的 SINR 量化成固定位宽再跑一遍 CQI 映射对比浮点和定点的吞吐量差异差距一般不超过 5% 是可以接受的。如果差异大于 10%说明量化位宽不够或者 CQI 映射区间分界点选取不合理需要重新审视量化策略。回到这套 SISO.zip 工程本身我的建议是别把它当黑匣子用。先按前文步骤跑通默认配置再用rr和pf对比看调度器是否正常工作最后把快衰更新间隔改成 10 验证一下性能是否符合预期。我自己的习惯是改任何参数前先跑一遍基线配置存盘之后的任何改动都对着基线数据做差值而不是每次重跑一次全量仿真。这样既能快速回归也能避免数据口径不一致导致的误判。希望这套流程能帮你少走几趟弯路把时间花在真正想验证的方案上。本文还有配套的精品资源点击获取