3. 基于信噪比的丢包阈值判定与验证
为什么用 SNR 而不是 RSSI 做阈值
RSSI 只反映接收到的总功率,噪声底抬升时 RSSI 可能仍然“正常”,但解调质量已经恶化。SNR(信噪比)直接刻画信号与噪声的相对关系,更适合作为丢包风险的判据。本例用浮标端记录的每包 SNR 与对应确认结果,构建一个可验证的三级阈值划分。
先明确数据口径:每个数据包记录 snr_db(浮标接收下行信号的信噪比估计,单位 dB)与 ack(1 表示收到确认,0 表示该包在重传窗口内未获确认,记为丢包)。阈值判定只使用 snr_db,ack 仅用于验证,避免“用结果反推阈值”的循环论证。
阈值划分与验证指标
设定两个阈值 T_low 与 T_high,把 SNR 划分为三个风险等级:
- 高风险:
snr_db < T_low,预测为丢包; - 中风险:
T_low ≤ snr_db < T_high,预测为不确定(可触发降速或重传策略); - 低风险:
snr_db ≥ T_high,预测为正常。
验证时把“高风险”视为正类预测,与真实 ack=0 比较,计算准确率与召回率。召回率在这里尤其关键:漏掉真正会丢包的包,代价远高于误报。
用历史记录验证阈值
下面用一段可运行的 Python 脚本完成阈值扫描与指标计算。数据为教学示例:模拟 2000 个包的 SNR 与 ack,其中真实丢包概率随 SNR 降低而升高,便于观察阈值移动对召回率与准确率的影响。
import numpy as np
rng = np.random.default_rng(42)
n = 2000
# 示例 SNR:主体分布在 4~14 dB,低 SNR 尾部更稀疏
snr = np.clip(rng.normal(9.0, 2.5, n), 0, 20)
# 真实丢包概率:SNR 越低越容易丢,用 logistic 形式构造示例标签
p_loss = 1 / (1 + np.exp((snr - 6.5) / 1.2))
ack = (rng.random(n) > p_loss).astype(int) # 1=确认, 0=丢包
def evaluate(t_low):
pred_loss = snr < t_low # 高风险判为丢包
tp = np.sum((pred_loss == 1) & (ack == 0))
fp = np.sum((pred_loss == 1) & (ack == 1))
fn = np.sum((pred_loss == 0) & (ack == 0))
tn = np.sum((pred_loss == 0) & (ack == 1))
recall = tp / (tp + fn) if (tp + fn) else 0.0
precision = tp / (tp + fp) if (tp + fp) else 0.0
acc = (tp + tn) / len(ack)
return recall, precision, acc
print("T_low 召回率 精确率 准确率")
for t in np.arange(3.0, 9.5, 0.5):
r, p, a = evaluate(t)
print(f"{t:4.1f} {r:6.3f} {p:6.3f} {a:6.3f}")
运行后得到一张阈值—指标表。判读要点:随着 T_low 升高,召回率上升(更多包被判为高风险),但精确率下降(误报增多)。选择阈值时先设定召回率下限(例如 ≥0.85),再在该约束下取准确率最高的 T_low。示例数据下通常落在 6.0~7.0 dB 区间,具体以实际运行输出为准。
阈值不是一次定死的。建议按季度用新数据重跑扫描,观察最优
T_low 是否漂移;若漂移明显,往往意味着噪声底或天线状态发生了变化,值得进一步排查。不要把
ack=0 直接等同于“链路物理丢包”。确认超时也可能来自浮标侧排队溢出或卫星侧调度丢弃。验证前应先按例 1 的口径清洗事件,否则召回率会被非链路因素污染。可直接套用的阈值验证记录表
| 字段 | 示例值 | 说明 |
|---|---|---|
| 数据集 | 2024-Q2 下行包,n=2000 | 注明时段、方向、样本量 |
| T_low | 6.5 dB | 高风险判定阈值 |
| T_high | 9.0 dB | 低风险判定阈值 |
| 召回率 | 0.86 | 示例输出,需以实跑为准 |
| 准确率 | 0.81 | 示例输出,需以实跑为准 |
| 结论 | 满足召回率≥0.85,采纳 | 写明约束与取舍理由 |
把这张表随阈值一起归档,下次复评时可直接对比指标变化,判断阈值是否需要调整。