计算没有 getSpeed() 方法的导航应用程序的速度
Posted
技术标签:
【中文标题】计算没有 getSpeed() 方法的导航应用程序的速度【英文标题】:Calculating Speed for a navigation app without getSpeed() method 【发布时间】:2014-02-20 01:16:08 【问题描述】:我正在开发一个应用程序,它更像是您朋友之间的时移竞赛。
我需要计算移动车辆的速度,我不想使用Location.getSpeed()
方法。 (在底部详细解释了为什么我不想使用它)
我正在尝试借助可用的纬度和经度来计算速度,而这正是我需要帮助的地方。
需要的帮助:我想知道的是:
算法是否正确 我应该用厘米而不是米来计算 如果有任何可用的代码/库可以做到这一点。我正在使用以下代码:
这给了我两个 LatLng 点之间的距离:
long getDistanceBetweenPoints(double lat1, double lng1, double lat2, double lng2 )
double dLat = Math.toRadians(lat2 - lat1);
double dLon = Math.toRadians(lng2 - lng1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(Math.toRadians(lat1))
* Math.cos(Math.toRadians(lat2)) * Math.sin(dLon / 2)
* Math.sin(dLon / 2);
double c = 2 * Math.asin(Math.sqrt(a));
long distanceInMeters = Math.round(6371000 * c);
return distanceInMeters;
下面的代码是如何使用的:
if(lastLat == -1 && lastLng == -1)
lastLat = location.getLatitude();
lastLng = location.getLongitude();
lastTimeStamp = location.getTime();
return;
long distanceInMeters = getDistanceBetweenPointsAndSetTotal(lastLat, lastLng, location.getLatitude(), location.getLongitude());
long timeDelta = (location.getTime() - lastTimeStamp)/1000;
long speed = 0;
if(timeDelta > 0)
speed = (distanceInMeters/timeDelta);
Log.d("Calculations","Distance: "+distanceInMeters+", TimeDelta: "+timeDelta+" seconds"+",speed: "+speed+" Accuracy: "+location.getAccuracy());
lastLat = location.getLatitude();
lastLng = location.getLongitude();
lastTimeStamp = location.getTime();
当我运行它时,我会从该 LogCat 获得以下输出:
Distance: 0, TimeDelta: 0 seconds,speed: 0 Accuracy: 5.0
详细原因 目标消费者不应该拥有配备高品质 GPS 芯片的高品质设备,因此无法在设备移动时始终获得非常准确的定位。
因此我不想依赖Location.getSpeed()
方法,因为我观察到它仅在精度在 5~8 米范围内时才会给出速度值。
我在一般情况下获得的正常精度范围是 10-15 米,而getSpeed()
没有给出任何速度。甚至 hasSpeed()
也开始返回 false。
我已经在这件事上琢磨了 3 天多,对此的任何帮助将不胜感激。
在此先感谢您!
【问题讨论】:
为什么不这样。 developer.android.com/reference/android/location/… 【参考方案1】:我开发了MyTrails,这是一个 Android 地图和跟踪应用程序,和你一样,我一开始也为谷歌认为适合在 Android 中包含的非常粗糙的位置 API 苦苦挣扎。
当 GPS 芯片没有足够好的修复来根据多普勒效应计算速度时,hasSpeed() 为假。即使是这样,如果速度低于 5 公里/小时左右,我通常也不相信。
我处理速度计算的方法是使用粗略的低通滤波器:我每秒记录一个轨迹点(基于LocationManager.requestLocationUpdates()
,至少相距 5m,为了计算最近的速度,我返回几个样本来获得一个足够距离的样本(但不超过 30 秒),然后执行你正在做的平均。
我正在使用 Location.distanceBetween() 进行实际距离计算。请注意,它在极少数(但不幸)数量的设备上失败,因此您拥有的 hasrsine 方法可能是一个更好的选择。不过,您可能想检查一下,我所拥有的是
/**
* Gets distance in meters, coordinates in RADIAN
*/
private static double getDistance(double lat1, double lon1, double lat2, double lon2)
double R = 6371000; // for haversine use R = 6372.8 km instead of 6371 km
double dLat = lat2 - lat1;
double dLon = lon2 - lon1;
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1) * Math.cos(lat2) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
//double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
// simplify haversine:
//return 2 * R * 1000 * Math.asin(Math.sqrt(a));
(注意 1000 因子)
【讨论】:
我会试试这个方法。我认为它会稍微减慢 UI 上的速度更新速率,但只要它不为零,它应该可以工作。你知道getSpeed()
使用的逻辑吗?我尝试在源代码中搜索它,但找不到它。似乎speed
它的返回被设置在其他地方。
这是 GPS 返回的数据。您可以通过注册 NmeaListener 来获取原始数据。不要忘记接受您收到的答案之一:-)
我正在尝试和调整您的方法,一旦发现有用的答案,我肯定会立即接受 :) 您能告诉我使用 NMEA 值有什么好处吗?
我不是建议您使用 NMEA 值,只是提供如果您出于好奇想要获取原始 GPS 数据,您会这样做。获取 NMEA 数据的一个重要原因是:获取您所在位置的大地水准面(海拔高度与 WGS84 椭圆体上方的高度之差),因为 Location.getAltitude 报告的高度基于椭圆体和可能超过 100m。
虽然我现在使用不同的方法来欺骗 UI 并继续使用 getSpeed()
,但您的回答让我非常接近。接受它。谢谢!【参考方案2】:
我同意 Pierre 的观点,你也在对结果进行四舍五入。如果这些点之间的距离不够远,则四舍五入可能只提供 0。我不知道如何定义舍入公差。 我总是以米为单位计算 - 它让事情变得更容易。我建议在您的代码中遵循 SI 标准单位。 您的输出还显示 timeDelta 为零,因此实际上没有计算距离。
【讨论】:
这正是正在发生的事情。由于这些点太近了,并且一切都以米/秒为单位,因此它的计算结果为零。我正在考虑进一步降低到厘米/毫秒。您认为这是一个好方法吗? 不,永远不要使用厘米,使用 Si 单位,但使用双米。 四舍五入正在发生,但它不应该很重要:如果距离是亚米,则 GPS 误差(通常 > 5m)大于您使用的误差。这就是我使用我在回答中概述的方法的原因。【参考方案3】:天哪.....
Location
检查此方法 - 它允许您计算 2 个地理点之间的距离,只需将其除以您的时间。它应该比你的更准确,因为它以更好的近似值计算距离(WGS83 而不是使用 sin、cos 和其他东西)。
好的,一般的想法是将所有数据保存在简单的单位中,例如 m、s、kg 等,并且只为向用户显示数据而进行更改。
【讨论】:
【参考方案4】:算法是否正确?
距离计算看起来像是正确的半正弦公式。 (对于小距离,有更快的公式(而且你只使用小距离),但是haversine会起作用)
我应该用厘米而不是米来计算吗?
永远不要使用厘米,使用 SI 单位,速度单位是米/秒。只需使用仪表作为浮点数(双精度)。
ios,我正在开发一个跟踪应用程序,似乎与 Location 类中的 getSpeed() 网络更友好。
但我(再次?)警告您使用慢速。如果您的速度无效,则只需停止计算或在您的应用中将其标记为无效。 如果 GPS 芯片不能提供有效的速度,它有充分的理由这样做,你是否会做得更好是一个有趣的问题。 在低速时,GPS 倾向于在真实位置周围随机跳跃,跳跃距离为 5-30m。 您自己计算的速度很可能显示出设备正在(不)移动的速度。 尝试修复您的应用,使其不需要低速运行。
【讨论】:
是的,这就是半正弦公式。你能告诉哪些其他公式对于小距离更快,因为两点之间的距离会非常小。好的,我坚持使用 SI 单位,我想我已经在浮点中使用米了。哦,iOS更好。这个应用程序的 iPhone 版本运行流畅,如果不一样的话,我预计会提供类似的平滑度。抱歉,不以慢速显示速度不是我的选择:-/ 我希望你不需要实现一个指南针:如果你认为 Android API 不如 iOS 丰富,你会惊讶于磁力计 API 是多么粗糙和低级(低级本身并不坏,但缺少更高级别的 API 是)。 @Pierre-LucPaour 我已经实现了一个指南针,ios API 提供 0.0 到 360.0° 之间的航向。这是一个非常高级的 API:有关更多信息,请查看 - (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading @SheikhAman 更快的公式:例如,使用 Cyclindrical EquidDistante Projection(一个乘法和一个余弦)将坐标转换为笛卡尔空间,然后使用毕达哥拉斯计算距离的平方。 >> 抱歉,不以慢速显示速度不是我的选项:我怀疑,总是有一个选项,如果不可能,那就没有。点。以上是关于计算没有 getSpeed() 方法的导航应用程序的速度的主要内容,如果未能解决你的问题,请参考以下文章
如何获取Android设备用户移动的速度? Location.getSpeed 可靠吗?
使用 Fused Location API,Marshmallow 不会使用 location.getSpeed()
为啥 getSpeed() 在 android 上总是返回 0
为啥在 android 中使用 NETWORK_PROVIDER 时 location.getSpeed() 总是返回 0?