Program Listing for File filter.hpp

Return to documentation for file (lib/dsp/filter.hpp)

// ---------------------------------------------------------------------
// This file is part of falcon-core.
//
// Copyright (C) 2015, 2016, 2017 Neuro-Electronics Research Flanders
//
// Falcon-server is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Falcon-server is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with falcon-core. If not, see <http://www.gnu.org/licenses/>.
// ---------------------------------------------------------------------

#pragma once

#include "gram_savitzky_golay.hpp"

#include <yaml-cpp/yaml.h>

#include <array>
#include <vector>
#include <cassert>
#include <cstring>
#include <fstream>
#include <map>
#include <regex>
#include <string>
#include <algorithm>
#include <cctype>
#include <exception>


namespace dsp {
namespace filter {

class IFilter {
public:
    IFilter(std::string description) : description_(description) {}

    virtual ~IFilter();

    std::string description() const;

    virtual IFilter *clone() = 0;
    virtual unsigned int order() const = 0;

    unsigned int nchannels() const;
    bool realized() const;
    void realize(unsigned int nchannels, double init = 0.0);
    void unrealize();

    // single channel, single sample
    virtual double process_channel(double, unsigned int channel) = 0;

    // all channels, single sample
    virtual void process_sample(std::vector<double> &, std::vector<double> &) = 0;
    virtual void process_sample(std::vector<double>::iterator,
                                std::vector<double>::iterator) = 0;
    virtual void process_sample(double *, double *) = 0;

    // single channel, multiple samples
    virtual void process_channel(std::vector<double> &, std::vector<double> &,
                                 unsigned int channel = 0) = 0;
    virtual void process_channel(uint64_t nsamples, std::vector<double>::iterator,
                                 std::vector<double>::iterator,
                                 unsigned int channel = 0) = 0;
    virtual void process_channel(uint64_t nsamples, double *, double *,
                                 unsigned int channel) = 0;

    // all channels, multiple samples
    virtual void process_by_channel(
            std::vector<std::vector<double>> &,
            std::vector<std::vector<double>> &) = 0;  // samples<channels>
    virtual void process_by_sample(
            std::vector<std::vector<double>> &,
            std::vector<std::vector<double>> &) = 0;  // channels<samples>
    virtual void process_by_channel(uint64_t nsamples, double **,
                                    double **) = 0;  // samples<channels>
    virtual void process_by_sample(uint64_t nsamples, double **,
                                   double **) = 0;  // channels<samples>
    virtual void
    process_by_channel(uint64_t nsamples, std::vector<double> &,
                       std::vector<double> &) = 0;  // samples<channels>
    virtual void
    process_by_sample(uint64_t nsamples, std::vector<double> &,
                      std::vector<double> &) = 0;  // channels<samples>

protected:
    virtual bool realize_filter(unsigned int nchannels, double init) = 0;
    virtual void unrealize_filter() {};

protected:
    std::string description_;
    bool realized_ = false;
    unsigned int nchannels_ = 0;
};

class FirFilter : public IFilter {
public:
    FirFilter(const std::vector<double> &coefficients, std::string description = "");
    virtual IFilter *clone();

    static FirFilter *FromStream(std::istream &stream, std::string description,
                                 bool binary = false);

    unsigned int order() const final;

    std::size_t group_delay() const;

    // single channel, single sample
    double process_channel(double input, unsigned int channel = 0) final;

    // all channels, single sample
    void process_sample(std::vector<double> &input,
                        std::vector<double> &output) final;
    void process_sample(std::vector<double>::iterator input,
                        std::vector<double>::iterator output) final;
    void process_sample(double *input, double *output) final;

    // single channel, multiple samples
    void process_channel(std::vector<double> &input, std::vector<double> &output,
                         unsigned int channel = 0) final;
    void process_channel(uint64_t nsamples, std::vector<double>::iterator input,
                         std::vector<double>::iterator output,
                         unsigned int channel = 0);
    void process_channel(uint64_t nsamples, double *input, double *output,
                         unsigned int channel = 0);

