Can a library remember variables values

Hi all,

I'm trying to learn on creating a library.
What i want to make is a function for averaging values read from a sensor.
Each time a sensor is read, the value should be passed and averaged with the previous values.

I have the skecth which i want to use for this, see below.

const int numAvr = 25;
int readings [numAvr];
int distance = 0;
int avr_distance = 0;
int readIndex = 0;
int average = 0;
int total = 0;

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

void loop() {

  distance = analogRead(A0);
  total = total - readings[readIndex];
  readings[readIndex] = distance;
  total = total + distance;
  readIndex = readIndex + 1;
  if (readIndex >= numAvr) {
    readIndex = 0;
  }
  avr_distance = total / numAvr;

  Serial.print(distance);
  Serial.print("\t");
  Serial.println(avr_distance);
  delay(10);
}

What I want to know is how to deal with the array containing the old data.
Do i keep (and update) this in the main sketch and pass it to the function that handles it or would it be possible to just pass one value to the function which then internally "logs" the old values?

if I have to update the array in the main sketch, most of the works is still done there (and a library with this function does not seem to make much sense).

Or maybe a total different route should be followed for such a averaging tool?

Thanks,

What ever you can do in a sketch you can do in your library/Class.

.

Exactly. You'll probably declare the array in the header file of your library (say KingBeeAverage.h) and it will present from the time your library class is instantiated in the main sketch ( KingBeeAverage myAverage ; ) and will not vanish (under normal circumstances) until your sketch ends.

Ok, clear answer.
I'll give it a try, thanks

The first thing you would do is modify your existing sketch to put the library stuff out into a separate .cpp and .h file. There's a couple of steps to doing this. The .h needs to contain declarations for any stuff that the user of your library will need, and the .cpp file is not pre-processed in the way that an .ino is, so it will have to explicitly include <Arduino.h>.

A library is simply that .cpp and .h file in a directory under 'libraries", with a library.properties file containing stuff like the library version and name.

Ok,

I've got the basic concept working.
I do have some problem defining the array where all the measurements are stored.
I want to have an array with the size "range" which is a value passed to the class.
Results in a error however, unless i make it a fixed value (25 in .h file below), then all works fine.

/*
  Library for averaging values.
  11/6/2016
*/
#ifndef MBMath_h
#define MBMath_h

#include "Arduino.h"

class MBMath
{
  public:
    MBMath(int value, int range);
    int mov_average(int value, int range);
  private:
    int _value;
	int _range;
	int readings [25];
	int height_read;
	int result;
	int readIndex;
	int total;
};

#endif

.ccp

/*
  Library for averaging values.
  11/6/2016
*/

#include "Arduino.h"
#include "MBMath.h"

MBMath::MBMath(int value, int range)
{
  _value = value;
  _range = range;
  readings[_range]=0;
  total =0;
  readIndex=0;
  result=0;
}

int MBMath::mov_average(int _value, int _range)
{
  total = total - readings[readIndex];
  readings[readIndex] = _value;
  total = total + _value;
  readIndex = readIndex + 1;
  if (readIndex >= _range) {
    readIndex = 0;
  }
  result = total / _range; 
  return result;
}

How can i get a variable array size here?

Thanks,

I guess you can do something like this:

  private: 
    static const int myRange = 25 ;
    int readings[ myRange ] ; 
    . . .
    . . .

But that is probably not exactly what you want. You want to specify via an argument to the constructor function, what the array dimensions should be. I'm curious to see what other answers you get, but I believe that it must be clear at compile time what the array dimensions should be.

So that would mean i have to define a large enough array to suit most needs, say 50 long.
Off course would be better if it can be defined.

You might also want to create a begin() method like the serial library and use new/malloc. Just make sure not to over use it, just allocate one time.

//  'size_t'       - <http://en.cppreference.com/w/c/types/size_t?
// class templates - <http://en.cppreference.com/w/cpp/language/class_template>

template<const size_t RANGE>
class MBMath
{
    const size_t    kRANGE;
    
    int             _v[RANGE];
    int             _index;
    int             _value;
    int             _total;
    
public:
    // Using templates and constructor initializaation list type constructors
    // you can specify per instance buffers of specified size with the template
    // parameter RANGE above

    // <http://en.cppreference.com/w/cpp/language/initializer_list>

