2. 雷达位移数据时间序列对齐与重采样

为什么时间戳不一致会让预警序列错位

多台边坡雷达往往由不同厂商、不同批次部署,采样间隔可能是 6 min、10 min 或 30 min,且各台设备的时钟存在秒级到分钟级漂移。若直接把两台雷达的位移序列按行号拼接或按“第 n 个点”对齐,就会出现同一时刻的位移被错配到相邻时刻,导致合成速率、阈值判定和预警等级整体偏移。本节的任务是:把多源位移序列统一到一条规则时间基准上,并给出可验证的对齐结果。

统一时间基准与重采样策略

工程上通常选一个“主基准”:以采样最密、时钟最可信的一台雷达的采样时刻作为公共时间轴,或直接构造固定步长的规则时间轴(如 10 min)。对齐分两步:

  • 时间对齐:把各序列的时间戳归一到同一时区与同一格式(建议统一为 UTC 毫秒或 ISO 8601),并处理重复时间戳(同测点同一时刻取均值或保留最后一条)。
  • 重采样:对规则时间轴上的每个时刻,用“前向保持(ffill)+ 最大容忍间隔”或“线性插值”取值。位移是缓变量,线性插值通常可接受;但跨越长时间断档(如设备离线)时不应插值,应标记为缺失,避免伪造位移。
关键约束:插值只允许在相邻有效点间隔不超过 max_gap(例如 2 倍标称采样间隔)时进行;超过则输出 NaN 并记录断档,供后续清洗与预警模块识别。
多源位移序列 → 统一时间轴 → 重采样结果 雷达A(6 min,基准) 00:00 00:06 00:12 00:18 00:24 00:30 雷达B(10 min,时钟偏移 +3 min) 00:03 00:13 00:23 00:33 雷达C(6 min,00:12–00:24 断档) 00:00 00:06 00:24 00:30 断档 > max_gap 对齐+重采样 统一时间轴(10 min 步长) 00:0000:10 00:2000:30 00:4000:50 A:插值 B:插值 C:NaN 红点=断档区间输出 NaN 对齐规则:时间戳统一 UTC → 去重 → 按 10 min 规则轴取值;相邻有效点间隔 ≤ max_gap 才插值,否则置 NaN。 验证:对齐后各序列长度一致、时间戳严格递增、NaN 位置与断档记录一一对应。

可运行的 Python 实现

下面用 pandas 完成对齐与重采样。示例数据为教学构造,时间戳与位移值均为假设值,用于演示处理逻辑,不代表真实监测结果。

import pandas as pd
import numpy as np

# 教学示例:三台雷达的原始位移记录(时间戳为假设值)
raw = {
    "A": pd.DataFrame({
        "ts": pd.to_datetime(["2024-06-01 00:00","2024-06-01 00:06","2024-06-01 00:12",
                              "2024-06-01 00:18","2024-06-01 00:24","2024-06-01 00:30"]),
        "disp": [10.0, 10.6, 11.1, 11.9, 12.4, 13.0]}),
    "B": pd.DataFrame({
        "ts": pd.to_datetime(["2024-06-01 00:03","2024-06-01 00:13",
                              "2024-06-01 00:23","2024-06-01 00:33"]),
        "disp": [10.3, 11.2, 12.1, 13.2]}),
    "C": pd.DataFrame({
        "ts": pd.to_datetime(["2024-06-01 00:00","2024-06-01 00:06",
                              "2024-06-01 00:24","2024-06-01 00:30"]),
        "disp": [9.8, 10.4, 12.2, 12.9]}),
}

STEP = "10min"      # 统一时间基准步长
MAX_GAP = "20min"   # 允许插值的最大相邻间隔(2 倍标称间隔)

def align_one(df, step=STEP, max_gap=MAX_GAP):
    df = df.sort_values("ts").drop_duplicates("ts", keep="last").set_index("ts")
    # 规则时间轴:从最早到最晚,按 step 生成
    axis = pd.date_range(df.index.min(), df.index.max(), freq=step)
    # 先重采样到规则轴,再按间隔限制插值
    s = df["disp"].reindex(df.index.union(axis)).interpolate(method="time")
    s = s.reindex(axis)
    # 计算每个目标时刻与最近有效原始点的间隔,超限置 NaN
    orig = df["disp"]
    gap = pd.Series(index=axis, dtype="timedelta64[ns]")
    for t in axis:
        if t in orig.index:
            gap[t] = pd.Timedelta(0)
        else:
            prev = orig.index[orig.index <= t].max() if (orig.index <= t).any() else pd.NaT
            nxt = orig.index[orig.index >= t].min() if (orig.index >= t).any() else pd.NaT
            d = min([abs(t - prev) if pd.notna(prev) else pd.Timedelta("999D"),
                     abs(nxt - t) if pd.notna(nxt) else pd.Timedelta("999D")])
            gap[t] = d
    s[gap > pd.Timedelta(max_gap)] = np.nan
    return s

aligned = pd.DataFrame({k: align_one(v) for k, v in raw.items()})
print(aligned)

运行后得到统一 10 min 时间轴上的三列位移。雷达 C 在 00:10、00:20 两个时刻因断档超过 max_gap 被置为 NaN,而 A、B 通过时间插值补齐。这样后续速率计算与阈值判定就不会把不同时刻的位移混在一起。

对齐结果的验证要点

检查项通过条件不通过时的处理
时间轴唯一性索引严格递增、无重复去重时保留最后一条并记录
序列长度一致各雷达列长度相同检查时间轴生成范围是否覆盖全部设备
断档标记NaN 位置与断档日志一一对应核对 max_gap 设置是否过宽
插值合理性插值点位于相邻实测值之间检查是否误用了跨断档插值
不要用“按行号对齐”替代时间对齐;也不要在断档区间强行插值,否则会生成虚假的连续位移,直接污染后续速率与预警判定。