BME680 Altitude code is incorrect

After doing a heap of research and loads of math, it turns out that the Adafruit library for the BME680 does an incorrect equation for altitude. As far as I can work out, it should be more like this:

float Alt = ((((((10 * log10((bme.pressure / 100.0) / 1013.25)) / 5.2558797) - 1) / (-6.8755856 * pow(10, -6))) / 1000) * 0.30);

This returns the altitude in meters above sea level, and should be accurate to 39 kilometers (high enough for a weather balloon).

I got the formula from here.

I'm not sure who to contact for this library, so I'm posting it here.

Originally, I was trying to figure out why this sensor was saying that I live 21 meters below the sea level instead of 44 meters above sea level, I was quite surprised when I pulled apart the formula and found out it is actually for a completely different sensor!

If anyone sees any errors in my formula, let me know where, and why you think it is incorrect.

I would say the BME is measurig the air pressure. The air pressure depends on the weather. As long as you use only constants (beside the measured pressure) in your formula it can't be accurate.
Your source is calculating the pressure drop with increasing height in a ideal system.

@intstarep
True.
However, in the original formula, there are only two numbers that aren't constant. One of those (sea level pressure) has been made a constant, just like in the original library code, as we have no way of measuring it besides sticking a second BME680 on the water (at exact sea level), which isn't ideal for anyone wanting to use one of these sensors if they don't live on a boat.

Where did the original library formula come from??? From the link posted inside the library, it came from an ancient adafruit library. And where did they get the formula from for that sensor? If you can find it, that would be great. I haven't been able to find another formula like that anywhere else. Most formulas are even more complex than the one I included in my first post, and include a whole lot more variable data then the BME680 is able to provide.

This formula also gives me 0.2 meter accuracy, which is 60 meters better accuracy then the original formula.

In other words, this sensor never was and never will be accurate then, because the proper formula also takes into account all of these:
image
Some of which the BME680 cannot provide.

Raise an issue on the Github page where Adafruit have saved the library .......

Please learn more about atmospheric pressure and procedures. You can measure the air pressure before start and reduce it to sea level using the known height of the airfield where you start from. In the following you have to live with all the effects affecting atmospheric pressure over time and height. If you plan to land then you should get the height and current pressure from your landing zone for re-adjustment of your actual height.

@DrDiettrich
Meteorologists use a metric unit for pressure called a millibar and the average pressure at sea level is 1013.25 millibars. If that number is good enough for a meteorologist, it is good enough for this very limited sensor.

This worked with my BMP180 and BME280 sensors:

To get an accurate altitude the formula needs the current corrected sea level pressure. That can be obtained from the nearest airport. They put out the current "altimeter setting" in inches of mercury (US). Convert to hPa and enter it into the function (in hg = hPa * 33.86388667).

altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);

That is the exact line that is giving me so much trouble. I don't want to edit the code every day so that I can get a accurate altimeter reading. And using the average sea pressure of 1013.25 hPa gives my altitude as -22 meters. My altitude is 44m. The formula I suggested always returns 43.54 meters, which rounded up is 44 meters.

@groundFungus
Would you mind testing the following code and telling me what Serial monitor returns?

#include <math.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME680 bme;

void setup() {
  Serial.begin(9600);
  if (!bme.begin()) {
    Serial.println("Could not find a valid BME680 sensor, check wiring!");
    while (1);
  }
}

void loop() {
  if (! bme.performReading()) {
    Serial.println("Failed to perform reading");
    return;
  }
  float P = bme.pressure;
  float Alt = ((((((10 * log10((P / 100.0) / 1013.25)) / 5.2558797) - 1) / (-6.8755856 * pow(10, -6))) / 1000) * 0.30);
  Serial.print("My Formula: ");
  Serial.println(Alt);
  Serial.print("Adafruit Formula: ");
  Serial.println(bme.readAltitude(SEALEVELPRESSURE_HPA));
  delay(5000);
}

My Serial monitor returns this:

My Formula: 43.55
Adafruit Formula: -20.21
My Formula: 43.55
Adafruit Formula: -20.38

