BME680 Observed gas 'ohms' readings

Just to pass on what I observed, at a guess these banded ranges correspond to the air quality labels in the datasheet with one extra

the readings are banded, though the values I have are only the observed range for each band might be bit more bit less but jumps to somewhere in next band around those points.

so I doubt these are ‘ohms’ readings, the tests were with standard pimoroni library and the read-all example modified to log in a csv friendly format.

based on about 30mb of readings over few days

521177 - 431331 - good?
297625 - 213212 - average ?
148977 - 108042 - little bad ?
75010 - 54586 - bad ?
37395 - 27080 - worse ?
18761 - 13591 - very bad ?
9008 - 8371 - can’t see the exit ?

Thanks! That’s very useful! I’ll definitely try to incorporate that into my air quality example. How did you do this? Did you set two up side by side, running our software and the BSEC software?

I might try to do that side by side comparison to reverse engineer their temperature compensation that you mentioned in another thread.

I’m also very interested in how you did this. Two additional BME680 sensors arrived this morning (for a total of 3), so I hope to put them all into action side by side later today to see how stable the readings are. I tried to toy with the BSEC software but it’s been ages since I dabbled with C and static libraries so no luck so far, so I just disabled the air quality reading thus far as the % didn’t make much sense to me. If these bands are correct, however, that would make the air quality measurement a lot more useful!

I did a load of testing today, so apologies for this long post.

Here are some of my calibration notes on these BME680 sensors. I have calibrated my 3 sensors using 3 other cheapo sensors (AMIR hygrometers) and a Netatmo thermostat (very accurate, but only temperature).

In my setup I started off with the sensors positioned about 40cm away from their respective Raspberry Pi using some wire jerky (more on that later), and the gas measurements disabled (more on that later). Under these circumstances, I’m impressed how stable the BME680 sensors are. The humidity deviates no more than 0.2% between sensors, the hPA deviates by no more than 1 hPA and the temperature is within 0.2C. Not bad at all.

The thermostat reads 20.4C (± 0.1), the BME680s read 20.52C, 20.57C, and 20.32C (± 0.5), and the AMIR read 20.8C, 20.5, 20.1 (± 1). As you would expect, the most accurate sensor sits in the middle of the temperature range, the BME680 closely cluster around that reading, and the AMIR cluster around the BME680s readings. I also ordered the readings according to how far they sit away from the radiator. As it turned out, the AMIR near the radiator liked to overreport and the one furthest liked to underreport. When I swapped their positions all three agreed on the temperature given by the thermostat. I did the readings a number of times, and the results were always in the same ballpark.

A lot of measuring later and I calibrated each BME680 sensor by ±0.1C. If your sensor needs more calibrating, something is off (read on).

The humidity is trickier. For example, at one point the AMIRs all read 50% (± 5), with the BME680s reading 41.9%, 41.8%, and 41.6% (± 3%). Those readings are very close to the range limit, so I’m wondering if the BME680s need to have a +3% humidity reading? Another measurement, an hour later, gave me 49%, 50%, and 47% for the AMIRs and 43.6%, 43.3%, and 43.2% for the BME680s. Closer, but still suggesting the BME680s are underreporting. The problem is that I don’t have a third type of sensor to validate the humidity. I think the AMIR overreport, but I’m gonna err on the side of caution (I’m in the humid UK after all), and add 3% to each sensor. If anyone could try this out on their end, that would be great!

I don’t know (or care too much) about the pressure reading. One sensor measured 0.2 hPa higher than the others, so I corrected it accordingly.

With all sensors calibrated, now was the time to figure out the effect of the heating profile. I used the standard profile with heating to 320°C for a duration of 150ms. This caused the temperature to jump by 0.7C and the humidity to drop by 2%. Without a doubt, you need to apply some temperature compensation to correct for these errors. For the fun of it, I tried to reduce the duration to 40ms. Now the temperature jumped by 0.25C and the humidity dropped by 0.7%. Not surprisingly, the error doesn’t scale linearly. A drop in duration of a factor 3.75 caused the error to drop by 2.8. it also halved the Ohms that were read … I don’t have a clue what I’m doing and this Ohms reading still feels completely arbitrary. For the time being, until some proper temperature compensation is available, I’m disabling the gas readings.

And one final thing. Mounting the BME680 as on the pictures on the product page is A Bad Idea™. The temperature measures were more than 3.4C higher from the heat radiation from the Pi Zero (not even a W, only running read-all.py). I tested it naked (the Pi, that is), with the official case, and with a Pibow. The results were always similar. If you want reliable readings, use some wire jerky and get the sensor away from the Pi. Don’t do it like Pimoroni did in the photos. Bad Pirates.

right, that mounting it is that bad eh, that seems to tie in roughly with how much off I see against BME280 BMP180 HTU21D all mounted remotely from zero w.

but still even when surrounds very cold it reads high so I will see what happens when mounting remote.

no that’s just using the code I posted on my BME680 thread in support forum.

