Using Average.h => rollingAverage

Hello people :slight_smile:

I’m stuck getting the Through-Glass Door Bell code to work, as it seems there is a problem with the rollingAverage function not being implemented anymore in the current version of Average.h, although the Playground states this function to be available.

exit status 1
‚ÄėrollingAverage‚Äô was not declared in this scope

Average.h states a function called ‚Äúrolling‚ÄĚ seems to be adequate; i.e. I see ‚Äúfloat rolling(T entry);‚ÄĚ under public. I‚Äôm no good at textual programming and can‚Äôt transfer that into the code given by Instructables. Doing a search & replace for rolling only repeats

exit status 1
‚Äėrolling‚Äô was not declared in this scope

I guess it’s something simple but I can’t get around this :confused:

Thanks for helping,
Patrick

I tried to download the code from instructables but it's empty. Can you upload yours in between code tags.
If I had to guess Id say that rollingAverage is a variable added by the user and is just not declared properly. I don't see it defined in the library.

Keep in mind too that you can always write around a lacking in a library. Most libraries are written in the same language that your are using inside the sketch and just encapsulate a bunch of regular code into nice neat packages you can call with one command.
(ok that’s a huge over simplification, but for average.h its really not)

Thank you for answering, ardshark.

ardshark:
If I had to guess Id say that rollingAverage is a variable added by the user and is just not declared properly. I don’t see it defined in the library.

Thought so too, but I’m not proficient with textual programming (I’m from the visual programming domain) so proper structures and definitions are just vague assumptions from my side …

Here’s the code:

/*
  Through-Glass Doorbell
 
 Reads the difference in capacitance from a piece of aluminium foil, or foil tape, applied 
 to one side of a glass pane, when touching the glass on the other side. The Arduino sketch
 then triggers a solenoid which rings a bell.
 
 The sketch relies on two libraries to work properly, first the Capacitive Sensing Library
 ( http://playground.arduino.cc/Main/CapacitiveSensor ) to read and interpret change in 
 capacitance on the aluminium foil, and second the Average Library to perform a bit of 
 data filtering, and smooth out values ( http://playground.arduino.cc/main/average ).
 
 
 The circuit:
 
 A piece of conductive material (aluminium foil) connected between two digital pins on 
 the Arduino board, with a high value resistor connected in between. Power is provided 
 externally from a 6-12V power supply and is connected to the Vin pin on the Arduino.
 Power is also connected to a solenoid which is controlled with a TIP120 transistor
 conected to an Arduino digital pin with a 2.2kOhm resistor inbetween the digital pin
 and the base on the transistor. A 1N4001 rectifier is added between the leads of the
 solenoid.
 
 Refer to http://www.instructables.com/id/Through-Glass-Doorbell/ for full schematic.
 
 created 15 Apr. 2015
 by Daniel Jansson
 http://www.switchandlever.com
 
 This code is in the public domain.
 
 */

#include <Average.h>            // Averaging library:
#include <CapacitiveSensor.h>   // Capacitive sensing library:

#define AvgCnt1 50    // set up a large sample to average
#define AvgCnt2 10    // set up a smaller sample to average

int d[AvgCnt1];       // create array to hold the large sample of data to average
int e[AvgCnt2];       // create array to hold the smaller sample of data to average

CapacitiveSensor cs_4_2 = CapacitiveSensor(4,2);        // 10M resistor between pins 4 & 2, pin 2 is sensor pin, add a wire and or foil if desired

int solenoid = 12;      // attach the solenoid to digital pin 12

int multiplier = 1.8;   // the change in capacitive value which will trigger the solenoid, will need to be fine tuned

int dingPoke = 5;       // for how many milliseconds to engage the solenoid, will need to be adjusted depending on your solenoid and bell
int dingPause = 500;    // how long to pause (disengage solenoid) between dings

unsigned long timer = 0; // stores the time used to make sure it doesn't trigger too often


void setup()
{
  cs_4_2.set_CS_AutocaL_Millis(0xFFFFFFFF);     // turn off autocalibrate on channel 1 - just as an example
  Serial.begin(9600);                           // start serial communication for debug purposes
  pinMode(solenoid, OUTPUT);                    // set the solenoid pin to output
}


