
做6G协议栈研究的人十有八九都会被MAC层这块硬骨头硌过牙。物理层还可以靠公式推导网络层直接套现成方案唯独MAC层夹在中间既要理解波形、帧结构、信道互动的物理约束又要处理调度、重传、资源分配这些系统级的决策逻辑——说白了MAC层是“物理层跑通了就忘掉、网络层配置好就扔一边”的那个中间商但整条链路的性能上限恰恰卡在它手里。这是我做“6G网络仿真_6.MAC层仿真”这个专题最想聊清楚的一件事仿真不是为了把图跑得漂亮而是为了在对手写代码构建的协议机制进行验证时把每个调度决策、每次重传选择背后的因果链彻底看清楚。这次的内容我打算从6GMAC层的技术背景拆起中间结合一个1基站3终端的小型仿真场景讲清楚动态帧结构、比例公平调度器、HARQ重传模型这几个核心模块怎么搭、参数怎么算、日志怎么看最后把我在仿真路上踩过的坑整理成速查表。不敢说这是标准答案但对初次接触6G MAC层仿真的开发者、研究生至少能少走两三个月的弯路。1. 6G MAC层仿真为什么难先理解四个背景问题1.1 超高频段把帧结构压缩到了“快进模式”6G瞄准的不是5G的毫米波而是向太赫兹频段扩张100GHz以上甚至到THz范围都有候选频段。这个频段的好处是带宽动辄几个GHz但换来的代价是传播损耗极大、覆盖范围极小更麻烦的是——它把OFDM符号宽度压得非常短。按5G NR的扩展逻辑子载波间隔为480kHz时一个时隙长度约31.25微秒因为480kHz 15kHz × 32对应μ5时隙长度就是1ms除以32。如果再上行到960kHz一个时隙甚至只有15.6微秒。这个效果非常直观整个MAC调度周期被压缩到几十微秒级别留给调度器做决策的时间窗口几乎没有缓冲余地。在5G里一个调度周期可以有1毫秒MAC层还能慢慢算6G场景下这种“慢慢算”根本不现实。所以6G MAC层设计里“低时延调度”不再只是优化目标而是物理约束——调度器要在几个时隙内完成信道测量接收、调度计算、控制信令下发、数据处理这一整套流程。仿真的时候如果还按5G的毫秒级时钟去推演整个实验结果的意义就要打折扣。1.2 多业务混跑让“调度”从公平问题变成约束求解问题5G时代讲eMBB、URLLC、mMTC三大场景到了6G又新增了很多细分目标但MAC层感知最明显的变化是URLLC类业务时延要求低于0.1毫秒级别的场景出现得越来越多。这不再是“多拨点资源给谁”的问题而是“如何在正常业务流里穿插一个紧急小包同时尽量不伤害大流量业务的吞吐”。行业里常用“抢占式调度”或“打孔”机制就是把已经分配给eMBB用户的时频资源临时让给URLLC包。这种机制在协议层面很好画但在仿真模型里实现却要处理大量状态转换被抢占的传输是取消还是重传HARQ进程怎么复位反馈窗口怎么对齐这些都是MAC层仿真绕不开的状态机细节。1.3 AI调度出现后MAC层和物理层的边界在模糊6G一个热门方向就是用AI做调度决策替代或者部分替代传统的比例公平、轮询规则。这给仿真带来了很现实的问题传统仿真里的物理层是一个固定的“吞吐量查表”AI调度器需要的是实时信道状态、缓存状态、历史调度记录这些高维度输入输出则从资源块分配变成了决策概率分布。MAC层仿真里多了一个“AI代理”之后因果解释变得特别难——你很难判断一个准时延表现是因为调度算法好还是因为信道样本碰巧有利。所以仿真设计里要格外注意控制变量同一个随机种子下分别跑AI调度器和传统调度器对比才有意义。1.4 现有仿真平台对6G的支持是“半成品”状态说句实在话6G标准化还在推进中开源仿真工具基本都停留在5G的成熟模型上NS-3有毫米波模块但那是针对5G毫米波设计的OMNeT生态里有一些自定义6G分支但社区规模和验证程度参差不齐MATLAB的5G Toolbox做链路级仿真很顺手但系统级MAC层调度仿真还得自己搭框架。所以当前做6G MAC层仿真本质上是在成熟工具上做协议扩展既要懂原工具的数据结构又要有能力改写调度核心。这不是坏事反而给了我们很大的建模自由度——如果未来6G标准真正落地这些提前写好的模块改起来也能更快。2. 仿真工具怎么选对比之后我更倾向哪条路2.1 现成工具的一次横向梳理我做过一次相对系统的工具对比主要看四个维度开源程度、MAC层建模能力、6G扩展难度、社区活跃度。简单整理如下工具优势劣势适合场景NS-3开源、模块化清晰、事件驱动仿真效率高mmWave模块并非6G专用需自行扩展系统级协议验证、AI与协议结合研究OMNeT / INET组件化建模直观图形化调试友好网络层组件多但PHY/MAC深度不够教学演示、轻量级系统仿真MATLAB 5G Toolbox物理层模型精确自带NR参考链路系统级MAC调度需要大量自定义代码链路级与PHY/MAC联合仿真Sionna基于TensorFlow支持可微信道模型偏向物理层与深度学习结合MAC层几乎空白AI信道建模、端到端可微通信系统自建C/Python模拟器完全可控、最适合理解机制开发维护成本高、验证难度大教学从零实现、专项机制验证2.2 为什么我的项目主体选了NS-3作为扩展底座我个人更推荐在NS-3基础上做6G MAC层仿真原因很具体。第一NS-3的模块化程度足够高MAC层模块、PHY抽象层、信道模型、移动模型彼此解耦我可以只替换调度器和HARQ模块不用把整个协议栈推翻重来。第二NS-3自带真实TCP/UDP/IP协议栈跑出来的端到端时延和吞吐指标更接近实际应用层的感受而不仅仅是一个“链路级别”的数据。第三NS-3在RNG随机数管理上做得很细不同运行可以精确复现同一种信道状况这对调度算法公平对比至关重要——我在做AI调度实验时同一组信道种子配合不同调度策略对照结果的说服力远高于重跑统计平均。可能有人会问既然自建模拟器自由度更高为什么不自己写一个我的经验是除非目标是彻底搞清楚某一种机制的内部流程比如HARQ状态机否则自建模拟器的时间成本非常大而且验证环节很容易出错。NS-3的调试符号、日志系统、可视化工具NetAnim都很成熟把精力花在改协议逻辑上比花在写基础设施上划算得多。对于有C基础的研究者和学生NS-3的学习曲线是值得投入的。2.3 基于NS-3扩展6G MAC层模型需要动哪些模块一个相对轻量的扩展思路是这样的复用mmwave模块里的物理层抽象和信道模型然后自己重写或重载MAC层调度相关类。需要重点关注三部分帧结构配置修改参数让TTI传输时间间隔和时隙周期匹配6G的超大子载波间隔比如把子帧周期从1ms改成31.25微秒级别。调度器接口NS-3中MAC调度器通过调度请求SR和缓冲区状态报告BSR驱动6G动态帧结构下需要增加时隙格式指示SFI的生成与下发逻辑。HARQ状态管理复用多进程HARQ框架但要调整重传时序使重传窗口匹配更短的往返时延。另外如果在做AI相关实验可以接ns3-ai框架把调度器的决策入口替换成外部机器学习模型推理接口。这个后面我还会展开说。3. 场景设计与参数推算从一个1基站3终端的小场景开始3.1 仿真场景设定与业务模型选择为了避免一上来就被超大拓扑淹没我的做法是先搭一个“最小可验证”场景1个gNB基站3个UE终端。三个UE的业务模型刻意做成差异化UE1跑URLLC类业务周期2毫秒发送一个128字节的小包模拟工业控制指令UE2和UE3跑eMBB类业务持续下载大文件模拟视频流或数据导流。仿真时长取100毫秒足够观察到调度行为的变化又不至于让日志文件爆炸。这个配置看起来小而简单但它能立刻暴露出一个问题URLLC小包穿插在eMBB大流里调度器到底怎么分配资源块才不把大流拖垮。三个UE都做满缓冲区状态报告显然不行真实的MAC层会区分业务优先级。我的模型里给每个UE的队列增加了优先级标识URLLC队列优先处理。这样当UE1的周期包到达时调度器可以立刻响应未必要等到下一个完全空闲的时隙。这个细节在5G帧结构里已经成立放到6G的短时隙场景下约束更紧——因为你不能随便把一个URLLC包推到后面的时隙去那会直接击穿时延要求。3.2 MAC层核心对象清单与建模要点动手写代码前先把要建模的MAC层核心对象列清楚不然写着写着很容易陷入“调度器里全是函数、不知道状态存哪”的困境。我按照NS-3里MAC实体的逻辑拆成了四块调度器实体负责维护UE缓存信息、信道质量信息、上一轮资源分配结果生成调度决策信息DCI或EDCI。HARQ实体为每个UE维护多个并行HARQ进程跟踪进程状态空闲、传输中、等待反馈、重传。缓存队列为每类业务维护独立的缓冲区按优先级出队。随机接入模块6G仿真初期可以简化成初始连接后周期性重测但至少要把UE注册过程保留不然调度器没有用户上下文。这四块的交互关系是数据包到达物理层时缓存队列触发调度请求调度器按优先级和可用资源生成DCI物理层按HARQ进程传输反馈回来后更新HARQ状态再决定是新传还是重传。我在建模的时候没有把随机接入做得很深因为当前专题聚焦调度与HARQ接入过程用仿真配置直接静态接入即可但如果你想研究6G大规模接入的碰撞控制那是另一个维度的问题。3.3 从子载波间隔到调度时延参数的推算链MAC层仿真的一个核心乐趣在于参数推算——把物理层参数和MAC调度时延建立量化联系。我拿480kHz子载波间隔举例算一遍子载波间隔SCS480kHz对应μ5时隙长度 1ms / 2^5 1ms / 32 0.03125ms约31.25微秒普通循环前缀下一个时隙含14个OFDM符号因此一个OFDM符号约2.23微秒如果前4个符号用做控制区包含DCI、SFI等控制信令数据区剩10个符号则一次传输可承载的时频资源约为10个符号时间现在假设目标URLLC时延是0.05ms也就是50微秒。这意味着从数据包到达MAC层开始到调度指令下发、数据完成传输、反馈返回最多只有约1.6个时隙的预算。在5G的1ms帧结构里这个预算根本谈不上压力到了6G短帧结构里调度器就必须在接收到调度请求后马上计算并在下一个或两个时隙内完成分配没有任何“攒一攒再调度”的空间。这就是为什么6G MAC层仿真里调度器的执行效率和数据结构的紧凑程度都要作为重要指标去测——不只是测协议机制也在测系统实现是否能跟得上物理层节奏。小贴士很多人做仿真时容易忽略控制符号的占用直接在全部时隙资源里分配数据。这样算出来的峰值吞吐是虚高的因为DCI/SFI本身就要吃符号。建议建模时把控制开销至少按1~2个符号预留并单独计入调度开销日志否则后续跟真实系统对齐时你会被差距吓一跳。4. 三个核心机制的实现与配置动态帧结构、比例公平调度、HARQ4.1 动态帧结构SFI下发与时隙方向切换6G的帧结构不再像4G那样固定上下行比例而是强调动态调整。我的实现里每个时隙开始时基站根据缓存和业务需求通过时隙格式指示把当前时隙标记为下行、上行或者灵活符号。关键逻辑是灵活符号可以按需分配给上行或下行但切换不能太频繁否则终端还没完成收发切换配置时隙就结束了。仿真里我对切换代价做了简化处理每次方向切换固定消耗0.5个符号作为收发转换保护间隔GP。这个值是根据微波器件开关时间推算的实践经验值未必符合实际硬件特性但可以作为一个可调参数方便你后续对照不同切换速度的效果。在代码配置上SFI信息需要在控制符号里显式下发。我在NS-3的MACTxlsTransfer类里加了一个字段专门存SFI结构每个时隙的主广播信道里携带下一条时隙的方向指示。观测下来这个做法是可行的但带来了一个新问题终端收到SFI后需要等待至少一个时隙才能执行切换因为解析和执行本身有耗时。这意味着动态帧结构并不能“这个时隙决定下个时隙立刻换方向”中间有信息处理延迟。这个延迟在5G可能无所谓在微秒级时隙下同样是一个需要计入的关键参数。4.2 调度器实现从轮询到比例公平再到优先级穿孔一个最简单的轮询调度器伪代码只有十几行但它无法区分业务优先级不适合多业务混跑场景。所以我采用比例公平加优先级修正的方案每个UE的调度权重由瞬时可达速率除以历史平均速率得到URLLC UE再乘一个优先级加权系数。给个核心伪代码参考def proportional_fair_schedule(ue_list, available_rbs): weights [] for ue in ue_list: instant_rate estimate_rate_from_cqi(ue.cqi, available_rbs) avg_rate ue.average_throughput priority_bias urllc_weight if ue.traffic_type URLLC else 1.0 weights.append((ue.ue_id, instant_rate / avg_rate * priority_bias)) weights.sort(keylambda x: -x[1]) allocate_rbs(weights, available_rbs)这段代码看着简单实际操作中有一个容易被忽视的点estimate_rate_from_cqi函数必须基于当前时隙的信道质量指示CQI做容量映射而不是直接用历史统计值。因为6G的时隙很短信道变化速度相对更快CQI过期就会做出“给弱信道用户分配大量资源”的错误决策。我吃过这个亏后来在调度器里为CQI添加了时间戳超过3个时隙没有更新的CQI自动降级处理。URLLC穿孔策略也值得一提。我在调度决策里为URLLC预留了“高优先级穿孔”通道当URLLC包到达时如果当前时隙资源已被eMBB分配完调度器会在eMBB所分配资源块里选择一个低MCS调制编码等级区域打孔插入URLLC数据并触发对被抢占eMBB进程的HARQ重传。这个实现比单纯抢占一个整个RB要精细得多它会显著影响大流的吞吐但不会直接杀掉所有eMBB连接。仿真的关键指标就是看穿孔策略对eMBB吞吐的损伤率这个指标我会在结果走读里用到。4.3 HARQ重传模型多进程与同步时序HARQ的作用不只是“出错重传”它更是一种链路自适应机制初始传输用较高的MCS失败后重传采用较低的有效码率以提升成功率。我在仿真里为每个UE维护了8个HARQ进程下行传输后固定延迟4个时隙收到反馈反馈为NACK时在下一个可用下行时隙重传同时把重传包的调度优先级设为最高保证重传不会被新数据挤到后面排队。这里有一个需要谨慎配置的参数HARQ往返时延。在TDD动态帧结构下下行传输反馈回来的时序取决于帧的方向切换情况如果在反馈窗口内恰好是上行时隙反馈可以正常走如果SFI把那个时隙设成下行反馈就要等到后续的上行时刻。我的做法是每个HARQ进程绑定一个定时器超时未收到反馈就自动转入重传准备状态避免死等。同时在HARQ模块日志里单独标记每个进程的反馈接收时隙方便排查时序错位问题。仿真结果里我发现一个值得注意的现象重传并非总是改善时延在信道质量较好的情况下重传消耗的资源反而拉低了整体吞吐。所以我在调度器里加了一个“重传上限”策略超过3次仍失败后丢弃该传输块并上报丢包事件。这跟实际系统的做法一致也让仿真的端到端丢包率更可信。4.4 把调度器接到AI代理的扩展思路如果你对6GAI调度感兴趣这里给一条明确的实现路径在NS-3里用ns3-ai接口架桥每毫秒或每几个时隙把信道状态、缓存队列长度、历史吞吐组成特征向量交给外部的Python推理进程处理。推理进程用训练好的神经网络输出各UE的调度权重再把结果回传给NS-3调度器。训练阶段可以用传统比例公平调度器产生的数据做模仿学习先让神经网络学会比例公平的决策边界再逐步加入URLLC时延约束做强化学习策略优化。这种架构的好处是门槛清晰协议侧改动小AI侧纯Python开发两部分通过共享内存通信。需要注意的点是共享内存的数据交换频率不能太高——如果每个时隙都做一次跨进程通信通信开销可能比调度算法本身还大。我的经验是设置AI推理周期为若干毫秒而不是跟着时隙走同时在AI不推理的间隙用比例公平兜底保证实验不会因为推理延迟崩溃。5. 验证与结果走读指标设计、日志阅读和一次失败实验分析5.1 关注哪些指标才能说明问题仿真跑完不能看一眼总体吞吐就收工。我固定记录五类指标每次实验都导成CSV方便画图对比端到端时延CDF主要观察URLLC业务的P50、P99时延eMBB平均吞吐和URLLC周期包的成功率资源块利用率PRB utilization和时隙方向切换频率HARQ进程的重传次数分布穿孔抢占事件的数量与对eMBB吞吐的损伤率以UE1周期2ms发送128字节的URLLC包为例如果P99时延超过0.1ms说明调度紧急包的处理链路里有某处在排队——排查点通常不是调度器“没分到资源”而是控制信令下发延迟或缓存队列延迟。5.2 读取MAC层日志找到调度决策的因果链NS-3的日志输出我喜欢精简化不追求每行都有但关键事件必须完整。下面是我实验中的一段典型日志slot32 t0.001000 MAC_TX: UE1 BSR128B priorityURLLC SR_triggered slot33 t0.001031 MAC_SCH: allocate RB(4~8) to UE1, preempt from UE2 low_mcs region slot34 t0.001062 PHY_RX: UE1 CRCOK pid3 slot35 t0.001093 MAC_RX: UE1 ACK pid3 new_data_indication读日志的顺序很重要先看SR是什么时候触发的再看调度器是否在下一个或两个时隙内响应最后核对HARQ反馈是否按时回来。如果在“SR_triggered”和“MAC_SCH”之间间隔超过2个时隙基本可以断定调度器决策延迟过大如果在“PHY_RX”之后“MAC_RX”间隔过长问题出在反馈时序配置而不是调度本身。5.3 一次失败实验URLLC时延抖动到底从哪里来的我在早期仿真里遇到过这么一次URLLC平均时延很漂亮但P99时延出现周期性尖峰每次都精确落在eMBB大包完成传输的那个时隙上。刚开始怀疑是随机数种子问题换成不同种子后尖峰依然存在。最后查代码发现调度器在做资源分配时优先满足了大业务的整块分配请求把URLLC的穿孔决策放到了同一时隙的后半段执行导致URLLC包虽然分到了资源但已经在队列里等了一个完整时隙。解决办法很简单在调度器主循环开头先处理URLLC紧急队列再做常规大流分配尖峰就消失了。这件小事给我印象很深——在6G的短时隙下“调度顺序”这个在5G里几乎可以忽略的实现细节变得直接影响业务性能。6. 常见问题与排查技巧实录6.1 高频报错与排查对照表现象可能原因排查思路日志里大量“BSR overflow”缓存队列溢出URLLC包被丢弃检查业务包速率是否超过资源上限或队列深度是否过小调度器同一时隙给同一RB分配了两个UERB分配图未在时隙边界重置检查调度周期结算函数是否在每个时隙开始时清了分配位图HARQ进程反馈永远收不到TDD方向切换导致反馈时隙不在上行在日志中标记SFI方向和HARQ进程反馈时间核对是否路径错位重传次数异常偏高MCS选择过于激进降低初传MCS档位或检查CQI映射表是否偏乐观UE接入后调度器始终不分配资源UE没有上报CQI/SR检查MAC层是否有SR触发条件未满足确认URLLC队列到达事件是否注册正确6.2 仿真配置类问题的特殊心得这类问题最隐蔽也最浪费时间。我列三条实际体会第一带宽和子载波间隔是一套组合拳改一个必须检查另一个。比如把子载波间隔从30kHz改到480kHz如果带宽还是按原来RB数配置实际总频宽会扩大和大而深的覆盖场景产生矛盾。第二随机数种子不统一会让对比实验失去意义。调度器性能对比必须在同一信道种子集下跑否则你没法区分是算法差异还是信道随机性差异。第三日志保留时长要克制。100毫秒仿真日志全开可能要几百MB建议用环境变量控制只打印特定UE和特定事件类型要数据的时候再放大范围。6.3 仿真规模跑不动怎么办6G毫米波/太赫兹场景仿真本身就是重负载UE数一多CPU时间就指数增长。我的经验是先把“全细节”跑在最小场景里做正确性验证再通过设置代表性UE典型信道质量、典型业务类型来扩大网络场景而不是简单地把每个UE都建模到位。比如模拟一个40 UE的园区场景可以对UE按信道环境分成5类每类选一个代表做完整协议栈其余用简化终端模型占位。这个“分层建模”的思路在做系统级仿真时几乎是必须的否则仿真规模的增长速度会让你崩溃。写在最后的一点经验这套MAC层仿真我前前后后改了十几版最大的体会是仿真本身不产出结论它只是把你对协议机制的理解变成可验证的因果链。你写下的每个调度规则、每组HARQ时序、每个优先级判断都会在一个意外的时延尖峰或吞吐拐角里反过来拷问你。很多人以为做6G仿真难在代码其实难在“你到底理解不理解一个资源块在微秒级时间尺度上从产生到完成传输之间经历了什么”。如果你也想上手千万别直接搭一个大而全的场景先从一个UE、一个时隙、一条调度日志开始。跑通这个最小闭环后面那些AI调度、动态帧结构、多业务共存才有讨论的底子。最后再分享一个小建议每改一处MAC层逻辑就配一个能复现的测试用例脚本把信道种子、UE配置、业务参数全部固化好不然后续回归排查时你会被自己当时的临时参数坑得体无完肤。