Moving average

This module implements a moving average filter which calculates the unweighted mean of the previous \(k\) data points (sampling window). The number of data points \(k\) is adjustable during run-time with a maximum filter length which is determined during initialization of the filter.

\[\frac{1}{k}\sum^n_{i=n-k+1} p_i = \frac{p_{n-k+1} + p_{p-k+2} + ... + p_n}{k}\]

with the data points \(p\) and the number of entries in the ring buffer \(n\) [1].

To speed up the calculation and prevent looping through every member of the circular buffer a different approach is used.

\[\frac{1}{k}\sum^{n+1}_{i=n-k+2} p_i = sum_{k,prev} + \frac{1}{k}(p_{n+1} - p_{n-k+1})\]

Thus, for each function call the oldest value in the circular buffer (circularBuffer array) will be deleted and the newest one will be added.

Setup

Configuration

typedef struct uz_movingAverageFilter_t uz_movingAverageFilter_t

Object definition for uz_movingAverageFilter_t.

struct uz_movingAverageFilter_config

Configuration struct for movingAverageFilter. Accessible by the user.

Public Members

uint32_t filterLength

Length of the filter. Must be larger than 0 and smaller or equal to the length of the cirucularBuffer array

uz_movingAverageFilter_t *uz_movingAverageFilter_init(struct uz_movingAverageFilter_config config, uz_array_float_t circularBuffer)

Initialization of the moving Average Filter object.

Parameters
  • config – uz_movingAverageFilter_config configuration struct

  • circularBuffer – circularBuffer array. The length of the array will be the MAX_LENGTH of the filter

Returns

uz_movingAverageFilter_t* pointer to uz_movingAverageFilter_t instance

The circularBuffer array has to be initialized by using the UltraZohm Array module. The length of the array will automatically be the maximum possible length of the filter. I.e. if the array has 50 entries, the filter length can’t be higher than 50, otherwise an assertion triggers. However, it is possible for the filter length to be lower than the maximum length.

Listing 74 Example to initialize the configuration struct
 1#include "uz/uz_movingAverageFilter/uz_movingAverageFilter.h"
 2int main(void) {
 3   struct uz_movingAverageFilter_config config_SMA = {
 4      .filterLength = 30U
 5   };
 6   float data [50] = {0};
 7   uz_array_float_t circularBuffer = {
 8      .length = UZ_ARRAY_SIZE(data),
 9      .data = &data[0]
10   };
11}

Init function

During the initialization the config struct as well as the circularBuffer array have to be function arguments of the init function.

Listing 75 Example function call to init the movingAverageFilter instance.
1int main(void) {
2   uz_movingAverageFilter_t* SMA_instance = uz_movingAverageFilter_init(config_SMA, circularBuffer);
3}

Warning

Each instance of the moving average filter requires it’s own circularBuffer array!

Example of initialization for two independent moving average filters:

Listing 76 Example function call to init the movingAverageFilter instance.
 1#include "uz/uz_movingAverageFilter/uz_movingAverageFilter.h"
 2int main(void) {
 3   float data_1 [50] = {0};
 4   uz_array_float_t circularBuffer_1 = {
 5      .length = UZ_ARRAY_SIZE(data_1),
 6      .data = &data_1[0]
 7   };
 8
 9   float data_2 [20] = {0};
10   uz_array_float_t circularBuffer_2 = {
11      .length = UZ_ARRAY_SIZE(data_2),
12      .data = &data_2[0]
13   };
14
15   struct uz_movingAverageFilter_config config_SMA_1 = {
16      .filterLength = 30U
17   };
18
19   struct uz_movingAverageFilter_config config_SMA_2 = {
20      .filterLength = 20U
21   };
22
23   uz_movingAverageFilter_t* SMA_instance_1 = uz_movingAverageFilter_init(config_SMA_1, circularBuffer_1);
24   uz_movingAverageFilter_t* SMA_instance_2 = uz_movingAverageFilter_init(config_SMA_2, circularBuffer_2);
25}

Sample-functions

Two versions are implemented:

  • float uz_movingAverageFilter_sample(uz_movingAverageFilter_t *self, float sample)

    Calculates one sample of the moving average filter with fixed filter length.

    Parameters
    • self – pointer to uz_movingAverageFilter_t instance

    • sample – sample input of the moving average filter

    Returns

    float output of the filter

  • float uz_movingAverageFilter_sample_variable_length(uz_movingAverageFilter_t *self, float sample)

    Calculates one sample of the moving average filter. The filter length can be changed dynamically during runtime. It uses different approaches to calculate the result with the least amount of loop-iterations possible.

    Parameters
    • self – pointer to uz_movingAverageFilter_t instance

    • sample – sample input of the moving average filter

    Returns

    float output of the filter

Listing 77 Example function call
1int main(void) {
2  float sample = 23.4f;
3   float output_fixed_length = uz_movingAverageFilter_sample(SMA_instance, sample);
4   float output_variable_length = uz_movingAverageFilter_sample_variable_length(SMA_instance, sample);
5}

Set filter length

void uz_movingAverageFilter_set_filterLength(uz_movingAverageFilter_t *self, uint32_t new_filterLength)

Sets a new filter length.

Parameters
  • self – pointer to uz_movingAverageFilter_t instance

  • new_filterLength – new value for the filter length

Changes the filter length to the input value. Filter length has to be equal or lower to the MAX_LENGTH and larger than 0. Otherwise an assertion triggers.

Listing 78 Example function call to reset the movingAverageFilter instance.
1int main(void) {
2   uint32_t new_filter_length = 5U;
3   uz_movingAverageFilter_set_filterLength(SMA_instance, new_filter_length);
4}

Reset

Resets the movingAverageFilter module. All elements of the circularBuffer will be reset to 0.0f.

Listing 79 Example function call to reset the movingAverageFilter instance.
1int main(void) {
2   uz_movingAverageFilter_reset(SMA_instance);
3}

Sources

1

Moving average, Wikipedia