void loop()
{

  unsigned long start = millis();                        // stores the start time of every loop
  unsigned long total =  cs_4_2.capacitiveSensor(30);    // read capacitive data

  unsigned int capAvg = rollingAverage(d,AvgCnt1,total);        // take, and average, a large sample of readings
  unsigned int capAvgShrt = rollingAverage(e,AvgCnt2,total);    // take, and average, a small sample of readings

  Serial.print("Mean: ");                   // printing out data to serial monitor for debugging purposes
  Serial.print(capAvg);
  Serial.print("\t");
  Serial.print(capAvgShrt);
  Serial.print("\t");
  Serial.println(total);

  if (capAvgShrt > (capAvg*multiplier)){    //  trigger if the small sample of readings is bigger than the large sample, times multiplier

      if(timer < millis()){                 // trigger only if at least five seconds has passed since the last time being triggered
        Serial.println("Success!");
        timer = millis()+5000;              // reset timer to be current time, plus five seconds
        ding();                             // trigger 'ding' function

    }
      else {                                // otherwise, do nothing
    }
  }

  delay(5);                                 // short delay for stability
}

void ding(){

  digitalWrite(solenoid, HIGH);   // activate solenoid
  delay(dingPoke);                // keep engaged for 'dingPoke' milliseconds
  digitalWrite(solenoid, LOW);    // deactivate solenoid
  delay(dingPause);               // keep off for 'dingPause' milliseconds
  digitalWrite(solenoid, HIGH);
  delay(dingPoke);
  digitalWrite(solenoid, LOW);
  delay(dingPause*2);
}

The part in question (so far) is

 unsigned int capAvg = rollingAverage(d,AvgCnt1,total);        // take, and average, a large sample of readings
unsigned int capAvgShrt = rollingAverage(e,AvgCnt2,total);    // take, and average, a small sample of readings

ardshark:
Keep in mind too that you can always write around a lacking in a library.

Sounds good, but please I’d need help to get this done properly … :wink:
FYI, using Arduino 1.6.8 here. Thanks for the code tags :smiley:

Moderator edit: CODE TAGS

I see what you mean - looking into it

Somethings up with that library. If you take the examples right out of either the lib or from the web in the playground, they won't compile either. You get a scope error on any of the predfined classes.
Not giving up though.

Here's a different running average library
http://playground.arduino.cc/Main/RunningAverage
While you will have to alter the code in your sketch to incorporate it, this one does seem to work.

I've been trying in vain for quite a while now to get the other lib to work. It no longer seems to recognize that class that was at one time valid (I guess). Its interesting that none of the current examples call rollingAverage... coincidence?. I did however get all the other functions to work (mean, max mode etc.)

If you want to write your own code for a running average you don't need to make a library or even a class.
It simply this:

Make an array that has as many samples as you want to average - that code of yours uses 50.
Populate that array with 50 samples and then each time through the loop, add (concat would be a better word to use) a sample to the end of the array and drop the first value in the array - this way there are always 50 samples in the array but each time a new sample gets added to the bunch. Then add up all
the elements in the array and divide by the number of samples in the array each time through the loop.

A couple of notes: with any kind of averaging you will usually require a float value since you invariably get decimals during the division. Also make sure that when you add all the values together the variable that holds that total is defined large enough to do so - so int might not be big enough. Last, the division step is horribly slow for the arduino, so if you get a flicker or it can't seem to sample and average fast enough, take your number of samples and divide it into 1. So 50 samples would be 0.02. Make that a constant and use that to calculate the average but instead of dividing, multiply 0.02 with the total of all the summed samples.

You can roll your own averaging tool, using a simple circular buffer. I did they recently, you can see a floating point example here:

#include "CircularBuffer.h"

CircularBuffer myBuffer(10);  // create a 10 element (float) array

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if (Serial.available())
  {
    myBuffer.addElement(Serial.parseFloat());
    for (int i = 0; i < myBuffer.numElements(); i++)
    {
      Serial.print(myBuffer.arrayElement(i));
      if (i < myBuffer.numElements() - 1) Serial.print(',');
    }
    Serial.println();
    Serial.print("Average: ");
    Serial.println(myBuffer.mean());
    Serial.print("Maximum: ");
    Serial.println(myBuffer.maxVal());
    Serial.print("Minimum: ");
    Serial.println(myBuffer.minVal());
    Serial.print("Standard Deviation: ");
    Serial.println(myBuffer.sigma());
  }
}

