5

I am writing a watch-face which displays the altitude. The altitude is calculated with SensorManager.getAltitude(seaLevelPressure, currentPresure).

But in order to initialize this I need the pressure at sea level. Unfortunately there is no SensorManager.getSeaLevelPressure(currentPressure,currentAltitude).

For doing so I found the following formula (see http://rechneronline.de/barometer/ )

private float calcSeaPressure(float pressure, int altitude) {
  float temperature = 9 + 273.15f;
  float tempGradient = 0.0065f;

  float v3 = temperature + tempGradient * altitude;
  float sealevelPressure = (float) (pressure / Math.pow((1 - tempGradient * altitude / v3), .03416f / tempGradient));
  sealevelPressure = (float) Math.round(sealevelPressure * 100) / 100;
  return sealevelPressure;
}

But it seems that this algorithm and the one used in SensorManager.getAltitude do not fit good together. If I do:

public void setCurrentAltitude(int currentAltitude) {
  sealLevelPressure = calcSealevel(currentAltitude,currentPresure);
  altitude = SensorManager.getAltitude(seaLevelPressure, currentPresure)
}

The calculated altitude is different to the given currentAltitude. For small values (<1000m) the difference is acceptable. But for example 4000m the difference is 250m, which is no longer acceptable.

Now my question: How do I have to calculate the sealevel, so that setCurrentAltitude() does not report different values?

Or do you know about other Java Classes which can be used for this? Keep in mind, the values should be calculated!

Thanks

weston
  • 54,145
  • 21
  • 145
  • 203

3 Answers3

2

If you are calibrating from an altitude (after all you have setCurrentAltitude method), then this is the technique:

public void setCalibrationAltitudeAndPressure(float calibrationAltitude, float currentPressure) {
   this.calibrationAltitude = calibrationAltitude;
   this.calibrationPressure = currentPressure;
}

public float getCurrentAltitude(float currentPressure) {
    float altitudeDifference =
            sensorManager.getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, currentPressure) -
            sensorManager.getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, calibrationPresure);
    return calibrationAltitude + altitudeDifference;
}

Now you don't need to care about sea level pressure.

Calibrating

You need a calibration altitude, and you can use GPS for this. It's altitude is not likely to be that accurate (see Android: How to get accurate altitude?), but you could use the lat and long to get altitude from this service: https://developers.google.com/maps/documentation/elevation/ but that's not good for people using the app in planes!

But if you're hitting a service up for that, then might as well get accurate sea-level pressure from a service: http://www.worldweatheronline.com/api/marine-weather-api.aspx

Community
  • 1
  • 1
weston
  • 54,145
  • 21
  • 145
  • 203
  • Yep but you're moving the problem. Now the "point" is on your calibrationAltitude. – greywolf82 Mar 01 '15 at 10:33
  • @greywolf82 what do you mean "point"? My code is just a full implementation of the documented way to calculate differences in altitude. – weston Mar 01 '15 at 10:37
  • I meant that the new problem is now how to calculate the calibrationAltitude. Your code looks good to me but I think it's not the best thing to do in this particular case, because the app couldn't ever know what is the best and accurate calibrationAltitude. – greywolf82 Mar 01 '15 at 10:40
  • @weston: yes this is the way to go, if i am not able to calculate the sealevel pressure correctly. – Joachim Fricker Mar 01 '15 at 10:40
  • There are a few options for getting that calibration altitude, GPS being one as you mentioned. You only need do that once and does not require GPS to be on after calibration. – weston Mar 01 '15 at 10:42
  • @weston Oh yes this is true, however it requires at least one access. – greywolf82 Mar 01 '15 at 10:44
  • I think if you want accuracy, then getting sea-level pressure from service is the way to go. – weston Mar 01 '15 at 10:48
1

Documentation about getAltitude() says:

Typically the atmospheric pressure is read from a TYPE_PRESSURE sensor. The pressure at sea level must be known, usually it can be retrieved from airport databases in the vicinity. If unknown, you can use PRESSURE_STANDARD_ATMOSPHERE as an approximation, but absolute altitudes won't be accurate.

To calculate altitude differences, you must calculate the difference between the altitudes at both points. If you don't know the altitude as sea level, you can use PRESSURE_STANDARD_ATMOSPHERE instead, which will give good results considering the range of pressure typically involved.

So you can use the PRESSURE_STANDAR_ATMOSPERE but the value it couldn't be the "right" value. My suggestion is to use the Google Play fused location api, in order to get more accurate value (mainly from GPS). You can check if your watch has got a GPS inside the code and if present, use the wearable location API directly, or request the location to your phone otherwise.

greywolf82
  • 21,813
  • 18
  • 54
  • 108
  • Yep the usage of PRESSURE_STANDAR_ATMOSPERE could be the way to go, if i cannot calculate the sealevel pressure correctly. – Joachim Fricker Mar 01 '15 at 10:29
  • I read that documentation as saying `PRESSURE_STANDARD_ATMOSPHERE` is OK for approximations for altitude **differences**, but not accurate when used for **absolute** altitudes. Do you agree? – weston Mar 01 '15 at 10:50
  • I think I will give it at try and see how it works, where the real test will be in 2 weeks in the alpes! – Joachim Fricker Mar 01 '15 at 17:15
1

I have now been in my Ski Holidays in the alps and could verify the accuracy of the sensor and the calculation of the altitude. I used the following formula

sensorManager.getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, currentPressure) 
- sensorManager.getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, calibrationPresure);

This works very good! The accuracy was +/-30m. Starting Point was arround 1200m and I went up to 2700m.

I am now proud owner of a new altimeter :-)