Go Down

Topic: Understanding the equations for the Grove Alcohol Sensor (Read 481 times) previous topic - next topic

ArduinoBasics

Hi everyone,

I am currently following a tutorial from the Seeedstudio Wiki that relates to the Grove Alcohol Sensor.
Look here for reference: http://wiki.seeedstudio.com/Grove-Alcohol_Sensor/

Here is the code in question:
Code: [Select]
#define heaterSelPin 15

void setup() {
    Serial.begin(9600);
    pinMode(heaterSelPin,OUTPUT);   // set the heaterSelPin as digital output.
    digitalWrite(heaterSelPin,LOW); // Start to heat the sensor
}

void loop() {
    float sensor_volt;
    float RS_air; //  Get the value of RS via in a clear air
    float sensorValue;

/*--- Get a average data by testing 100 times ---*/
    for(int x = 0 ; x < 100 ; x++)
    {
        sensorValue = sensorValue + analogRead(A0);
    }
    sensorValue = sensorValue/100.0;
/*-----------------------------------------------*/

    sensor_volt = sensorValue/1024*5.0;
    RS_air = sensor_volt/(5.0-sensor_volt); // omit *R16
    Serial.print("sensor_volt = ");
    Serial.print(sensor_volt);
    Serial.println("V");
    Serial.print("RS_air = ");
    Serial.println(RS_air);
    delay(1000);
}

.
.
I understand the sensor_volt equation. Essentially converting the analog reading back to a voltage.
I personally think they should be dividing by 1023, but that is not my question.
My question relates to the next equation.
Code: [Select]
RS_air = sensor_volt/(5.0-sensor_volt);
I am guessing that they are converting the voltage back to resistance?? Can anyone explain how that equation works, or point me in the right direction ? I am trying to understand how they came up with that equation.

The grove alcohol sensor uses an MQ303A sensor.
Datasheet for the grove module and the MQ303A sensor can be found within the wiki (see link above).

Thanks
Scott

jremington

To accurately convert an ADC value to voltage, it is correct to divide by 1024, but probably not to multiply by 5.0. Substitute the actual ADC reference voltage instead.

The RS_air value is a dimensionless ratio that is useful for calculating the sensed alcohol concentration. In principle it could be a resistance (note the comment "omit *R16") and comes from the use of a voltage divider in the sensor. Consult the sensor data sheet for more information.

It looks to me that the code (as well as the comments) in the second part of the tutorial is wrong, specifically this section. The RS_gas formula lacks the parentheses.
Code: [Select]

    RS_gas = sensor_volt/5.0-sensor_volt; // omit *R16

  /*-Replace the name "R0" with the value of R0 in the demo of First Test -*/
    ratio = RS_gas/RS_air;  // ratio = RS/R0


To make sense of the data requires calibrating the sensor in air, with known alcohol concentrations.

You should find this electronic nose tutorial useful.

ArduinoBasics

Ok thanks for your reply.
I think it makes sense now.

I am almost certain that it is a resistance calculation. However, the lack of a resistor value (from a voltage divider equation) confused me.


Code: [Select]
    Vout = Vin * (R2/(R1+R2))

or if I use their variables, it would look something like this:

    sensor_volt = 5.0 * (RS_air/(R1 + RS_air))


And after shuffling the variables around, I get this:

    RS_air = (sensor_volt * R1) / (5.0 - sensor_volt)


If you look at their equation - they have this:

    RS_air = sensor_volt  / (5.0 - sensor_volt)




As you can see, the R1 is missing from their equation.
Then I suddenly realised (as you pointed out) that they use this RS_air value in a ratio.

Which means that when you divide RS_gas by RS_air, the R1 values cancel out.
So you don't need to know the R1 value - and probably why it is omitted.

I did not know what "R16" was in their code comment. But now it makes sense when you look at the datasheet for the grove sensor (that you highlighted). It is the 10k resistor connected to the MQ303A,  alcohol sensor. And I guess it acts like a voltage divider.

Thank you very much for your help.

Now, the next niggling point, that relates to the sensor_volt calculation:
Code: [Select]
sensor_volt = sensorValue/1024*5.0;

The division by 1024.
You said that the division by 1024 is correct, but the multiplication by 5.0 is not correct.

I think it should be:

Code: [Select]
sensor_volt = (sensorValue/1023)*5.0;

Mainly because of this tutorial:
https://www.arduino.cc/en/Tutorial/ReadAnalogVoltage

But also I thought you could do it this way:
Code: [Select]
sensor_volt = map(sensorValue, 0, 1023, 0, 5);

Using the map equation found here - you could re-write the above map function like this:

Code: [Select]
sensor_volt = ((sensorValue - 0) * (5.0 - 0)) / ((1023 - 0) + 0);

