New reading to be fed into moving average routine.
UPDpulse
Update. Push a new value into the moving average routine.
Resetpulse
Restart moving average. Internally, delete all stored readings.
Donepulse
Pulse each time moving average (Avg) is updated.
Avgnumber
Moving average.
To use the node in your project you should have the wayland/moving-average library installed. Use the “File → Add Library” menu item in XOD IDE if you don’t have it yet. See Using libraries for more info.
C++ implementation
// Based on https://github.com/ThingEngineer/movingAvgFloat which in turn is derived from https://github.com/JChristensen/movingAvg
node {
// Internal state variables defined at this level persists across evaluations
uint16_t m_interval; // number of data points for the moving average
Number m_nbrReadings; // number of readings
Number m_sum; // sum of the m_readings array
uint16_t m_next; // index to the next reading
Number *m_readings; // pointer to the dynamically allocated interval array
// initialize - allocate the interval array
void init()
{
m_readings = new Number[m_interval];
}
// add a new reading and return the new moving average
Number reading(Number newReading)
{
// add each new data point to the sum until the m_readings array is filled
if (m_nbrReadings < m_interval)
{
(Number)++m_nbrReadings;
m_sum = m_sum + newReading;
}
// once the array is filled, subtract the oldest data point and add the new one
else
{
m_sum = (Number)m_sum - m_readings[m_next] + newReading;
}
m_readings[m_next] = newReading;
if (++m_next >= m_interval) m_next = 0;
return (Number)(m_sum / m_nbrReadings);
}
// just return the current moving average
//float getAvg()
//{
// return (Number)(m_sum / m_nbrReadings);
//}
// start the moving average over again
void reset()
{
m_nbrReadings = 0.0;
m_sum = 0.0;
m_next = 0;
}
void evaluate(Context ctx) {
if (isSettingUp()) {
m_interval = getValue<input_N>(ctx);
init();
}
if (isInputDirty<input_UPD>(ctx)) {
emitValue<output_Avg>(ctx, reading(getValue<input_New>(ctx)));
emitValue<output_Done>(ctx, 1);
}
if (isInputDirty<input_Reset>(ctx)) {
reset();
}
}
}