I can find a lot of code for 60 second averages, but none that I can readily see how to adapt to counting events in a rolling 60 second window.
For example, say a pulse is registered every one second, then in 60 seconds a total of 60 pulses were received. After 60 seconds, the count of pulses in any 60 second window would be 60, Great. What if the pulses come at random intervals?
For example, say after 60 seconds a pulse was registered at at seconds 1, 12, 17, 25, 37, 42, & 54. The count of pulses is seven.
But, at second 62, after subtracting 60, I want to return the number of pulses in that 60 second window (2 to 62). The first pulse should be omit as it is outside of the new 60 second sampling period, so six. This would repeat every second forever.
I think there is a way to do this by populating an array everytime a pulse is registered, but that only grows the array. I'd need a way to prune the array, too, which seems to be a little difficult from what I've read. If you can prune the array, how do I handle a period with fewer array entries for times when fewer pulses were registered? Can the array container be of variable length?Any ideas? Thank you.
What if they do? There will still be a fixed number of pulses in the 60 second window.
How many pulses are you expecting in the 60 second window, max? Time-stamping the events will be necessary. Then, you just count how many of those events happened in the last 60 seconds. Using a circular array approach, where the size of the circle is the maximum number of events you expect, would allow you to reuse the same array. Just move one pointer forward as you add events. Move the other forward once a second, dropping off (or proving space for them to be overwritten) older events. The number of events, then, is simply the distance between the two pointers.
What if they do? There will still be a fixed number of pulses in the 60 second window.
No there won't. It isn't an every-60-second sample I'm after, it's a count how many pulses were received in the last 60 seconds, updating every new second. So if they came at seconds 10, 20, 30, 40, 50, 60, 90, 110, there would be fewer pulses in the latter stage of a rolling 60 second window (ie 1 to 60 has 6 but 31 to 90 has just 4). These are example intervals.
I also have no way of knowing how many pulses, let's say 60 in any single minute is the ceiling. Can you expand on the calculation part? I can handle the ++ part to increment array pointer but the second array I'm unclear on.
Yes, there will. At the end of any 60 second window, there will be a fixed number of pulses that have arrived during that window. It won't necessarily be the same number as that that arrived in some other 60 second window.
You only need one array. But, you need two pointers - one to point to where to write the next value and one to point to the oldest value less than 60 seconds old. OK, maybe indexes is a better term. Move the one forward as a new pulse is entered. When it hits the end of the array, reset to 0. Move the other pointer every time you check to point to the oldest value less than 60 seconds old.
The number of elements between the indexes (or between one index and the end of the array and between the start of the array and the other index) is the number of pulses in the last 60 seconds.
Think of the mechanism in a dry cleaners. You drop off stuff to be dry cleaned. You go back to get it. The conveyor system is at the letter G. Your stuff is at D. The conveyor moves around to H, I, J, ..., Z, A, B, C, and then D. The oldest stuff in your array is at one position. The newest is at another position. One position moves as new events occur. The other moves as time passes.
Google circular arrays if this doesn't make sense. You'll find pictures that illustrate the point better than words.
Yes, there will. At the end of any 60 second window, there will be a fixed number of pulses that have arrived during that window. It won't necessarily be the same number as that that arrived in some other 60 second window.
I disagree in that the number is not fixed, there will be some number, but it certainly is not fixed. If it were there'd be no reason to count it in the first place. You're just doing that silly word splitting thing again... and it finally happened to me.
I'll try to work up something and see what happens. Thanks for the direction.
If you are only interested in the count within a 60 second window, and not at what sepcific time within that window they arrived, you could do something like this (in English):
make an array: byte numPulses[60]
make a count variable
make an accumulator variable.
set a "producer" pointer to index 0
set a "consumer" pointer to index 0
at time 0, start counting pulses.
at each 1 second interval
store the count in the array
advance the 'producer' pointer and set to 0 if past the end index
add count to an accumulator
when time reaches 60
report the value in the accumulator (or whatever else you need to do with it)
advance the consumer pointer
Now comes the interesting part.
For every second after the first 60 seconds
store count in the array at the producer pointer index
add count to the accumulator
subtract value at consumer pointer from accumulator
report value of accumulator
advance consumer pointer
dotJason:
I like it. It'll take me a few days but I will try it out. Seems like I can follow that. Thanks.
I did forget a couple of important things, though they are probably pretty much self-evident. You will need to set count back to zero after storing it in the array and adding it to the accumulator. As well, I forgot to mention adcancing the producer pointer in the final, ongoing loop.
I didn't follow all (or much, actually 8)) of that, but just thought I'd throw something in which may or may not be significant: can more than one pulse be logged in in the same second? Can you get a 10, 11, 11, 12, 23, 28, 32, 32, 53 kind of thing? Does it matter?
JimboZA:
I didn't follow all (or much, actually 8)) of that, but just thought I'd throw something in which may or may not be significant: can more than one pulse be logged in in the same second? Can you get a 10, 11, 11, 12, 23, 28, 32, 32, 53 kind of thing? Does it matter?
Think of it as a circular buffer, in which you can hold counts gathered over 1 second periods. There is enough room for 60 seconds worth of counts. Once you have gathered 60 seconds worth of count, and have added them all to the accumulator, you then only need to add the next 1 second worth of counts, subtract the single out-of-date one, and keep doing that.
So it really doesn't matter if there are 0, 1, or 100 counts in any given second, as long as you have time to deal with counting them while doing whatever else needs to be done.
I would use an array with 60 elements, one for each second.
I would have an index representing the current second, which designates one slot in the array.
Each time pulse comes in, I would increment the value in that array slot.
Each time a second has elapsed, I would advance the current second pointer to the next slot, wrapping around at
the end of the array, and zeroing the value in the slot.
To find the number of pulses in the last 60 seconds, add up all the elements of the array, you
don't actually need to do this, you can keep a running total and just increment and decrement
each time the number changes.
This method will also work, if you get more than one pulse in a particular second.
You also need to think a bit carefully, about whether it matters what count you get when
pulses are very close to 60 seconds apart.
I don't think he specifically said they only come once per second.
Have an array of unsigned long (not too large, you don't have a lot of memory). Record the current timestamp in that (from millis) when a pulse arrives.
However before you do that, discard any entries in the array which are more than 60 seconds old.
If you want a nice data structure, a STL deque would do it, or simply a linked list. A circular buffer would be another approach.
Because I like the Standard Template Library so much I've done an example which uses that.
#include <iterator>
#include <deque>
#include <algorithm>
#include <functional>
#include <pnew.cpp> // placement new implementation
std::deque<unsigned long> events;
volatile bool eventHappened;
volatile unsigned long when;
void anEvent ()
{
// ignore if not handled yet
if (eventHappened)
return;
when = millis ();
eventHappened = true;
} // end of anEvent (ISR)
void setup ()
{
Serial.begin (115200);
Serial.println ();
pinMode (2, INPUT_PULLUP);
EIFR = bit (INTF0); // clear flag for interrupt 0
attachInterrupt (0, anEvent, FALLING);
} // end of setup
unsigned long lastReport;
// function object to check if event is old
class fTimeCheck
{
unsigned long now_;
public:
// constructor - remember time
fTimeCheck (unsigned long now) : now_ (now) { };
bool operator() (const unsigned long event)
{
return now_ - event >= 60000;
};
}; // end of class fTimeCheck
void loop ()
{
// get rid of old events
std::deque<unsigned long>::iterator iter;
// remove old ones
iter = remove_if (events.begin (), events.end (), fTimeCheck (millis ()));
// adjust deque size
events.erase (iter, events.end ());
// add new one
if (eventHappened)
{
events.push_back ((unsigned long) when);
// debug
Serial.println ("Added event!");
eventHappened = false;
} // end of a new event
// report every 5 seconds
if (millis () - lastReport >= 5000)
{
Serial.print ("Events in last 60 seconds = ");
Serial.println (events.size ());
lastReport = millis ();
} // end if time to report
} // end of loop
Example run:
Events in last 60 seconds = 0
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Events in last 60 seconds = 7
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Events in last 60 seconds = 14
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Events in last 60 seconds = 32
Added event!
Added event!
Events in last 60 seconds = 34
Events in last 60 seconds = 34
Events in last 60 seconds = 34
Events in last 60 seconds = 34
Events in last 60 seconds = 34
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Added event!
Events in last 60 seconds = 45
Events in last 60 seconds = 45
Events in last 60 seconds = 45
Events in last 60 seconds = 45
Events in last 60 seconds = 38
Events in last 60 seconds = 31
Events in last 60 seconds = 13
Events in last 60 seconds = 11
Events in last 60 seconds = 11
Events in last 60 seconds = 11
Events in last 60 seconds = 11
Events in last 60 seconds = 11
Events in last 60 seconds = 0
I haven't added debounce code, I'll leave that as an exercise. You can see that the event count goes up, and then as events stop, it falls back to zero.
The code uses a deque (double-ended queue). The remove_if algorithm is used to scan the queue and remove items matching the condition, itself being tested inside a function object (fTimeCheck).
New events are added with push_back(), and the current number is found with size().
byte data[59]; //set it as a global
byte p = 0; //global
//inside some function
if (p>59)
p=0;
value=sensorreadingvalue; //get data value
data[p]=value; //stick value in the array to be totaled and averaged up.
p++; //increment where to stick the data in the array
// total up and get average
for (...... i can't be bothered since you already have)
I can't see how your snippet would work. You aren't saving times, thus how do you know what the last 60 seconds is, in that array?
He wants to count pulses, they don't necessarily come every second, thus you can't just keep an array of 60. You need to know which ones (maybe 5) arrived in the last 60 seconds.
I have an extra Mega arriving today so I can't sandbox this out at the moment. I really appreciate the efforts you all have spent assisting me. Nick seems to understand the dilemma well. If it helps, I'm able to throw away the first 60 seconds until the count 'builds up' the initial value.
The pulse count is generated by the power consumption of my home's appliances. That wildly fluctuates throughout a day depending on who's home and what's happening. I have watched on serial monitor and viewed minutes roll by with as few as 5 pulses and when things are roaring upward of 50 pulses fly by. There really is no static element to this.