    // all channels, multiple samples
    void
    process_by_channel(std::vector<std::vector<double>> &input,
                       std::vector<std::vector<double>> &output) final;
    void
    process_by_sample(std::vector<std::vector<double>> &input,
                      std::vector<std::vector<double>> &output) final;
    void process_by_channel(uint64_t nsamples, double **input,
                            double **output) final;
    void process_by_sample(uint64_t nsamples, double **input,
                           double **output) final;

    virtual void process_by_channel(uint64_t nsamples, std::vector<double> &input,
                                    std::vector<double> &output);
    virtual void process_by_sample(uint64_t nsamples, std::vector<double> &input,
                                   std::vector<double> &output);

protected:
    bool realize_filter(unsigned int nchannels,
                        double init = 0.0) final;
    void unrealize_filter() final;

protected:
    std::vector<double> coefficients_;
    double *pcoefficients_;
    unsigned int ntaps_;

    std::vector<std::vector<double>> registers_;
    std::vector<double *> pregisters_;

    double *preg_;
};

class SlopeFilter : public FirFilter {
public:

    SlopeFilter(uint32_t window_size, uint32_t order, uint32_t derivative_order, std::string description=""):
        FirFilter(gram_sg::compute_weights(window_size, window_size, order, derivative_order), description),
        window_size_(window_size), order_(order), derivative_order_(derivative_order){};

    static SlopeFilter *FromStream(std::istream &stream,
                                   std::string description,
                                   bool binary);

    virtual IFilter *clone(){
        return new SlopeFilter(window_size_, order_, derivative_order_);
    };

protected:
    size_t window_size_;
    uint32_t order_;
    uint32_t derivative_order_;
public:
    static constexpr uint16_t DEFAULT_WINDOW_SIZE = 4;
    static constexpr uint8_t DEFAULT_ORDER = 1;
    static constexpr uint8_t DEFAULT_DERIVATIVE_ORDER = 1;
};

class BiquadFilter : public IFilter {
public:
    BiquadFilter(double gain, std::vector<std::array<double, 6>> &coefficients,
                 std::string description = "");
    virtual IFilter *clone();

    static BiquadFilter *FromStream(std::istream &stream, std::string description,
                                    bool binary);

    unsigned int order() const final;

    // single channel, single sample
    double process_channel(double x, unsigned int c = 0) final;

    // all channels, single sample
    void process_sample(std::vector<double> &input,
                        std::vector<double> &output) final{};
    void process_sample(std::vector<double>::iterator input,
                        std::vector<double>::iterator output) final;
    void process_sample(double *input, double *output) final;

    // single channel, multiple samples
    void process_channel(std::vector<double> &input, std::vector<double> &output,
                         unsigned int channel = 0) final;
    void process_channel(uint64_t nsamples, std::vector<double>::iterator input,
                         std::vector<double>::iterator output,
                         unsigned int channel = 0) final;
    void process_channel(uint64_t nsamples, double *input, double *output,
                         unsigned int channel = 0) final;

    // all channels, multiple samples
    void
    process_by_channel(std::vector<std::vector<double>> &input,
                       std::vector<std::vector<double>> &output) final;
    void
    process_by_sample(std::vector<std::vector<double>> &input,
                      std::vector<std::vector<double>> &output) final;
    void process_by_channel(uint64_t nsamples, double **input,
                            double **output) final;
    void process_by_sample(uint64_t nsamples, double **input,
                           double **output) final;

    virtual void process_by_channel(uint64_t nsamples, std::vector<double> &input,
                                    std::vector<double> &output);
    virtual void process_by_sample(uint64_t nsamples, std::vector<double> &input,
                                   std::vector<double> &output);

protected:
    bool realize_filter(unsigned int nchannels,
                        double init = 0.0) final;
    void unrealize_filter() final;

protected:
    double gain_;
    std::vector<std::array<double, 6>> coefficients_;

    unsigned int nstages_;

    std::vector<std::vector<std::array<double, 2>>> registers_;
};

std::map<std::string, std::string> parse_file_header(std::istream &stream);
IFilter *construct_from_file(std::string file);

IFilter *construct_from_yaml(const YAML::Node &node);

}  // namespace filter
}  // namespace dsp