robert-hh / BME680-Micropython

Micropython driver for the BME680 sensor
34 stars 11 forks source link

Add VOC calculation #3

Open StevenCellist opened 2 years ago

StevenCellist commented 2 years ago

Hi Robert,

I would like to see VOC calculation added to the these drivers. I would like to use this issue to discuss calibration and calculation. Yesterday, the Extech VFM200 arrived, so I gave it a shot this afternoon to try and see if I could find a way to calculate the VOC contents of the air using the BME680 resistance measurement.

See the figure below. Here, the blue line as indicated is as measured by the VFM200 sensor. The orange line (method 1) is my best shot at using relative changes in values, which should be the way to get the VOC. This is because the resistance measurements are heavily influenced by polling frequency mostly. Note that this method requires knowledge of previous values which could be a problem on some microcontrollers using deepsleep. Problem here is that the starting point has been manually entered by myself because there are no previous values. The green line (method 2) is a direct calculation of the VOC based on the current measured values which is much simpler but sketchy and as said not to be trusted.

Curve-fit2

Measurement method: 30 minutes total, polled every 10 seconds. Minutes 0-14: inside room behind window Minutes 14-22: open window Minutes 22-30: in enclosure with active (and somewhat ventilated) 3D-printer

Please let me know your thoughts and I will try to follow this up with additional measurements with other polling frequencies or other environments for longer duration. Will need a better way to get the values without manually working my way through each frame of a timelapse.

EDIT Another note: both sensors are completely passive, no active ventilation.

robert-hh commented 2 years ago

That looks indeed promising. Did you change the BME680 driver or did you just called the gas value method? And what were the sample rates for the two BME680 series?

StevenCellist commented 2 years ago

I used your driver with sleepmode (see pull request). I let the sensors stabilize for a few minutes (measure every 0.5 seconds for one minute, then a couple of minutes every 10 seconds), after which I started the measurement. Every 10 seconds, I measure the temperature, relative humidity (and calculate the absolute humidity using a seperate function) and resistance, and display those 4 on a small OLED display. After a single measurement in Forced mode, I set the device to sleepmode using the new function. (And then after 10 seconds it performs one measurement in Forced mode etc...) The VFM200 was put right next to it, and every 10 seconds I took a picture using my phone's Timelapse function with 10s interval.

Note that I optimized the curve fit for this specific run, so it may not be as accurate outside the house in 10C for example.. will see about that later :)

robert-hh commented 2 years ago

The PR looks fine and is a useful addition. So you were sampling every 10 seconds for the better fit, and how often for the worse fit?

StevenCellist commented 2 years ago

Both fits were based on the same data, but the first is done using two logarithms working on the difference between current and previous values and some constants in order to find the best fit, while the second one is a straight forward calculation based on only current values.

StevenCellist commented 2 years ago

After reducing the amount of magic happening in the calculation, I did another run from inside my room next to a closed-open-closed window. Interestingly enough, the VFM200 did not manage to react to me closing the window, while my algorithm on the BME680 data clearly does (which may be expected since indoor VOC contents are generally significantly higher than outdoor). There are only two magic numbers right now: one that helps calculating the initial value automatically, and one that says how much it should react to relative changes.

Below are the updated calibration on the first run and also the second run: Curve-fit2 Curve-fit3

robert-hh commented 2 years ago

In the second attempt both sensor series went flat zero, even if started in the same range. The VMW200 may have needed more time to recover. Is there an underflow situation?

StevenCellist commented 2 years ago

That could be very much possible. My graph not going below zero was me limiting the minimum value to zero. So it might be that Extech in their calculations did just the same and it takes much longer for the sensor to recover than for the BME680 in my current calculation method!

StevenCellist commented 2 years ago

While I did not have a chance yet to do more official calibration runs, I did leave the device running for two days and two nights. Sadly, during the nights my serial connection crashed so I only have results from wakeup (8am) to signing off (10pm). I also can not prove that these values are somewhat correct since I did not record the VFM200, but they are at least quite likely and definitely quite stable (which cannot be said about calculations I found on the internet). See image below. Regarding the run on 12-02: I was in the room until about 1pm after which I went for lunch and left for the day. A clear decrease in VOC contents is visible. A funny thing to note is that my presence in the room on 13-02 can be seen very clearly: VOC contents rose when I was in the room, while they dropped when I left (up to four times). So all in all very reasonable results! Will have to see coming days if this algorithm also holds when the sensor is outside only.. I am expecting worse results, TBH. 12-13_02

StevenCellist commented 2 years ago

I just started looking at the VOC calculations again. I am now using the Pimoroni driver, which allows settings the heater target temperature and duration. And this sure is going to be a catastrophe: the measured resistance is HEAVILY influenced by both parameters (temp / duration). And there's a third independent variable at play: polling frequency. Measuring every 50 seconds vs every 60 seconds also noticably alters the measured values. Even worse: for all three parameters, there is no clear relation visible to my eyes (e.g. linear). It will already be hard to try and unify my 60 LoPy4 nodes' sensors... (yep same person as the Pycom forum ;))

robert-hh commented 2 years ago

This gas sensor thing is still on my list. I plan to set up first a method for

It is clear, that: a) the gas readings depend highly on the temperature. So it may be better to heat the sensor before reading, such that the sensor is at a known temperature substantially different from the environmental temperature. b) that after heating the device one has to wait long enough before the next temperature/humidity reading is made. I do not know what long enough is, but I expect several minutes. c) That the sensor must be set to sleep mode (or off) between reading cycles.

StevenCellist commented 2 years ago

Regarding a), the sensor does that automatically: it defaults to a heating temperature of 320C for a duration of 150ms. The temperature range can be set from 200-400 and duration from 1-4095 milliseconds manually (up to 10 profiles can be stored and selected in the sensor's memory). For b), I hardly see any problems polling every 30 seconds: the values I get are very close to the multiple temperature sensors I have in house. c) is also included in the Pimoroni library and my multimeter agrees with the sleep modes that they use.