moving-average

wayland/moving-average/moving-average

Calculate moving average.
moving-average
@/moving-average
Calculate moving average.
Nnumber
Number of data points for the moving average.
Newnumber
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.
moving-average
N
New
UPD
Reset
Avg
Done
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();
        }

    }
}