跳到正文

全部文章

累计里程为什么少了两百公里

同一份四十五万行的车辆运行数据,换一种积分方式,总里程多出约 200 公里。两种口径都不算错,差别在于它们对「数据缺失的那一段」各自默认了什么。

约 3 分钟 数据处理车联网口径

导出的车辆运行数据里没有现成的累计里程,得自己算。最初的算法很直接:每行有车速和时间戳,用车速乘以相邻两行的时间差,一路加下去。

跑了一阵子没觉得有问题,直到把结果和另一套数据对账,发现少了两百公里出头。数据量是四十五万行左右,不算小,误差也不算小。

缺的不是精度,是整段路

一开始怀疑是精度问题——浮点累加、单位换算之类。查下来都不是。

真正的原因在采样上。这份数据名义上是 1 Hz 采样 每秒采集一个数据点。车载数据导出常见的采样率。 按 1 Hz 算,一台车跑一整天是 8.64 万行;五十台车一天就是四百多万行 —— 这个量级决定了处理方式必须是流式而非全量装载。 采样,实际并不连续。熄火、信号丢失、设备重启,都会在数据里留下一段空白。空白两侧的时间差,短的几十秒,长的能到几分钟。

按车速积分时,这些 采样断点 数据流中连续缺失一段的现象。车辆熄火、信号中断、设备重启都会造成断点。 断点的处理方式往往比算法本身更影响最终结果 —— 跳过、插值、还是分段,三种选择会给出三个不同的答案。 是被跳过的——没有采样点,就没有对应的车速,那一段自然不进累加。等价于默认车辆在这段时间里没有移动。

可它常常是在动的。信号丢失往往恰恰发生在车开进隧道、驶入厂区、经过遮挡的时候。这几种场景下车都在走。

换成按轨迹算

既然每行都有经纬度,那就不用车速,直接用相邻两点的球面距离累加,也就是 Haversine 公式 由两点经纬度计算球面大圆距离的公式。相比把经纬度当平面坐标直接算欧氏距离,它在高纬度和长距离下不会明显偏小。 实现时注意用的是球面近似,地球实际是扁的;对车辆轨迹这种百米到百公里的尺度,误差在 0.5% 以内,够用。 积分。断点两侧的点仍然存在,距离就还在。

这样确实把那两百公里找回来了。但它引入了一个反向的问题:断点如果足够长,两点之间的直线距离就不再能代表实际路程。车可能中途停了两小时,也可能绕了一大圈回到附近。

所以加了一个最大间隔阈值:相邻两点的时间差超过阈值,这一段就不累加。

阈值取多少,是看数据定的。把真实数据的相邻间隔画出来,绝大多数落在 1 秒附近,形成一个很尖的峰;超过十分钟的间隔数量很少,且基本都对应设备停机。最后把阈值定在十分钟——宁可少算一段,也不要凭空造出一段直线距离。

顺带清掉的两个坑

同一批数据里还有两处需要先处理,否则里程会被污染得更厉害。

一是车速字段有大量 255。它不是每小时 255 公里,是信号缺失的哨兵值。这类行整行剔除,而不是把车速当 0——把它当 0 会让「缺失」被误算成「停着」,正好又踩回上一个坑。

二是车速字段的分辨率不是 1。原始值要乘以系数才是真实车速。这个在协议文档里写着,但导出的表格没写,光看数据看不出来——直到发现算出来的速度普遍只有合理值的一半。

两个口径都不算错

按车速积分,默认缺失段车辆静止,结果系统性偏小。 按轨迹积分,默认缺失段走的是直线,结果在长断点处系统性偏大,所以必须配一个阈值把它掐掉。

哪个对,取决于这个数字要拿去做什么。做能耗分析,偏小的口径会低估;做行驶范围核对,偏大的口径会误判。

真正的教训不是「应该用 Haversine」。是报里程的时候必须同时报 积分口径 把离散采样点累加成总量时所依据的规则:用哪个字段、跨多大间隔仍视为连续、缺失时如何处理。 两个口径可以都「正确」而结果差很多。给出数字时必须同时给出口径,否则数字没有意义。 :用了哪个字段、断点阈值多少、哪些行被剔除了。少了这些,四十五万行数据能算出两个都说得通、但差两百公里的答案。