/*
Smoothing_improved
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.
The circuit:
- analog sensor (potentiometer will do) attached to analog input 0
created 22 Apr 2007
by David A. Mellis <dam@mellis.org>
modified 9 Apr 2012
by Tom Igoe
improved (remove abnormal peak) 10 Dec 2019
by Antonio De Vincentiis <https://devincentiis.it)
This example code is improved of the the public domain.
http://www.arduino.cc/en/Tutorial/Smoothing
*/
// 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 us use this
// value to determine the size of the readings array.
const int numReadings = 10;
float readings[numReadings]; // the readings from the analog input
int readIndex = 0; // the index of the current reading
float total = 0; // the running total
float average = 0; // the average
int continuativePeak = 0; // countinuos peak sequence counter
int previousPeakIndex = 0; // readIndex of last peak
bool noSmoothing=false; // active - deactive delete peak value
int inputPin = A0;
void setup() {
// initialize serial communication with computer:
Serial.begin(9600);
// initialize all the readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
readings[thisReading] = 0;
}
}
void loop() {
// read from the sensor:
float readValue=analogRead(inputPin)/5;
// float readValue=analogRead(inputPin)/5; // example LM35 temperature sensor
if (!(abs(readValue)/abs(readValue-average)<20&&noSmoothing)){
// value accepted only if the difference with the average
// is between 0 and 5% (<20)
// subtract the last reading:
total -= readings[readIndex];
readings[readIndex] = readValue;
// add the reading to the total:
total += readings[readIndex];
// advance to the next position in the array:
readIndex++;
// if we're at the end of the array...
if (readIndex >= numReadings) {
// ...wrap around to the beginning:
readIndex = 0;
noSmoothing=true; // ... and add peak control
}
// calculate the average:
average = total / numReadings;
} else { // read an abnormal peak
//Serial.println("Peak!!");
// if it is a peak immediately following the counter increment
if (previousPeakIndex==readIndex){
continuativePeak++;
}else{ // else reset peak counter
continuativePeak=0;
}
// remove smoothing if more than half of the values exceed the average
if (continuativePeak==(numReadings/2)){
noSmoothing=false;
continuativePeak=0;
}
previousPeakIndex=readIndex;
}
// send it to the plotter
//Serial.print("Read value:");
//Serial.print(readValue);
//Serial.print(", average:");
//Serial.println(average);
delay(10); // delay in between reads for stability
}
The returned A/D value depends on two things. Temp and Aref.
If you measure with the potentially dirty/unstable default Aref (5volt supply), then you never will get a stable readout.
Try measuring the LM35 with 1.1volt Aref enabled in setup.
That will also get you a five times higher resolution.
Also make sure you don't share LM35 ground with other (breadboard) users.
Example sketch attached.
Leo..
// connect LM35 to 5volt A0 and ground
// calibrate temp by changing the last digit(s) of "0.1039"
const byte tempPin = A0;
float calibration = 0.1039;
float tempC; // Celcius
float tempF; // Fahrenheit
void setup() {
Serial.begin(9600);
analogReference(INTERNAL); // use internal 1.1volt Aref
// change INTERNAL to INTERNAL1V1 for a Mega
}
void loop() {
tempC = analogRead(tempPin) * calibration; // get temp
tempF = tempC * 1.8 + 32.0; // C to F
Serial.print("Temperature is ");
Serial.print(tempC, 1); // one decimal place resolution is all you get
Serial.print(" Celcius ");
Serial.print(tempF, 1);
Serial.println(" Fahrenheit");
delay(1000); // use a non-blocking delay when combined with other code
}
Thanks Wawa,
I used Vref = 1.1v and 5v directly on the LM35 with the share ground.
I updated the sketch because in my opinion there is another conceptual error when subtracting and adding the reading to total (lines 45 and 49), it could happen that when the microcontroller works for a long time, every possible calculation error is added up.
I preferred to recalculate the total, and therefore the average for each cycle.
/*
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.
The circuit:
- analog sensor (potentiometer will do) attached to analog input 0
created 22 Apr 2007
by David A. Mellis <dam@mellis.org>
modified 9 Apr 2012
by Tom Igoe
improved (remove abnormal peak) 10 Dec 2019
by Antonio De Vincentiis <https://devincentiis.it)
This example code is improved of the the public domain.
http://www.arduino.cc/en/Tutorial/Smoothing
*/
// 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 us use this
// value to determine the size of the readings array.
const int numReadings = 10;
int readValue =0;
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.01; // the average
int continuativePeak = 0; // countinuos peak sequence counter
int previousPeakIndex = 0; // readIndex of last peak
bool noSmoothing=false; // active - deactive delete peak value
int inputPin = A0;
void setup() {
// initialize serial communication with computer:
Serial.begin(9600);
// initialize all the readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
readings[thisReading] = 0;
}
}
void loop() {
// read from the sensor:
readValue=analogRead(inputPin);
// value accepted only if the difference with the average
// is between 0 and 5% (<20)
if (!((abs(readValue)/abs(readValue-average))<20&&noSmoothing)){
readings[readIndex] = readValue;
// advance to the next position in the array:
readIndex++;
// compute total from array content
total=0;
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
total += readings[thisReading];
}
// calculate the average:
average = total / numReadings/1.01;
// if we're at the end of the array...
if (readIndex >= numReadings) {
// ...wrap around to the beginning:
readIndex = 0;
noSmoothing=true; // ... and add peak control
}
} else { // read an abnormal peak
Serial.println("Peak!!");
// if it is a peak immediately following the counter increment
if (previousPeakIndex==readIndex){
continuativePeak++;
}else{ // else reset peak counter
continuativePeak=0;
}
// remove smoothing if more than half of the values exceed the average
if (continuativePeak==(numReadings/2)){
noSmoothing=false;
continuativePeak=0;
}
previousPeakIndex=readIndex;
}
// send it to the plotter
Serial.print("Total:");
Serial.print(total);
Serial.print("Read value:");
Serial.print(readValue);
Serial.print(", average:");
Serial.println(average);
delay(1); // delay in between reads for stability
}
Wawa:
What does that mean.
I see nothing of that in your code, and I did say NOT share ground.
An LM35 should NOT have ANY peaks at all.
Post a picture of the setup.
Leo..
I have voluntarily used and created a hardware device as noisy as possible to analyze and improve the result through the code. The aim is to achieve a very resilient response to noise.
Greetings
P.S.
Not even the original example Smoothing.ino has Vref
antoniodv:
Not even the original example Smoothing.ino has Vref
The Arduino smoothing example uses a ratiometric source (a potentiometer).
Then you must use default Aref (which is internally connected to the same supply as the pot).
If both sensor and A/D are ratiometric, then supply fluctuations are cancelled out.
You told us you were testing an LM35, which has a 'voltage' output (not ratiometric).
Then it's a bad idea to use default Aref.
A stable LM35 and a potentially unstable/fluctuating supply results in unstable A/D values.
All of this has nothing to do with smoothing, just the correct way of measuring a 'sensor'.
The wrong way can introduce instablility. No amount of smoothing can fix that.
Leo..