WIP
This commit is contained in:
parent
d42f63388e
commit
caffec76a4
1
config
1
config
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
*/
|
|
@ -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
|
||||||
|
*/
|
|
@ -5,6 +5,8 @@
|
||||||
* License: GPLv3
|
* License: GPLv3
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
} // end namespace FIR
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* options for text editors
|
/* options for text editors
|
||||||
|
|
|
@ -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
|
|
@ -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}..."
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 < \a corner <
|
||||||
|
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
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue