3. MAC层核心功能:调度器设计原理,HARQ重传机制,随机接入过程(RACH)
好,咱们今天聊聊MAC层最核心的三个功能模块。说实话,这三个东西搞明白了,你对基站协议栈的理解就及格了。我当年刚入行时,光一个调度器就啃了两个月,后来才发现——嗯,其实核心思想没那么玄乎。
3.1 调度器设计原理
调度器是MAC层的“大脑”。它决定谁在什么时候、用什么资源发数据。说白了,就是管分配。
我个人习惯把调度器分成两类:上行调度和下行调度。下行调度好理解——基站说了算,想给谁发就给谁发。上行调度就麻烦点,你得先知道用户有数据要发,然后才能分配资源。
调度器的核心目标有三个:
- 公平性——不能老让一个用户占着资源
- 吞吐量——系统总速率要尽量高
- 时延——特别是URLLC业务,延迟必须低
这三个目标其实是互相打架的。你追求吞吐量,就可能牺牲公平性。你照顾时延,吞吐量就会掉。所以调度器本质上是个多目标优化问题。
3.1.1 经典调度算法
我列几个常用的,你们感受一下:
| 算法 | 核心思想 | 适用场景 |
|---|---|---|
| Round Robin | 轮流来,每人一次 | 公平性要求高,业务量均匀 |
| Max C/I | 谁信道好就给谁 | 追求最大吞吐量 |
| PF (Proportional Fair) | 兼顾公平和吞吐量 | 最常用,商用基站标配 |
PF算法我得多说两句。它的公式很简单:
优先级 = 当前速率 / 历史平均速率
你想想看,如果一个用户信道一直很好,历史平均速率就高,优先级反而会降下来。这就给了信道差的用户机会。我在项目中遇到过,有些团队直接用Max C/I,结果边缘用户永远抢不到资源——用户体验极差。
3.1.2 调度器的实现架构
调度器在代码里通常是个事件驱动的模块。每个TTI(传输时间间隔)触发一次调度决策。我习惯把它拆成三层:
- 输入层——收集CQI、BSR、优先级等信息
- 决策层——运行调度算法,生成资源分配结果
- 输出层——生成DCI(下行控制信息)或UL Grant
这里有个坑——我曾经在决策层里直接操作全局变量,结果多线程调度时出了竞态条件。后来改成消息队列,问题就解决了。
3.2 HARQ重传机制
HARQ,全称是混合自动重传请求。说白了,就是“如果数据传错了,再传一次”。但它的巧妙之处在于——不是简单重传,而是把新传和重传的数据合并起来解码。
为什么会这样?因为无线信道有衰落。第一次传可能被深衰落打中,第二次传时信道可能变好了。你把两次的软比特信息合并,解码成功率就高很多。
3.2.1 两种HARQ模式
3GPP定义了两种:
- CC (Chase Combining)——重传时发同样的数据,接收端做最大比合并
- IR (Incremental Redundancy)——重传时发不同的冗余版本,接收端做码字合并
IR的效率更高,但实现复杂。我建议在信道条件差的场景用IR,信道好的场景用CC就够了。
3.2.2 HARQ进程管理
每个UE有多个HARQ进程。比如LTE是8个进程,NR是16个。为什么是16个?因为NR的时延要求更低,需要更多的并行进程来“流水线”操作。
进程的状态机是这样的:
空闲 → 激活(发送初传) → 等待ACK →
├─ 收到ACK → 空闲
└─ 收到NACK → 重传 → 等待ACK → ...(最多重传4次)
我曾经在调试时发现,某个UE的HARQ进程一直卡在“等待ACK”状态。查了半天,原来是物理层没把ACK反馈送上来——嗯,接口时序没对齐。
3.3 随机接入过程(RACH)
随机接入,是UE和基站建立连接的“第一握手”。UE刚开机,或者从空闲态回来,它不知道基站的时序,也不知道自己的上行同步——所以得先“喊一声”。
RACH分两种:
- 基于竞争的——多个UE可能同时发,会冲突
- 基于非竞争的——基站指定资源,不会冲突
大部分场景用的是基于竞争的。流程分四步:
- Msg1:UE发前导码(Preamble)——就是一段特定的序列
- Msg2:基站回RAR(随机接入响应)——告诉UE你的时序调整量、上行授权
- Msg3:UE发RRC连接请求——带上自己的身份信息
- Msg4:基站回冲突解决——确认谁成功了
这里有个细节——Msg1的发送时机。UE不知道基站的时序,所以前导码要在一个特定的时频资源上发。这个资源叫PRACH时隙。
3.3.1 随机接入的触发条件
不是只有开机才做RACH。以下情况也会触发:
- 上行失步——UE长时间没发数据,时序漂移了
- SR(调度请求)失败——UE有数据要发,但没拿到上行授权
- 切换——UE从一个基站切到另一个基站
我记得有一次,某个UE频繁触发RACH,导致网络负载飙升。查了半天,发现是UE的TA(时序提前)定时器设置得太短——还没到时间就认为失步了。
3.4 三个功能的协同
调度器、HARQ、RACH不是孤立的。它们之间有很多交互:
- RACH成功后,调度器要给UE分配初始资源
- HARQ重传时,调度器要预留资源给重传
- 调度器做决策时,要考虑HARQ进程的状态
我习惯在代码里用一个全局状态表来管理这些信息。每个UE一行,记录它的HARQ进程状态、调度优先级、RACH状态等。这样三个模块查起来都方便。
好了,这一章就到这里。调度器、HARQ、RACH这三个东西,你搞清楚了,MAC层的大框架就立起来了。下一章我们聊聊MAC层的其他功能——比如BSR、PHR、DRX这些。嗯,到时候再细说。