I just observed the stepping and made a guess that that is what is happening. Having tested it with cigarrette smoke and seeing it does respond and clear and step when exposed (or not) to that.

and then only sometimes outside it gets to top range, I reckon inside has a residual paint or something voc or boron? problem?

@skypi: makes sense to me that you only get to the top range when outside. There are a lot of VOC sources inside any house.

More on the humidity: the sensor seems to be woefully inaccurate … I tried to calibrate both an AMIR and BME680 sensor using the table salt test. The AMIR sensor very quickly settles on a humidity of 75%, which it should be. The BME680 sensor settles on 68%. This means the BME680 is 7% off. In fact, all of the BME680s seem to be 7% off. I did a fairly quick check of the code but all seems fine with the _calc_humidity function. Maybe it’s somewhere else in the code, or maybe the sensors are just off.

It would be really great if Pimoroni could release a binary based on the Bosch C code or, even better, based on the BSEC library. It feels like we are groping in the dark here as we have no other point of reference for these sensors.

PS: I put one of the sensors outside to compare it with my local weather report. I hid the sensor in an empty toilet roll, so it wasn’t exactly fool-proof when it came to wind. The sensor had a temp calibration of +0.x C and a humidity calibration of +7.y %. The outside temperature/humidity reported by DarkSky is 3.1C/85%. The calibrated BME680 oscillated in the range of 3.0-3.2C, and 83.5%-86.5% humidity. So, yeah, I’m fairly convinced that somewhere in the BME680 package there is an error of 7% humidity (but I can’t find it). Or all these BME680 sensors are off by 7%RH.

I tested the C code to an extent against the pimoroni python library and the results seemed very similar, so it seems to me the sensors are high temperature and low humidity which makes sense as there is a heater on the chip and as you said the mounting direct on gpios not good…

The air quality gas readings seem good as long as you keep polling the sensor every few seconds, and a fixed compensation on temperature and humidity will work well enough for me. But seems a chip to buy more for the air quality sensor than if you just want temp/humidity which a cheap chinese bme280 will do.

There is a C example using the Bosch C library on github that the link to is in the other thread on support forum.

Of course, the gas reading is the selling point of this sensor. Nevertheless, I’m sad to see such a strong error … It still feels to me there must be a programming error (which I then assume is in the Bosch library), but as you mentioned it is easy to correct.

I have been trying a lot of different approaches for the gas readings, but the readings do seem to be related to how often you sample and how hot the plate gets. For example, using the 320C, 40ms, and sampling every second I get a value around 250,000. If I sample every 30 seconds the readings stabilise around 70,000.

You mentioned you tested the C code. Do you mean the code that corresponds to the Pimoroni Python library, or the BSEC one? I think we need to get that BSEC one up and running on a Raspberry to make any sense of the gas readings, as you need temperature compensation and/or read time compensation.

I would not touch the bsec library, the readings make sense to me, bosch want to hide it in their proprietary library… gas readings make sense, (I noticed the code seemed to be doing a stepping thing) other sensors off by a fixed amount depenent on proximity to a heat or cooling source…

probably to stop the awesome Chinese cl0ners clowning them and selling them for a fiver!

30 seconds is too long, like I said, in default state of example need to keep it rolling at less than 3s (Ns undefined) per poll, there are other states of the sensor, like ultra low power, but no documentation of how any of it works… what does work is polling in 3s or les and just average it if you want slower readings… it retrigs calibration…

the mounting is crucial! do not mount it vertical on the raspberry, mounted remotely (about 20cm away from raspberry) alongside a bmp180 and htu21d readings are within tolerance/cross-correlation.

cross correlating gas sensor against an MQ135 and an MQ7 on an arduino hooked up to raspberry which both cross correlate (same response curves different names) the stepping drops that I mention fits with the plot of both analog gas sensors… so the stepping ranges I mention seem correct!

but bme680 definitely different gas responses (says not co2 sensitive) some dips/rises where no correlation, wondering if the bosch know that at different heater profiles it responds to different gasses in a known proportion…

The BME680 is running on a separate raspberry in a slightly different area of the same room. BME rises for better air quality, analog sensors rise for poorer air quality. BME Stepping makes it not that conducive to easy graphing… But sure you can all see they mainly match.

My observed readings after few days are like the one you mentioned in this topic. It’s showing usually a value between 400k and 500k when the ‘air is pure’

It took about a week of 24h readings to reach these values. In fact, during the first days I was not able to reach 250k and I was setting 250k as max value for iaq calculation. Now am always using the highest value reached as top iaq (I save the max value in a file)
Am using the standard settings of gas readings and the 75% 25% algorithm to calculate iaq based in adafruit example (bit accurate than pimoroni)

And I confirm there is high offset in temperature and humidity when you mount the bme680 near to the raspberry. Am using a zero w and the pimoroni garden hat
I have 7% offset of humidity probably because of the gas reading. I can see humidity going down during the startup. I think I will disable gas reading for calibration one day.
The temperature also I ve set -4 degree of offset, again it’s due to the gas reading but also my mounting
Am fine with these offset as far as they r stable ^^

