PMS5003 gas measurement with an enviro+ on a Raspberry

Hi, I have a small question regarding information provided on this link: https://learn.pimoroni.com/tutorial/sandyj/getting-started-with-enviro-plus

I got the reading for the different type of gases (reducing, oxidising, nh3) in Ohms (if I am not mistaken). However, how do I calculate the concentration value of the gas in ppm as seen in the graph provided in the explanation above:

What will be the CO concentration of a 237175.141075 Ohms for “reducing”?

What are Rs and R0? Is there a way to adapt the estimation of the gas based on the condition in which the measurement take place (like temperature, average humidity, or something like that).

Thank you for your help!

1 Like

I came across your post when searching before posting on a similar topic.

If you look at the example programs, they all read the values for the gas sensors, divide each by 1000 and display the result as kOhms. That is easy to do, and is the Rs value.
In contrast, we do not know what the R0 value is. If you read the Notes at the bottom of the second page of the MiCS-6814 data sheet, R0 is defined as the resistance under controlled conditions (synthetic air at specific temperature and humidity). As hobbyists, we are not able to produce such conditions. Also on page 2, we see that R0 has a very wide specification (100 to 1500 kO for the reducing CO sensor, 0.8 to 20 kO for the oxidising NO2 sensor and 10 to 1500 kO for the NH3 sensor).
Even more concerningly, the lines for reducing CO and for NH3 have negative gradient (slope downwards), meaning that a higher Rs means a LOWER gas concentration. The example programs are not intended to give accurate readings, but they should at least move in the correct direction, so that a high value means a high gas concentration, and ideally we would have some degree of proportionality (so that 10x the value means 10x the gas concentration, even if we cannot calibrate accurately).
So I set about trying to create a better conversion formula - which basically involves working out an equation for each of the calibration lines [not so simple, because they are log-log plots to make straight lines], including somehow estimating R0. For the latter, I assumed that my rural air is fairly but not completely clean, and mapped that to a value about double the minimum detectable concentration (again from page 2 of the sensor datasheet).
I can share my formulae, but before doing so would appreciate feedback from the community to reassure me that I am progressing appropriately and am not missing to see something. To be honest, I find it odd that the example programs seem to contain such a glaring mistake - making me think I may be off-track, and yet I don’t think I am.

I have now looked at the tutorial you referred to (I’ve not see it previously!) and it answers some points:

  1. It does acknowledge that

The reducing and NH3 resistance readings will drop with increasing concentrations of the gases that they detect, and the oxidising sensor will increase with increasing levels of nitrogen dioxide.

so at least that confirms that I am correct to say there is a problem (or at least, room for improvement)
2. Elsewhere in the product description, Pimoroni say:

The analog gas sensor can be used to make qualitative measurements of changes in gas concentrations, so you can tell broadly if the three groups of gases are increasing or decreasing in abundance. Without laboratory conditions or calibration, you won’t be able to say “the concentration of carbon monoxide is n parts per million” , for example.

But I think we can do a lot better than just reporting the raw resistance of the sensor, with values moving in the wrong direction!
3. To understand my mentions of ‘second page of the MiCS-6814 data sheet’, use this link. This is where the graphs came from, but I now realise you may not have seen it! It’s at https://www.sgxsensortech.com/content/uploads/2015/02/1143_Datasheet-MiCS-6814-rev-8.pdf

As you pointed out, these sensors are really for qualitative measurements, you can’t really convert the readings into ppm values because you don’t know the proportion of gasses it is detecting, and some of them will have negative influences on the readings.

Unfortunately it’s super hard to get precise gas readings, but these sensors are cheap so people put up with the qualitative nature of it. Adafruit recently released a ppm-accurate CO2-specific sensor board, but despite being the cheapest sensor of that type they could find it’s far more expensive and bulky.

Thanks. There’s all the difference in the world between

The reducing and NH3 resistance readings will drop with increasing concentrations of the gases that they detect, and the oxidising sensor will increase with increasing levels of nitrogen dioxide.

which means that the values displayed for reducing (CO) and NH3 are actully misleading, and making a semi-decent attempt to display values that (a) move in the right direction and (b) give some indication of the magnitude of change.

I found an earlier post which has derived conversion formulae in a form which are similar to mine, and that gives me the reassurance that I am heading the right way.

So, the equations (code) I am presently using are (is) as follows [note you cannot simply copy my numerical factors - need to work out your own]:

from math import log10
gases = gas.read_all()
# oxidising, NO2: ppm = Rs /(6.5 * R0)
NO2 = gases.oxidising/6.5/20000 # R0 chosen to give value approx 0.01 in fresh air (detectable = 0.05 to 10)
# reducing,CO: ppm = 10^((log10(Rs / 3.5 / R0)) / -0.845 )
CO = 10**((log10(gases.reducing/3.5/150000)) / -0.845) # R0 chosen to give value approx 2 in fresh air (detectable = 1 to 1000)
# NH3: ppm = =10^((log10(Rs / 0.77 / R0)) / -0.5335 )
NH3 = 10**((log10(gases.nh3/0.77/570000)) / -0.5335) # R0 chosen to give value approx 2 in fresh air (detectable = 1 to 300)

The formula for oxidising, NO2 is simpler because things happened to cancel out in derivation, not because that is the line with positive gradient.

The previous post that I mentioned has equations of a similar form (except uses math.pow(10, …) rather than the more conventional 10**(…) for antilog, and he has moved the 3.5 and 0.77 factors outside of the antilog. But basically the same. He has also uses a stable value after sensors have been powered on for 100 minutes to derive R0 - which seems a good idea, and may allow selection to be semi-automated. Don’t forget that the parameter values will vary a lot between different sensors. I’ve yet to examine in more detail.
The previous post is at: Enviro+ / Ohms to PPM - #6 by Jdtinker

After much further inspection, I really like the work roscoe has done, and I recommend it.

It takes all the Pimoroni example programs and builds them into a coherent working system. It reads the PM and the 3 gas sensors. It reports the PM2.5 and PM10 to Luftdaten, and can upload the PM and gas sensors (as well as standard weather measurements) to a personal page on http://io.adafruit.com . It takes care of selecting appropriate values for R0 (as though by magic - just let it do its stuff), and corrects the value each day at 0300, based on experience from the previous week.
I built a ‘Gases’ display page to better meet my needs than the provided samples - take a look at my page at IO - Adafruit