I want to measure the temperature of the room at intervals of 1 minute, and average it every 5 minutes. But I don't know how to average it. What code should I add to average?
Add an array of length 5, a variable to point to one of the 5 elements, and use it as a circular buffer. Each minute you'd write a new value in the buffer, do the bookkeeping, then sum and average the 5 elements & use it.
think about it how you would do it on a piece of paper by hand
writing down the 1st measuring
writing down the 2nd measuring
writing down the 3rd measuring
writing down the 4th measuring
writing down the 5th measuring
add them all
divide by 5
now there are two different methods
start a completely new measuring period every five minutes then the above is sufficient
moving average which means
take measuring of 1st minute out add 6th measuring divide by 5
and this can be done by using an array
with 5 elements.
counting up the indexnumber
storing the new measuring in that array-element
sum up all 5 new divide by 5
Arrays are explained here. From the fact that arrays are paragraph 17 you can conclude you should know some basic things before learning arrays
If you have at least learn what variables are you can jump forward to learn arrays
Here is a code-version where you have to find out two things to make it work with your sensor and your Arduino-IDE
reactivating the dht-library
adjusting serial communication with IDE
This code is consequently structured in functions where each function is a senseful subunit of code
It uses non-blocking timing. You will have to adjust the timing-constant to 1 minute
//#include <DHT11.h>
const int pin = A1;
unsigned long myMeasuringTimer;
const unsigned long MeasuringINterval = 2000;
byte IndexNr = 0;
float myTempartureArray[5]; // FIVE elements with index 0,1,2,3,4
float myTestData[5]; // FIVE elements with index 0,1,2,3,4
float myTempartureSum;
float myTempartureAverage;
//DHT11 dht11(pin);
void setup() {
Serial.begin(115200);
Serial.println("Setup-Start");
for (IndexNr = 0; IndexNr < 5; IndexNr++) {
myTempartureArray[IndexNr] = 0.0;
printExplanation1(IndexNr, 0.0);
}
IndexNr = 0;
myTestData[0] = 1.0;
myTestData[1] = 2.0;
myTestData[2] = 3.0;
myTestData[3] = 4.0;
myTestData[4] = 5.0;
Serial.println("setup done");
Serial.println();
}
void loop() {
int err;
float humi;
float temp;
if ( TimePeriodIsOver(myMeasuringTimer, MeasuringINterval) ) {
//if ( (err = dht11.read(humi, temp)) == 0) {
myTempartureArray[IndexNr] = myTestData[IndexNr];
printExplanation1(IndexNr, myTestData[IndexNr]);
calculateAverage();
IndexNr++;
if (IndexNr == 5) { // count 0,1,2,3,4 which are 5 elements
IndexNr = 0;
}
}
}
// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long & startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - startOfPeriod >= TimePeriod ) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
}
else return false; // actual TimePeriod is NOT yet over
}
void printExplanation1(byte p_Idx, float p_value) {
Serial.print("assigning myTempartureArray[");
Serial.print(p_Idx);
Serial.print("] value ");
Serial.println(p_value);
}
void printExplanation2(byte p_Idx, float p_value) {
Serial.print("+ myTempartureArray[");
Serial.print(p_Idx);
Serial.print("] has value ");
Serial.println(p_value);
}
void calculateAverage() {
Serial.println("calculating average");
myTempartureSum = 0.0;
for (int i = 0; i < 5; i ++) {
myTempartureSum += myTempartureArray[i];
printExplanation2(i, myTempartureArray[i]);
}
Serial.print("myTempartureSum= ");
Serial.println(myTempartureSum);
myTempartureAverage = myTempartureSum / 5.0;
Serial.print("myTempartureAverage= ");
Serial.print(myTempartureAverage);
Serial.print("C");
Serial.println();
Serial.println();
}
An N=8N=5 (oops, thx Alto777) or 0.8 & 0.2 would give the same 20% weight to the most recent observation as the 1 minute out of 5 in the OP.
Those two algorithms are equivalent, and are sometimes called an "Exponentially Weighted Moving Average", since the i-th older observations in to the past are weighted (1/N)^i or alpha^i in the average. The EWMA as a low pass filter is a good procedure, since it is simple and requires minimum memory (1 state variable) and processing (1 multiplication per observation), and with the right weight parameter, can produce the statistically "optimal" estimate for many underlying processes.
Check my maths. N = 8 would be 0.875 and 0.125 to make the two expressions equivalent.
But yes, the two statements do the same thing. The more verbose less efficient expression shows the process better, and is, indeed, what one might write after seeing a graphic representation of the low pass filter:
Where alpha is the (small) part of the sample and (1 - alpha) is the (large) part of the old average.
@gcjr One can "short-circuit" the 3RC "filltime" by seeding the algorithm - assign a single reading to the average in setup(). Then just start with whatever averaging strategy is preferred.
Clearly, depends on the noise type and magnitude, but often useful.
You are right. I was aiming for the OP's sample five and average post and mistyped.
There's lots of low pass filters, but the easy one in electronics is the RC network which has exponetial decay.
The common one folks think of on a spreadsheet or in code is a block mean (like the OP) or rolling window moving average (like my first post) or a rolling window median, or other central tendency statistic. (ETA: Oh, and there's the simple running averages based on all the data (sum(x)/n), or year-year-to-date, both of which are worse forecasters than the EWMA)
I'm partial to the EWMA/RC/lowpass filter since I spent a couple years on a thesis applying them to certain processes--The most recent observation is the best forecast, unless there's some benefit from considering deeper history, (but that has diminishing returns the deeper into the past you dig.)