This commit is contained in:
Laurence Withers 2014-07-10 10:36:49 +00:00
parent caffec76a4
commit 739ef26da3
9 changed files with 335 additions and 52 deletions

View File

@ -11,6 +11,11 @@
// standard includes, or includes needed for type declarations // standard includes, or includes needed for type declarations
#include <vector> #include <vector>
// forward declares, allowing us to avoid including the C library header
extern "C" {
struct fir_filter_t;
}
/*! \defgroup libfirpp C++ library */ /*! \defgroup libfirpp C++ library */
/*! \brief All %FIR library functions and classes. /*! \brief All %FIR library functions and classes.

View File

@ -15,6 +15,7 @@
#include "fir++.h" #include "fir++.h"
// Below are all the includes used throughout the library. // Below are all the includes used throughout the library.
#include <alloca.h>
namespace FIR { namespace FIR {

View File

@ -0,0 +1,76 @@
/* libfir/src/libfir++/100_Filter.cc
*
* Copyright: ©2014, Laurence Withers.
* Author: Laurence Withers <l@lwithers.me.uk>
* License: GPLv3
*/
Filter::Filter(int ncoeff, const double* coeff, Symmetry symm)
{
fi_ = fir_filter_new(ncoeff, coeff, static_cast<enum fir_symmetry>(symm));
}
Filter::Filter(const Filter& other)
{
fi_ = fir_filter_clone(other.fi_);
}
Filter::Filter(const std::vector<double>& coeff, Symmetry symm)
{
int ncoeff = coeff.size();
double* cc = static_cast<double*>(alloca(ncoeff * sizeof(double)));
for(int i = 0; i < ncoeff; ++i) cc[i] = coeff[i];
fi_ = fir_filter_new(ncoeff, cc, static_cast<enum fir_symmetry>(symm));
}
Filter::~Filter()
{
fir_filter_free(fi_);
}
double
Filter::f(double x)
{
return fir_filter(fi_, x);
}
Symmetry
Filter::symmetry() const
{
return static_cast<Symmetry>(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
*/

155
src/libfir++/100_Filter.h Normal file
View File

@ -0,0 +1,155 @@
/* libfir/src/libfir++/100_Filter.h
*
* Copyright: ©2014, Laurence Withers.
* Author: Laurence Withers <l@lwithers.me.uk>
* 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<double>& 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 &lt; \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
*/

View File

@ -1,47 +0,0 @@
/* libfir/src/libfir++/100_fir.h
*
* Copyright: ©2014, Laurence Withers.
* Author: Laurence Withers <l@lwithers.me.uk>
* 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<double>& 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
*/

View File

@ -9,6 +9,7 @@
/* Below are all the includes used throughout the library. */ /* Below are all the includes used throughout the library. */
#include <alloca.h> #include <alloca.h>
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>

View File

@ -46,7 +46,7 @@ symm_setup(struct fir_filter_t* fi, int delay)
struct fir_filter_t* 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; struct fir_filter_t* fi;
@ -107,7 +107,7 @@ fir_filter_free(struct fir_filter_t* fi)
struct fir_filter_t* struct fir_filter_t*
fir_filter_clone(const struct fir_filter_t* fi) 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; 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 /* options for text editors
vim: expandtab:ts=4:sw=4 vim: expandtab:ts=4:sw=4
*/ */

View File

@ -45,8 +45,8 @@ enum fir_symmetry {
/*! \brief Allocate %FIR filter instance. /*! \brief Allocate %FIR filter instance.
\param coeff Pointer to array of coefficients.
\param ncoeff Number of coefficients in \a coeff (must be 1). \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. \param symm Whether there is any symmetry.
\returns Newly-allocated filter object. \returns Newly-allocated filter object.
\retval 0 on error (and see \a errno). \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. 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); enum fir_symmetry symm);
@ -82,6 +82,7 @@ void fir_filter_free(struct fir_filter_t* fi);
/*! \brief Clone %FIR filter instance. /*! \brief Clone %FIR filter instance.
\param fi Filter object to clone. \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 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 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 &lt; \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 /* options for text editors
vim: expandtab:ts=4:sw=4:syntax=ch.doxygen vim: expandtab:ts=4:sw=4:syntax=ch.doxygen

View File

@ -41,7 +41,7 @@ fir_sinc_lowpass(int npoints, double corner, double gain)
coeff[i] *= gain; coeff[i] *= gain;
} }
return fir_filter_new(coeff, spoints, return fir_filter_new(spoints, coeff,
(npoints & 1) ? fir_symmetry_odd : fir_symmetry_even); (npoints & 1) ? fir_symmetry_odd : fir_symmetry_even);
} }