PostGIS_小白笔记_清洗轨迹漂移点

背景

因为GPS设备和网络的原因,采集到的位置信息会出现各种异常情况,包括但不限于

  • 设备掉线,导致相邻的两个点之间有很大的时间差和距离(跳跃点)。
  • 设备异常,导致在连续的时间戳下,GPS点位置有突然很大偏差(漂移点)。
  • 设备异常,导致相同时间戳下,返回多条数据(重复数据)。

结合我们的业务场景,我们可以粗略的认为

  • 通过简单的按时间戳去重算法,很容易去掉重复数据。
  • 在可以接受的时间范围内,可以容忍数据中断造成的跳跃点(或者通过拟合算法来模拟缺失数据)。
  • 漂移点会对后续分析造成很大的影响,不能接受明显地漂移(比如跨地区这种光速漂移)。

在数据预处理过程中,我们需要排除掉漂移点数据,严谨的算法有

  • 滑动窗口过滤法(中值,均值);
  • 卡尔曼滤波法;
  • 粒子滤波法;

速度推算法

算法描述和代码

结合具体业务场景(普通小型车辆速度必须在180KM/H以内,重卡速度在100以内),我们这里使用一个简单的算法,基于推算速度进行过滤。思路如下

  1. 假设一段时间内,车辆的速度满足正态分布;
  2. 按时间序列对GPS点进行排序;
  3. 通过相邻两个GPS点之间的时间差和距离差,推算出当前GPS点的速度。
  4. 因为存在缺失点,漂移点等情况,所以推算速度和实际速度并不一样;
  5. 推算速度大于50米/秒(即180KM/H)的数据,疑是漂移点;
  6. 从轨迹序列中去除漂移点;

注意: 这个算法假设正态分布,并预设最大速度阈值,所以结果并不严谨。

drop function if exists f_get_clean_trajectory;
/*
基于推算速度判断异常轨迹点,清除异常点后返回新的轨迹。
@traj 轨迹
@mps_max 用米/秒作为单位的速度阈值
*/
create or replace function f_get_clean_trajectory(traj geometry, mps_max int=50)
  returns geometry
as $$
declare
  traj_clean geometry;
  pt geometry;
  p0 geometry=null;
  dur_meters float=0;
  dur_seconds int=0;
begin
  for pt in select (st_dumppoints(traj)).geom loop
    -- 1st point
    if p0 is null then
      p0 := pt;
      traj_clean := st_makeline(pt);
    -- other points 
    else
      dur_meters := st_distance(pt::geography, p0::geography);
      dur_seconds := st_m(pt) - st_m(p0);
      -- 根据相邻两点的距离和时间,推算当前点的速度。推算速度小于阈值,就认为是正常GPS点
      if ( dur_meters / dur_seconds ) <= mps_max then
        --raise notice '% - % - %',  dur_meters, dur_seconds, ( dur_meters / dur_seconds );
        traj_clean := st_addpoint(traj_clean, pt);
        p0 := pt;
      else
        --raise notice '% - % - %',  dur_meters, dur_seconds, ( dur_meters / dur_seconds );
        null;
      end if;
    end if;
  end loop;
  return traj_clean;
end;
$$ language plpgsql strict;

算法测试

通过观察清洗前后的轨迹图形,人肉评估一下算法的效果。因为样本数据是北京出租车轨迹,在城市内出租车时速不会超过120KM/H,所以我们设置阈值30M/S。

-- 增加一个清洗后轨迹字段
alter table demo.t_taxi_trajectory add column traj_clean geometry;
update demo.t_taxi_trajectory 
  set traj_clean = demo.f_get_clean_trajectory(traj,30)
where traj_clean is null
;

还原轨迹点,并在QGIS展现

-- 还原轨迹点
with dump_pt as
(
  select 
    tid, dt,
    --(st_dumppoints(tr.traj)) as dpt -- 原始轨迹
    (st_dumppoints(tr.traj_clean)) as dpt -- 清洗后轨迹
  from demo.t_taxi_trajectory tr
  where tr.tid = 1353 and tr.dt = '2008-02-03' 
),
--
pt_list as
(
  select 
    (dpt).path[1] as rn,
    (dpt).geom as pt ,
    *
  from dump_pt
)
--
select 
  tid, dt, rn,
  to_timestamp(st_m(pt)) as ts,
  st_distance(pt::geography, (lag(pt) over w)::geography)::int as len_m ,
  to_timestamp(st_m(pt)) - (lag(to_timestamp(st_m(pt))) over w)  as dur,
  pt,
  1 as endflag
from pt_list 
window w as (partition by tid order by dt)
order by tid, ts
;

目测效果-漂移点

效果图如上,红色实线是原始轨迹,蓝色虚线是清洗轨迹。对比可见

  • 正常点的轮廓完全重合,说明整体并没有变形;
  • A点,是明显的漂移点,被清除掉了;
  • B点,不是漂移点,但是轨迹有明显的跳跃,应该是B点附近出现了较长时间缺失点。

目测效果-缺失点

进一步观察,B点序号是913,我们来验证913附近是否出现了长时间缺失点。

rn  |           ts           | len_m |   dur
-----+------------------------+-------+----------
 910 | 2008-02-03 20:25:28+08 |    67 | 00:04:28
 911 | 2008-02-03 20:28:55+08 |     2 | 00:03:27
 912 | 2008-02-03 20:29:36+08 |   355 | 00:00:41
 913 | 2008-02-03 20:46:53+08 |  5945 | 00:17:17
 914 | 2008-02-03 20:58:17+08 | 12019 | 00:11:24
 915 | 2008-02-03 21:02:01+08 |  1636 | 00:03:44
 916 | 2008-02-03 21:02:06+08 |    20 | 00:00:05

从查询结果来看

  • 轨迹点的正常采集时间间隔应该在3分钟之内;
  • 点913,914出现了明显地时间间隔(17分钟,11分钟);
  • 验证了有长时间缺失点的设想;

延展思考: 如果是严格的应用场景,可以在跳跃点附近对这一段轨迹进行拆分,形成连续的多段轨迹数据。

https://juejin.im/post/5df99a2e518825123751c11f

「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论