【技术教程】如何获取道路实时车速?丨城市数据派 您所在的位置:网站首页 平均车速怎么计算 【技术教程】如何获取道路实时车速?丨城市数据派

【技术教程】如何获取道路实时车速?丨城市数据派

2024-06-26 18:44| 来源: 网络整理| 查看: 265

图2 获取的道路矢量数据和路况

获取数据2. 道路当前车速

对于所关注的路段,可以得到它当前的通行车速,单位为km/h。

图3 道路当前车速

获取数据3. 道路历史车速

对于关注的路段,可记录它在历史不同时刻的车速。

点击图3中的详情,以折线图形式展示过去24小时内的数据,采集频率为10分钟一次。

图4 历史车速

准备工作

1. 申请自己的高德路径规划API的key,大家可自行上官网申请。目前这个接口是免费的,并且每天免费调用次数相当多;只要高德地图能够导航到的地方,就能用这个接口。

2. 了解高德导航接口,即高德路径规划API的规则,官网地址如下,只需看驾车路径规划部分:https://lbs.amap.com/api/webservice/guide/api/direction

3. ArcGIS, 用来描点和画线。

方法原理

在高德地图中选定合理的OD点,然后利用高德路径规划接口定时每10分钟抓取一次数据,并对数据进行匹配、速度计算等处理后存入数据库,归档现状和历史数据。

具体操作步骤

获取路网底图

首先得有个矢量路网作为参考底图,在路网中根据需求绘制OD点用来导航。路网的获取方法我在之前一篇文章中有详细的介绍, 这里就不多说了。原文见-->

路网模型构建

许新昆,公众号:城市数据派 惊艳!这样处理可得到细至可用于交通模型的路网数据丨城市数据派

路网模型构建

许新昆,公众号:城市数据派 惊艳!这样处理可得到细至可用于交通模型的路网数据丨城市数据派

如果没有高德路网,用OSM路网应该勉强也行,不过记得把坐标系转为高德坐标。

为保证路网的准确,我用的是高德的原始路网,研究区域内的局部道路如图5所示。为了能看清道路的方向,我给每条”线”(路段)添加了方向箭头,可以看到,对于双向道路,不同通行方向用不同的线表示,每条道路由很多条”线”组成。

图5路网底图

绘制OD点

以上图为例,如果想知道进香河路由北往南的车速,可以在这条路的最北处设置一个起点,最南处设置一个终点,进行导航,该方法可行,但是你得为每一条路的每一个方向设置一个起终点进行,费时费力还费key,目前大多数人都是这么做的。

但其实仔细阅读官方API文档,会发现路径规划接口有个参数waypoints,说明摘录如下。

waypoints---途径点:

规则1: 经度和纬度用","分割,经度在前,纬度在后,小数点后不超过6位,坐标点之间用";"分隔;

规则2: 最大数目:16个坐标点。如果输入多个途径点,则按照用户输入的顺序进行路径规划.

高德路径规划API文档

waypoints---途径点:

规则1: 经度和纬度用","分割,经度在前,纬度在后,小数点后不超过6位,坐标点之间用";"分隔;

规则2: 最大数目:16个坐标点。如果输入多个途径点,则按照用户输入的顺序进行路径规划.

高德路径规划API文档

简单来说,可以在waypoints里面加入途径点,这样只需调用接口一次就能得到原先最多16次导航的数据,这大大减小了key的调用次数。强烈推荐使用waypoints设置中途点。

具体怎么做呢,我们知道,线由多个点构成,于是我们可以画一条包含多个点的线,然后将线的第一个点作为起点,第二、三……n-1个点作为waypoints途径点,最后一个点作为终点,以图6小区域为例,我画了一条包含9个点的(黑)线,组成线的点的顺序我用序号标出来了,这样只需导航一次,就能获取图中八条路(绿线)的车速了。

图6 利用waypoints设置中途点

