Analog read / drifting.

Hi all.

I have this conductivity interface ec meter - DFR0300 - Gravity: Analog Electrical Conductivity Sensor - DFRobot

Example: When my conductivity probe is in 2.764 mS/cm calibration solution;
I am getting Analog readings of 75 to 82. It is drifting.

Can we say that it is normal?
Can I fix it by software calibration?

Thanks in advance.

Analog sensors like that do tend to drift. There is nothing you can do about it, except to establish some method that gives reasonably repeatable readings.

My approach to measuring conductivity with a cheap meter is to alternate between taking readings of pure, distilled water, standard solutions, and the sample and average the results.

Ok.
I have the code to read analog input and convert it to EC value (including temp. compensation).
I have EC calibration solutions of 1.41mS/cm and 2.76mS/cm which are close to my working range.

But I don't know how to apply calibration to my code. Can you help me please?

void read_sensor_ec() {
 float TempCoefficient = 1;
 float ec_volts = 0;

 sensor_ec.raw_pv = analogRead(pin_sensor_ec); // read sensor data:
 ec_volts = sensor_ec.raw_pv * 4097.0 / 1024;

 if (sensor_ds.sensorOK)
 TempCoefficient = 1.0 + 0.0185 * (sensor_ds.temperature_float - 25.0);
                // temp. compensation: result @25º C = reading ÷ (1.0 + 0.0185 * (temp - 25.0)):

 sensor_ec.comp_volts = ec_volts / TempCoefficient;
        sensor_ec.comp_volts = sensor_ec.comp_volts*1.26;

 if (sensor_ec.comp_volts < 150.0) {
             sensor_ec.under_range = true;
        }
 else if (sensor_ec.comp_volts > 3300.0) {
             sensor_ec.over_range = true; 
        }
 else
 { sensor_ec.under_range = false; sensor_ec.over_range = false;

 if (sensor_ec.comp_volts <= 448.0)
 sensor_ec.float_pv = 6.84 * sensor_ec.comp_volts - 64.32; // 1ms/cm  < EC <= 3ms/cm:
 else if (sensor_ec.comp_volts <= 1457.0)
 sensor_ec.float_pv = 6.98 * sensor_ec.comp_volts - 127; // 3ms/cm  < EC <= 10ms/cm:
 else
 sensor_ec.float_pv = 5.3 * sensor_ec.comp_volts + 2278; // 10ms/cm < EC <  20ms/cm:

 sensor_ec.float_pv /= 1000.0; // convert us/cm to ms/cm:
 sensor_ec.scaled_pv = (uint16_t)(sensor_ec.float_pv * 100.0); // scale up by 100 for modbus:
 }
}

Adafruit has a nice tutorial on calibration.

sensor_ec.raw_pv = analogRead(pin_sensor_ec); // read sensor data:
sensor_ec.raw_pv = analogRead(pin_sensor_ec); // read sensor data:
ec_volts = sensor_ec.raw_pv * 4097.0 / 1024;

read twice.
it would remove any stray voltages on pin that might induce creep in the signal.

I did not review your code for how many decimal places you use but
ec_volts = sensor_ec.raw_pv * 4097.0 / 1024;

could be written as

ec_volts = sensor_ec.raw_pv * 4;

because there are 3 zeros in the decimal places before your first number.
or try 4.001
I would offer that you could run the numbers and see what effect that would have. it might be so minimal that there is zero alteration in results.

float offers 6-7 decimals of precision and your formula has the same values for the first 4 places.
I offer that since you are working with a 10 bit value, the step change does not offer any benefit by trying to run out decimals to great lenghts.

@jremington Thanks for the link. @dave-in-nj I am reading twice now.

Ok, adafruit gives this equation:
CorrectedValue = (((RawValue – RawLow) * ReferenceRange) / RawRange) + ReferenceLow

I measured my 1413mS/cm calibration solution.
ADC Drift: 5
Average ADC value: 40
Average mV: 8.19
Average EC: 1.05