Which is the same as:

sensor_volt = (sensorValue * 5.0)/1023



Maybe I have overlooked something here though??

jremington

Quote
I think it should be:
sensor_volt = (sensorValue/1023)*5.0;
You would be wrong on two counts.

There are 1024 steps in the ADC result, so 1024 is the divisor to use. (You would not use "1" as the divisor for a 2 step ADC).

If you want to know the best estimate of the actual voltage reported by the ADC, you have to use the actual value of the reference voltage, which is almost never 5.000 V. If you are using USB to power the Arduino, it is probably about 4.5V. Measure it with your multimeter.

Many people incorrectly use 1023 as the divisor, and this has been debated many times, particularly on this forum. Please look up those discussions.

ArduinoBasics

You are right - there are many debates relating to the divisor 1023 vs 1024.  :o
For those playing at home, you may find this thread interesting to read.

After all that debating, I am not sure if anyone clearly knows which is correct.
You are clearly sitting in the 1024 camp.
I don't know where I sit anymore.

But hey, the tutorial has it as 1024, so I guess there is no need to change it.

And yes - I am aware of the reference voltage requirement. But used 5.0 to keep it consistent with the tutorial from Seeedstudio.

Thanks again for your input (no pun intended).


jremington

Quote
After all that debating, I am not sure if anyone clearly knows which is correct.
Anyone who understands basic mathematics and thinks about it for a bit can explain why 1024 is correct.

Then, courtesy of the people who designed and made the processor, there is the data sheet, ADC section:



It is silly to stick with someone else's example, if it gives you the wrong answer.


ArduinoBasics

Anyone who understands basic mathematics and thinks about it for a bit can explain why 1024 is correct.
...
It is silly to stick with someone else's example, if it gives you the wrong answer.
I personally don't think that the ability to do basic maths has anything to do with the "divide by 1023 vs 1024" debate. I do think, however that there are far too many examples on the internet (including the one from the official Arduino website), that show the method that I employed above, and not enough examples which explain the key information required to make an informed decision.

The biggest misconception that I had - actually related to the Analog reading of 1023, and what that reading actually means. I thought that the reading of 1023 equates to 5V, or to the Vref. So when you have that misconception, it doesn't make sense to divide by 1024
----------------------------------------------------------------------------
For example,
If Vin is 5V, and Vref is 5V, then using the formula you provided, ADC = 1024. But you never get a reading of 1024, you get a reading of 1023.

Put another way, if you get a reading of 1023 on the analog pin, and know that Vref is 5V, and try to calculate Vin using that formula, you will NOT get the expected answer of 5V. You get 4.995117. But if you instead, divide by 1023, you get the expected result of 5V... and the misconception is fortified.

-----------------------------------------------------------------------------
But there is some VERY IMPORTANT INFORMATION MISSING.

According to the datasheet:
"The ADC converts an analog input voltage to a 10-bit digital value through successive approximation. The
minimum value represents GND and the maximum value represents the voltage on the AREF pin minus 1 LSB.
"

With that information in mind, the formula you provided from the datasheet makes a whole lot more sense.
That means, if you have a Vref of 5.0, the maximum Vin that the ADC can detect is actually 4.995117 and not 5V.

Which means, that if you supply any voltage between 4.995117 to 5V to the Analog pin, it will show a reading of 1023.
Penny dropped at that moment.

Which means that if you choose to divide by 1024, you must understand that the calculated Vin may be out by as much as 1 LSB.  So not only must you use the formula that you provided, you also need to calculate 1 LSB, in order to understand the range that the Analog reading represents.

Now that may have been clear to you all along, but if more people provided that key bit of information, then there would be much less debating.










jremington

Use of any number other than 1024 is mathematically incorrect, but here is a hint: there are 1025 values (endpoints) associated with an interval divided into 1024 segments.

You can't represent all of the endpoint values using 1024 numbers, you can represent only the 1024 ranges of values associated with each interval.

But if additional information, like how the ADC works, helps you to accept the correct answer, that is fine.

MarkT

The 1023/1024 thing depends on the nature of the ADC circuitry, either is entirely possible.  In
fact with a SAR (successive approx) ADC, its the inbuilt DAC's characteristics that determine
which the correct divider is.  R-2R DACs are in the 1024 camp, resistor-string are 1023, unless it
has 1/2R resistors at each end.  Some ADC techniques won't be that accurately defined anyway.

This doesn't matter as its only going to matter for high accuracy where you'd be calibrating anyway.

It would matter a lot for a 3-bit ADC, of course!
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

ArduinoBasics

You are right, the uncertainty of measurement related to the alcohol sensor far outweighs the decision to divide by 1023 or 1024.  But I did learn something from this process.  :)

Go Up