int pin = 1; // analog pin
int tempc = 0,tempf=0; // temperature variables
int samples[8]; // variables to make a better precision
int maxi = -100,mini = 100; // to start max/min temperature
int i;
void setup()
{
Serial.begin(9600); // start serial communication
}
void loop()
{
for(i=0;i<=7;i++){ // gets 8 samples of temperature
samples = ( 5.0 * analogRead(pin) * 100.0) / 1024.0;
_ tempc = tempc + samples*;_
_ delay(1000);_
_}_ tempc = tempc/8.0; // better precision Serial.print(tempc,DEC); Serial.println("º"); tempc = 0; delay(1000); // delay before loop
_}_
_[/quote]*_ But it happens that I have great differences between reads... 17º 16º 16º 17º 15º 19º 17º 19º 16º 21º 19º 16º 16º 13º 16º 20º 21º 16º 20º 18º 18º 18º What can I do? The cable that I'm using, is a 2 meters shielded cable with 3 wires, the same cable used on encoders. Please let me know Thanks on advance Pedro Ferrer
You must be the lucky one who actually received something from futurlec.
I would start with changing the tempc variable to type float. As it is now you accumulate innacuracy through each analog read iteration due to integer rounding.
To further improve analog sampling, it is typically always better to increase number of samples averaged. That is if your sketch has nothing else to do, you may as well keep sampling continuesly until next output is needed. The trick to achieve this would be to model your skecth after the blink without delay example, maintain a sample counter and then eliminate all calls to delay. When your time interval is reached you calculate the average, output the result and reset the sample counter and accumulator.
You can probably improve results somewhat using the internal Atmega 1V1 reference, but you may have to add an analog amplifier stage to get decent accuracy from this sensor. An unstable power supply may also be an issue. As it is now a single bit variation is equivalent to 0.5 degrees and this is likely to give you fluctuations.
You can try the 1V1 reference and calculate a running average (no delay's) from something like 4096 samples to see if a software approach is sufficient.
a running average (no delay's) from something like 4096 samples
How big should the window be? NB a running average only takes the last N readings into account... and keeping 4096 readings in memory might be too much for Arduino.
a running average (no delay's) from something like 4096 samples
How big should the window be? NB a running average only takes the last N readings into account... and keeping 4096 readings in memory might be too much for Arduino.
Or do you mean a 'normal' average?
I use this formula and keep it accumulating between outputs.
THIS QUESTION CAPslock has been up a few times... You are not the only one with this problem. The general solution seems to be the one mentioned: take a number of samples and use the average. But as you have noticed, the average fluctuates as well
You can get a little better resolution by using the 1.1 volt voltage reference which gives 1.1/1024 = ?? instead of the standard 5/1024 =?? volts resolution. This limits the upper temperature one can measure though.
I tried both solutions and was not satisfied.
I did try putting a resistor in series with the signal from the transmitter, and that seemed to calm the variation (but not good enough for my taste). Maybe a really small capacitor together with that ? (there are suggestions on "filtering" the signal in the sensors datasheet).
I decided that the ADC sucked... at least for directly measuring small variations in room temperature with an analog sensor like that.
One thing I did not try was use the ADC Noise Canceler function(did know about it then and it was to complicated for me at that time anyway). Basically it puts the processor in sleep mode to reduce noise from the cpu and I/O :s when it makes the conversion (page 256 in my datasheet for the processor). Thats not for beginners though (I think).
I would scope the output of the sensor. I will predict you will see a significant AC on the LM35 output signal, I have see this many times. The easiest way to solve it is to decouple it using a 0.1uf cap to gnd.
You're still averaging 8 samples. The difference comes from the count of samples, not the formula. The formula is needed to maintain mathematical precision across thousands of samples.
sample_avg is not initialized to 0.0 and not reset when samplecount is reset to 0
The formula used gives a different weigth to different readings,
sample_avg = sample_avg + (val - sample_avg) / sample_count;
Note: the first counts for ~10%, the second for 5%, the 3rd for ~3%, 4th for 2.5% while the last counts for ~ 0.01% (spreadsheet wisdom).
This means that the first 4 readings make up 20% of your avg , (11 -> 30%; 50 -> 50%) , so if there is a misreading in your first 4 readings it affects the final average quite much.
try the code below (closer to your original code) to determine the samples needed for a stable reading ; the output is comma separated so you can copy it into a spreadsheet and make a graph.
I expect that depending on the precision you will need between 50-500 samples iso 4096
sample_avg is not initialized to 0.0 and not reset when samplecount is reset to 0
The formula used gives a different weigth to different readings,
sample_avg = sample_avg + (val - sample_avg) / sample_count;
All static variables in C not explicitly initialized by user code will be initialized to zero. This is part of the C/C++ language definition. Explicit initialization does no harm, but will generate additional code and increase the size of your program.
There is no need to reset sample_avg as the formula assigns 100% weight to the difference once sample_count gets reset (that is sample_avg = val for the first sample).
A problem with the proposed change is that precision drops off as sample_sum increases to the extent that additional samples eventually carry no weight. Running a test with print for every sample delays time between samples and so is not representative for how you would run the final program and results may be quite different.
In short, I would leave experiments regarding sampling theory to a project in itself as it is not trivial to determine what is best.
As for reading button states, you will have to change analogReference prior to reading and then change back once finished. A single read of button state may be sufficient and so this could be done when you reset the sample counter for your LM35.
As for reading button states, you will have to change analogReference prior to reading and then change back once finished. A single read of button state may be sufficient and so this could be done when you reset the sample counter for your LM35.
I understand that.
Do and Undo state to analogReference, no problem.
At the moment I'm using the following lines code on temp sketch. It seems to me that is stable.
int sample_count;
float val;
float sample_avg;
float temp;
void setup()
{
Serial.begin(9600); // start serial communication
analogReference(INTERNAL1V1);
}
All static variables in C not explicitly initialized by user code will be initialized to zero. This is part of the C/C++ language definition. Explicit initialization does no harm, but will generate additional code and increase the size of your program.
100% true, but it is no good coding practice. Always initializing vars prevents errors, as for local vars it is a must. Further if a platform does not proporly implements the language definition there is trouble.
There is no need to reset sample_avg as the formula assigns 100% weight to the difference once sample_count gets reset (that is sample_avg = val for the first sample).
Didn't see that, nice trick ...
A problem with the proposed change is that precision drops off as sample_sum increases to the extent that additional samples eventually carry no weight.
True (but only marginally for 4000 samples) if you use float for the sum as I proposed., the precision of a float is ~6 digits = 0-1.000.000; so if the sum exceeds this you loose significant digits, but these are lost anyway by the division by 4096.
Better is to use a unsigned long to summerize the raw samples. In fact an unsigned long can hold minimal 2^32 / 2^10 = 2^22 = 4 M samples without loss of precision (until divided by samplecount)
Running a test with print for every sample delays time between samples and so is not representative for how you would run the final program and results may be quite different.
True, but if the variation in the individual samples is "big" as one can read in original post, the code I posted will give an indication of how much samples are needed for a certain precision and i'm quite confident (but could be wrong) that the number is lower than 4096. Imho it cannot be true that a sensor needs to be averaged over 4000 samples to become reliable.
In short, I would leave experiments regarding sampling theory to a project in itself as it is not trivial to determine what is best.
It allways depend on the project requirements and the sensor used.
robtillaart:
A small test shows no loss of precision when using a float for 4096 samples.
The loss of precision comes from float data type limitations when you add a high value (sum) to a small value (single sample). This is because floats are normalized and can only maintain precision with respect to its exponent. If you change sum to an integer type, you avoid this issue, but risk overflowing the sum variable sooner. Also if the analog integral stays close to zero (such as with a gyro and accelerometer), your proposal works fine.
What I proposed is often preferred when averaging runs continuously for the lifetime of the application (temperature is a good example). An initial test is done to determine a reasonable number of samples required for a target precision/accuracy. Once you reach this count (lets say 256), you simply stop incrementing sample_count so that each additional sample carries an equal weight. sample_count then becomes a means to control sensitivity to change. A high max count equals low sensitivity whereas a low max count will respond quickly to change.
The loss of precision comes from float data type limitations when you add a high value (sum) to a small value (single sample). This is because floats are normalized and can only maintain precision with respect to its exponent. If you change sum to an integer type, you avoid this issue, but risk overflowing the sum variable sooner.
I know the theory - including the risks, my sample sketch only shows that adding up 4096 AnalogRead() samples (as was proposed) does not show this effect in practice when using a float for ("normal") averaging.
What I proposed is often preferred when averaging runs continuously for the lifetime of the application (temperature is a good example). An initial test is done to determine a reasonable number of samples required for a target precision/accuracy. Once you reach this count (lets say 256), you simply stop incrementing sample_count so that each additional sample carries an equal weight. sample_count then becomes a means to control sensitivity to change. A high max count equals low sensitivity whereas a low max count will respond quickly to change.