    MBMath(int value)
        : kRANGE(RANGE)
        , _index(0)
        , _value(value)
        , _total(0)
    {
        // ... SET THE INITIAL BUFFER CONTENTS TO ZERO ...
        memset(_v, 0, kRANGE);
    }
    
    int mov_average(int value)
    {
        _total    -= _v[_index];
        _v[_index] = _value;
        _total    += _value;
        _index     = ((_index + 1) % kRANGE);
        
        return _total / kRANGE;
    }
};

const size_t    BUFF_LEN_1  = 10;
const size_t    BUFF_LEN_2  = 20;
const int   kVALUE          = 10;


// create 2 instances of 'MBMath' each with an internal buffer of the specified length

MBMath<BUFF_LEN_1>    average1(kVALUE); // internal buffer 10 int's
MBMath<BUFF_LEN_2>    average2(20);     // internal buffer 20 int's

thanks lloyddean

Let us know if it was useful.

Still working on it, will post the results.

lloydean,

Must admit I'm quite lost with your code (understand some, but clearly not all).
The template approach is new to me, so i'm tying to figure out what it exactly is.

Not sure how to use it either, how would i use this in a sketch file?

Thanks,

Yes!

OK, but I wish to give it based somewhat on how YOU were planning on using it!

So, I request from you that you provide a sketch of how you were going to use yours which I will modify.

Great,

Well basically I want to use it to average out values read from a IR distance sensor.
Noting more fancy than what i have below.

#include "MBMath.h"

int result;
int reading = 0;
MBMath test(0,0);

void setup() {
  Serial.begin(230400);

}

void loop() {
  reading= analogRead(A0);
  result = test.mov_average(reading,10);
  Serial.print(reading);
  Serial.print("\t");
  Serial.println(result);
  delay(10);
}

Would seem to be a bit overkill for this one, but trying to learn as I go.

Thanks,

If you set your avarage size on declaration, I dont see the point to use it on mov_average function, by so, you dont need array_size template.

in other hand, like lloyddean pointed out, you will need and initializer list on your class.
great tutorial here... tutorial

Learn much from this site...

regards

Template based code should be placed in an single header file not split per usual library of .h and .cpp files.

Compiled but not tested!

// FILE - MBMath.h

#ifndef MBMath_H
#define MBMath_H

// ... THE TEMPLATES 'RANGE' PARAMETER SPECIFIES THE LENGTH OF THE BUFF '_V' ...
// ... AT COMPILE TIME ...
template<const size_t RANGE>
class MBMath
{
    const size_t    kRANGE;
    
    int             _v[RANGE];  // ... AND IS USED TO SET THE BUFFERS LENGTH ...
    int             _index;     // ... OUR RUNNING BUFFER INDEX ...
    int             _total;     // ... OUR RUNNING TOTAL ...
    
public:
    // Using templates and constructor initializaation list type constructors
    // you can specify per instance buffers of specified size with the template
    // parameter RANGE above

    // <http://en.cppreference.com/w/cpp/language/initializer_list>

    MBMath()
        : kRANGE(RANGE)         // ... CONSTANTS MUST BE INIT"D DIRST ...

        , _index(0)             // ... THEN INSTANCE VARIABLES ...
        , _total(0)
    {
        // ... SET THE INITIAL BUFFER CONTENTS TO ZERO ...
        memset(_v, 0, kRANGE);  // CLEAR OUR BUFFER
    }
    
    int mov_average(int value)
    {
        // ... RESTATED VERSION OF YOUR MOVEING AVERAGE CODE ...

        _total    -= _v[_index];
        _v[_index] = value;
        _total    += value;

        // ... UPDATE INDEX TO USE NEXT SLOT IN BUFFER '_v' ...
        _index     = ((_index + 1) % kRANGE);
        
        return _total / kRANGE;
    }
};
#endif
// FILE - SomeSketch.ino

#include "MBMath.h"

#define BAUD_RATE       (230400UL)

// Instance with internal buffer 10 int in length
MBMath<10>      test;

void loop()
{
    const int   reading = analogRead(A0);
    const int   result  = test.mov_average(reading);

    Serial.print(reading);
    Serial.print("\t");
    Serial.println(result);
    delay(10);
}

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

Works!

Thanks a lot!