4. 轨迹数据预处理

农机在田间作业时,北斗/GNSS终端通常以1~5 Hz的频率记录定位点,一条完整的作业轨迹动辄数万甚至数十万个点。但原始轨迹几乎不可能直接用于面积计算或质量评价:卫星信号在树荫、机库、高压线附近会发生多路径反射,产生偏离田块的“漂移点”;终端在低速或停车状态下反复输出同一位置,形成“重复点”;信号遮挡或设备断电又会导致时间间隔异常,形成“缺失段”。本节围绕这三类问题,讲清楚判断依据、清洗方法和实际操作。

一、先明确判断标准,再动手清洗

清洗不是盲目删点,而是先建立可量化的判据。工程上常用的三个基础量是:相邻点间距离、瞬时速度、时间间隔。设相邻两点为 Pi(xi, yi, ti) 与 Pi+1,则

d_i = √[(x_{i+1}-x_i)² + (y_{i+1}-y_i)²]      # 平面距离,单位 m
v_i = d_i / (t_{i+1} - t_i)                     # 瞬时速度,单位 m/s
Δt_i = t_{i+1} - t_i                            # 采样间隔,单位 s

以拖拉机田间作业为例,合理假设其作业速度不超过 3 m/s(约 10.8 km/h),转场速度不超过 8 m/s。若某点计算出的 vi 超过 8 m/s,且前后两点距离都很近,则该点极可能是漂移点;若 Δti 远大于正常采样间隔(如 1 s 采样却出现 60 s 间隔),则说明中间存在缺失段,不能简单当作匀速插值处理。需要强调的是,这些阈值必须结合机具类型、采样频率和作业场景设定,不能照搬。

二、三类问题的处理策略

漂移点:阈值过滤 + 邻域一致性检验。 单纯用速度阈值会误删高速转场段的正常点,因此更稳妥的做法是“速度阈值初筛 + 邻域一致性复核”。具体做法:对每个点计算其与前后各 2 个点的平均距离,若该点速度超阈值、且它到前后点的距离都显著大于邻域平均距离,则判定为孤立漂移点并剔除。对于连续多个点整体偏移(如整段信号跳变),则需按段标记,整段剔除后重新连接。

重复点:按距离与时间双重去重。 当机具停车怠速时,终端仍持续输出坐标,相邻点距离可能小于 0.1 m。处理时设定最小位移阈值(如 0.2 m),若连续点间距离小于该阈值且时间间隔小于设定值,则仅保留首点。注意:停车点本身是有意义的作业状态信息,去重时应保留“进入停车”和“离开停车”两个端点,而不是把整段停车记录全部删除。

缺失值:区分“可插值”与“不可插值”。 短时缺失(如 1~3 个采样周期)可用线性插值或三次样条补齐;但若缺失时间超过设定上限(如 10 s),或缺失期间机具可能转弯、掉头,则不应插值,而应把轨迹在此处断开为两段,避免凭空生成一条穿过田块的虚假直线,污染后续面积统计。

判断顺序建议:先按时间排序并检查 Δt 异常 → 再做重复点去重 → 然后漂移点过滤 → 最后处理缺失段。顺序颠倒会导致阈值计算基于脏数据,误判率上升。

三、平滑算法:让轨迹更贴近真实行驶线

过滤只能去掉明显异常点,剩余点仍带有 1~3 m 的随机抖动。此时可用平滑算法抑制高频噪声。常用方法有两类:

  • 滑动平均:对每个点取前后各 k 个点的坐标均值。实现简单,但会“削平”转弯处的尖角,k 越大越明显,适合直线作业段。
  • Savitzky-Golay 滤波:在滑动窗口内做低阶多项式最小二乘拟合,取拟合值作为输出。它能在去噪的同时较好保留转弯形态,窗口长度取奇数(如 7、9、11),多项式阶数取 2 或 3。对 1 Hz 采样、速度 1.5 m/s 的作业轨迹,窗口 9 点约对应 13.5 m 的行驶距离,是一个可参考的起点。

平滑参数不是越大越好。窗口过大,地头掉头的小半径圆弧会被拉直,导致作业幅宽覆盖判断失真。实操中可先用小窗口试算,观察转弯处曲率变化,再逐步调整。

四、实战操作示例

下面给出一段基于 Python 的清洗流程示例(示例参数,非实测结果),输入为按时间排序的 CSV,字段为 time、lon、lat:

import pandas as pd, numpy as np
from scipy.signal import savgol_filter

df = pd.read_csv("track.csv", parse_dates=["time"])
df = df.sort_values("time").reset_index(drop=True)

# 1. 投影到平面(示例:简化为等距圆柱近似,实际应使用当地投影)
df["x"] = (df.lon - df.lon.mean()) * 111320 * np.cos(np.radians(df.lat.mean()))
df["y"] = (df.lat - df.lat.mean()) * 110540

# 2. 计算距离、速度、时间间隔
dx, dy = df.x.diff(), df.y.diff()
df["d"]  = np.hypot(dx, dy)
df["dt"] = df.time.diff().dt.total_seconds()
df["v"]  = df.d / df.dt

# 3. 重复点去重:位移小于 0.2 m 且间隔小于 2 s
mask_dup = (df.d < 0.2) & (df.dt < 2)
df = df[~mask_dup].reset_index(drop=True)

# 4. 漂移点过滤:速度超 8 m/s 且邻域距离异常
df["d_prev"] = df.d.shift(1)
df["d_next"] = df.d.shift(-1)
mask_drift = (df.v > 8) & (df.d_prev > 5) & (df.d_next > 5)
df = df[~mask_drift].reset_index(drop=True)

# 5. 缺失段断开:间隔超过 10 s 处打段号
df["seg"] = (df.dt > 10).cumsum()

# 6. 分段 Savitzky-Golay 平滑
for s, g in df.groupby("seg"):
    if len(g) >= 9:
        df.loc[g.index, "x_s"] = savgol_filter(g.x, 9, 2)
        df.loc[g.index, "y_s"] = savgol_filter(g.y, 9, 2)

运行后应重点检查三件事:一是清洗前后点数变化比例,若删除超过 20%,说明阈值可能过严或原始数据质量差,需要回看原始轨迹;二是分段数量,段数过多意味着缺失频繁,应排查终端供电或信号环境;三是平滑前后转弯处的轨迹形态,若掉头圆弧被明显压扁,应减小窗口长度。

农机轨迹清洗与去噪处理链 原始轨迹(含三类问题) 漂移点 重复点 缺失段 清洗判据与操作 ① 时间排序,检查 Δt 异常 ② 去重:d < 0.2 m 且 Δt < 2 s ③ 漂移:v > 8 m/s 且邻域异常 ④ 缺失:Δt > 10 s 处断开分段 平滑与质量检查 Savitzky-Golay(窗口9,阶数2) 或滑动平均(直线段适用) 检查:删除比例 < 20% 检查:分段数、转弯形态 清洗前后对比(示意) 清洗前:抖动 + 漂移 + 断点 清洗后:连续、平滑、无孤立点 正常点 漂移点 重复点 缺失段

清洗完成后,建议把处理参数(速度阈值、去重距离、缺失上限、平滑窗口)与清洗统计(原始点数、删除点数、分段数)一并记录在数据说明中。同一批次作业的轨迹应使用同一套参数,否则不同地块之间的面积与轨迹质量指标将失去可比性。这也是后续作业质量分析能够成立的前提。