Filters

Filters convolve the provided input data stream with either the defined array of coefficients (finite-impulse, infinite-impulse) or the previous inputs (averaging filter). The VSlib provides three types of filters: FIRFilter implementing finite-impulse filter, IIRFilter implementing infinite-impulse filter, and BoxFilter implementing averaging filter.

General interface

All implemented filters derive from the Filter class and follow its interface. The Filter base class ensures that each filter is a library Component and implements all its features. All Filters provide a consistent interface of a single main access method to be called to access its functionality: filter, which takes one double` argument and returns double-type filtered value, and a reset method to clear the input (and output for IIRFilter) history buffers.

Sliding-window averaging filter

The BoxFilter class implements the Sliding-window averaging filter. It has no settable Parameters. The inputs are filtered with the general method filter. They are continuously accumulated using fixed-point arithmetic to minimize accumulation of floating-point errors. There are two template parameters that can be set: filter order to define the size of the previous inputs history buffer size (order + 1), and maximal value that is expected to be filtered. The maximal value template parameter has a default value of 100’000, and if the value you intend to filter with this component is not likely to be larger than that, this parameter does not need to be specified.

For more details regarding the API, see the API documentation for BoxFilter.

Usage example

#include <array>

#include "boxFilter.h"

using namespace vslib;

int main() {
    RootComponent root;
    BoxFilter<5> filter("swd", &root);

    std::array<double, 4> input = {1.0, 2.0, 3.0, 4.0};

    // filter inputs one-by-one
    auto output1 = filter.filter(input[0]);
    auto output2 = filter.filter(input[1]);
    auto output3 = filter.filter(input[2]);
    auto output4 = filter.filter(input[3]);

    // reset filter between not-connected uses to clear history
    filter.reset();

    return 0;
}

Example usage in a vloop:

#include "vslib.hpp"

namespace fgc::user
{
    class Converter : public vslib::RootComponent
    {
    public:
        Converter() noexcept
        : vslib::RootComponent("example"),
          interrupt_1("stg", *this, 128, vslib::InterruptPriority::high, RTTask),
          filter_1("box_filter_1", *this)
        {
        }

        // Define your interrupts here
        vslib::PeripheralInterrupt<Converter> interrupt_1;

        // Define your public Components here
        vslib::BoxFilter<5> filter_1;

        void init() override
        {
            interrupt_1.start();
        }

        void backgroundTask() override
        {
        }

        static void RTTask(Converter& converter)
        {
            // Read the input value:
            const double input = converter.m_data[0];

            const auto output = converter.filter_1.filter(input);
            // use the output
        }

        private:
            // actual source of data omitted for simplicity
            std::array<double, 1> m_data{0.0};
    };
}   // namespace fgc::user

Finite-impulse filter

The finite-impulse filter (FIR) convolves the provided input data stream with the defined array of coefficients, saving history of previous inputs up to the length of the coefficient array. This component requires the order of the filter to be defined at the initialization as a template parameter (see example below).

The FIRFilter has one settable Parameter : array of coefficients (std::array<double>) called coefficients. In addition to the main access method, filter, the FIR filter provides also a method for filtering an entire array in one go, also called filter but one requiring a template parameter: length of the input array to be filtered, to be provided.

For more details regarding the API, see the API documentation for FIRFilter.

Usage example

#include <array>

#include "firFilter.h"
#include "rootComponent.h"

using namespace vslib;

void your_function(RootComponent& root)
{
    FIRFilter<5> filter("fir", root);

    // set filter coefficient array to the desired value

    std::array<double, 4> input = {1.0, 2.0, 3.0, 4.0};

    // filter inputs one-by-one
    auto output1 = filter.filter(input[0]);
    auto output2 = filter.filter(input[1]);
    auto output3 = filter.filter(input[2]);
    auto output4 = filter.filter(input[3]);

    // reset filter between not-connected uses
    filter.reset();

    // filter entire array data in one go
    auto output = filter<4>.filter(input);

    return 0;
}

Example usage in a vloop:

#include "vslib.hpp"

namespace fgc::user
{
    class Converter : public vslib::RootComponent
    {
    public:
        Converter() noexcept
        : vslib::RootComponent("example"),
          interrupt_1("stg", *this, 128, vslib::InterruptPriority::high, RTTask),
          filter_1("fir_filter_1", *this)
        {
        }

        // Define your interrupts here
        vslib::PeripheralInterrupt<Converter> interrupt_1;

        // Define your public Components here
        vslib::FIRFilter<5> filter_1;

        void init() override
        {
            interrupt_1.start();
        }

        void backgroundTask() override
        {
        }

        static void RTTask(Converter& converter)
        {
            // Read the input value:
            const double input = converter.m_data[0];

            const auto output = converter.filter_1.filter(input);
            // use the output
        }

        private:
            // actual source of data omitted for simplicity
            std::array<double, 1> m_data{0.0};
    };
}   // namespace fgc::user

Infinite-impulse filter

The ifinite-impulse filter (IIR) convolves the provided input data stream with the defined array of coefficients, called numerator_coefficients and the history of previous outputs with the defubed array of denominator_coefficients, saving history of previous inputs and outputs up to the length of the coefficient arrays (order + 1). This component requires the order of the filter to be defined at the initialization as a template parameter (see example below).

The IIRFilter has two settable Parameters: numerator and denominator coefficients (both of type std::array<double>), called numerator_coefficients and denominator_coefficients, respectively. In addition to the main access method, filter, the IIR filter provides also a method for filtering an entire array in one go, also called filter but one requiring a template parameter: length of the input array to be filtered, to be provided.

For more details regarding the API, see the API documentation for IIRFilter.

Usage example

#include <array>

#include "iirFilter.h"
#include "rootComponent.h"

using namespace vslib;

void your_function(RootComponent& root)
{
    IIRFilter<3> filter("iir", root);

    // set two filter numerator and denominator coefficient arrays to desired values

    std::array<double, 4> input = {1.0, 2.0, 3.0, 4.0};

    // filter inputs one-by-one
    auto output1 = filter.filter(input[0]);
    auto output2 = filter.filter(input[1]);
    auto output3 = filter.filter(input[2]);
    // the first input and output are now forgotten
    auto output4 = filter.filter(input[3]);

    // reset filter between not-connected uses
    filter.reset();

    // filter entire array data in one go
    auto output = filter<4>.filter(input);

    return 0;
}

Example usage in a vloop:

#include "vslib.hpp"

namespace fgc::user
{
    class Converter : public vslib::RootComponent
    {
    public:
        Converter() noexcept
        : vslib::RootComponent("example"),
          interrupt_1("stg", *this, 128, vslib::InterruptPriority::high, RTTask),
          filter_1("iir_filter_1", *this)
        {
        }

        // Define your interrupts here
        vslib::PeripheralInterrupt<Converter> interrupt_1;

        // Define your public Components here
        vslib::IIRFilter<5> filter_1;

        void init() override
        {
            interrupt_1.start();
        }

        void backgroundTask() override
        {
        }

        static void RTTask(Converter& converter)
        {
            // Read the input value:
            const double input = converter.m_data[0];

            const auto output = converter.filter_1.filter(input);
            // use the output
        }

        private:
            // actual source of data omitted for simplicity
            std::array<double, 1> m_data{0.0};
    };
}   // namespace fgc::user

Performance

Filter performance depending on the order