实际上,对于示例中从东大到新街口围起来的区域,我只画了6条线就将所有道路捕捉到了,也就是说只调用了6次key就搞定了这样一片区域的所有道路。按照这种方法,如果想获得整个南京市所有道路的速度,画100多条线就够了,按照key每天额度30000次算,每10分钟调用一次都够用。(我做的这个示例就是每10分钟调一次)。

关于如何从线中依次抽取点构成waypoint参数,方法有很多, 我这里给出oracle数据库参考代码。别看代码很长,以下代码只是一条SQL语句,其中,GD_NAV_ROAD为保存画线的表名。

WITHDSE AS (SELECT OBJECTID,PROJECT,TO_CHAR(ROUND(BB.X,6))||','||TO_CHAR(ROUND(BB.Y,6)) S, TO_CHAR(ROUND(CC.X,6))||','||TO_CHAR(ROUND(CC.Y,6)) E FROM GD_NAV_ROAD AA, table(SDO_UTIL.GETVERTICES(AA.POLYLINE)) BB,table(SDO_UTIL.GETVERTICES(AA.POLYLINE)) CC WHERE BB.ID = 1 AND CC.ID = SDO_UTIL.GETNUMVERTICES (AA.POLYLINE)),D2 AS (SELECT OBJECTID,TO_CHAR(ROUND(BB.X,6))||','||TO_CHAR(ROUND(BB.Y,6)) D FROM GD_NAV_ROAD AA, table(SDO_UTIL.GETVERTICES(AA.POLYLINE)) BB WHERE BB.ID = 2),D3 AS (SELECT OBJECTID,TO_CHAR(ROUND(BB.X,6))||','||TO_CHAR(ROUND(BB.Y,6)) D FROM GD_NAV_ROAD AA, table(SDO_UTIL.GETVERTICES(AA.POLYLINE)) BB WHERE BB.ID = 3),D4 AS (SELECT OBJECTID,TO_CHAR(ROUND(BB.X,6))||','||TO_CHAR(ROUND(BB.Y,6)) D FROM GD_NAV_ROAD AA, table(SDO_UTIL.GETVERTICES(AA.POLYLINE)) BB WHERE BB.ID = 4),D5 AS (SELECT OBJECTID,TO_CHAR(ROUND(BB.X,6))||','||TO_CHAR(ROUND(BB.Y,6)) D FROM GD_NAV_ROAD AA, table(SDO_UTIL.GETVERTICES(AA.POLYLINE)) BB WHERE BB.ID = 5),D6 AS (SELECT OBJECTID,TO_CHAR(ROUND(BB.X,6))||','||TO_CHAR(ROUND(BB.Y,6)) D FROM GD_NAV_ROAD AA, table(SDO_UTIL.GETVERTICES(AA.POLYLINE)) BB WHERE BB.ID = 6),D7 AS (SELECT OBJECTID,TO_CHAR(ROUND(BB.X,6))||','||TO_CHAR(ROUND(BB.Y,6)) D FROM GD_NAV_ROAD AA, table(SDO_UTIL.GETVERTICES(AA.POLYLINE)) BB WHERE BB.ID = 7),D8 AS (SELECT OBJECTID,TO_CHAR(ROUND(BB.X,6))||','||TO_CHAR(ROUND(BB.Y,6)) D FROM GD_NAV_ROAD AA, table(SDO_UTIL.GETVERTICES(AA.POLYLINE)) BB WHERE BB.ID = 8),D9 AS (SELECT OBJECTID,TO_CHAR(ROUND(BB.X,6))||','||TO_CHAR(ROUND(BB.Y,6)) D FROM GD_NAV_ROAD AA, table(SDO_UTIL.GETVERTICES(AA.POLYLINE)) BB WHERE BB.ID = 9)SELECT DSE.OBJECTID,DSE.S,DSE.E,D2.D || DECODE(D3.D,NULL,NULL,';'||D3.D) || DECODE(D4.D,NULL,NULL,';'||D4.D) || DECODE(D5.D,NULL,NULL,';'||D5.D) || DECODE(D6.D,NULL,NULL,';'||D6.D) || DECODE(D7.D,NULL,NULL,';'||D7.D) || DECODE(D8.D,NULL,NULL,';'||D8.D) || DECODE(D9.D,NULL,NULL,';'||D9.D) MFROM DSE LEFT JOIN D2 ON DSE.OBJECTID = D2.OBJECTID LEFT JOIN D3 ON DSE.OBJECTID = D3.OBJECTID LEFT JOIN D4 ON DSE.OBJECTID = D4.OBJECTID LEFT JOIN D5 ON DSE.OBJECTID = D5.OBJECTID LEFT JOIN D6 ON DSE.OBJECTID = D6.OBJECTID LEFT JOIN D7 ON DSE.OBJECTID = D7.OBJECTID LEFT JOIN D8 ON DSE.OBJECTID = D8.OBJECTID LEFT JOIN D9 ON DSE.OBJECTID = D9.OBJECTID ;

