如何去除GPS骑行轨迹中的海拔异常值?
桥梁/隧道处海拔异常值的去除方法
一、基于运动状态+地形的规则过滤
桥梁/隧道处的异常值通常有两个核心特征:一是短距离内海拔突变(比如桥梁段突然升高几十米又快速回落,隧道段则是突然降低再回升);二是这段轨迹的速度稳定(骑行通过桥梁/隧道时不会出现大幅变速)。
可以通过设定阈值实现过滤:
- 计算相邻点的海拔差Δh,若|Δh|超过设定阈值(比如10米,可根据当地地形灵活调整)
- 同时检查这段区间的速度波动(比如滑动窗口内速度标准差小于±2km/h)
- 满足条件则标记为异常段,用前后正常海拔的线性插值替换
代码示例(Python):
import pandas as pd import numpy as np # 读取轨迹数据 df = pd.read_csv("track_data.csv") # 计算相邻海拔差绝对值 df["delta_h"] = df["altitude"].diff().abs() # 计算骑行速度(假设distance单位为米,采样间隔1秒,转成km/h) df["speed"] = df["distance"].diff() * 3.6 # 标记异常段:海拔突变+速度稳定 threshold_h = 10 threshold_speed_std = 2 df["is_outlier"] = (df["delta_h"] > threshold_h) & (df["speed"].rolling(window=5).std() < threshold_speed_std) # 用线性插值替换异常值 df["altitude_clean"] = df["altitude"].mask(df["is_outlier"], np.nan) df["altitude_clean"] = df["altitude_clean"].interpolate(method="linear")
二、滑动窗口自适应滤波
普通均值/中位数滤波容易模糊正常地形起伏,改用自适应滑动窗口滤波更适配骑行轨迹:
- 窗口大小根据局部海拔波动动态调整:地形平缓时用大窗口(增强平滑效果),地形起伏大时用小窗口(保留真实地形)
- 对窗口内数据用中位数过滤,剔除偏离中位数超过2倍标准差的点
代码示例:
def adaptive_median_filter(series, base_window=5, max_window=15): cleaned_data = [] for idx in range(len(series)): # 根据局部海拔波动调整窗口大小 window_size = base_window if idx > base_window and idx < len(series)-base_window: local_std = series[idx-base_window:idx+base_window].std() if local_std < 2: # 地形平缓,放大窗口 window_size = min(max_window, base_window*2) # 确定窗口边界 start = max(0, idx - window_size//2) end = min(len(series), idx + window_size//2 +1) window_data = series[start:end] median_val = np.median(window_data) std_val = window_data.std() # 替换异常值 if abs(series[idx] - median_val) > 2*std_val: cleaned_data.append(median_val) else: cleaned_data.append(series[idx]) return pd.Series(cleaned_data) df["altitude_clean"] = adaptive_median_filter(df["altitude"])
三、结合DEM数据的分段修正
既然已经用DEM做了海拔增强,可进一步针对桥梁/隧道优化:
- 通过轨迹匹配地图数据(或手动标记)定位桥梁/隧道的地理边界
- 桥梁段:用DEM提供的桥面海拔(而非地面海拔)替换异常值;隧道段:用入口/出口的海拔做线性插值填充
- 若没有精确边界,可通过海拔突变段定位异常区间,直接用DEM的平滑地形数据覆盖
四、轨迹剖面拟合修正
将整个海拔剖面视为连续曲线,用三次样条拟合剔除异常值:
- 先标记明显偏离DEM数据的点(比如偏差超过15米)
- 用剩余正常点做三次样条拟合,生成平滑的海拔曲线
- 用拟合曲线的值替换原始异常点
代码示例:
from scipy.interpolate import CubicSpline # 假设dem_alt是DEM处理后的海拔数据 df["dem_delta"] = abs(df["altitude"] - df["dem_alt"]) df["is_outlier"] = df["dem_delta"] > 15 # 提取正常点的索引和海拔 valid_idx = df[~df["is_outlier"]].index valid_alt = df[~df["is_outlier"]]["altitude"] # 三次样条拟合生成平滑曲线 cs = CubicSpline(valid_idx, valid_alt) df["altitude_clean"] = cs(df.index)
内容的提问来源于stack exchange,提问作者DJJazz
相关产品推荐
相关产品推荐

