ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

GPS轨迹噪点剔除:算法原理、参数调优与API实现

GPS轨迹噪点剔除:算法原理、参数调优与API实现 简介针对GPS轨迹数据中常见的噪点与异常值干扰这套Python代码包为开发者提供了一整套降噪解决方案。资源基于轨迹点间的欧氏距离分布设定阈值自动剔除偏离过大的异常点并结合高德地图与百度鹰眼两大在线地图API实现从数据上传、服务器清洗到结果返回的全流程处理。代码共3个Python文件压缩包仅7KB体量小巧却覆盖完整核心脚本负责降噪与平滑处理两个API封装文件分别对接高德和百度轨迹接口免去繁杂签名与请求细节只需调用封装函数即可获得干净轨迹数据。目前已有149人学习下载适合正处理GPS数据、需要快速清洗轨迹的Python开发者、GIS分析人员及算法学习者。通过研读代码既能掌握距离阈值降噪的算法原理也能学习API封装与数据处理实战技巧为智能交通、户外运动等场景下的轨迹分析提供可直接复用的基础工具。1. GPS轨迹噪点剔除为什么先处理脏数据比调业务模型更值钱做车载定位或运动轨迹分析的人大多见过这种画面一段本该沿主干道走的轨迹突然有一两个点扎进旁边的建筑区然后在屏幕或地图上拉出一条几百米的直线。这不是设备坏了而是GPS原始数据天生就带噪点。GPS轨迹噪点剔除降噪API及算法做的事情就是把经纬度序列里明显偏离真实路径的点识别出来、删掉或修正再把干净轨迹交给里程统计、地图匹配、电子围栏这些下游业务。我一般会同时交付两部分一套可独立运行的python算法和一个能暴露成HTTP接口的API服务。适合谁用物流轨迹回溯、共享出行计费、运动APP记录以及需要把第三方GPS定位器数据接进自建系统的开发团队。只要数据源是GPS这篇就能直接参考。2. GPS误差模型与数据接口噪点从哪里来先把数据格式定下来2.1 三种典型噪点形态跳点、慢漂与静止抖动GPS噪点不是一种东西至少分三种形态处理方式完全不同。第一种是跳点也叫离群点。一个点的坐标突然偏离真实位置几百米甚至几公里常见于车辆经过高架桥下、隧道口、密集楼群时卫星信号被遮挡或反射接收机解算出错误的伪距。跳点的特征是瞬时速度极大前后两个间隔的距离除以时间会得到一个离谱的速度值比如从 30km/h 瞬间变成 800km/h。第二种是慢漂。一段时间内的轨迹整体缓慢偏移看起来像一条平行位移的曲线。常见于城市峡谷中可见卫星数量少、卫星几何分布差定位误差呈系统性漂移。慢漂的可怕之处在于它的速度看起来正常大部分阈值算法对它无感。第三种是静止抖动。设备其实没动但坐标在 10 到 30 米半径内来回游走。车载定位器熄火后、运动手表放在桌上时都会这样。如果直接按坐标画轨迹会画出一团乱麻。这三种形态决定了你不能用一把尺子量所有噪声。降噪方案要能同时处理瞬时跳点和缓慢漂移并且对静止场景有专门策略。2.2 误差来源多路径效应、卫星几何与接收机噪声GPS误差来源可以粗分成四层卫星星历误差、电离层和对流层延迟、多路径效应、接收机噪声。前两层属于空间段和传播段误差单点定位无法消除只能靠差分技术或高精度定位模块去压。后两层是算法能处理的范畴。多路径效应最常见也最麻烦。信号打到玻璃幕墙、金属车身、水面再反射进接收机伪距被拉长定位结果就会往反射方向偏。GPS模块的天线走线如果离金属外壳太近、天线净空区不足多路径会更严重。我遇到过一批定位器上报数据噪点率超过 30%换算法没用最后查出来是硬件天线布局的问题。所以做软件降噪前先确认硬件侧的gps误差是否正常算法只是兜底不是万能后悔药。接收机噪声则表现为高频随机抖动幅度小但频率高主要影响静止场景。卡尔曼滤波对这类噪声有较好的压制效果。理解误差来源后你对降噪目标会有一个合理预期降噪不是让轨迹完全贴合真实道路而是把明显不可能的点和大幅抖动的毛刺去掉剩下的事情交给地图匹配去做。2.3 统一输入格式时间戳、经纬度和速度字段的JSON约定做API之前先把数据格式定死。我见过太多轨迹数据源有的给毫秒时间戳有的给秒级时间戳有的把经纬度放在lng/lat有的放在lon/lat还有的混用 GCJ-02 和 WGS84。不统一格式后面所有算法都是空中楼阁。我一般约定如下JSON格式作为API的请求体{ points: [ {ts: 1690000000, lat: 39.9042, lng: 116.4074, speed_kmh: 35.2}, {ts: 1690000010, lat: 39.9043, lng: 116.4075, speed_kmh: 36.1}, {ts: 1690000020, lat: 40.1042, lng: 116.5074, speed_kmh: 35.8} ], max_speed_kmh: 150.0, max_accel_ms2: 8.0 }注意ts统一用秒级Unix时间戳13位毫秒时间戳在进入算法前先除以1000否则算出来的速度会小1000倍。speed_kmh是可选字段很多定位器硬件会上报速度但硬件算的速度在静止漂移时往往非零、不可信所以算法不依赖这个字段只把它当参考。坐标系默认WGS84GCJ-02坐标系的数据进来前要转换API内部不处理坐标系偏移。输出格式同样要固定否则下游接起来乱{ clean_points: [ {ts: 1690000000, lat: 39.9042, lng: 116.4074}, {ts: 1690000010, lat: 39.9043, lng: 116.4075} ], removed_indices: [2], statistics: { total: 3, removed: 1, clean: 2 } }removed_indices返回原始数组中的下标方便调用方做数据对齐和审计。statistics里放统计字段让调用方一眼看到这次调用剔除的比例。一个包含原始索引的返回结构在后续排查哪个点为什么被删时能省大量时间。3. 用速度与加速度双阈值做第一版降噪APIPython实现与三个必调参数3.1 为什么第一版先上启发式阈值法第一版方案我强烈建议从速度和加速度双阈值开始不要一上来就卡尔曼滤波或DBSCAN聚类的全家桶。理由是启发式阈值法逻辑直观、运行开销小、参数可解释出了问题能一眼定位。对于以跳点为主的轨迹数据它能解决 80% 的噪点问题。卡尔曼滤波适合做平滑而不是删点DBSCAN聚类适合离线批量清洗它们各有代价后面章节展开。第一版API的主要目标是能在线上把明显不合理的点剔掉并且让业务方理解为什么这个点被删了。阈值法天然满足这两点一个点的瞬时速度超过设定的最大速度或者加速度超过物理极限它就有问题。这个方法有明确的物理依据。普通乘用车的合法行驶速度不会超过 160km/h急加速的加速度一般不超过 3-5m/s²急刹车也不超过 8-10m/s²。一个 GPS 点如果要用 800km/h 的速度才能从上一个点飞到当前位置那它几乎不可能是真实位置。3.2 核心算法速度与加速度双阈值剔除的Python代码下面这段代码是完整可运行的降噪核心输入符合条件的轨迹点列表输出清洗后的索引列表和被剔除的索引列表。import math from typing import List, Dict, Tuple EARTH_RADIUS_M 6371000.0 def haversine_m(lat1: float, lng1: float, lat2: float, lng2: float) - float: 计算两个经纬度点之间的球面距离单位米 p1, p2 math.radians(lat1), math.radians(lat2) dp math.radians(lat2 - lat1) dl math.radians(lng2 - lng1) a math.sin(dp / 2) ** 2 math.cos(p1) * math.cos(p2) * math.sin(dl / 2) ** 2 return 2 * EARTH_RADIUS_M * math.asin(math.sqrt(a)) def speed_between(points: List[Dict], i: int, j: int) - float: 计算 points[i] 到 points[j] 的瞬时速度单位km/h dt abs(points[j][ts] - points[i][ts]) if dt 1: return 0.0 d haversine_m(points[i][lat], points[i][lng], points[j][lat], points[j][lng]) return d / dt * 3.6 # m/s - km/h def denoise_by_threshold( points: List[Dict], max_speed_kmh: float 150.0, max_accel_ms2: float 8.0, ) - Tuple[List[int], List[int]]: 速度加速度双阈值剔除噪点。 参数: points: [{ts: 秒级时间戳, lat: 纬度, lng: 经度}, ...] max_speed_kmh: 最大允许速度超过则判为可疑点 max_accel_ms2: 最大允许加速度超过则判为可疑点 返回: (clean_indices, removed_indices) n len(points) removed [False] * n # 第1轮速度阈值 # 用前后两段速度的较小值做判断避免把高速行驶中的正常点误删 for i in range(1, n - 1): v_back speed_between(points, i - 1, i) v_fwd speed_between(points, i, i 1) if min(v_back, v_fwd) max_speed_kmh: removed[i] True # 第2轮加速度阈值 # 相邻两段速度变化率超过物理极限判为跳点 for i in range(1, n - 1): if removed[i]: continue v_prev speed_between(points, i - 1, i) v_next speed_between(points, i, i 1) dt abs(points[i 1][ts] - points[i - 1][ts]) if dt 0: continue accel abs(v_next - v_prev) * 1000 / 3600 / dt # km/h - m/s, 再除以秒 if accel max_accel_ms2: removed[i] True clean_idx [i for i in range(n) if not removed[i]] removed_idx [i for i in range(n) if removed[i]] return clean_idx, removed_idx逻辑说明第一轮速度检查之所以取min(v_back, v_fwd)是因为真实轨迹在正常高速行驶时前一段速度大、但后一段速度会回落两者取小值可以避免把高速路上正常行驶的点误删。而真正的跳点从前一个点跳过来和跳向下一个点的速度都会异常大min 之后依然超阈值。第二轮加速度检查针对的是速度变化率异常的孤立点。比如前一段速度 30km/h后一段速度变成 300km/h这中间的点几乎不可能真实存在。时间间隔用 i-1 到 i1 的总时长相当于把速度变化摊到两个采样周期上看避免单段时间过短导致数值爆炸。3.3 用FastAPI封装成可调用的HTTP接口算法写好后用FastAPI封装成独立服务。FastAPI 自带请求体校验和接口文档对内外协作都方便。from fastapi import FastAPI, HTTPException from pydantic import BaseModel from typing import List, Optional app FastAPI(titleGPS Trajectory Denoise API, version0.1.0) class TrackPoint(BaseModel): ts: int # 秒级Unix时间戳 lat: float lng: float speed_kmh: Optional[float] None # 硬件上报速度仅参考 class DenoiseRequest(BaseModel): points: List[TrackPoint] max_speed_kmh: Optional[float] 150.0 max_accel_ms2: Optional[float] 8.0 class DenoiseResponse(BaseModel): clean_points: List[TrackPoint] removed_indices: List[int] statistics: dict app.post(/api/denoise, response_modelDenoiseResponse) def denoise(req: DenoiseRequest): if len(req.points) 3: raise HTTPException(status_code400, detail至少需要3个轨迹点) pts [p.model_dump() for p in req.points] clean_idx, removed_idx denoise_by_threshold( pts, max_speed_kmhreq.max_speed_kmh, max_accel_ms2req.max_accel_ms2, ) clean_points [pts[i] for i in clean_idx] return DenoiseResponse( clean_pointsclean_points, removed_indicesremoved_idx, statistics{ total: len(pts), removed: len(removed_idx), clean: len(clean_idx), }, )启动服务用uvicorn main:app --host 0.0.0.0 --port 8000然后curl -X POST http://localhost:8000/api/denoise -H Content-Type: application/json -d body.json就能调。接口文档自动生成在/docs路径前端或测试同学可以直接打开浏览器调试。注意代码里的model_dump()是 Pydantic v2 的写法如果环境里是 v1要改成.dict()。FastAPI 在这两个版本下都能跑但序列化方法不通用这是个容易忽略的细节。3.4 参数必调清单max_speed_kmh、max_accel_ms2与时间间隔参数调优是最玄学的部分不同业务场景差异很大。先给一张经验参数表参数默认值适用场景建议max_speed_kmh150一般车辆轨迹高速场景可放宽到 180骑行/步行场景必须收到 30 以下max_accel_ms28.0一般车辆出租车/网约车可放宽到 12物流货车建议 6-8时间间隔dt1秒高频定位器上报间隔大于 10 秒时速度阈值要放松否则连续两点间距离天然大车辆场景max_speed_kmh设 150 基本够用。但如果你处理的轨迹来自电动自行车或行人默认值会漏掉大量跳点必须下调。有一个技巧先统计正常数据里相邻点速度的 P99 分位数用这个值乘以 1.5 作为初始阈值比拍脑袋准得多。时间间隔这个参数很关键。低频轨迹比如 30 秒一个点的相邻点距离天然很大速度算出来轻松超过 200km/h但这不是噪点。处理低频数据时要么把max_speed_kmh调高要么按实际时间间隔做分桶后分别设阈值。4. 从速度阈值到聚类算法与卡尔曼滤波离线清洗和轨迹平滑的进阶选择4.1 速度阈值处理不了的两种场景双阈值法在两类场景下会失效连续漂移和静止抖动。连续漂移的特点是一段轨迹整体偏移但段内点与点的速度正常。比如车辆在街道上直线行驶多路径效应让整段坐标往北偏了 50 米这段轨迹的内部相对位置是正确的速度检查完全通过。双阈值算法会把它当干净数据放过。静止抖动的问题正好相反。设备停在原地GPS坐标在小范围内随机游走速度值都很小远低于阈值。如果画在地图上会看到一团杂乱的点云而不是一个静止点。这两种场景分别对应聚类算法和卡尔曼滤波的用武之地。4.2 DBSCAN聚类降噪的Python实现与eps、min_samples设参DBSCAN 聚类算法的核心思想是把空间上密集分布的点归为一个簇离所有簇都太远的点标记为噪点。在轨迹场景中跳点通常空间上孤立与前后点距离远超正常采样间距因此会被聚类算法自然识别出来。from sklearn.cluster import DBSCAN import numpy as np def denoise_by_dbscan( points: List[Dict], eps_m: float 30.0, min_samples: int 2, ) - Tuple[List[int], List[int]]: 用DBSCAN聚类剔除空间离群点。 适用于离线批量处理需要完整轨迹段参与聚类。 if len(points) min_samples 1: return list(range(len(points))), [] # 把经纬度投影到近似平面坐标单位换算成米 # 以第一个点为基准点小范围内这种等距近似足够用 lat0, lng0 points[0][lat], points[0][lng] coords [] for p in points: x (p[lng] - lng0) * 111320.0 * np.cos(np.radians(lat0)) y (p[lat] - lat0) * 110540.0 coords.append([x, y]) X np.array(coords) clustering DBSCAN(epseps_m, min_samplesmin_samples, metriceuclidean) labels clustering.fit_predict(X) # labels -1 表示噪点 removed_idx [i for i, lab in enumerate(labels) if lab -1] clean_idx [i for i, lab in enumerate(labels) if lab ! -1] return clean_idx, removed_idx参数设置是这个方案的核心。eps_m是邻域半径单位是米它取决于正常轨迹的采样间距1 秒一个点的车辆轨迹点间距 10-30 米eps 设 30 比较合适如果轨迹低频、点间距天然在 100 米以上eps 要相应放大。min_samples在轨迹场景中一般设 2 或 3。设 2 意味着一个点周围 2 个点内至少要有 1 个邻居才能成簇孤立跳点会被标记为 -1。设太大会把真实轨迹的端点误删因为轨迹两端的点天然邻居少。这个算法的前提是投影后的误差异可接受。小范围内的等距近似投影在几公里范围内误差不超过几米对聚类判断足够。但要注意 DBSCAN 不看时间顺序它只依赖空间分布。如果一条轨迹在同一个地方来回绕圈或者低采样率导致点与点之间断开聚类结果会不稳定。4.3 卡尔曼滤波平滑轨迹状态方程、噪声矩阵与Python实现卡尔曼滤波做的事情和删点不同它把轨迹上的每个点修正到更可信的位置。对持续慢漂移和接收机噪声平滑效果显著。我用的模型是恒定速度模型状态向量为[纬度, 经度, 纬度方向速度, 经度方向速度]。import numpy as np def kalman_smooth( points: List[Dict], process_noise: float 1e-4, measure_noise: float 4.0, ) - List[Dict]: 恒定速度模型卡尔曼平滑返回修正后的轨迹点。 注意输入前要把经纬度换算成米制平面坐标 否则噪声协方差矩阵的单位米²与状态度不匹配。 if len(points) 2: return points # 转米制坐标以第一个点为原点 lat0, lng0 points[0][lat], points[0][lng] raw [] for p in points: x (p[lng] - lng0) * 111320.0 * np.cos(np.radians(lat0)) y (p[lat] - lat0) * 110540.0 raw.append([x, y]) n len(raw) dt 1.0 # 均匀采样时的默认值非均匀轨迹在循环内按实际值更新 # 状态转移矩阵 F F np.array([ [1, 0, dt, 0], [0, 1, 0, dt], [0, 0, 1, 0], [0, 0, 0, 1], ], dtypefloat) # 观测矩阵 H只观测位置不观测速度 H np.array([ [1, 0, 0, 0], [0, 1, 0, 0], ], dtypefloat) # 过程噪声与观测噪声 Q np.eye(4) * process_noise R np.eye(2) * measure_noise # 初始状态前两个点估计初始位置和速度 x np.array([raw[0][0], raw[0][1], 0.0, 0.0], dtypefloat) P np.eye(4) * 10.0 smoothed_xy [] for i in range(n): z np.array(raw[i], dtypefloat) # 非均匀采样时用实际时间差更新 F if i 0: dt_real max(points[i][ts] - points[i - 1][ts], 1.0) F[0, 2] dt_real F[1, 3] dt_real # 预测 x_pred F x P_pred F P F.T Q # 更新 y z - H x_pred S H P_pred H.T R K P_pred H.T np.linalg.inv(S) x x_pred K y P (np.eye(4) - K H) P_pred smoothed_xy.append([x[0], x[1]]) # 转回经纬度输出 smoothed [] for i, (x, y) in enumerate(smoothed_xy): smoothed.append({ ts: points[i][ts], lat: y / 110540.0 lat0, lng: x / (111320.0 * np.cos(np.radians(lat0))) lng0, }) return smoothed两个噪声参数是调节平滑强度的关键。measure_noise表示对GPS单点观测的信任程度取值与定位精度相关开阔地带定位精度约 3-5 米可以设 4 左右城市峡谷中误差更大可以设 10-20数值越大滤波输出越平滑但也越滞后。process_noise表示对运动模型的信任度目标运动越剧烈这个值要越大否则滤波结果会出现明显滞后轨迹被拉直。4.4 三套方案怎么选型方案适用场景实时性特点速度加速度阈值在线API跳点为主单点级实时简单直观参数可解释对连续漂移无效DBSCAN聚类离线批量清洗需要整段数据识别空间离群点强受采样密度影响大卡尔曼滤波在线平滑慢漂/抖动单点级实时不删点只修正参数调不好会滞后我的习惯是组合使用线上 API 用双阈值法快速剔除明显跳点离线修复历史轨迹时先跑 DBSCAN 删空间离群点再用卡尔曼滤波平滑剩余轨迹。三条路径互相补充单靠其中任何一个都覆盖不了全部噪点形态。5. GPS降噪API落地避坑5个高频问题与排查思路5.1 阈值调大漏噪、调小误删高速公路正常点被当跳点现象把max_speed_kmh设成 120结果高速上正常行驶的轨迹被删掉一大片调到 250漏删的跳点明显增多。原因高速上的真实速度接近阈值上限速度波动稍微大一点就会超过阈值。另一个隐蔽因素是GPS误差本身会放大瞬时速度一个点随机偏差 20 米1 秒间隔下就会造成 72km/h 的虚增速度。解决不要用单段速度做判断改用前后两段速度取小值的策略代码里已经这样处理。更稳的办法是先用一段正常历史轨迹统计速度分布取 P99 分位数再乘 1.3-1.5 作为阈值。这个思路在低速场景同样适用。5.2 设备静止但轨迹缓慢漂移速度阈值完全失效现象设备停在停车场几个小时后轨迹在地图上画出几十米的杂乱线段速度值全程不超过 10km/h双阈值法一个点都没删。原因静止漂移是接收机噪声和卫星几何变化造成的坐标游走速度特征与真实移动接近阈值法无法区分缓慢移动和静止漂移。解决如果业务能拿到车辆的熄火/点火状态优先用硬件状态位决定是否过滤静止段。拿不到状态位时对连续 5 分钟以上位移小于 50 米的片段单独做聚类取该簇的中心点作为整段的锚点坐标替换掉这段原始点。前后两段的轨迹用插值连接。5.3 时间戳抖动导致瞬时速度异常现象同一批设备的轨迹点时间戳不是严格等间隔偶尔出现相邻两个点时间差只有 0.3 秒、甚至为 0 的情况速度计算值异常放大。原因定位器上报机制不保证固定周期有的设备在信号差的时候会缓存点然后集中补报缓存点的时间戳是真实采点时刻但到达服务器的顺序可能错乱。更常见的是 13 位毫秒时间戳混在 10 位秒级时间戳里没做归一化。解决进入算法前先做时间戳归一化统一转成秒级浮点数。顺带做一次时间排序确保points按ts升序排列。代码中dt 1时速度直接赋 0就是为了防止 0 间隔导致除零异常。5.4 经纬度直接进卡尔曼滤波量纲不匹配导致参数没法调现象把纬度值比如 39.9042和经度值直接作为卡尔曼滤波的状态量measure_noise设成 4想象成4米滤波结果完全不对轨迹要么不动要么乱跳。原因经纬度的单位是度度与米的换算比例不是 1:1。纬度 1 度约 110540 米经度 1 度在赤道约 111320 米、在纬度 40 度约 85265 米。把 4 米写成 4 度相当于把观测噪声放大了 4 万倍滤波器几乎完全忽略观测值。解决卡尔曼滤波前必须把经纬度投影到米制平面坐标滤波完成后再转回经纬度。4.3 节代码里已经做了这一步。另一个容易忽略的点是纬度和经度的米制缩放系数不同转换时必须分别乘以对应系数不能只乘一个统一值。5.5 剔除后轨迹断裂下游地图匹配反而变差现象噪点剔除后轨迹出现空洞地图匹配算法在空洞处频繁切换道路路程统计结果甚至比清洗前更差。原因跳点剔除后留下的空洞地图匹配需要跨越空洞猜测路径如果空洞前后点的时间间隔过大比如 30 秒以上匹配算法的搜索空间暴增误匹配概率升高。解决设定一个时间间隔阈值超过它时对空洞做线性插值而不是直接跳过。插值点不参与统计只保证轨迹连续。注意插值只适用于短空洞一般 5 分钟以内长空洞建议直接切段。被剔除点的索引要保留在返回结构里这样下游能区分真实点和插值点避免把插值数据误用于计费。6. 用仿真轨迹做回归测试降噪效果怎么验证才靠谱算法上线前最怕的事情是凭感觉调参。我习惯的做法是先构造一条带标签的仿真轨迹注入已知噪点跑完算法后对比标签量化评估再决定参数去留。import numpy as np np.random.seed(42) # 构造理想轨迹100秒匀速直线行驶 t np.arange(100) lat 39.90 0.0001 * t # 每秒向北约11米 lng 116.40 0.0001 * t # 每秒向东约9米 # 叠加高斯噪声模拟GPS误差标准差约5米 lat np.random.normal(0, 0.00005, sizet.size) lng np.random.normal(0, 0.00005, sizet.size) # 注入3个真实跳点记录标签 gt np.zeros(t.size, dtypeint) for j in [20, 55, 80]: lat[j] 0.003 # 约330米偏移 lng[j] 0.003 gt[j] 1 # 组装成API输入格式 points [ {ts: int(1690000000 i), lat: float(lat[i]), lng: float(lng[i])} for i in range(t.size) ] # 跑降噪算法 clean_idx, removed_idx denoise_by_threshold( points, max_speed_kmh30.0, max_accel_ms25.0 ) pred np.zeros(t.size, dtypeint) pred[removed_idx] 1 # 计算精确率与召回率 tp np.sum((pred 1) (gt 1)) fp np.sum((pred 1) (gt 0)) fn np.sum((pred 0) (gt 1)) precision tp / (tp fp) if tp fp 0 else 0.0 recall tp / (tp fn) if tp fn 0 else 0.0 print(fprecision{precision:.3f}, recall{recall:.3f})这段代码的评估逻辑很直观gt是真实标签pred是算法预测精确率表示删掉的点里真噪点的比例召回率表示真噪点被找到的比例。好的降噪参数应该让两者同时接近 1.0。如果召回率低说明阈值太宽漏了噪点如果精确率低说明阈值太紧误删了正常点。把仿真轨迹换成真实历史轨迹时我会标注一小段100-200 个点作为固定回归集每次调整算法或参数后重跑一遍保证改动不会让效果倒退。这个过程比任何文档都有说服力。后来我养成的习惯是任何GPS降噪算法的改动必须附带一份前后对比轨迹图才能提交评审。画图用 matplotlib把原始轨迹、清洗轨迹、被剔除点叠加在一张图上人工扫一眼就能判断有没有明显逻辑错误。这一步帮我拦下过好几次翻车改动。希望帮到你。本文还有配套的精品资源点击获取
返回列表