SCD30 CO2 sensor: how to properly perform a forced recalibration

Hi, I bought the SCD30 sensor a while ago and I have to admit I missed to fully read your manual :oops:

To be more precise, I did not let it run for 7 days and did not put it into fresh air for at least 1 hour per day. The result is that is displays now values which are way too high. So I looked into your library at github [1], and found the function ```
setForcedRecalibrationFactor


My idea to implement it into my Arduino code, was as follows:

void calibrateSensor(){
int co2_offset = 410;
airSensor.setForcedRecalibrationFactor(co2_offset);
}


But I could find no information on how long I should let this run, and if it is correct to just enter the more or less default value of 410 there...? 

Any hint or comment would be greatly appreciated :)

[1] [https://github.com/sparkfun/SparkFun_SC ... ibrary.cpp](https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library/blob/master/src/SparkFun_SCD30_Arduino_Library.cpp)

Look at the datasheet from the SCD30, page 14. The 400PPM is an assumed outside-air CO2. Over the many years this has been increasing. Around the year 1900 it was about 200ppm and increasing since due to pollution.(our Co2 problem) The 400PPM value for outside air was agreed to be the current around 1985 but it is still increasing. Depending on the place you live it might be higher or lower and you can instruct the SCD30 to take that into account when producing the output. Looks like you expect it to be 410ppm .You will have set after each power-down / up again. The value is not saved.

However the SCD30 has another mechanism as well: Automatic Self-Calibration (ASC) (page 13 of the datasheet). ASC (once started) will continue to calibrate (and you need to place it in outside air for at least one hour assuming that will be the air with the lowest CO2). The result is stored in non-volatile RAM and used every time after power-up. ASC, once enabled, we also turn on after power-on. You can disable ASC with airSensor.setAutoSelfCalibration(false). In the Sparkfun library it is turned ON every time airSensor.begin() is called.

You can NOT use BOTH FRC and ASC at the same time. The last setting/instruction sent is used. So setting FRC will overwrite the ASC value to use and vice-versa. FRC will NOT overwrite the ASC value in non-volatile RAM, just the value to use !

The best you can do is :

  • Keep ASC enabled (e.g. restart the sketch, without FRC).

  • Expose you SCD30 to outside air for at least one hour a day and then to inside air. Do so for a couple of days and it will self-calibrate. DO NOT power-off for the time of calibration, it will need at least 7 days.

  • Once you get good output numbers you trust, you should actually in your sketch right after airSensor. begin() add airSensor.setAutoSelfCalibration(false). Of course you can also de-activate and then change the Sparkfun library begin() call to comment out setAutoSelfCalibration(true).

The stored ASC value in non-volatile RAM will continue to be used even with ASC disabled. You just disable further update to that value.

First of all, thanks a lot for your detailed reply!

paulvha:
You will have set after each power-down / up again. The value is not saved.

Wait, I thought using the **forced recalibration** will **save** that corresponding values obtained during that recalibration **into the non-volatile RAM** ? Which means that I only need to do this once it a while...?

paulvha:
However the SCD30 has another mechanism as well: Automatic Self-Calibration (ASC) (page 13 of the datasheet). ASC (once started) will continue to calibrate (and you need to place it in outside air for at least one hour assuming that will be the air with the lowest CO2). The result is stored in non-volatile RAM and used every time after power-up. ASC, once enabled, we also turn on after power-on. You can disable ASC with airSensor.setAutoSelfCalibration(false). In the Sparkfun library it is turned ON every time airSensor.begin() is called.

I turned it off using ``` airSensor.begin(Wire, false) ``` because the sensor will be placed in a more or less fixed position and exposing it to real fresh air is not really possible, this is why I wanted to do the forced recalibration only once in a while (every few months or so)

paulvha:
The best you can do is :

  • Keep ASC enabled (e.g. restart the sketch, without FRC).

  • Expose you SCD30 to outside air for at least one hour a day and then to inside air. Do so for a couple of days and it will self-calibrate. DO NOT power-off for the time of calibration, it will need at least 7 days.

keeping it running for 7 full days is also not possible (not with at least several interruptions, for example when bringing it outwards because then I need to connect it to a portable USB-charger, when being inside again, however, I need to connect it to the grid/laptop - and every interruption will reset this calibration process)

paulvha:
The stored ASC value in non-volatile RAM will continue to be used even with ASC disabled. You just disable further update to that value.

unless I do the forced recalibration, correct?

Forced calibration is NOT saved. It is a one-time (until next power down/up) instruction to the running program in SCD30 to use that PPM as a base. It will NOT force a change or calibration for longer time, it is just a one-time variable change for the current running program in the SCD30.

Start begin( Wire, false) will indeed NOT start measurement and start ASC. You will have to start measurement instead with setMeasurementInterval(2); (for every 2 seconds). However if you have run begin() ONCE before without false, the ASC will start every time, updating the value, and you have to de-active ASC manual. Once activated ASC will be active after each power down / up unless you de-activate . An FRC call will only overrule the base PPM value the current running program has first read from NOV-RAM.

paulvha:
Forced calibration is NOT saved. It is a one-time (until next power down/up) instruction to the running program in SCD30 to use that PPM as a base. It will NOT force a change or calibration for longer time, it is just a one-time variable change for the current running program in the SCD30.

Start begin( Wire, false) will indeed NOT start measurement and NOT (again) start ASC. You will have to start measurement instead with setMeasurementInterval(2); (for every 2 seconds). However if you have run begin() ONCE before without false, the ASC will start every time, updating the value, and you have to de-active ASC manual. Once activated ASC will be active after each power down / up unless you de-activate . An FRC call will only overrule the base PPM value the current running program has first read from NOV-RAM.

Thanks again for your detailed reply!

paulvha:
Forced calibration is NOT saved. It is a one-time (until next power down/up) instruction to the running program in SCD30 to use that PPM as a base. It will NOT force a change or calibration for longer time, it is just a one-time variable change for the current running program in the SCD30.

Don't get me wrong, but are you sure about this, because the documentation says _The FRC method imposes a permanent update of the CO 2 calibration curve which persists after repowering the sensor._ [Page 14]

paulvha:
Start begin( Wire, false) will indeed NOT start measurement and start ASC. You will have to start measurement instead with setMeasurementInterval(2); (for every 2 seconds).

in my code I am only using ``` begin( Wire, false) ``` without explicitly calling ``` setMeasurementInterval(2); ```, but still get continuous measurements - well, to be more precise, I get values returned by ``` airSensor.getCO2(); ```.... I am puzzled now....

paulvha:
However if you have run begin() ONCE before without false, the ASC will start every time, updating the value, and you have to de-active ASC manual. Once activated ASC will be active after each power down / up unless you de-activate . An FRC call will only overrule the base PPM value the current running program has first read from NOV-RAM.

Ok, I did not knew that (and could not found that in the documentation, but that might not mean much), thanks a lot! I will now explicitly deactive ASC, just to be sure.

Agree this is confusing as on the same page 14 it states : After repowering the sensor, the command will return the standard reference value of 400 ppm

As for your code: you use the right sequence, but after begin(wire, false) do you FRC call : setForceRecalibration(410), and then start measurement etc.

A last point: Sparkfun library was written against the documentation that was valid at that time. In May2020 a new datasheet was submitted by Sensirion with additional functions. I had already taken the Sparkfun library as a starting point and added addiotional functions and examples. The library https://github.com/paulvha/scd30 now also has the additional functions and now you can read the FRC : with getForceRecalibration(). This will also work on an ESP32, which by default does not support clock-stretching which is needed)

paulvha:
Agree this is confusing as on the same page 14 it states : After repowering the sensor, the command will return the standard reference value of 400 ppm

Just to clarify this, since I had a discussion with Sensirion about this topic: **both sentences are correct**.

The first sentence in the manual reads “The FRC method imposes a permanent update of the CO2 calibration curve which persists after repowering the sensor.” Sensirion confirmed that this is true.

The second sentence was “After repowering the sensor, the command will return the standard reference value of 400 ppm.” This refers to a command reading out the reference value. Sensirion confirmed that only before repowering, the sensor returns the updated value used in the FRC process. After repowering, the standard reference value is read out, altough this is not the value which is actually used in our case - it is still the value which we set doing the FRC before.

paulvha:
As for your code: you use the right sequence, but after begin(wire, false) do you FRC call : setForceRecalibration(410), and then start measurement etc.

Since you are asking about my calibration, this is the calibration code, which is part of the setup() function
airSensor.begin(Wire, autoSelfCalibration);
delay(1000);
airSensor.setAltitudeCompensation(altitudeOffset);
airSensor.setTemperatureOffset(TempOffset);

If I do an FRC, I call the calibrateSensor() function mentioned in an earlier post in the loop() function, i.e. after the calibration function.

paulvha:
A last point: Sparkfun library was written against the documentation that was valid at that time. In May2020 a new datasheet was submitted by Sensirion with additional functions. I had already taken the Sparkfun library as a starting point and added addiotional functions and examples. The library https://github.com/paulvha/scd30 now also has the additional functions and now you can read the FRC : with getForceRecalibration(). This will also work on an ESP32, which by default does not support clock-stretching which is needed)

Thanks a lot for all your work!

Thanks … good to know !