Why would the Adafruit formula change like this when I haven't moved the sensor??
Mine doesn't!!

Why guess a pressure if you have a pressure sensor at hand?

@DrDiettrich

Because I need the current pressure at my altitude, and the sea level pressure which is not my altitude. Can I be at two places at once? Secondly, I am many kilometers from where I would have to go to measure the pressure at sea level (I am inland).
Thirdly, I don't want seawater in my sensor. I've heard bad things about sensors and salt mixed together.
@groundFungus
Fourthly, I am also an awfully long way from the nearest airport (50km), and if you research barometric pressure, you will quickly learn that one place is not the same as another when it comes to barometric pressure.
So the simplest thing is to take the same number meteorologists use which happens to be 1013.25 hPa.

I do not have a BME680.

On my altimeter I have a rotary encoder that I use to dial in the altimeter setting, just like a real aircraft altimeter.

My bad. Sorry, I mistook the BME280 you mentioned for a BME680.

So why do you care about sea level if you only want to measure a pressure?

If you want to calculate an altitude then you need some reference altitude. You can use as reference the altitude of your starting place or sea level, as you like.

@DrDiettrich

The formulas do not require any altitudes at all. Please read and understand the formulas before posting comments.
Both the original formula and the formula I posted in post #1 require the barometric pressure at sea level. No-where does it need to know a altitude of any kind. The formula is constructed in such a way that it is working out the altitude, it isn't copying a altitude that I enter into the formula. I think you need to learn a few concepts about this subject.

An edit to your post would be to make it say:

And the easy answer for that is that I am already doing that. Hence the reason that the formula uses the average barometric pressure at sea level. And sea level is obviously 0m, so why would I need to enter that into the formula????

The original formula doesn't have any numbers for the altitude. I f you have a close look, it is working out the formula purely by barometric pressure.
image

Then I'm out :frowning:

@DrDiettrich
Interesting. I just tried your idea. It has made my original formula even more accurate. Thank you for that idea.

P0 is the formula for working out the current sea level pressure using a known height (in this case 44 as that is my current altitude).

#include <math.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME680 bme;

void setup() {
  Serial.begin(9600);
  if (!bme.begin()) {
    Serial.println("Could not find a valid BME680 sensor, check wiring!");
    while (1);
  }
}

void loop() {
  if (! bme.performReading()) {
    Serial.println("Failed to perform reading");
    return;
  }
  float P1 = (bme.pressure / 100.0);
  float h = 44;
  float T = bme.temperature;
  float P0 = (P1 * pow(1 - ((0.0065 * h) / ((T + (0.0065 * h)) + 273.15)), -5.257));
  Serial.println(P0);
  float P = bme.pressure;
  float Alt = ((((((10 * log10((P / 100.0) / P0)) / 5.2558797) - 1) / (-6.8755856 * pow(10, -6))) / 1000) * 0.30);
  Serial.print("My Formula: ");
  Serial.println(Alt);
  Serial.print("Adafruit Formula: ");
  Serial.println(bme.readAltitude(SEALEVELPRESSURE_HPA));
  delay(5000);
}

However, what I said hasn't changed. The adafruit formula still says I am -22 meters. Mine, however, is 0.3 meter more accurate.

You don't need to call the airport. Like @DrDiettrich says, you just need a reference. I use the altitude of my house found via Google maps and verified with GPS. A friend for whom I built an altimeter to use 4 wheeling uses the local post office whose altitude is published. To set the altimeter, just dial in the known altitude of where you are sitting and it is ready to go.

That is my experience, you can take it or leave it.

1 Like

@outbackhut
You confuse others and confuse yourself. Without knowing the current sealevel pressure (at the moment) - it is not possible to calculate the height of the place only from pressure readings and standard sealevel pressure 1013.25.
Your formula gives the correct height only because you plug the correct answer to the formula first.

Please look at your code:
First you calculate base pressure P0 for your height 44m, and next plug it in your final formula to calculate Alt:

The formula from Adafruit lib is absolutely correct.