选定基准路网

我们需要将不同时间抓取到的同一道路赋予唯一一个ID,这样才能通过筛选该道路ID,得到其不同时间段的速度,这就需要处理路段匹配问题。

要为每次新抓取的路段赋值ID,且ID要跟旧的数据相同,首先需要设置一个基准路网,将第一次爬取的数据作为基准路网,为每个路段设置ID,对于新抓取的路段,利用基础路网对其匹配,赋予每个路段唯一的ID值。

具体算法怎么写? 可以利用OGC标准的equals函数判定,也可以将polyline的坐标视为字符串,字符串相同时即视为两条路段相同(如重写JAVA的hashCode和equals方法)。实现方法多种多样,效率不同而已,示例中数据量很小,不管用什么方法都能在几秒内就能解决。当数据量很大时,用索引能很大程度上解决效率问题,这不是本教程的重点,就不展开说了。

JAVA中路段匹配(两路段完全相同)算法可参考如下代码:

@Overridepublic int hashCode {return polyline.toText.toString.hashCode;}@Overridepublic boolean equals(Object o) {GdNavLinkNJ p2 = (GdNavLinkNJ)o;// 判定条件:1.geom满足equals关系;2.方向相同boolean if_equal = polyline.toText.equals(p2.getPolyline.toText) &&orientation.equals(p2.getOrientation);return if_equal;}

计算车速

处理车速,首先需要知道路径规划接口中step和tmc的概念,还是以进香河路为例,如图,step是长路段,tmc是短路段,一条step等效于多条tmc首尾相接,如图中的1条step等效于5条tmc,为了好看,我把step往右挪了。

对于step,返回数据给出了它的通行时间和路段长度,据此我们可以算出速度; 对于tmc,返回数据只给了它的状态(畅通、缓行、拥堵),并未给出速度,我们可以直接取step的速度给到tmc,因此这5个tmc的速度相同,都等于step的速度,对于我们交通建模分析需求而言,这样的精度完全够了。

强调一下,由于将相同的step速度赋给5个tmc,所以经常会出现tmc颜色(拥堵状态)不一样,但是速度一样的情况,出现该情况说明这个速度是长路段step上的平均速度,而不是这短短tmc的速度。

假如想知道短短的tmc如图中tmc2,长30米左右,它的速度,你可以在绘制OD点描线时在tmc2的起点和终点分别点一下,这样就可以单独为它”导航”一次,就可以获取它的速度了。大多数时候,我们不需要做这么细,用step的速度就行了。

定时抓取数据

编写定时器,每10分钟抓取一次数据,需要为每次抓取的数据设置一个批次号,记录抓取时间,利用基准路网为新数据赋值ID,计算车速,所有这些都处理好之后,再存入数据库归档。

获取源代码

已将路网抓取、匹配、车速计算的代码发布到github。关注”城市数据派”公众号,发送”南京车速”四个字,可获得源代码地址。

示例网址: http://jtxx02.fzghy.com:8080/nj

作者邮箱: [email protected]返回搜狐,查看更多



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有