From 739ef26da322016bc0b2c6c0ede791917f4b045f Mon Sep 17 00:00:00 2001 From: Laurence Withers Date: Thu, 10 Jul 2014 10:36:49 +0000 Subject: [PATCH] WIP --- src/libfir++/000_TopHeader.h | 5 ++ src/libfir++/000_TopSource.cc | 1 + src/libfir++/100_Filter.cc | 76 ++++++++++++++++ src/libfir++/100_Filter.h | 155 ++++++++++++++++++++++++++++++++ src/libfir++/100_fir.h | 47 ---------- src/libfir/000_TopSource.c | 1 + src/libfir/100_fir.c | 57 +++++++++++- src/libfir/100_fir.h | 43 ++++++++- src/libfir/200_common_filters.c | 2 +- 9 files changed, 335 insertions(+), 52 deletions(-) create mode 100644 src/libfir++/100_Filter.cc create mode 100644 src/libfir++/100_Filter.h delete mode 100644 src/libfir++/100_fir.h diff --git a/src/libfir++/000_TopHeader.h b/src/libfir++/000_TopHeader.h index 5291fec..697e38d 100644 --- a/src/libfir++/000_TopHeader.h +++ b/src/libfir++/000_TopHeader.h @@ -11,6 +11,11 @@ // standard includes, or includes needed for type declarations #include +// forward declares, allowing us to avoid including the C library header +extern "C" { +struct fir_filter_t; +} + /*! \defgroup libfirpp C++ library */ /*! \brief All %FIR library functions and classes. diff --git a/src/libfir++/000_TopSource.cc b/src/libfir++/000_TopSource.cc index ca7c76e..1cf3efb 100644 --- a/src/libfir++/000_TopSource.cc +++ b/src/libfir++/000_TopSource.cc @@ -15,6 +15,7 @@ #include "fir++.h" // Below are all the includes used throughout the library. +#include namespace FIR { diff --git a/src/libfir++/100_Filter.cc b/src/libfir++/100_Filter.cc new file mode 100644 index 0000000..201d868 --- /dev/null +++ b/src/libfir++/100_Filter.cc @@ -0,0 +1,76 @@ +/* libfir/src/libfir++/100_Filter.cc + * + * Copyright: ©2014, Laurence Withers. + * Author: Laurence Withers + * License: GPLv3 + */ + + + +Filter::Filter(int ncoeff, const double* coeff, Symmetry symm) +{ + fi_ = fir_filter_new(ncoeff, coeff, static_cast(symm)); +} + + + +Filter::Filter(const Filter& other) +{ + fi_ = fir_filter_clone(other.fi_); +} + + + +Filter::Filter(const std::vector& coeff, Symmetry symm) +{ + int ncoeff = coeff.size(); + double* cc = static_cast(alloca(ncoeff * sizeof(double))); + + for(int i = 0; i < ncoeff; ++i) cc[i] = coeff[i]; + fi_ = fir_filter_new(ncoeff, cc, static_cast(symm)); +} + + + +Filter::~Filter() +{ + fir_filter_free(fi_); +} + + + +double +Filter::f(double x) +{ + return fir_filter(fi_, x); +} + + + +Symmetry +Filter::symmetry() const +{ + return static_cast(fir_filter_get_symmetry(fi_)); +} + + + +int +Filter::ncoeff() const +{ + return fir_filter_get_ncoeff(fi_); +} + + + +double +Filter::coeff(int idx) const +{ + return fir_filter_get_coeff(fi_, idx); +} + + + +/* options for text editors +vim: expandtab:ts=4:sw=4 +*/ diff --git a/src/libfir++/100_Filter.h b/src/libfir++/100_Filter.h new file mode 100644 index 0000000..06a46d9 --- /dev/null +++ b/src/libfir++/100_Filter.h @@ -0,0 +1,155 @@ +/* libfir/src/libfir++/100_Filter.h + * + * Copyright: ©2014, Laurence Withers. + * Author: Laurence Withers + * License: GPLv3 + */ + + + +/*! \defgroup libfirpp_fir Basic FIR filtering + +\ingroup libfirpp + +*/ + + + +/*! \brief %FIR filter symmetry. + +\ingroup libfirpp_fir + +The library extensively takes advantage of the symmetry that is often present +in %FIR filter coefficient sets. + +\note The numeric constants match those used in \ref libfir, so it is possible +to pass them directly between the libraries as required. + +*/ +enum Symmetry { + /*! \brief No symmetry. */ + SymmetryNone, + + /*! \brief Odd symmetry (odd total number of points). */ + SymmetryOdd, + + /*! \brief Even symmetry (even total number of points). */ + SymmetryEven, +}; + + + +/*! \brief Basic FIR filter object. + +\ingroup libfirpp_fir + +*/ +class Filter { +public: + /*! \brief Construct new filter. + + \param ncoeff Number of coefficients in array \a coeff. + \param coeff Pointer to array of %FIR filter coefficients. + \param symm Whether coefficients are symmetric or not. + + Builds a new filter. The number of coefficients \a ncoeff should reflect the + number of elements in the array \a coeff. If the filter is symmetric, the + actual %FIR filter itself will consist of \a 2*ncoeff (even symmetry) or + \a 2*ncoeff-1 (odd symmetry) points, as the symmetrical coefficients are + not passed. + + */ + Filter(int ncoeff, const double* coeff, Symmetry symm = SymmetryNone); + + + + /*! \brief Construct filter by copying coefficients from another instance. + + \param other Filter to copy coefficients from. + + Constructs a new filter object which copies the coefficients (but not the + state, i.e. previous sample values) from the filter object \a other. + + */ + Filter(const Filter& other); + + + + /*! \brief Construct new filter. + + \param coeff Array of coefficients. + \param symm Whether coefficients are symmetric or not. + + Builds a new filter. If the filter coefficient set is symmetric, then + \a coeff should only contain the non-repeated elements. + + */ + Filter(const std::vector& coeff, Symmetry symm = SymmetryNone); + + + + /*! \brief Destructor (frees underlying memory). */ + virtual ~Filter(); + + + + /*! \brief Filter a sample. + + \param x Input sample. + \returns Filter output. + + Filters a sample. If this is the very first sample passed to the instance + after construction, it will be taken as the steady-state DC input and the + filter primed appropriately. + + */ + double f(double x); + + + + /*! \brief Query filter's symmetry. + + \returns Symmetry of filter. + + */ + Symmetry symmetry() const; + + + /*! \brief Query number of coefficients in filter. + + \returns Number of coefficients. + + This function returns the number of coefficients. It ignores symmetry, so it + returns the total number of coefficients regardless of whether symmetry has + allowed us to store only half of them. + + */ + int ncoeff() const; + + + + /*! \brief Retrieve value of coefficient from filter. + + \param idx Index of coefficient (0 ≤ \a idx < \ref ncoeff()). + \returns Value of coefficient. + + This function retrieves the coefficient at \a idx. This works even for + coefficients that are not actually stored due to symmetry. + + */ + double coeff(int idx) const; + + + +private: + struct fir_filter_t* fi_; + + // disallow assignment + Filter& operator=(const Filter& other); +}; + + + +/* options for text editors +vim: expandtab:ts=4:sw=4:syntax=cpp.doxygen +*/ diff --git a/src/libfir++/100_fir.h b/src/libfir++/100_fir.h deleted file mode 100644 index 8189b5d..0000000 --- a/src/libfir++/100_fir.h +++ /dev/null @@ -1,47 +0,0 @@ -/* libfir/src/libfir++/100_fir.h - * - * Copyright: ©2014, Laurence Withers. - * Author: Laurence Withers - * License: GPLv3 - */ - - - -/*! \defgroup libfirpp_fir Basic FIR filtering - -\ingroup libfirpp - -\todo need our own symmetry enum -\todo forward declares -\todo coefficient query - -*/ - - - -/*! \brief Basic FIR filter object. - -\ingroup libfirpp_fir - -*/ -class Filter { -public: - Filter(int ncoeff, double* coeff, - enum fir_symmetry symm = fir_symmetry_none); - Filter(const Filter& other); - Filter(const std::vector& coeff, - enum fir_symmetry symm = fir_symmetry_none); - virtual ~Filter(); - -private: - struct fir_filter_t* fi_; - - // disallow assignment - Filter& operator=(const Filter& other); -}; - - - -/* options for text editors -vim: expandtab:ts=4:sw=4:syntax=cpp.doxygen -*/ diff --git a/src/libfir/000_TopSource.c b/src/libfir/000_TopSource.c index a1fc33c..79e8aef 100644 --- a/src/libfir/000_TopSource.c +++ b/src/libfir/000_TopSource.c @@ -9,6 +9,7 @@ /* Below are all the includes used throughout the library. */ #include +#include #include #include #include diff --git a/src/libfir/100_fir.c b/src/libfir/100_fir.c index c407761..c437f3e 100644 --- a/src/libfir/100_fir.c +++ b/src/libfir/100_fir.c @@ -46,7 +46,7 @@ symm_setup(struct fir_filter_t* fi, int delay) struct fir_filter_t* -fir_filter_new(const double* coeff, int ncoeff, enum fir_symmetry symm) +fir_filter_new(int ncoeff, const double* coeff, enum fir_symmetry symm) { struct fir_filter_t* fi; @@ -107,7 +107,7 @@ fir_filter_free(struct fir_filter_t* fi) struct fir_filter_t* fir_filter_clone(const struct fir_filter_t* fi) { - struct fir_filter_t* out = fir_filter_new(fi->coeff, fi->ncoeff, fi->symm); + struct fir_filter_t* out = fir_filter_new(fi->ncoeff, fi->coeff, fi->symm); return out; } @@ -157,6 +157,59 @@ fir_filter(struct fir_filter_t* fi, double x) +enum fir_symmetry +fir_filter_get_symmetry(const struct fir_filter_t* fi) +{ + return fi->symm; +} + + + +int +fir_filter_get_ncoeff(const struct fir_filter_t* fi) +{ + switch(fi->symm) { + case fir_symmetry_none: + return fi->ncoeff; + + case fir_symmetry_odd: + return 2 * fi->ncoeff + 1; + + case fir_symmetry_even: + return 2 * fi->ncoeff; + } + + assert(0); + return fir_symmetry_none; +} + + + +double +fir_filter_get_coeff(const struct fir_filter_t* fi, int idx) +{ + switch(fi->symm) { + case fir_symmetry_none: + break; + + case fir_symmetry_odd: + if(idx >= fi->ncoeff) { + idx = 2 * (fi->ncoeff - 1) - idx; + } + break; + + case fir_symmetry_even: + if(idx >= fi->ncoeff) { + idx = 2 * fi->ncoeff - 1 - idx; + } + break; + } + + return fi->coeff[idx]; +} + + + /* options for text editors vim: expandtab:ts=4:sw=4 */ diff --git a/src/libfir/100_fir.h b/src/libfir/100_fir.h index f9513da..11e647d 100644 --- a/src/libfir/100_fir.h +++ b/src/libfir/100_fir.h @@ -45,8 +45,8 @@ enum fir_symmetry { /*! \brief Allocate %FIR filter instance. -\param coeff Pointer to array of coefficients. \param ncoeff Number of coefficients in \a coeff (must be ≥ 1). +\param coeff Pointer to array of coefficients. \param symm Whether there is any symmetry. \returns Newly-allocated filter object. \retval 0 on error (and see \a errno). @@ -61,7 +61,7 @@ The contents of \a coeff are copied so it is not necessary to keep the original array in order to run the filter. */ -struct fir_filter_t* fir_filter_new(const double* coeff, int ncoeff, +struct fir_filter_t* fir_filter_new(int ncoeff, const double* coeff, enum fir_symmetry symm); @@ -82,6 +82,7 @@ void fir_filter_free(struct fir_filter_t* fi); /*! \brief Clone %FIR filter instance. \param fi Filter object to clone. +\returns Newly-allocated filter object. Clones the %FIR filter object \a fi, returning a new %FIR filter object that is ready to use. The new copy will have its own copy of the required @@ -112,6 +113,44 @@ double fir_filter(struct fir_filter_t* fi, double x); +/*! \brief Find symmetry of filter. + +\param fi Filter object. +\returns Symmetry. + +*/ +enum fir_symmetry fir_filter_get_symmetry(const struct fir_filter_t* fi); + + + +/*! \brief Find number of coefficients in filter. + +\param fi Filter object. +\returns Number of coefficients. + +This function returns the number of coefficients. It ignores symmetry, so it +returns the total number of coefficients regardless of whether symmetry has +allowed us to store only half of them. + +*/ +int fir_filter_get_ncoeff(const struct fir_filter_t* fi); + + + +/*! \brief Retrieve value of coefficient from filter. + +\param fi Filter object. +\param idx Index of coefficient (0 ≤ \a idx < \ref fir_filter_get_ncoeff()). +\returns Value of coefficient. + +This function retrieves the coefficient at \a idx. This works even for +coefficients that are not actually stored due to symmetry. + +*/ +double fir_filter_get_coeff(const struct fir_filter_t* fi, int idx); + + + /*!@}*/ /* options for text editors vim: expandtab:ts=4:sw=4:syntax=ch.doxygen diff --git a/src/libfir/200_common_filters.c b/src/libfir/200_common_filters.c index de9546d..17d374f 100644 --- a/src/libfir/200_common_filters.c +++ b/src/libfir/200_common_filters.c @@ -41,7 +41,7 @@ fir_sinc_lowpass(int npoints, double corner, double gain) coeff[i] *= gain; } - return fir_filter_new(coeff, spoints, + return fir_filter_new(spoints, coeff, (npoints & 1) ? fir_symmetry_odd : fir_symmetry_even); }