I'm getting disappointing variability with a PT1000 temperature sensor. I am happy that that my analog circuitry is behaving and gives a stable output. My fluke DVM gives millivolt stability and detects no AC on the output. Furthermore I have slugged the analog input with a 1uF capacitor on the Uno board.
What I see is jitter on the ADC result taken at 1 second intervals at nearly 10% from reading to reading.
My dc input is around 950mV and I'm using the internal 1.1v reference so operating close to full scale of the ADC but with a margin.
I accept that the 10 bit ADC will only have an ENOB of say 8 bits but I'm getting far worse that this.
As an experiment, I also changed the reference to default 5v and measured the 3.3v regulator line and this also gave an ENOB of only 6 to 7 bits.
So my basic question is am I expecting too much from the internal ADC or are there ways to improve the reading stability.
I've read about shutting down the processor during ADC read cycles but as I have a PWM output running to drive a simple charge pump for a negative supply line I'm reluctant to do this as the -ve supply could sag just as the reading is taken.
I would class myself as a experienced analog designer but unsure of what to expect from these low cost internal ADCs
The data sheet from Atmel suggests a series resistor-capacitor filter on Aref, but Arduino didn't do that. I believe some people have modified the board to provide that.
Using a good external reference is a possibility.
Also, using an external power supply with low ripple may give different results.
Voltage is Voltage; SomeThing is bouncing... I don't think this is a digital domain effect you are seeing...
9fingers:
I'm getting disappointing variability with a PT1000 temperature sensor. I am happy that that my analog
I accept that the 10 bit ADC will only have an ENOB of say 8 bits but I'm getting far worse that this.
PT1000 sensors require a high quality instrument amplifier/transformer to provide a high quality output signal for Arduino.
Most cheap instrument transformers forPT100 and PT1000 are PURE CRAP and cannot provide good signal output quality.
If your instrument transformer for PT1000 is one of "crap quality", go and purchase a better and more expensive one which provides better output signal!
Here in Germany I could purchase PT1000 instrument amplifier/ transformer for about 10 Euros, but they are bad quality only.
I don't know about your country, which PT1000 amplifier/transformer you are using and which price or quality class it is.
Sorry, I can't help you with your poor sensor signal quality. Most likely, poor signal quality is not caused by the Arduino, but by the PT1000 signal amplifier/transformer you are using in your circuit.
Need a good ADC circuit such as one based on MAX31865.
Attached code is from Atmel Application engineer.
Put in your specifics on these 2 lines:
float Reference_Resistor; //Reference Resistor installed on the board.
float RTD_Resistance; //RTD Resistance at 0 Degrees. Please refer to your RTD data sheet.
like = 4000; for the first one
and = 1000; for the second one
I think those are the values for PT1000.
Thanks for your replies so far. I've only just popped in to have a look and no time to post diagrams or code at the moment - will do later once I've tried a few things that you have suggested.
But for now forget the Pt1000 circuit as a source of a problem. As you will see in my original post, I'm getting poor results just measuring the the 3.3v reference with a 5v supply derived reference. So there is a problem just using the UNO R3 stand alone. I will try another supply - currently running on the USB supply which I thought would be fine as I'm using the the internal 1.1v reference which will be band gap derived and unrelated to the the 5v line.
Hw about adding a running average to your inputted data?
runningAvg.h
#ifndef runningAvg_h
#define runningAvg_h
class runningAvg {
public:
runningAvg(int inNumData);
~runningAvg(void);
float addData(float inData);
float getAve(void);
protected:
int maxData; // Total amount allowed.
int numValues; // The amount we have.
int index; // Write the next value, here.
float *theValues; // The array of values.
float result; // Just in case they ask, we'll keep a copy.
};
#endif
runningAvg.cpp
#include "runningAvg.h"
#include <stdlib.h>
runningAvg::runningAvg(int inNumData) {
theValues = (float*) malloc(sizeof(float)*inNumData);
maxData = inNumData;
numValues = 0;
index = 0;
result = 0;
}
runningAvg::~runningAvg(void) {
free(theValues);
theValues = NULL;
}
float runningAvg::addData(float inData) {
float sum;
if (numValues<maxData) { // Early stages while filling.
theValues[index++] = inData; // Never been full so index must be ok.
numValues++;
} else {
if (index==maxData) { // Meaning its pointing past the array.
index = 0; // Cycle around.
}
theValues[index++] = inData; // And stuff the value in.
}
sum = 0;
for (int i=0;i<numValues;i++) { // We loop up to numValues but not including numValues.
sum = sum + theValues[i];
}
result = sum/numValues;
return result;
}
float runningAvg::getAve(void) { return result; }
I've now had a chance to do some further experimentation.
My conclusions are that there is something subtly wrong with my interface circuit for the PT1000 as several of you predicted.
Also the on board ADC is indeed just fine as others of you said.
I would like to try and avoid the Maxim solution as eventually I want several Pt1000 inputs which will prove costly to buy as modules from China at 11UKP each. My tools are not good enough for surface mount packages. The alternative of a front end multiplexer on a single maxim device could also introduce errors so I will carry on investigating my interface design in detail for now.
I also thank Jim Lee very much for the introduction to the running average code which could prove useful to me in other projects. I don't want to use it on the temperature signal as I prefer to get to the root of the problem rather than paper over the cracks with an averaging scheme.
Thanks very much to you all, your time is much appreciated to help out a newbie.
Hi,
If you replace the PT1000 with a fixed resistor, does your signal to the arduino still have the same "noise".
Have you bypassed the terminals at the PT1000 connection to your circuit?
The problem is unchanged when the pt1000 is replaced with a 1K metal film resistor.
I've added various rf bypass capacitors and they make little useful difference.
Variation is now down to around 2% so definite progress today.
The charge pump is driven from a PWM output which seemed a neat idea at the outset but I think I might replace that method with a stand alone oscillator on the interface board with its own local decoupling.
I might also use some lower gain bandwidth op amps and a proper PCB instead of strip board on the final version.
9fingers:
The charge pump is driven from a PWM output which seemed a neat idea..
What charge pump.
Spikes on the MCU supply can indeed upset the A/D converter.
I found less stable A/D outputs when e.g. PWM-ing the backlight of an LCD display powered from the 5volt rail.
There is also the odd A/D value (few values off) when nothing else is running or connected.
That's why I usually average A/D results. 0.1-0.2% should be possible.
Leo..
Hi Leo,
My interface circuit uses a charge pump to achieve a negative reference voltage that I need.
I could achieve this in a different way I suppose but I will still need to have some PWM outputs in the final system so I need to learn to live with them. I am warming towards using some averaging/integration if only to reduce the risk of any "impulse" decisions being sent to the boiler.
I'm building a boiler optimiser ("furnace" for you lot on the left hand side of the pond!)
It will be a combination of a weather compensation system and one to maximise the time the boiler spends in condensation mode where it is most efficient.
The inputs are several pt1000 sensors for external temperature, flue temperature and return water temperature, several opto-coupled logic inputs for the heating system status and a custom built opto-resistive output driven by PWM to modulate the boiler output power.
At the moment I've completed the boiler modulator and now just experimenting with various sensors in isolation before integrating everything around an Arduino.
I don't see the need for pt1000 sensors for external temp andwater temp etc.
They need expensive preamps, and resolution will be bad because of the huge temp span.
Better use common DS18B20 for that range.
Makes things a lot easier.
Leo..
I chose PT1000 sensors because I already had one and could buy more cheaply. I'm familiar with the one wire devices and have used them elsewhere in the system but spent ages building the probes although I have recently found encapsulated ones similar to PT1000 sealed packaging.
The working temperature range of each sensor in my application is no more than 30 degrees C so I don't follow that comment.
I now have a very effective cheap interface working giving 1 degree resolution using the internal ADC in ratiometric mode. Software averaging has been very useful so thanks for mentioning that.
AFAIK PT100/1000 interface boards (that you MUST use for these sensors) have inbuild A/D converters.
So you don't use Arduino's A/D, and you don't have problems there.
If you want to go cheap (no interface board), then don't use platinum sensors.
DS18B20 sensors are a much better option for a small temp span.
Leo..
I have an adequate (1C resolution) solution working on the uno using the ratiometric method employed by the expensive interface boards. The internal ADC does not cause any problems to me now I understand it.
Hi,
Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?
Also at the moment are you only coding for one analog input.
That is, only looking at one AtoD or scanning the AtoD inputs.
Scanning one AtoD input after the other also produces a jitter characteristic do to with the fact that there is only one AtoD and it is switched from input to input.
The solution is to read each analog input twice and keep the second reading.
RawVal = analogRead(A0);
RawVal = analogRead(A0);
The last RawVal will be kept and used.
From what I can see of the cost of an interface board, even on ebay, getting a stable signal may require a lot of work and research.
What temperature range are you looking at and resolution?
As requested. Apologies I can't see how to embed figures in the text
The basic circuit. file 1
The ratiometric equation. file 3- note that the value of the reference voltage does not appear!
Calculating the temperature. file 4
Studying the data sheet, it say a) that the Aref pin is connected directly to the ADC for the purpose of external decoupling (100nF on the Uno pcb) and should not be used with other than a capacitive load.
I calculate the output resistance on that pin in external mode to be about 10 ohms when loaded with my circuit. Due to the use of the ratiometric method, this does not introduce any errors. However as I will eventually use more sensors powered from the same point I will use the improved circuit in file 2.
Note that whiles the ratiometric method works irrespective of the actual reference voltage (must >=5v reqd by the uno). I have kept it to about a volt to minimise self heating in the sensor.
I realise this is very simple but it serves my purpose and is remarkable stable due to the averaging and gives 1 degree resolution.
I only need a range of 30 C on each sensor and R1 can be selected to be the same as the sensor in the nominal centre of each range
So far I've use the outside temperature sensor as an example and -5 to 15C is all I'll need as above 15 the heating will be switched off and here in Southern UK, -5 is very rarely seen indeed.
I've used R=1k quality metal film resistor and naughtily not made it a variable in the code yet but I'm sure you can cope with this!
Bob
This is my code added to someones averaging code lifted from the playground (which has a few warts on startup) but it illustrates the point once it gets going.
/*
Smoothing.
Reads repeatedly from an analog input, calculating a running average
and printing it to the computer. Keeps ten readings in an array and
continually averages them.
Created 22 April 2007
By David A. Mellis <dam@mellis.org>
modified 9 Apr 2012
by Tom Igoe
http://www.arduino.cc/en/Tutorial/Smoothing
This example code is in the public domain.
*/
// Define the number of samples to keep track of. The higher the number,
// the more the readings will be smoothed, but the slower the output will
// respond to the input. Using a constant rather than a normal variable lets
// use this value to determine the size of the readings array.
const int numReadings = 10;
int readings[numReadings]; // the readings from the analog input
int readIndex = 0; // the index of the current reading
int total = 0; // the running total
float average = 0; // the average
int inputPin = A0;
void setup() {
Serial.begin(9600);
analogReference(INTERNAL); // select internal ADC reference 1.1v nominal
// initialize all the readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
readings[thisReading] = 0;
}
}
void loop() {
// subtract the last reading:
total = total - readings[readIndex];
// read from the sensor:
readings[readIndex] = analogRead(inputPin);
// add the reading to the total:
total = total + readings[readIndex];
// advance to the next position in the array:
readIndex = readIndex + 1;
// if we're at the end of the array...
if (readIndex >= numReadings) {
// ...wrap around to the beginning:
readIndex = 0;
}
// calculate the average:
average = total / numReadings;
// send it to the computer as ASCII digits as a check
Serial.print(average);
//calculate results
float resistance = (average/(1023-average)); //convert to sensor resistance in k ohms
float temperature = ((resistance-1)/0.00385);//convert resistance to degrees Celsius
Serial.print(" ");
Serial.print (resistance,4);
Serial.print(" ");
Serial.println(temperature,0);
delay(1000); // delay in between display updates
}