An analogue sensor sends a voltage level, usually between 0 and 5V, representing a physical value. This voltage can be subject to measurement noise (electronic interference, electromagnetic interference, measurement accuracy, etc.). In some applications, you will need a fairly stable value to make your calculations or to detect the events you are interested in. A simple method to set up is the sliding average method which allows you to modify the value read according to the measurement history.
Hardware
- Computer
- Arduino UNO
- USB cable A Male to B Male
- An analogue sensor
Principle of operation
The principle of rolling average is to record a certain number of measurements in an array and then average these values at each reading. There are several shortcomings to this:
- the array takes a while to fill in. There is, therefore, a delay in establishing the average. Please take this into account when starting the microcontroller.
- the variation of the measurement will be slower, so it will be impossible to detect “fast” phenomena. Check carefully the behaviour of what you want to measure.
- the array takes up more memory space and requires more management time
Schematic
An analogue input is preferably connected to an analogue pin on the microcontroller. There is no additional connection required to operate the sliding average. It is a purely algorithmic solution. For more controlled results, it is possible to put electronic filters on your measurement circuit.
Code
We are going to create a function that will read the analog input and manage the table and the calculation of the average. In this code we have placed a delay() in the loop, so that the display on the serial monitor is slower. Be sure to remove this delay() for more consistent results.
//Parameters const int aisPin = A0; const int numReadings = 10; int readings [numReadings]; int readIndex = 0; long total = 0; //Variables int aisVal = 0; void setup() { //Init Serial USB Serial.begin(9600); Serial.println(F("Initialize System")); //Init AnalogSmooth pinMode(aisPin, INPUT); } void loop() { readAnalogSmooth(); Serial.print(F("ais avg : ")); Serial.println(smooth()); delay(200); } void readAnalogSmooth( ) { /* function readAnalogSmooth */ ////Test routine for AnalogSmooth aisVal = analogRead(aisPin); Serial.print(F("ais val ")); Serial.println(aisVal); } long smooth() { /* function smooth */ ////Perform average on sensor readings long average; // subtract the last reading: total = total - readings[readIndex]; // read the sensor: readings[readIndex] = analogRead(aisPin); // add value to total: total = total + readings[readIndex]; // handle index readIndex = readIndex + 1; if (readIndex >= numReadings) { readIndex = 0; } // calculate the average: average = total / numReadings; return average; }
Result
On the serial monitor we see that the raw value fluctuates between 306 and 308 while the moving average remains stable at 305.
Applications
- Measurement filtering
- Reducing noise when measuring a temperature
Sources
- https://www.aranacorp.com/en/give-senses-to-your-robot/
- https://www.arduino.cc/reference/en/language/functions/analog-io/analogread/
Find other examples and tutorials in our Automatic code generator
Code Architect
The actual values varies between 306 to 310.
How come the average be 305? Average value outside the reading values…
It’s a moving average so there is a delay with the actual average which depends on the number of stored values
Hi, I understand that the function works only for one input and is only callable once. How to call the same moving average function again for different input?
Hi,
excellent question!
you can define an array of inputs and compute the average in a for loop while passing the index as an input
const int aisPin[2] = {A0,A1};
const int numReadings[2] = {10,20};
int readings [2][numReadings];
int readIndex[2] = {0,0};
long total[2] = {0,0};
long smooth(int i)