I measured my 2764mS/cm calibration solution.
ADC Drift: 13
Average ADC value: 82
Average mV: 16.79
Average EC: 2.18

I am trying to put my values into the equation.
RawValue: I don't know.
RawLow: 1.05
ReferenceRange: 2.764 - 1413 = 1.351
RawRange: 2.18 - 1.05 = 1.13
ReferenceLow: 1.413

Am I going right?
What is the RawValue?

Thanks in advance.

RawValue is the measurement.

Sorry but measurement of what?

Measurement of the conductivity.
Evidently, you did not understand the article on calibration, so I suggest you reread it.

if you 2 point calibration, he discusses water. 0C and 100C or a 100.00 range.

you boil water, it is 100.00 C
you have ice water, it is 0,01C

the physical range is 100

you take a reading when the water is ice water at 0.01 and you get -0.5 = RawLow = -0.5°C
you take a reading when the water is boiling water at 100 and you get 96 = RawHigh = 96.0°C
RawRange = 96.5°C

when you take a reading and the raw reading is 37 you have to apply the correction to get the correct reading.

@jremington :slight_smile:

Ok, I was a bit confused but understood now. I will try.

Thank you.

beingobserver:
Hi all.

I have this conductivity interface http://www.dfrobot.com/index.php?route=product/product&keyword=conductivity&product_id=1123#.VuWRZJN9524

Example: When my conductivity probe is in 2.764 mS/cm calibration solution;
I am getting Analog readings of 75 to 82. It is drifting.

Can we say that it is normal?
Can I fix it by software calibration?

Thanks in advance.

It says the accuracy is +/-5%, so that's just within spec.

Thanks MarkT.

Now I am getting acceptable EC results but I should take the average of the readings.

I tried Arduino Smoothing tutorial but I think there were problems with the data types.

Now my code is looking like this. What is the best way to take the average of 30 readings for example.

void read_sensor_ec() {
 float TempCoefficient = 1;
 float CorrectedValue;
// float ec_comp_volts = 0;
 float ec_volts = 0;

 sensor_ec.raw_pv = analogRead(pin_sensor_ec); // read sensor data:
 sensor_ec.raw_pv = analogRead(pin_sensor_ec); // read sensor data:
 ec_volts = sensor_ec.raw_pv * 4097.0 / 1024;

 if (sensor_ds.sensorOK)
 TempCoefficient = 1.0 + 0.0185 * (sensor_ds.temperature_float - 25.0); // temperature compensation: result @25º C = reading ÷ (1.0 + 0.0185 * (temp - 25.0)):

 sensor_ec.comp_volts = ec_volts / TempCoefficient;

 if (sensor_ec.comp_volts < 150.0) { sensor_ec.under_range = true; }
 else if (sensor_ec.comp_volts > 3300.0) { sensor_ec.over_range = true; }
 else
 { sensor_ec.under_range = false; sensor_ec.over_range = false;

 if (sensor_ec.comp_volts <= 448.0)
 sensor_ec.float_pv = 6.84 * sensor_ec.comp_volts - 64.32; // 1ms/cm  < EC <= 3ms/cm:
 else if (sensor_ec.comp_volts <= 1457.0)
 sensor_ec.float_pv = 6.98 * sensor_ec.comp_volts - 127; // 3ms/cm  < EC <= 10ms/cm:
 else
 sensor_ec.float_pv = 5.3 * sensor_ec.comp_volts + 2278; // 10ms/cm < EC <  20ms/cm:


 CorrectedValue = (((sensor_ec.float_pv - 1050) * 1350) / 1130) + 1413;

 sensor_ec.float_pv = CorrectedValue;
 sensor_ec.float_pv /= 1000.0; // convert us/cm to ms/cm:
 sensor_ec.scaled_pv = (uint16_t)(sensor_ec.float_pv * 100.0); // scale up by 100 for modbus:
 } 
}

Add up 30 readings and divide by 30.

Ice water is 0.00C at atmospheric pressure. Its the triple point of water that's 0.01C. You need
very pure water to get the ice point or triple point that precise though.

Thanks for the answers guys.