2. 卫星链路RSSI与丢包率的时序关联分析
为什么要把 RSSI 与丢包率放在同一时间轴上
浮标端通信日志里,RSSI 是逐秒(或逐包)记录的瞬时量,丢包率则是按卫星过顶窗口统计的比率量。两者采样粒度不同、时间基准也可能有偏差(浮标本地时钟 vs 过顶窗口起始时刻)。直接拿"过顶期间平均 RSSI"和"过顶丢包率"做一次相关,会掩盖 RSSI 在窗口内的骤降过程——而骤降恰恰是丢包突增最直接的诱因。因此本例的核心动作是:统一时间基准 → 重采样对齐 → 滑动窗口相关 → 定位骤降-突增配对。
数据准备与对齐口径
假设浮标日志导出为两张表(示例数据,非实测):
rssi_log.csv:字段utc_time, rssi_dbm,采样间隔 1 s,RSSI 典型范围 −120 ~ −85 dBm。pkt_log.csv:字段utc_time, seq, acked,每包一条记录,acked=0表示未收到确认(丢包)。
对齐口径约定:以 UTC 整秒为公共时间栅格;丢包率按 10 s 窗口统计(窗口内 acked=0 的包数 / 总包数);RSSI 在同一 10 s 窗口内取均值与最小值两个特征。这样每个时间点得到三元组 (t, rssi_mean, rssi_min, loss_rate)。
若浮标时钟与地面站存在固定偏移,先用过顶窗口的首包到达时刻做一次粗对齐,再检查对齐后 RSSI 曲线在窗口边沿是否出现台阶状跳变——有跳变说明偏移未消除。
滑动窗口相关系数的计算逻辑
对对齐后的序列,取窗口长度 W=60 个 10 s 点(即 10 分钟),步长 1 点,逐窗计算 Pearson 相关系数:
r_k = Σ[(x_i - x̄)(y_i - ȳ)] / sqrt(Σ(x_i - x̄)² · Σ(y_i - ȳ)²)
其中 x = rssi_mean(或 rssi_min),y = loss_rate,i ∈ [k, k+W)
预期符号为负:RSSI 越低,丢包率越高。若某窗口 r_k 接近 0 甚至为正,说明该时段丢包并非由信号强度主导(可能是协议重传、遮挡或调度问题),需要单独标记。
关键实现(Python,可直接运行)
import numpy as np
import pandas as pd
# 1) 读取并统一到 UTC 整秒
rssi = pd.read_csv("rssi_log.csv", parse_dates=["utc_time"])
pkt = pd.read_csv("pkt_log.csv", parse_dates=["utc_time"])
rssi["sec"] = rssi["utc_time"].dt.floor("s")
pkt["sec"] = pkt["utc_time"].dt.floor("s")
# 2) 10 s 窗口聚合
rssi["win"] = rssi["sec"].dt.floor("10s")
pkt["win"] = pkt["sec"].dt.floor("10s")
rssi_w = rssi.groupby("win")["rssi_dbm"].agg(rssi_mean="mean", rssi_min="min")
pkt_w = pkt.groupby("win")["acked"].agg(loss_rate=lambda s: 1 - s.mean())
df = rssi_w.join(pkt_w, how="inner").sort_index().reset_index()
df = df.dropna(subset=["rssi_mean", "loss_rate"])
# 3) 滑动窗口 Pearson 相关(W=60 点,步长 1)
W = 60
def rolling_corr(x, y, w):
out = np.full(len(x), np.nan)
for k in range(len(x) - w + 1):
xs, ys = x[k:k+w], y[k:k+w]
if xs.std() == 0 or ys.std() == 0:
continue
out[k + w - 1] = np.corrcoef(xs, ys)[0, 1]
return out
df["corr_mean"] = rolling_corr(df["rssi_mean"].values, df["loss_rate"].values, W)
df["corr_min"] = rolling_corr(df["rssi_min"].values, df["loss_rate"].values, W)
# 4) 识别 RSSI 骤降 + 丢包突增的配对事件
df["d_rssi"] = df["rssi_mean"].diff()
df["d_loss"] = df["loss_rate"].diff()
events = df[(df["d_rssi"] < -3.0) & (df["d_loss"] > 0.15)]
print(events[["win", "rssi_mean", "loss_rate", "d_rssi", "d_loss", "corr_mean"]])
阈值 −3 dB 与 +15% 是示例判据,需按实际链路噪声水平调整:先看 d_rssi 与 d_loss 的分布分位数,取约 90% 分位作为"骤降/突增"的门限,避免阈值过松导致事件泛滥。
时序关联的判读结构
下图把"原始 RSSI 序列 → 窗口聚合 → 滑动相关 → 事件配对"的判读关系画在一起,重点看 RSSI 骤降点与丢包突增点在时间轴上的相对位置,以及相关系数曲线在事件附近的负向凹陷。
结果判读与验证要点
- 符号一致性:正常链路的
corr_mean应稳定为负;若某窗口转正,优先检查该窗口内是否有大量重传包(seq重复)或调度异常,而非直接归因于信号。 - 时间滞后:RSSI 骤降与丢包突增之间可能存在 1~2 个 10 s 窗口的滞后(链路层重传缓冲)。可对
loss_rate做 ±3 点平移后再算相关,取绝对值最大的滞后量作为实际响应延迟。 - 事件配对验证:对每个
events行,回查原始pkt_log中该窗口的seq连续性,确认丢包是连续段丢失还是随机散失——连续段丢失更符合 RSSI 骤降导致的链路中断特征。 - 阈值敏感性:把
−3 dB / +15%分别放宽到−2 dB / +10%与收紧到−5 dB / +20%,观察事件数量变化;若事件数对阈值极敏感,说明判据不稳,应改用分位数门限。
相关系数只反映线性关联,不能直接作为因果结论。RSSI 骤降与丢包突增同时出现,仍可能是同一天线遮挡或姿态变化共同导致,需结合姿态数据(见后续案例)交叉验证。