I’m trying to build my own office weather station, meant to monitor bad working conditions.
I have been observing the bare readings for a few weeks now and I came to some conclusions regarding the gas resistance which may be interesting for the community:

  1. The gas resistance seems to have an exponential dependency on the humidity. When you plot the logarithm of the gas readings over the humidity you may notice parallel streaks in the scattered values, indicating a constant slope with varying offset.
  2. The offset observed varies over long timespans (several days) and seems to originate from the sensor drift. I think it could be compensating by just fitting a linear function to the measurements of the past days.
  3. I tried around with different heating profiles. There I observed, that a new profile is not immidiately loaded but after the next reading. So you have to set a new profile, thean read sensor values and after that you can read values using the new profile. I am not sure if this is due to the bme itself or the python library. In general I observed that the risistance decreases for longer heating (ant hence interaction) time and higher heating temperatures. In the response to air pollution I was not albe to find any difference aside from different scalings, but maybe I was just not probing the right substances.

Currently I am trying out different algorithms for compensating the sensor drift but I think I am pretty close to obtain stable results.

was wondering if humidity was directly influencing the result so interesting to see you reckon so, it makes sense at a cooler external temperature and humidity (probably two externals affecting the heater by interdependent amounts) the heating profile might need to be change to give same absolute sensor variables. guess it depends if the time in the heater profile is enough at all external conditions to heat to target temperature perhaps, if temperature is the primary target in the firmware.

Finally, after several month I now got time to come back to my bme680 project and can share some thoughts with you.

What I have forgotten to mention in my previous post: I did some research on the sensor type used in the bme680, hoping to find some useful information in research papers. In the datasheet on page 23 it is stated that the bme680 uses a metal oxide-based sensor. In these sensors, the resistance of a thin metal oxide surface layer is measured, which is altered by adsorbing volatile gas compounds from the surrounding atmosphere. Such sensors come in heated and passive forms, depending on materials, structure and desired sensitivity, where the bme is obviously a heated-type sensor. These sensors are inherently sensitive to water vapour (by cracking the molecules down) and hence the resistance reading depends on the humidity.

Now to processing the resistance readings: For compensating the impact of humidity, I took the logarithm of the resistance readings (R_gas) and substracted the humidity (hum) multiplied by a slope-factor, which I determined from fitting the streaks in my scatter plots belonging to weekends, where no additional voc-sources were active inside my office. As a foumula, this reads:
comp_gas = log(R_gas[ohm]) + 0.04 log(Ohm)/%rh * hum[%rh] .
The slope strongly depends on your heating profile and the polling frequency!
Looking at this compensated logarithmic gas value over serveral month of data aquisition, it follows quite well my personal experience of air quality inside the office. More importantly, it yields consistent results over several weeks!
In order to determine a quality index, I simply track the maximum readings into a list, that frequently drops the oldest readings to compensate for long-time drift and set the lists mean as my 100% air quality. This method requires that from time to time you open a window and of course that you trust your outide air to be clean. The official Bosch library also uses some compensation, where you can choose the timeframe taken into consideration, but they probably use some more sophisticated algorithms.

very interesting but sorry I haven’t understood your formula…could you please explain ?
And also R_gas[ohm] and ohm are the same?
hum[%rh] and %rh are the same?
Slope factor how ca be calculated?
thanks regards

thanks

the formula is actually quite simple, the square brackets indicate the units in which the quantities have to be fed into the equation: Gas resistance R_gas in Ohm and humidity hum in %rh. Hence, the slope factor is given in units of log(Ohm)/%rh to be mathematically correct.
In a program, you would just calculate
log(R_gas) + 0.04 * hum
If you want to determine your own slope factor you first have to run the bme for some time in a clean, still environment and record your sensor readings. From these you have to plot log(R_gas) over hum and your points should align on a few parallel lines. From these you have to determine the slope either by graphical construction, difference quotients of by fitting a linear function. Just choose the method that suits you best.

1 Like

@Billy_the_nid Thanks for your research!

According to your last comment, your formula is:

comp_gas = log(gas_reading) + 0.04 * humidity_reading

Or is it this, according to your comment in January 2019?

comp_gas = log(gas_reading) + 0.04 log(gas_reading)/humidity_reading * humidity_reading

I’m kind of confused by it.

Right now I’m using the following formula:

comp_gas = log(gas_reading) + 0.04 * humidity_reading

And I’m reading the data once a minute and let it graph:

BME680 OK - Air Quality is good (13.027415110627395), Gas: 148634ohm, Temp: 12.5458203125 C, Humidity: 27.954323084484688%, Pressure: 956.7120210317003hPa |iaq=13.027415110627395;;0;500 gas=148634;;; temp=12.5458203125;;; humidity=27.954323084484688;;; pressure=956.7120210317003;;;

Could you please verify if the Air Quality (13.027…) is correctly calculated according to your formula using the sensor data?

Do I interpret the result from your formula correctly that comp_gas is a value between 0 and 500 (where 0 stands for best and 500 for worst air quality)?