0

I have a vector of structures that stores a stream of values that arrive at different intervals. The structure consists of two elements , one for the value and the other records the time when the value arrived.

struct Data {
    Time timeOfArrival;
    Time value;
}cd;

Lets say that in another thread I want to calculate the moving average of the values that arrived in the last 10 (say) seconds. So in one thread the vector is being populated and in another I want to calculate the moving average.

Cœur
  • 37,241
  • 25
  • 195
  • 267
anikomei
  • 73
  • 1
  • 9
  • Will you store more than those 10 s of data in the vector? If not you can treat is as a circular buffer. Then you can just calculate the sum of the whole vector. When you add new elements you need to start adding at the beginning once you hit the end. If you don't have a circular buffer, then you just get an iterator to the last element and calculate the sum of the elements from it to 10 s ago (depends on how many elements that is). – rozina May 14 '15 at 09:31

2 Answers2

1

Here is how I would do it. For simplicity's sake I redefined Data as follows:

struct Data
{
    int timeOfArrival;
    int value;
};

One way to do what you asked is to use a circular buffer where you store just the amount of data that you need for your moving average.

enum { MOVING_AVG_SIZE = 64, };  // number of elements that you use for your moving average

std::vector<Data> buffer(MOVING_AVG_SIZE);
std::vector<Data>::iterator insertIt = buffer.begin();

// saving to circular buffer
Data newData;

++insertIt
if (insertIt == buffer.end()) insertIt = buffer.begin();
*insertIt = newData;

// average
int sum = 0;
for (std::vector<Data>::const_iterator it = buffer.begin(); it != buffer.end(); ++it)
{
    sum += it->value;
}
float avg = sum / (float)buffer.size();

If you don't have a circular buffer and you just keep adding values to your vector, then you can just get the last number of elements needed for calculating your moving average.

// saving to circular buffer
Data newData;
buffer.push_back(newData);

// average
// this algorithm calculates the moving average even if there is not enough samples in the buffer for the "10 s" 
std::vector<Data>::const_reverse_iterator it = buffer.rbegin();
int i;
int sum = 0;
for (i = 0; i < MOVING_AVG_SIZE || it == buffer.rend(); ++i)
{
    sum += it->value;
}
float avg = sum / (float)i;
rozina
  • 4,120
  • 27
  • 49
0

As you have already decided that one thread will always populate and another thread will do moving average. You can then do this:

Keep a structure with two elements RunningSum and no of items in vector.

Write a loop which removes elements which are older than 10 sec and deduct their values from RunningSum. All elemenst in vector are sorted on timeofArrival, so you need not iterate the whole vector. Add to sum the value of new elemnts which are not yet added.

You need a way to deffrentiate items that have been added( used in sum) and the one that are not yet summed. You can use a boolean for this or put them in a new dataStructure(internal to your class).

Keep count of number of elements and calculate the average.

SumitV
  • 186
  • 9