60

我只需要使用 GPS 来准确测量高度。

我试过Location.getAltitude()了,但那是非常不准确的。有什么建议吗?

4

8 回答 8

62

使用智能手机/平板电脑 GPS 的高度存在两个问题:

  1. 高度是 WGS84 参考椭球上方的高度。它不是高于地面或海平面的高度。这里有更多细节:http ://www.gpspassion.com/forumsen/topic.asp?TOPIC_ID=10915 。这个错误可以纠正;以下是如何手动操作的描述:http ://www.unavco.org/edu_outreach/tutorial/geoidcorr.html 。网络文章链接到计算器以获取大地水准面高度以进行校正;我不知道是否还有可用于此计算的 Web 服务。
  2. 对于相对便宜的 GPS 接收器,GPS 高度非常不准确。这是一篇关于此的文章:http: //gpsinformation.net/main/altitude.htm。处理这种不准确性的一种方法是过滤海拔数据。我使用圆形数组数据结构来记住最后几个(我使用了 4 个)高度读数并计算平均值。这足以让我的应用程序获得相对准确的垂直速度读数。
于 2012-02-24T14:29:54.107 回答
8

另一种方法是解析 NMEA 字符串。$GPGGA 语句已经包含经过校正的海拔高度数据。

因此,只需为您的 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 解析整个新位置。

于 2017-06-13T10:05:28.893 回答
5

另一种方法是从气压计测量高度。

通过使用压力,您可以计算用户的高度。我不确定这个的精度水平以及它是否比其他答案的方法更准确。

通过使用hypsometric 公式,您可以计算高度:

测压公式

变量定义:

P0: Sea-level pressure 
P: Atmospheric pressure 
T: Temperature 

您可以从环境传感器获得android中的压力

SensorManager.getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE,pressure)
于 2019-01-31T11:33:45.173 回答
2

如果设备有气压计,那么可以使用它来提高相对精度。我并不是要使用气压计来计算与海平面相关的高度,这可以在几个公式中找到,因为这高度依赖于天气条件。

当您知道该设备具有良好的定位和高精度值时,您想要做的是获取 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 分钟左右重新调整一次压力,这将为您提供一个良好的基础,通过两者之间的压力进行高度测量。

于 2020-06-30T12:42:07.310 回答
1

除了 GPS 之外,还有其他方法可以获取高度。您可以使用气压计,但由于配备气压传感器的设备并不多(只有新设备)。我会建议使用网络服务来获取所需的数据。

这是一个可以帮助您解决的问题:在Android中按经度和纬度获取高度

于 2013-01-25T20:39:44.597 回答
1

对于新手,我制作了一个库,将 LocationManager 包装到 rxjava observables 中,并添加一些可观察的助手来从 Nmea/GPGGA mre info here获取海平面高度

于 2018-11-02T10:42:09.027 回答
0

有一些库,例如开源 CS-Map,它提供了在大型表中进行这些查找的 API。您指定坐标,它会告诉您需要应用于该位置的椭球高度以获得“真实世界”正高的高度偏移。

注意:之前使用过 CS-Map,插入它并不是很简单的 5 分钟工作。提前警告您,它比使用一组经纬度坐标调用单个 API 并获取更复杂回一个高度。 我不再在我们从事此类工作的公司工作,因此很遗憾无法查看代码以准确说明要调用哪个 API。

现在(2019 年)进行谷歌搜索,似乎 CS-Map 已合并到 OSGeo 中的 MetaCRS 中,即“开源地理空间基金会”项目。同样的搜索让我找到了这个旧的 CS-Map wiki以及PROJ GitHub 页面,其中 PROJ 似乎是与 CS-Map 类似的项目。

于 2019-06-24T18:12:30.327 回答
-1

我会推荐使用NmeaListener,正如 sladstaetter 在他的回答中所建议的那样。然而,根据NMEA 文档,“$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!
    }
}
于 2019-07-01T11:51:40.210 回答