2. 基于最后遥测帧的失联前状态还原
为什么先看最后几帧,而不是先看告警
失联告警只说明“岸端收不到数据了”,它本身不携带故障原因。真正能区分“通信先断”还是“平台先失控”的,是失联前最后若干帧遥测中关键量的变化形态。本案例的任务是:拿到一段失联前的遥测记录,按时间顺序还原航向、航速、深度、电池电压、通信信号质量五条曲线,找出是否存在突变点,并据此给出排障方向初判。
判读的核心不是看某一帧的绝对值,而是看谁先变、谁后变、变化是否连续。典型规律有三类:
- 通信先劣化:信号质量(RSSI/信噪比)与丢包率先恶化,航向航速深度仍平稳,最后帧中断——指向链路问题。
- 平台先异常:航向或深度出现阶跃/持续漂移,航速异常升高或归零,而信号质量在中断前仍正常——指向控制或推进问题。
- 能源先塌陷:电池电压在数帧内快速下跌并伴随航速下降、通信功率不足——指向供电问题。
遥测帧结构与解析口径
假设平台按 1 Hz 上报,每帧含时间戳、航向(°)、航速(kn)、深度(m)、电池电压(V)、信号质量(dBm 或 0–100 归一值)、丢包率(%)。解析时先做三件事,避免误判:
- 统一时间基准:以平台帧时间戳为准,岸端接收时间只用于计算链路时延,不参与趋势判断。
- 标记缺帧:相邻帧时间差大于 1.5 倍上报周期即视为缺帧,缺帧本身是链路劣化的证据,不能简单插值抹平。
- 区分“突变”与“正常机动”:航向变化率超过设定阈值(示例取 30°/s)且持续不足 2 帧,视为突变;缓慢转向属于正常机动。
判读阈值应结合平台实际机动能力设定。下面示例中的阈值仅用于演示判读逻辑,不代表任何具体型号的指标。
失联前状态还原与突变点定位
下图把最后 12 帧的五条关键量按时间轴对齐呈现,并标出三个候选突变点:第 7 帧信号质量开始下滑、第 9 帧航向出现阶跃、第 11 帧后连续缺帧直至中断。通过“谁先变”可以快速锁定排障入口。
用脚本把判读过程固化下来
人工看曲线容易漏掉缺帧和细微阶跃。下面这段 Python 直接对遥测 CSV 做解析,输出每帧的时间差、各量变化率,并自动标记候选突变点。示例数据内嵌在脚本里,可直接运行验证逻辑。
import csv
import io
# 教学示例数据:帧序号, 航向(°), 航速(kn), 深度(m), 电压(V), 信号质量(0-100)
RAW = """seq,hdg,spd,depth,volt,signal
0,182.0,4.2,12.5,25.6,88
1,182.3,4.2,12.5,25.6,87
2,181.8,4.1,12.6,25.5,88
3,182.1,4.1,12.5,25.5,86
4,182.0,4.0,12.5,25.5,85
5,182.2,4.0,12.6,25.4,72
6,181.9,3.9,12.5,25.4,58
7,182.0,3.9,12.5,25.4,44
8,182.1,3.8,12.6,25.3,30
9,215.0,3.8,12.5,25.3,18
10,214.6,3.7,12.5,25.2,8
11,214.8,3.7,12.6,25.2,2
"""
# 判读阈值(示例,需按平台实际能力调整)
HDG_JUMP_DEG = 30.0 # 单帧航向变化超过此值视为阶跃
SIGNAL_DROP = 15.0 # 单帧信号质量下降超过此值视为劣化起点
VOLT_DROP = 0.5 # 单帧电压下降超过此值视为异常跌落
GAP_FACTOR = 1.5 # 帧间隔超过上报周期的1.5倍视为缺帧
PERIOD = 1.0 # 上报周期(s)
rows = list(csv.DictReader(io.StringIO(RAW)))
for r in rows:
for k in ("hdg", "spd", "depth", "volt", "signal"):
r[k] = float(r[k])
print(f"{'帧':>3} {'航向变化':>8} {'信号变化':>8} {'电压变化':>8} 标记")
events = []
for i in range(1, len(rows)):
prev, cur = rows[i-1], rows[i]
d_hdg = cur["hdg"] - prev["hdg"]
d_sig = cur["signal"] - prev["signal"]
d_volt = cur["volt"] - prev["volt"]
flags = []
if abs(d_hdg) > HDG_JUMP_DEG:
flags.append("航向阶跃")
if d_sig < -SIGNAL_DROP:
flags.append("信号劣化")
if d_volt < -VOLT_DROP:
flags.append("电压跌落")
if flags:
events.append((cur["seq"], flags))
print(f"{cur['seq']:>3} {d_hdg:>8.1f} {d_sig:>8.1f} {d_volt:>8.2f} {'/'.join(flags) or '-'}")
# 按“谁先变”给出排障入口初判
first = {}
for seq, flags in events:
for f in flags:
first.setdefault(f, seq)
print("\n首次出现顺序:", first)
if "信号劣化" in first and (("航向阶跃" not in first) or first["信号劣化"] < first["航向阶跃"]):
print("初判:通信链路优先排查")
elif "电压跌落" in first:
print("初判:供电系统优先排查")
elif "航向阶跃" in first:
print("初判:平台控制/推进优先排查")
运行后可以看到:信号质量在第 5 帧首次出现超过阈值的下降,航向阶跃出现在第 9 帧,电压全程无异常跌落。首次出现顺序为“信号劣化 → 航向阶跃”,因此初判指向通信链路。这与图中三个突变点的先后关系一致,说明脚本判读与人工判读互相印证。
若信号质量与航向几乎同帧突变,不能简单归因于链路。此时应检查该帧是否伴随姿态角速度异常,必要时把最后几帧原始报文完整导出,确认是否为平台失稳导致天线指向偏离,而非链路本身故障。
结果判读与排障入口对照
| 突变形态 | 典型先后关系 | 优先排查方向 | 需补充的证据 |
|---|---|---|---|
| 信号质量先降,航向航速平稳 | 信号 → 缺帧 → 中断 | 通信链路(天线、馈线、电台、中继) | 各段链路信号强度与丢包率 |
| 航向阶跃或深度持续漂移 | 姿态异常 → 信号劣化 | 平台控制、舵机、推进器 | 姿态角速度、控制指令回执 |
| 电压快速下跌伴航速下降 | 电压 → 航速 → 通信功率不足 | 电池组、供电配电 | 各电池单体电压、负载电流 |
| 深度突变伴信号骤降 | 深度 → 信号 | 水声通信、耐压与进水 | 深度传感器原始值、舱内湿度 |
遥测帧本身可能已被链路压缩或补发,出现“时间戳倒退”或“重复帧”时,应先按时间戳排序并去重,再做趋势判读,否则会把补发帧误判为突变。
交付物:失联前状态还原记录表
把上述判读结果整理成一张可直接填写的记录表,便于后续与链路分段测试、声速剖面核查等排查动作衔接。
| 字段 | 填写内容(示例) |
|---|---|
| 失联时刻 / 最后有效帧 | t0,帧序号 11 |
| 分析帧数 | 12 帧(1 Hz) |
| 缺帧情况 | t-1 至 t0 之间无缺帧,t0 后中断 |
| 航向趋势 | t-3 前稳定约 182°,t-3 阶跃至 215° |
| 航速趋势 | 4.2 → 3.7 kn,缓降 |
| 深度趋势 | 12.5–12.6 m,平稳 |
| 电池电压趋势 | 25.6 → 25.2 V,缓降,无跌落 |
| 信号质量趋势 | 88 → 2,t-6 起持续下滑 |
| 首个突变点 | t-6 信号质量下降超阈值 |
| 初判排障入口 | 通信链路 |
| 待补证据 | 岸基—中继—艇载各段信号强度与丢包率 |
完成本表后,排障方向已从“失联”这一笼统告警收敛到“通信链路优先”,后续即可按链路分段测试逐段定位具体故障点。