第三章 PHY层速率自适应:MCS选择算法、动态带宽调整、CSI反馈

各位同学,咱们今天聊点硬核的。PHY层的速率自适应,说白了就是让WiFi芯片自己判断“现在该跑多快”。你想想看,信道环境一直在变——有人走过来了,微波炉开了,隔壁邻居也在抢信道。芯片要是傻乎乎地一直用最高速率,那丢包率肯定惨不忍睹。

我刚开始做WiFi芯片那会儿,就吃过这个亏。当时我们用的MCS选择算法特别简单,就是看最近几个包的ACK成功率。结果呢?在移动场景下,速率切换总是慢半拍。用户拿着手机从客厅走到阳台,视频已经卡成PPT了,速率还没降下来。嗯,从那以后我就明白,速率自适应这事儿,没那么简单。

3.1 MCS选择算法:到底该用哪一档?

MCS,Modulation and Coding Scheme,调制与编码策略。802.11ac支持0到9共10档,802.11ax支持0到11共12档。每一档对应不同的调制方式(BPSK、QPSK、16QAM、64QAM、256QAM、1024QAM)和编码率(1/2、2/3、3/4、5/6)。

选择哪一档,核心就两个指标:信噪比(SNR)误包率(PER)。但实际工程中,你不能只看当前瞬间的SNR,因为信道是时变的。我个人习惯用滑动窗口+指数加权平均来做决策。

核心原则:在保证目标PER(通常1%~10%)的前提下,尽可能选择高阶MCS。说白了,就是“稳中求快”。

我给你们看一段伪代码,这是我当年在项目里用过的简化版MCS选择逻辑:

// 简化版MCS选择算法
// 输入:最近N个包的SNR估计值 snr_history[]
// 输入:最近N个包的ACK状态 ack_history[]
// 输出:建议的MCS索引

function select_mcs(snr_history, ack_history):
    // 1. 计算有效SNR(考虑衰落余量)
    avg_snr = mean(snr_history)
    snr_margin = 3.0  // dB,经验值
    effective_snr = avg_snr - snr_margin

    // 2. 查表得到候选MCS
    candidate_mcs = snr_to_mcs_table(effective_snr)

    // 3. 根据PER做降级保护
    per = calculate_per(ack_history)
    if per > 0.1:  // 丢包率超过10%
        candidate_mcs = max(0, candidate_mcs - 2)  // 降两档
    elif per < 0.01:  // 丢包率低于1%
        candidate_mcs = min(11, candidate_mcs + 1)  // 升一档试探

    return candidate_mcs

这里有个坑,我提醒一下。SNR到MCS的映射表,不同芯片厂商是不一样的。为什么?因为接收机灵敏度不同。你家的LNA噪声系数是3dB,我家的只有2dB,那同样的SNR下,我能用的MCS就比你高一档。所以千万别直接抄别人的映射表,一定要用自己的芯片实测数据来标定。

避坑指南:我曾经见过一个团队,直接用了参考设计里的SNR-MCS映射表,结果量产后发现,在弱信号场景下,芯片总是选错MCS,导致吞吐量比竞品低了20%。后来一查,是他们的PA线性度不够,高阶MCS下的EVM(误差向量幅度)超标了。所以,映射表必须结合你自家的射频前端特性来调整。

3.2 动态带宽调整:20MHz还是80MHz?

带宽越大,峰值速率越高,但受干扰的概率也越大。802.11ac支持20、40、80、160MHz四种带宽。802.11ax还支持80+80MHz的非连续绑定。

动态带宽调整,说白了就是回答一个问题:现在用大带宽划算,还是用小带宽更稳?

我建议用信道空闲评估(CCA)误码率两个维度来做决策。具体来说:

  • CCA检测到干扰:如果某个20MHz子信道的CCA经常报忙,那就把它从绑定中剔除。
  • 子信道误码率过高:如果某个子信道的误码率明显高于其他子信道,说明有窄带干扰,应该降带宽。

这里有个工程细节要注意。带宽切换不能太频繁,否则协议开销会吃掉你省下来的那点增益。我个人习惯设置一个滞回区间

当前带宽 降带宽条件(持续100ms) 升带宽条件(持续500ms)
80MHz 任意20MHz子信道PER > 15%
40MHz 任意20MHz子信道PER > 20% 所有子信道PER < 5% 且 SNR > 25dB
20MHz PER < 3% 且 SNR > 30dB

你看,降带宽的条件比升带宽宽松得多。为什么?因为降带宽是“保连接”,要果断;升带宽是“提性能”,要谨慎。你想想看,要是信道稍微好一点就升带宽,结果下一秒干扰来了又得降,那不就成“乒乓切换”了吗?

小技巧:在实际项目中,我还会结合RSSI(接收信号强度指示)来做辅助判断。如果RSSI很强但PER很高,那大概率是干扰,而不是信号弱。这时候降带宽比降MCS更有效。

3.3 CSI反馈:让发送端“看见”信道

CSI,Channel State Information,信道状态信息。这东西是802.11n引入的,到了802.11ac和802.11ax,已经成为速率自适应的核心依赖。

CSI反馈包含什么?说白了,就是接收端告诉发送端:“嘿,咱俩之间的信道长这样。”具体来说,CSI反馈包含每个子载波的幅度相位信息。在802.11ac中,CSI以压缩波束成形矩阵的形式反馈;在802.11ax中,还支持更细粒度的RU(资源单元)级别的CSI。

我当年做802.11ac芯片的时候,CSI反馈这块踩过一个大坑。当时我们为了省内存,把CSI的量化精度从8bit降到了6bit。结果呢?波束成形的增益直接掉了3dB。后来一分析,是相位量化误差太大,导致波束方向偏了。嗯,从那以后,我对CSI的量化精度就特别敏感。

CSI反馈的典型流程是这样的:

  1. 发送端发送NDP(空数据包)帧:这个帧不含数据,只用于信道探测。
  2. 接收端测量信道:根据NDP帧的已知序列,估计每个子载波的信道响应。
  3. 接收端反馈CSI:通过压缩波束成形报告(Compressed Beamforming Report)把CSI发回去。
  4. 发送端计算预编码矩阵:根据CSI调整后续数据帧的发送参数。

这里有个关键参数——CSI反馈的时效性。信道是时变的,你反馈的CSI越老,参考价值越低。802.11ac标准建议CSI反馈的有效期不超过100ms。但在实际工程中,我建议根据移动速度动态调整:

  • 静止场景:每200ms反馈一次就够了。
  • 步行场景(3km/h):每50ms反馈一次。
  • 车载场景(60km/h):每10ms反馈一次,甚至需要开环MCS选择。

重点:CSI反馈不是免费的。每次反馈都要占用信道时间,而且接收端要做FFT和矩阵运算,功耗也不低。所以,反馈频率要在性能和开销之间做权衡。我个人习惯的做法是:先以50ms为周期反馈,如果连续3次CSI变化很小,就把周期拉长到100ms;如果信道突然变化剧烈,就临时触发一次额外反馈。

最后说一句,CSI反馈在MIMO场景下尤其重要。没有CSI,你就没法做波束成形,空间流的增益就发挥不出来。我见过一些低端WiFi芯片,为了省成本把CSI反馈给砍了,结果MIMO性能跟SISO差不多。你说这图啥呢?

好了,这一章的内容就到这里。下一章咱们聊聊MAC层的多用户调度,那又是另一番天地了。