Altitude compensation for CO2

Hello,

I’m considering purchasing an Air Gradient One for measuring air quality in my child’s bedroom during the night, and my office during the day (I work from home). I live in a city with high relative humidity throughout the year, and at 800m above sea level.

I’ve been discussing different points around this with @Ethan_AirGradient on the breathe safe air forum. Ethan has been incredibly helpful and openly addressing and explaining every single detail to me.

My latest question, which I’m now bringing here as well, is regarding an altitude compensation for the CO2 sensor readings. I learned about it on the Aranet4 Forum: Altitude compensation

Based on Ethan’s latest reply (Night air quality monitor for child respiratory issues (at high RH) - #6 by Ethan - Air Quality Monitors - BreatheSafeAir Forum) , it seems that the S8 sensor may not have such compensation available off the shelf (or at least it is not explicitly documented), whereas it states to expect deviation of 1.6% per kPA. In my case, I’m under the impression this could lead to 16% deviation then.

I would like to ask if anyone has implemented such altitude compensation for the S8 sensor, either by incorporating a barometric sensor to the device and/or by manually using the known current altitude? I tried to search in the forum with some key words (barometric, pressure, altitude, elevation) but couldn’t find it yet.

Any ideas or suggestions would be appreciated :slight_smile:

1 Like

First I’ve heard of it.

I’m not aware of the Arduino or ESPHome firmware having this compensation factored in, but with ESPHome you could add a fixed offset if it is linear, or come up with the formula to substitute in. Same would be possible with the Arduino code, although I wouldn’t know where to start with that.

Thanks for your input here. Below is an illustration extracted from the Aranet4 's sensor (Sunrise) sheet:

So it might be that the ability to add a formula, based on my location’s air pressure, could do the trick here (?)

However, I’d be curious to further understand how that would potentially interact with the offset obtained from the sensor calibration? Or would the inserted custom formula completely replace the calibration offset?

1 Like

In case someone is interested to read more about it (how NDIR sensors can also be influenced by air pressure):

https://www.bapihvac.com/application_note/effects-of-temperature-and-barometric-pressure-on-co2-sensors-application-note/

And below the source link for the extracted figure in my previous post (sorry I forgot to add there):

Obtained from: Sunrise | Air quality & Gas sensing technology from Senseair

1 Like

I’ve reached out to Senseair to ask about such altitude compensation on the S8 sensor, below is their response:

We do not have the same airpressure/altitude function in S8 as we do on the Sunrise/Sunlight family.
We have added same type of functions on the new product S88 though.

Looking S88 up (S88 | Air quality & Gas sensing technology from Senseair), it seems to be a “refresh” of the S8 sensor, and they state the replacement should be smooth:

should you choose, transitioning from the S8 to the S88 is as smooth as possible.

Among the documents available, I can see that in the Modbus they provide the option to inform current pressure to the sensor, as shown below:

Modbus on S88: https://rmtplusstoragesenseair.blob.core.windows.net/docs/Dev/publicerat/TDE14367.pdf

@Achim_AirGradient , I would like to ask if you think it is potentially possible to replace the S8 with S88 in the Air Gradient One to allow for such altitude compensation as informed by the user? My gut feeling says I may still be ignoring many relevant details on this (due to my limited knowledge), thus wanted to hear your thoughts here too.

1 Like

@Guilherme this is very interesting. Thank you for sharing!

Currently we do not have immediate plans to switch away from the S8 because we first like to see new sensor modules in the market for a while to see their longer term performance.

We will look into this with our science team but my gut feeling is that in most cases it will not have much impact. The impact of the altitude is much lower in small concentrations and I believe the inherent inaccuracy of the ABC or general drift of the monitor will be larger.

For higher concentrations the CO2 is too high anyway and measures to reduce need to be taken.

I think it’s important to be very transparent and open here. Sensor modules in low cost monitors are not scientific reference instruments. There is and will always be inherent inaccuracies. The key is to get good enough information out of them to inform the users about potential health impacts or when for example to open windows etc.

Having said this, we always look into making them more accurate and our science team will look into this.

Hi @Achim_AirGradient, thank you for your further input in this discussion!

I appreciate having Air Gradient’s science team looking into this. If I can contribute with this investigation by any means, please let me know.

If not switching away from S8, I believe we might still have the alternative to implement a correction formula to mimic S88 / Sunrise behaviors while combining S8 raw readings with the end user’s informed altitude. I am not entirely sure how that interacts with the sensor calibration, but maybe Senseair could also contribute with that information.

While I appreciate both the opportunities and the challenges by low-cost sensors, I am also confident we can attempt to reduce the accuracy gap with reference instruments by incorporating such adjustments. This one in particular, if proven to be based on a multiplying factor derived from the user’s altitude, might be quite promising.

Looking forward to additional input from the science team. :slight_smile:

I’ve asked Senseair about the formula to correct this in the S8 sensor, below is their response:

General mathematics is pretty simple for what you aim to do as you can see on our technical documents on the web site.
We calibrate at factory against 1 std sea level atmosphere.
image

Most CO2 sensors anyway runs without altitude or pressure compensation and this work well for standard applications. So generally I would say you do not need to worry about this.
If you anyway want to implement something into your function use the simple formula shown here above.

@Achim_AirGradient , if I would like to implement that correction (16%, in my case), could I do directly by editing the open-source firmware code (e.g. when reading the CO2 level) before flashing?

1 Like

Yes, that is quite easily possible. You can add the factor in the firmware before its send to our server.

1 Like

I would love this too. I live at 6000 feet.

If anyone wants to learn more about this, I’ve done some testing at 1500 metres altitude, and the difference between an air pressure-corrected CO2 sensor and a non-corrected sensor appears to be quite significant!

1 Like

In case anyone is interested in altitude compensating their CO2 readings obtained from AirGradient, today I did manage to adapt the firmware code, flash it to the device, and I now see in the Serial Monitor both values (with and without compensation) being printed out as expected. It’s quite nice!

Below are the changes I introduced in the co2Update function defined in the OneOpenAir.ino (arduino/examples/OneOpenAir/OneOpenAir.ino at master · airgradienthq/arduino · GitHub):

static void co2Update(void) {
  int value = ag->s8.getCo2();
  if (value >= 0) {
    measurements.CO2 = 1.14 * value;
    getCO2FailCount = 0;
    Serial.printf("CO2 (ppm) (sensor raw value): %d\r\n", value);
    Serial.printf("CO2 (ppm) (altitude-compensated): %d\r\n", measurements.CO2);
  } else {
    getCO2FailCount++;
    Serial.printf("Get CO2 failed: %d\r\n", getCO2FailCount);
    if (getCO2FailCount >= 3) {
      measurements.CO2 = -1;
    }
  }
}

The 1.14 correction factor I used was determined based on my estimated current altitude (780 m), and then I used this online tool to retrieve the corresponding air pressure: Air Pressure at Altitude Calculator .

I estimated that at 20ºC, which is a typical indoor temperature here. The difference between the resulting air pressure (92447) and the one at sea level (101325) is then 8.88 kPA. And this is then applied to the Senseair pressure dependence mentioned in a previous post: “+1.6% for each kPA deviation from normal pressure”. Thus 8.88 * 1.6% ~= 14%

Using VSCode, I then edited the underlying code for the 3.1.4 AirGradient library installed in my Arduino IDE to incorporate the code snippet above. Then I followed following instructions to flash the adapted firmware to AG monitor: Install the Arduino Software for the ESP32-C3

And here are the results:

CO2 (ppm) (sensor raw value): 787
CO2 (ppm) (altitude-compensated): 897

As I’m only passing the latter (altitude-compensated) to the measurements.CO2 in the code, this is the one I get then to see in the AirGradient dashboard now.

1 Like

Isn’t S88 also much cheaper? In single quantities on DigiKey, the S88 is less than half as expensive at just 20 USD (15USD/ea for 250). S8 and SUNRISE meanwhile both are in proximity of 50USD (30 USD/ea for 250).

So the promise is not only an improved accuracy but also a significant decrease in BOM?

We are currently testing the S88. There are a couple of environments we want to test it in so it will take a while.

Follow-up: as I was thinking more about CO2 sensor calibration, I realized that my implementation above to compensate altitude has a potential flaw: the sensor is unaware of the altitude compensation being applied (as it was not designed to account for it), and is therefore still considering the uncompensated values for its weekly automatic calibration.

Thus, after one week of data at the higher altitude location, the sensor will find an offset X and apply that to reach 400 ppm internally. In my case, assuming the actual outdoor CO2 concentration was indeed 400 ppm, and that any deviation to that value was solely caused by the altitude, then we could expect the sensor to have registered internally a minimum value of 400 ppm / 1.14 = 351 ppm . Therefore, it will start to apply internally an offset of +49 ppm to all following readings:

sensor_offset = 400 - ( 400 / compensation_factor) = 400 - (400 / 1.14)= 49 ppm

More generic, if we didn’t know the S8 calibration target and the actual outdoor CO2 concentration:

sensor_offset = calibration_target - (CO2_outdoor / compensation_factor)

Now, the combined effect of my compensation formula on top of sensor calibration will rather result on (351 + 49) * 1.14 = 456 ppm, which will now be my indoor baseline moving forward and is likely wrong. As expected, all other values will be impacted as well by such artificial offset (for me: 56 ppm), as follows:

artificial_offset = sensor_offset * compensation_factor, or
artificial_offset = calibration_target * compensation_factor - CO2_outdoor

So, to avoid this kind of artificial offset, one could improve the compensation formula to be:

CO2 = (compensation_factor * value) - artificial_offset
CO2 = (compensation_factor * value) - (calibration_target * compensation_factor - CO2_outdoor)
CO2 = compensation_factor * (value - calibration_target) + CO2_outdoor

In my case, I’m unaware of the actual CO2 outdoor level, so I’m rather assuming this to be 400 ppm (same as the sensor calibration target), and therefore will correct the formula to simply be: (1.14 * value - 56)

1 Like

Just to add an unsolicited comment. I would also be interested in the outcomes of the S88 testing.

Looking to add a few DIY units to my existing purchase assembled units and the S88, based on the data sheets, looks like an improvement with a lower price.