【发布时间】:2012-03-10 20:05:45
【问题描述】:
我需要仅使用 GPS 获得准确的高度测量。
我试过Location.getAltitude(),但这非常不准确。
有什么建议吗?
【问题讨论】:
标签: android gps location altitude
我需要仅使用 GPS 获得准确的高度测量。
我试过Location.getAltitude(),但这非常不准确。
有什么建议吗?
【问题讨论】:
标签: android gps location altitude
使用智能手机/平板电脑 GPS 的高度存在两个问题:
【讨论】:
另一种方法是解析 NMEA 字符串。 $GPGGA sentence 已经包含经过校正的海拔高度数据。
因此,只需为您的 LocationManager 创建一个 NMEA 字符串侦听器并解析消息:
private GpsStatus.NmeaListener mNmeaListener = new GpsStatus.NmeaListener() {
@Override
public void onNmeaReceived(long timestamp, String nmea) {
parseNmeaString(nmea);
}
};
public void registerLocationManager(Context context) {
mLocationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE);
mLocationManager.addNmeaListener(mNmeaListener);
}
private void parseNmeaString(String line) {
if (line.startsWith("$")) {
String[] tokens = line.split(",");
String type = tokens[0];
// Parse altitude above sea level, Detailed description of NMEA string here http://aprs.gids.nl/nmea/#gga
if (type.startsWith("$GPGGA")) {
if (!tokens[9].isEmpty()) {
mLastMslAltitude = Double.parseDouble(tokens[9]);
}
}
}
}
您可以替换通过位置侦听器接收到的最后一个 Location 对象的高度,或者通过 NMEA 解析整个新位置。
【讨论】:
Call requires API level 24 ... android.location.LocationManager#addNmeaListener
NmeaListener 已弃用。请改用OnNmeaMessageListener。
type.endsWith("GGA") 结尾,不需要像你那样使用长模式
另一种方法是通过气压计测量高度。
通过使用压力,您可以计算出用户的高度。我不确定这个的精度水平以及它是否比其他答案的方法更准确。
使用hypsometric formula可以计算海拔高度:
变量定义:
P0: Sea-level pressure
P: Atmospheric pressure
T: Temperature
你可以通过environment sensors获取android中的压力
SensorManager.getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE,pressure)
【讨论】:
如果设备有气压计,那么可以使用它来提高相对准确度。我并不是要使用气压计来计算与海平面相关的高度,这可以在几个公式中找到,因为这高度依赖于天气条件。
您想要做的是在您知道设备具有良好定位且具有高精度值时获取 GPS 高度。此时,您获取大气压力并将该压力设置为参考。
当压力增加约 12 hPa 时,您会知道您的海拔高度下降约 100 m (https://en.wikipedia.org/wiki/Atmospheric_pressure "在海拔较低的高度,压力每下降约 1.2 kPa (12 hPa) 100 米。")。
不要将该值视为精确值,但由于树木覆盖视线和其他因素,GPS 确定的高度变化很大,而在这些条件下,气压计将保持非常精确。
下图是大约 1 小时 20 分钟的自行车骑行。起点和终点在海拔约 477 m 处相同,通过 GPS 确定。实测压力为 1015.223 hPA。
最低点为 377 m,实测压力为 1025.119 hPa。所以在这种情况下,100 m 会产生 10 hPa 的差异。
最高点550 m,实测压力1007.765 hPa。
终点高度相同,压力与起始条件完全相同(压力可能会因天气条件而变化,但事实并非如此)。温度下降了 1°C 左右,所以一切都很稳定。
包含许多变化的黑线是通过 GPS 测量的高度,镜像但干净的线是气压。它几乎没有变化,仅仅是因为压力不像 GPS 质量那样变化很大。这是一条非常平滑、非常精确的曲线。这不是由于滞后。这是用博世BME280传感器测量的,该传感器能够检测关门、楼层检测变化、电梯方向、无人机,噪声为0.2 Pa,等于1.7 cm,高度变化400m时误差为1m .这种传感器集成在一些智能手机中。例如,Pixel 3 包含一个博世 BMP380。
如果您镜像压力图,如黑色虚线所示,您会看到它与 GPS 高度非常匹配。它比 GPS 精确得多,但唯一的问题是不能将其作为绝对值。
GPS 和压力的样本都是以 1 秒的间隔采集的,因此 d3 库中没有曲线平滑导致一些错误印象。
因此,在 GPS 定位良好的情况下,也许每 10 到 30 分钟左右重新调整一次压力,这将为您提供一个良好的基础,以便通过两者之间的压力进行高度测量。
【讨论】:
除了 GPS 之外,还有其他方法可以获取高度。您可以使用气压计,但由于配备气压传感器的设备并不多(只有新设备)。我会建议使用网络服务来获取所需的数据。
这是一个可以帮助您解决的问题:Get altitude by longitude and latitude in Android
【讨论】:
对于新手,我制作了一个库,将 LocationManager 包装到 rxjava 可观察对象中,并添加一些可观察帮助器以从 Nmea/GPGGA mre info here 获取海平面高度
【讨论】:
有一些库,例如开源 CS-Map,它提供了在大型表中执行这些查找的 API。您指定坐标,它会告诉您需要应用到该位置的椭球高度以获得“真实世界”正高的高度偏移。
注意:之前使用过 CS-Map,插入它并不是完全直接的 5 分钟工作。提前警告您,它比使用一组 lat-long 调用单个 API 更复杂坐标并返回一个高度。 我不再在我们从事此类工作的公司工作,因此很遗憾无法查看代码以准确说明要调用哪个 API。
现在(2019 年)正在谷歌搜索它,似乎 CS-Map 已合并到 OSGeo 中的 MetaCRS 中,即“Open Source Geospatial Foundation”项目。同样的搜索让我找到了this old CS-Map wiki 和the PROJ GitHub page,其中PROJ 似乎与CS-Map 类似。
【讨论】:
我建议使用 NmeaListener 作为 sladstaetter 在his answer 中建议。然而,根据NMEA documentation 的说法,“$GPGGA”并不是你能得到的唯一句子。您应该查找任何“GGA”语句 ($--GGA)。
正则表达式非常适合,例如:
@Override
public void onNmeaReceived(final long timestamp, final String nmea) {
final Pattern pattern = Pattern.compile("\\$..GGA,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,([+-]?\\d+(.\\d+)?),[^,]*,[^,]*,[^,]*,[^,]*,[^,]*$");
final Matcher matcher = pattern.matcher(nmea);
if (matcher.find()) {
final float altitude = Float.parseFloat(matcher.group(1));
// ...enjoy the altitude!
}
}
【讨论】: