2

This is the code I am currently using, but I want to add an arithmetic mean to it. My goal is: when the pin A0 reads 5 values, I get the average on which the fan and led will depend to be turned on and off, instead of 5 separate measurements.

int tempPin = A0;
int fan = 3;
int led = 8;
int temp;
int tempreal;
int tempMin = 20;
int tempMax = 30;

void setup() 
{
  Serial.begin(9600);
  pinMode(fan, OUTPUT);
  pinMode(led, OUTPUT);
  pinMode(tempPin, INPUT);
}

void loop() 
{
  temp = analogRead(tempPin);
  tempreal = temp * 0.48828125;
  delay(1);
  if(tempreal > tempMax)
  {
    digitalWrite(fan,HIGH);
    digitalWrite(led,LOW);
    delay(1);
  } 
  else if (tempreal < tempMin)
  {
    digitalWrite(fan,LOW);
    digitalWrite(led,HIGH);
    delay(1);
  } 
  else if (tempreal >  tempMin && tempreal <  tempMax)   
  {
    digitalWrite(fan,LOW);
    digitalWrite(led,LOW);
    delay(1);
  }
}

Edit by Edgar Bonet – The OP added in a comment to my answer:

“I tried [averaging consecutive readings]. It worked as you would expect but it still does not solves my problem. My sensor is only getting right values in the beginning of the scanning and then it varies. That is why I wanted to make average value but it still does not work. Sadly I think I wont be able to change sensor, but is there any other way to camouflage this problem?”

Below is a screenshot showing both correct (✓) and incorrect (✗) readings:

Example readings

1

Seems too simple. am I missing something?

--- arithmetic-mean.ino.orig    2017-04-27 19:37:01.386458500 +0200
+++ arithmetic-mean.ino 2017-04-27 19:38:14.458114972 +0200
@@ -16,8 +16,11 @@

 void loop() 
 {
-  temp = analogRead(tempPin);
-  tempreal=temp * 0.48828125;
+  temp = 0;
+  for (int i = 0; i < 5; i++) {
+    temp += analogRead(tempPin);
+  }
+  tempreal = temp * 0.48828125 / 5;
   delay(1);
   if(tempreal > tempMax)
   {
  • 2
    @najkulime: Then you should rewrite your question. You asked about arithmetic mean, but that's not what you want: you want to sort out the valid from the invalid readings, which is a very different question. – Edgar Bonet Apr 27 '17 at 19:27
  • Maybe add a tiny delay after the analogRead. It would be helpful if you could print the values you get to the serial port, and show us that. – Gerben Apr 27 '17 at 19:46
1

A fixed sampling window can be hard to manage, especially if you want the calculation to be recursive, for space and speed considerations.

You can achieve similar results via exponential smoothing.

Yn = (1−α) Yn−1 + α Xn

Where Yn is the smoothed outcome, Xn is the current measurement, and α is the weight.

With some thoughts, it can be done with integers and without loss of precision.

edit: i ran a comparison of exponential smoothing vs. (fixed window) moving average. The moving average algorithm was written to be recursive for maximal speed.

the sampled data is a simulated sine wave:

1000 * sin(2pi*n/100) + 100 * noise. n = 0..19999, and noise = -0.5...+0.5.

So snr = 1000 / 50 = 20:1, or about 5 digits. far worse than what you would encounter in a 10-bit adc. enter image description here

the window I picked is 4.

As you can see, both approaches closely resemble each other. exponential smoothing uses much less ram and is also much faster. older data has lower weight on the output, something generally desirable in most applications.

  • Memory is not a big issue if you are only averaging 5 values. And the OP's problem cannot be solved by averaging: see the updated question. – Edgar Bonet Apr 28 '17 at 8:06
  • @dannyfI tried what you suggested but im getting real measurements too slow, it takes 10-15 sec to value stabilise. It looks more like this but it's too slow. link edit: maybe i shoud change alpha value? – hehexd Apr 29 '17 at 11:11
0

See Arduino Tutorials Smoothing https://www.arduino.cc/en/tutorial/smoothing

Create an array to hold a series of readings. And a variable to hold the sum.

Incrementally cycle through the array, subtracting the oldest value from the sum and replacing it in the array with the current reading. Divide by the number of readings for the average.

Remember to allow for a delay in each reading as is appropriate for the sensor.

  • No need here for a moving average: it's simpler to just take N readings and get their average, as in my answer. But note that the OP's problem cannot be solved by averaging: see the updated question. – Edgar Bonet Apr 28 '17 at 7:56
0

You could use a moving average. It will update at each cycle whenever you take a new reading. Suppose you want to average over N readings:

double moving_average(double old_average, double new_value) {
    double new_average = old_average;
    new_average -= old_average/N;
    new_average += new_value/N;
    return new_average;
}

I edited the function above. I had typed one of arguments incorrectly.

  • it is not going to work. – dannyf Apr 28 '17 at 1:35
  • Please elaborate why it will not work – vu2aeo Apr 28 '17 at 2:26
  • I took the liberty to fix your code, as you forgot to declare new_average. The usual meaning of “moving average” is the one given in @DavidJ's answer. What you are proposing here is instead an exponentially weighted moving average. Essentially an implementation of @dannyf's answer. But note that the OP's problem cannot be solved by averaging: see the updated question. – Edgar Bonet Apr 28 '17 at 8:04
  • "Please elaborate why it will not work" quite simple: both the old and new code suffer from one problem - you need to track the old_average exogenous, which is most of the challenges in such an implementation. you could have made that indigenous so your user only need to feed the code with the new_value and it will yield an average with one call. – dannyf Apr 28 '17 at 10:54
  • Are you saying the code will not work because the call has to be made with two arguments? – vu2aeo May 1 '17 at 5:26
0

My sensor is only getting right values in the beginning of the scanning and then it varies. That is why I wanted to make average value but it still does not work.

I had a similar problem. It turned out that I was reading writing and transmitting too fast. It means that since it seems that reading and writing can be interrupted during "their job", when you read a variable and in the same time someone is writing on that you're reading garbage. In my opinion this can be fixed by the application of "semaphores" or mutex or reducing the call of the reading. Randomly it would happen again but less frequently.

An idea can be found here https://forum.arduino.cc/index.php?topic=132813.0

Best

Gian Maria

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.