implementation file:

#include "CircularBuffer.h"
#include <Arduino.h>

CircularBuffer::CircularBuffer(size_t arraySize)
{
  size = arraySize;
  array = new float[arraySize];
  next = &array[0];
}

void CircularBuffer::addElement(float newElement)
{
  *next = newElement;
  index++;
  if (index >= size)
  {
    index = 0;
  }
  next = &array[index];
  if (++num_elements > size)
  {
    num_elements = size;
  }
}

float CircularBuffer::arrayElement(int location)
{
  return array[location];
}


float CircularBuffer::mean()
{
  float average = 0;
  for (int i = 0; i < num_elements; i++)
  {
    average += array[i];
  }
  return average / num_elements;
}

size_t CircularBuffer::numElements()
{
  return num_elements;
}

float CircularBuffer::maxVal()
{
  float maximum;
  for (int i = 0; i < num_elements; i++)
  {
    if (i == 0)
    {
      maximum = array[0];
    }
    else if (array[i] > maximum)
    {
      maximum =  array[i];
    }
  }
  return maximum;
}
float CircularBuffer::minVal()
{
  float minimum;
  for (int i = 0; i < num_elements; i++)
  {
    if (i == 0)
    {
      minimum = array[0];
    }
    else if (array[i] < minimum)
    {
      minimum =  array[i];
    }
  }
  return minimum;
}
float CircularBuffer::sigma()
{
  float average = mean();
  float sigma = 0;
  for(int i = 0; i < min(size, num_elements) ; i++)
  {
    sigma += ((array[i] - average) * (array[i] - average));
  }
  return sqrt(sigma / min(size, num_elements));
}

header file:

#ifndef CircularBuffer_h
#define CircularBuffer_h

#include <Arduino.h>

class CircularBuffer {
  public:
    CircularBuffer(size_t size);
    void addElement(float newElement);
    float mean();
    float maxVal();
    float minVal();
    float sigma();
    size_t numElements();
    float arrayElement(int location);

  private:
    float* array;
    float* next;
    size_t size;
    int index = 0;
    int num_elements = 0;
};

#endif

ardshark, Lowell, thank you so much for your elaborate answers! I'd been afk being sick and‚ÄĒstrangely enough, the board settings are broken and I can't opt for mail updates on any thread‚ÄĒwill catch up on your suggestions now. What's puzzling me is the fact that some folks over at Instructables had gotten it to work initially. Maybe Average.h had been changed at some point, rendering rollingAverage pretty much useless.

ardshark, while I could recreate your suggestion in vvvv, it would take some serious learning the Arduino IDE way of programming (I've never done Java, any C dialect and the like) for me to code this. Though I really really appreciate the time and effort you put into this!

BulldogLowell, while implementing your circular buffer way of doing would be already tough for me, rolling my own library adds up one more problem. As per Arduino Library Tutorial, it's more than just c&p text snippets into a folder, and I'm sure it'll run me into more problems.

Guys, you're really great helping me out here, but whereas the electronic part is all set and waiting for the Arduino bit to happen, I've hoped the latter would be just uploading that sketch and then getting to install the bits. I just can't manage the code part :confused:

Are you sure you installed the Average library correctly?

Yes, I think so. The folder "Average" contains
file:///Users/paco/Documents/Arduino/libraries/Average/Average.h
file:///Users/paco/Documents/Arduino/libraries/Average/debian/
file:///Users/paco/Documents/Arduino/libraries/Average/examples/
file:///Users/paco/Documents/Arduino/libraries/Average/keywords.txt
file:///Users/paco/Documents/Arduino/libraries/Average/LICENSE
file:///Users/paco/Documents/Arduino/libraries/Average/README.md
and resides there along with many other libs that show up in the IDE. Then again, ardshark could replicate the issue on his machine.

No dice? :confused:

patrick:
No dice? :confused:

I gave you a working example, did that not help?

I wasn't able yet to put the library together using your codes. Let's see:
If the header file is my CircularBuffer.h, what is the implementation file supposed to be?

patrick:
I wasn't able yet to put the library together using your codes. Let's see:
If the header file is my CircularBuffer.h, what is the implementation file supposed to be?

CircularBuffer.cpp

put them both in the same directory as your sketch. You will see them in your IDE as tabs in the project.