LM335A - increasing measurement resolution and accuracy

Hello,

After long battle with LM335A I have fairly good temperature indications, but I'm not satisfied with resolution which is about 0.5C (because ~5mV resolution at default reference voltage). I would like to have 0.1C resolution.

Is there any way to achieve that without decreasing overall accuracy?

At 21C I have 2,94V on the sensor (I don't plan to measure more than 35C) , so I thought that decreasing reference voltage would be the good idea. I applied Arduino 3,3V to VRef pin and modify calculations, what should increase resolution to ~0.33C, but unfortunately readings became unstable. For example I've got few 20,65C readings, then suddenly 22,31C; 19,05C and so on... :astonished:

Can I do something with this?

Generally the best solution would be to use 1.1V as reference voltage, which gives almost 0.1C resolution, but how to subtract somehow let's say 2.5V from sensor voltage (and make it temperature independent)? Is it possible anyway? That way I would have 0,44V at 21C, and I could measure with almost 0.1C resolution.

And my second problem:
From that battle I've mentioned I know that Arduino is very sensitive to input voltage fluctuations.
On the beginning I had completely wrong readings (over 60C). I discovered it's happening only when my Arduino is powered from USB... (That's probably because I have connected power hungry devices, like LCD and few relays).

But even when I'm using small 5W external power supply, it's not working perfectly. Turning on only one relay, increases the measurement by 1,5C =(

Should I use more powerful power supply or there is other way to do stable and reliable measurements?

For most analog devices you can make multiple readings and take either the average or running average. (Latter is faster)

  • Average
float conversionfactor = 0.123456789; // to be determined (please post your code how you do it now)
int sum = 0;
for (int i=0; i<10; i++) sum += analogRead(A0);
float val = sum / 10.0;
val *= conversionfactor;
Serial.println(val);
  • Running Average
float val = 0;
val = 0.9 * val + 0.1 * conversionfactor * analogRead(A0);  // weights 0.9 and 0.1 can be tuned to your needs NOte sum must be 1.0
Serial.println(val);

Problem B: more power, think of switching the relays indirectly with a power transistor and separate powersupply. (idealy they are optocoupled I think)
Remember that with multiple power supplies you must connect GND's so all share the same reference...

Succes,
Rob

I think you might be running supply current through wiring that's in series with your sensor's output voltage, thus affecting the value seen by the ADC.

The sensor should not share any current with the Arduino or other load. You need to use twisted pair if the leads are of any appreciable length, and adding capacitance will filter out high-frequency interference. Connect the sensor directly to a ground pin and an analog pin on the Arduino. Don't share that ground pin with anything else.

If the AREF supply isn't high accuracy then you won't get accurate readings. Perhaps use a dedicated 3.3V regulator to supply AREF?

BTW I've done some experiments with digital temperature sensor DS18B20 and its performance is impressive. 12 different sensors from several batches all matched with standard deviation of 0.06 degC IIRC, certainly a lot better than the nominal spec. And you don't have sources of error from the wiring since they are OneWire bus.

Keep in mind that while using the default internal Avcc voltage as the reference (nominal +5vdc) your accuracy is limited by the specific value of the board's +5vdc source. Rarely is the USB or on-board +5vdc regulator (active when using external power) exactly +5.000 volts. I think the USB spec for voltage is something like +4.75 to +5.25, and the internal regulator has it's own tolerance spec and can vary a little depending on load, room temp, phase of the moon, etc.

Make no mistake, the AVR internal analog ADC is very handy and useful, but it falls far short of instrumentation quality standards. If your basic accuracy and resolution requirements are higher then what the mega chip can do, you are better off using an external ADC module. My current favorite is the TI ADS1115 16 bit I2C chip which has internal reference, programmable gain settings, and many other features. As they say you shouldn't bring a knife to a gun fight so pick your weapon carefully. :wink:

http://www.ebay.com/itm/ADS1115-16-Bit-I2C-Analog-Digital-Breakout-Arduino-/230679397748?pt=LH_DefaultDomain_0&hash=item35b5904574

Lefty

It depends how fast measurements you do expect. Some time back I did measurements of a lm35 with pic24hj (12bit adc) and an external 2.5V adc reference. In a big loop I took ~300.000 samples (added all together in a smaller loop) each time, made an average from it, and did smoothing of the average values within big loop with new_value=Aold_value+Bnew_value (this is a low-pass filter, A+B=1, the smaller the B the bigger filtering effect, i.e. B=0.05).
All math done in 64bit float. I've got interesting results - the resolution ~10uV, the measurement is slow, however..
To make measurement better you may use "dithering" - a source of noise to be added to reference voltage or measured signal, this helps with averaging. P.

Dithering is a powerful technique - the added noise allows sub-LSB changes to become a statistical change in the proportion of high readings and low readings. Thus the average gets to cancel out the random noise but still see the sub-LSB variation (which would otherwise be hidden by the quantisation step). The caveat is that the added noise needs to be independent from the measured signal and the ADC has to have good linearity of response. Sometimes just buying a better ADC is easier :wink:

First of all - thank you all for comprehensive answers :slight_smile:

@robtillaart
I have optocoupled relays, but they are powered from Arduino 5V line, and thus they cause a little voltage drop when they are switched on. From my tests I can see, that without better power supply I won't get better results...

@MarkT
You know, at the beginning I wanted to do this simple and inexpensive way. I didn't know, there will be such problems. Now I think the best way is to buy digital temperature sensor :slight_smile:

@retrolefty
Now i know it. I had completely wrong readings while using USB. With LCD and relays connected to Arduino, I had only 4,37V...

@pito
Speed is not very important for me. But I think that first of all, I have to lower the reference voltage if I want to get real 0.1C resolution. With 5V it's only ~0.5C and math won't change it...

The question is, how to lower the sensor output voltage (which is 2,94V at 21C right now, and therefore I can't use 1.1V reference voltage)?

In spite of all I'll try to make my circuit better. I'm waterproofing my second sensor right now, which I'll use to measure outdoor temperature also.
I'll let you know about the results soon.

Thank you.

The question is, how to lower the sensor output voltage (which is 2,94V at 21C right now, and therefore I can't >use 1.1V reference voltage)?

You may use 3.3V reference voltage. It has no sense to lower sensor's output (ie. by an R divider) and use lower ref voltage. Be careful with ref voltage selection, there might be a minimum vref recommended for atmega.
P.

With R divider of course it has no sense. I thought about using diodes to decrease that sensor voltage (each one by 0.6V), but are there any diodes that are insensible to temperature changes?

It's rather impossible, so I'll use 3.3V...

..Si diodes (as well as all other Si semiconductor devices) have something like 2mV/degC, they are often used as a temp sensor.. :slight_smile:

I use the LM35DZ ,which give 10mV/degree. So the voltages I get are always low and I use the internal 1.1 reference voltage.
The instability of the read I also noticed. My solution is to simply average measurements.

#define smoothfactor 1000  // the number of values over which to average

int countmails=0;
float maxTemp=60;
float smoothTemp [smoothfactor];
float readTemp =0.0;
int smoothCount=0;

setup()
...
for (int i=0;i<smoothfactor;i++){ smoothTemp [i]=0.0; }
...

loop()
...
// SMOOTH READOUT
if(smoothCount==smoothfactor) 
smoothCount=0;
readTemp=analogRead(sensorPin);            // I had to write this out in 3 lines
readTemp=readTemp/(1024)*110;             // or it would not work
smoothTemp[smoothCount] = readTemp;      //
smoothCount++;
for (int i=0;i<smoothfactor;i++){ sensorValue=sensorValue + smoothTemp [i]; }  // fill the array
sensorValue=sensorValue/smoothfactor;
...

With a smoothfactor of 1000 it takes a few seconds before I get a stable readout. A 100 is already sufficient.
I guess the instability originates in noise, or the ADC.

readTemp=analogRead(sensorPin); // I had to write this out in 3 lines
readTemp=readTemp/(1024)*110; // or it would not work
...

in a oneliner: smoothTemp[smoothCount] = 0.1074 * analogRead(sensorPin);

Give this a try, think it stabelizes much faster... (let us know)

// running average version
float a = 0.0;
float b = 0.0;
float temperature;
long iterations = 0;

void setup()
{
  Serial.begin(115200);
  a = 0.95;
  b = 1-a;
  temperature =  getTemp(); // initial value;
} 

float getTemp()
{
  return 0.1074 * analogRead(sensorPin);
}

void loop()
{
  temperature  = a * temperature  + b * getTemp(); 
  Serial.print(iteration);
  Serial.print("\t");
  Serial.println(temperature, 3);
}

But even when I'm using small 5W external power supply, it's not working perfectly. Turning on only one relay, increases the measurement by 1,5C

This is probably caused by current in the ground line. Use one ground pin (the one next to Aref?) for the temp sensor and nothing else, and the other ground pins for everything else. Even better, connect the ground side of the temp sensor directly to the AGND pin of the mcu.

If using the 3.3v reference (which is a good idea, from both resolution and stability points of view), it might help to connect a load resistor (say between 330 ohms and 1K) between 3.3v and ground, to make sure the regulator is always loaded. Whether this makes a difference or not depends on the regulator.

Once you can get stable readings, to increase the resolution further, you can add some dither to the signal. Alternatively, you could use one or more digital output pins to adjust the Aref pin a milivolt or so away from 3.3v, so that you can take readings with two or more slightly different values of Aref.

Probably, you can subtract 2.5V with voltage reference diode in series :
http://www.national.com/mpf/LM/LM285-2.5.html#Overview