This commit is contained in:
Laurence Withers 2014-07-10 09:30:42 +00:00
parent d42f63388e
commit caffec76a4
14 changed files with 232 additions and 13 deletions

1
config
View File

@ -32,4 +32,5 @@ source "scripts/paths"
# Project-specific variables below. # Project-specific variables below.
[ -z "${CC}" ] && CC="gcc" [ -z "${CC}" ] && CC="gcc"
[ -z "${CXX}" ] && CXX="g++"
[ -z "${CFLAGS}" ] && CFLAGS="-g -O2 -W -Wall" [ -z "${CFLAGS}" ] && CFLAGS="-g -O2 -W -Wall"

View File

@ -9,6 +9,16 @@
#define HEADER_libfirpp #define HEADER_libfirpp
// standard includes, or includes needed for type declarations // standard includes, or includes needed for type declarations
#include <vector>
/*! \defgroup libfirpp C++ library */
/*! \brief All %FIR library functions and classes.
\ingroup libfirpp
*/
namespace FIR {
/* options for text editors /* options for text editors
vim: expandtab:ts=4:sw=4:syntax=cpp.doxygen vim: expandtab:ts=4:sw=4:syntax=cpp.doxygen

View File

@ -0,0 +1,23 @@
/* libfir/src/libfir++/000_TopSource.cc
*
* Copyright: ©2014, Laurence Withers.
* Author: Laurence Withers <l@lwithers.me.uk>
* License: GPLv3
*/
// "fir.h" includes <complex.h>, which uses a preprocessor define on the
// symbol complex. We need to include it first so that it gets its required
// define, and then clear it up before including anything that pulls in the
// C++ header <complex>.
#include "fir.h"
#undef complex
#include "fir++.h"
// Below are all the includes used throughout the library.
namespace FIR {
/* options for text editors
vim: expandtab:ts=4:sw=4
*/

47
src/libfir++/100_fir.h Normal file
View File

@ -0,0 +1,47 @@
/* 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

@ -5,6 +5,8 @@
* License: GPLv3 * License: GPLv3
*/ */
} // end namespace FIR
#endif #endif
/* options for text editors /* options for text editors

View File

@ -1,13 +1,11 @@
/* libfir/src/libfir++/TopSource.cpp /* libfir/src/libfir++/999_BottomSource.cc
* *
* Copyright: ©2014, Laurence Withers. * Copyright: ©2014, Laurence Withers.
* Author: Laurence Withers <l@lwithers.me.uk> * Author: Laurence Withers <l@lwithers.me.uk>
* License: GPLv3 * License: GPLv3
*/ */
#include "fir++.h" } // end namespace FIR
// Below are all the includes used throughout the library.
/* options for text editors /* options for text editors
vim: expandtab:ts=4:sw=4 vim: expandtab:ts=4:sw=4

View File

@ -6,6 +6,8 @@
# libfirpp_DEP_CFLAGS # libfirpp_DEP_CFLAGS
# libfirpp_DEP_LIBS # libfirpp_DEP_LIBS
build_target libfir
if [ -z ${libfirpp_BUILT} ] if [ -z ${libfirpp_BUILT} ]
then then
libfirpp_BASE=libfir++ libfirpp_BASE=libfir++
@ -15,7 +17,7 @@ then
libfirpp_DEP_CFLAGS="" # @TODO@ cflags libfirpp_DEP_CFLAGS="" # @TODO@ cflags
libfirpp_DEP_LIBS="" # @TODO@ libs libfirpp_DEP_LIBS="" # @TODO@ libs
SO_EXTRA="${libfirpp_DEP_CFLAGS} ${libfirpp_DEP_LIBS} -lstdc++ -lc \ SO_EXTRA="${libfirpp_DEP_CFLAGS} ${libfirpp_DEP_LIBS} -lstdc++ -lc \
-D_GNU_SOURCE" ${libfir} -D_GNU_SOURCE"
echo "Building library ${libfirpp}..." echo "Building library ${libfirpp}..."

View File

@ -11,7 +11,7 @@ then
MONOLITHIC_SOURCE="$(find src/libfir++/ -name '*.h' | sort)" MONOLITHIC_SOURCE="$(find src/libfir++/ -name '*.h' | sort)"
make_monolithic ${HDR} Ch || return 1 make_monolithic ${HDR} Ch || return 1
MONOLITHIC_SOURCE="$(find src/libfir++/ -name '*.cpp' | sort)" MONOLITHIC_SOURCE="$(find src/libfir++/ -name '*.cc' | sort)"
make_monolithic ${SRC} C || return 1 make_monolithic ${SRC} C || return 1
libfirpp_MONOLITHIC=1 libfirpp_MONOLITHIC=1

View File

@ -12,6 +12,8 @@
extern "C" { extern "C" {
#endif #endif
/*! \defgroup libfir C library */
/* standard includes, or includes needed for type declarations */ /* standard includes, or includes needed for type declarations */
/* options for text editors /* options for text editors

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 <errno.h>
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>

View File

@ -48,8 +48,14 @@ 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(const double* coeff, int ncoeff, enum fir_symmetry symm)
{ {
struct fir_filter_t* fi = malloc(sizeof(*fi)); struct fir_filter_t* fi;
if(ncoeff < 1) {
errno = EINVAL;
return 0;
}
fi = malloc(sizeof(*fi));
fi->coeff = malloc(sizeof(double) * ncoeff); fi->coeff = malloc(sizeof(double) * ncoeff);
memcpy(fi->coeff, coeff, sizeof(double) * ncoeff); memcpy(fi->coeff, coeff, sizeof(double) * ncoeff);
fi->ncoeff = ncoeff; fi->ncoeff = ncoeff;

View File

@ -7,29 +7,112 @@
/*! \defgroup libfir_fir Basic FIR filtering
\ingroup libfir
Routines in this section provide the basic building blocks for %FIR filter use:
allocation/build from coefficients, cloning, and the filter operation itself.
*/
/*!@{*/
/* opaque structure */
struct fir_filter_t; struct fir_filter_t;
/*! \brief %FIR filter symmetry.
The library extensively takes advantage of the symmetry that is often present
in %FIR filter coefficient sets.
*/
enum fir_symmetry { enum fir_symmetry {
/*! \brief No symmetry. */
fir_symmetry_none, fir_symmetry_none,
/*! \brief Odd symmetry (odd total number of points). */
fir_symmetry_odd, fir_symmetry_odd,
/*! \brief Even symmetry (even total number of points). */
fir_symmetry_even, fir_symmetry_even,
}; };
/*! \brief Allocate %FIR filter instance.
\param coeff Pointer to array of coefficients.
\param ncoeff Number of coefficients in \a coeff (must be 1).
\param symm Whether there is any symmetry.
\returns Newly-allocated filter object.
\retval 0 on error (and see \a errno).
Allocates a new %FIR filter based on the given set of coefficients \a coeff.
If the coefficient set is known to have odd symmetry of \a N points, then
pass \a ncoeff as \a (N+1)/2 (and this is the number of entries in \a coeff
that are read). If the coefficient set is known to have even symmetry of \a N
points, then pass \a ncoeff as \a N/2.
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(const double* coeff, int ncoeff,
enum fir_symmetry symm); enum fir_symmetry symm);
/*! \brief Free %FIR filter instance.
\param fi Filter object (may be 0).
\returns Newly-allocated filter object.
Frees all memory associated with the filter object \a fi. Does nothing if
passed a null pointer.
*/
void fir_filter_free(struct fir_filter_t* fi); void fir_filter_free(struct fir_filter_t* fi);
/*! \brief Clone %FIR filter instance.
\param fi Filter object to clone.
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
coefficients and does not hold any reference to the original.
Note that filter state (i.e. previous samples) is not copied; the new filter
will be fresh.
*/
struct fir_filter_t* fir_filter_clone(const struct fir_filter_t* fi); struct fir_filter_t* fir_filter_clone(const struct fir_filter_t* fi);
/*! \brief Run %FIR filter.
\param fi Filter object.
\param x Input sample.
\returns Output sample.
This function runs the filter for the given input sample \a x, returning an
output sample \a y. If this is the very first sample after creation (either via
\ref fir_filter_new() or \ref fir_filter_clone()), then this sample will be
considered as the steady-state value and the previous-sample values stored in
\a fi will be initialised to \a x.
*/
double fir_filter(struct fir_filter_t* fi, double x); double fir_filter(struct fir_filter_t* fi, double x);
/*!@}*/
/* options for text editors /* options for text editors
vim: expandtab:ts=4:sw=4 vim: expandtab:ts=4:sw=4:syntax=ch.doxygen
*/ */

View File

@ -8,11 +8,16 @@
struct fir_filter_t* struct fir_filter_t*
fir_sinc_lowpass(int npoints, double corner) fir_sinc_lowpass(int npoints, double corner, double gain)
{ {
double* coeff, t; double* coeff, t, sum = 0;
int i, spoints; int i, spoints;
if(npoints < 1) {
errno = EINVAL;
return 0;
}
/* find number of points after taking symmetry into account */ /* find number of points after taking symmetry into account */
spoints = (npoints + 1) / 2; spoints = (npoints + 1) / 2;
coeff = alloca(sizeof(double) * spoints); coeff = alloca(sizeof(double) * spoints);
@ -21,13 +26,21 @@ fir_sinc_lowpass(int npoints, double corner)
for(i = 0; i < spoints; ++i) { for(i = 0; i < spoints; ++i) {
if((i * 2 + 1) == npoints) { if((i * 2 + 1) == npoints) {
coeff[i] = 1; coeff[i] = 1;
sum += 1; /* not 2, as we don't repeat this coeff */
} else { } else {
t = i + 0.5 - npoints * 0.5; t = i + 0.5 - npoints * 0.5;
t *= corner * 2; t *= corner * 2;
coeff[i] = sin(t) / t; coeff[i] = sin(t) / t;
sum += coeff[i] * 2;
} }
} }
/* normalise gain */
gain /= sum;
for(i = 0; i < spoints; ++i) {
coeff[i] *= gain;
}
return fir_filter_new(coeff, spoints, return fir_filter_new(coeff, spoints,
(npoints & 1) ? fir_symmetry_odd : fir_symmetry_even); (npoints & 1) ? fir_symmetry_odd : fir_symmetry_even);
} }

View File

@ -7,10 +7,41 @@
struct fir_filter_t* fir_sinc_lowpass(int npoints, double corner); /*! \defgroup libfir_common Common filter types
\ingroup libfir
Routines in this section instantiate %FIR filters using algorithms to build
commonly-used types of filter, such as brickwall low-pass etc.
/* options for text editors */
vim: expandtab:ts=4:sw=4 /*!@{*/
/*! \brief Brickwall low-pass linear phase: sinc filter.
\param npoints Number of points required (1).
\param corner Corner frequency as fraction of sample rate.
\param gain Gain of filter.
\returns Newly-allocated %FIR filter.
Builds a truncated-sinc filter which has a low-pass, brickwall effect (cutoff
at \a corner, which is a fraction of sampling rate, i.e. 0 &lt; \a corner &lt;
0.5).
The number of points \a npoints is a trade-off between accuracy of filter (an
ideal sinc filter would have an infinite number of points) and computation time.
\a npoints may be odd or even; symmetry will be exploited in either case.
The DC gain of the filter is normalised to \a gain, which is often 1.0.
*/
struct fir_filter_t* fir_sinc_lowpass(int npoints, double corner, double gain);
/*!@}*/
/* options for text editors
vim: expandtab:ts=4:sw=4:syntax=ch.doxygen
*/ */