Android: How to Get Accurate Altitude

Android: How to get accurate altitude?

There are two issues with using altitude of a smartphone / tablet GPS:

  1. The altitude is the altitude above the WGS84 reference ellipsoid. It is not the altitude above ground level or sea level. Here is more detail on that: http://www.gpspassion.com/forumsen/topic.asp?TOPIC_ID=10915. This error can be corrected; here is a description how to do that by hand: http://www.unavco.org/edu_outreach/tutorial/geoidcorr.html. The web article links to a calculator to get the Geoid height for correction; I do not know if there is also a web service available for this computation.
  2. The GPS altitude is terribly inaccurate for relatively cheap GPS receivers. Here is an article on that: http://gpsinformation.net/main/altitude.htm. One method to cope with this kind of inaccuracy is to filter the altitude data. I used a circular array data structure to remember the last few (I used 4) altitude readings and compute the average. This sufficed to get a relatively accurate reading of vertical speed for my application.

Get altitude by longitude and latitude in Android

My approach is to use USGS Elevation Query Web Service:

private double getAltitude(Double longitude, Double latitude) {
double result = Double.NaN;
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
String url = "http://gisdata.usgs.gov/"
+ "xmlwebservices2/elevation_service.asmx/"
+ "getElevation?X_Value=" + String.valueOf(longitude)
+ "&Y_Value=" + String.valueOf(latitude)
+ "&Elevation_Units=METERS&Source_Layer=-1&Elevation_Only=true";
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse response = httpClient.execute(httpGet, localContext);
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
int r = -1;
StringBuffer respStr = new StringBuffer();
while ((r = instream.read()) != -1)
respStr.append((char) r);
String tagOpen = "<double>";
String tagClose = "</double>";
if (respStr.indexOf(tagOpen) != -1) {
int start = respStr.indexOf(tagOpen) + tagOpen.length();
int end = respStr.indexOf(tagClose);
String value = respStr.substring(start, end);
result = Double.parseDouble(value);
}
instream.close();
}
} catch (ClientProtocolException e) {}
catch (IOException e) {}
return result;
}

And example of use (right in HelloMapView class):

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
linearLayout = (LinearLayout) findViewById(R.id.zoomview);
mapView = (MapView) findViewById(R.id.mapview);
mZoom = (ZoomControls) mapView.getZoomControls();
linearLayout.addView(mZoom);
mapView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == 1) {
final GeoPoint p = mapView.getProjection().fromPixels(
(int) event.getX(), (int) event.getY());
final StringBuilder msg = new StringBuilder();
new Thread(new Runnable() {
public void run() {
final double lon = p.getLongitudeE6() / 1E6;
final double lat = p.getLatitudeE6() / 1E6;
final double alt = getAltitude(lon, lat);
msg.append("Lon: ");
msg.append(lon);
msg.append(" Lat: ");
msg.append(lat);
msg.append(" Alt: ");
msg.append(alt);
}
}).run();
Toast.makeText(getBaseContext(), msg, Toast.LENGTH_SHORT)
.show();
}
return false;
}
});
}

Is Android's GPS altitude incorrect due to not including geoid height?

The answers to all three of your questions are yes.

The altitude you get from GPS is the height above the WGS84 ellipsoid in metres, which is an approximation of the earth's surface. I know that because I've been developing Android software to use it.

A correction has to be applied to convert the figure to height above mean sea level, or altitude as it is usually known. Note that this may differ from the altitude reported by an altimeter set to the current pressure at mean sea level because an altimeter actually measures air pressure, but air pressure is not just a function of height; it is also a function of air density and temperature, so an altimeter shows an approximation. This effect is not seen with GPS.

The Earth Gravitational Model 2008 (EGM2008) maps the difference in mean sea level with the ellipsoid as a function of longitude and latitude. Details are here:

http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm2008/egm08_wgs84.html

A less accurate model that uses less data called EGM96 is also available. Google both of these to understand these better.

How to get barometric altitude in Android?

You need to use the pressure sensor to measure the pressure then use the SensorManager.getAltitude(float, float) call to convert the measures pressure along with a reference sea level pressure to get the altitude.

The tricky bit is what to use as the reference pressure. This will change with the weather and will drift over time. Typically you would do some sort of calibration to set this values and possibly update it. It depends on your use case what the right solution is.

If properly calibrated pressure based altitude is considerably more accurate then gps based altitude especially if want you are interested in is altitude differences rather than absolute altitudes. With a bit of filtering on the raw pressure sensor values you can easily detect holding the phone at face level or arms length above your head which you want do with gps.

How can I capture altitude on an Android phone?

If the phone has a barometric pressure sensor, you can use SensorManager.getAltitude to get the altitude based on a pressure reading. This method also requires the current pressure at sea level, which can either be obtained from local airport data (via a web service) or approximated with SensorManager.PRESSURE_STANDARD_ATMOSPHERE.

For more, see:

Android: How to use SensorManager.getAltitude(float p0, float p)?



Related Topics



Leave a reply



Submit