This commit is contained in:
Laurence Withers 2014-07-09 16:52:38 +00:00
parent 679b37dc35
commit d42f63388e
6 changed files with 251 additions and 1 deletions

View File

@ -8,6 +8,10 @@
#include "fir.h"
/* Below are all the includes used throughout the library. */
#include <alloca.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
/* options for text editors
vim: expandtab:ts=4:sw=4

156
src/libfir/100_fir.c Normal file
View File

@ -0,0 +1,156 @@
/* libfir/src/libfir/100_fir.c
*
* Copyright: ©2014, Laurence Withers.
* Author: Laurence Withers <l@lwithers.me.uk>
* License: GPLv3
*/
struct fir_symm_store {
double* d;
int pos, size;
};
struct fir_filter_t {
double* coeff;
int ncoeff;
int primed;
double* x;
int xpos;
enum fir_symmetry symm;
int nsymm;
struct fir_symm_store* symm_store;
};
static void
symm_setup(struct fir_filter_t* fi, int delay)
{
int i;
fi->symm_store = malloc(sizeof(struct fir_symm_store) * fi->nsymm);
for(i = 0; i < fi->nsymm; ++i) {
fi->symm_store[i].d = malloc(sizeof(double) * delay);
fi->symm_store[i].pos = 0;
fi->symm_store[i].size = delay;
delay -= 2;
}
}
struct fir_filter_t*
fir_filter_new(const double* coeff, int ncoeff, enum fir_symmetry symm)
{
struct fir_filter_t* fi = malloc(sizeof(*fi));
fi->coeff = malloc(sizeof(double) * ncoeff);
memcpy(fi->coeff, coeff, sizeof(double) * ncoeff);
fi->ncoeff = ncoeff;
fi->primed = 0;
fi->x = malloc(sizeof(double) * ncoeff);
fi->xpos = 0;
fi->symm = symm;
switch(symm) {
case fir_symmetry_none:
fi->nsymm = 0;
fi->symm_store = 0;
break;
case fir_symmetry_odd:
fi->nsymm = ncoeff - 1;
symm_setup(fi, 2 * ncoeff - 1);
break;
case fir_symmetry_even:
fi->nsymm = ncoeff;
symm_setup(fi, 2 * ncoeff);
break;
}
return fi;
}
void
fir_filter_free(struct fir_filter_t* fi)
{
int i;
if(!fi) return;
for(i = 0; i < fi->nsymm; ++i) free(fi->symm_store[i].d);
free(fi->symm_store);
free(fi->x);
free(fi->coeff);
free(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);
return out;
}
double
fir_filter(struct fir_filter_t* fi, double x)
{
int i, xpos, spos;
double p, y = 0;
if(!fi->primed) {
fi->primed = 1;
for(i = 0; i < fi->ncoeff; ++i) fi->x[i] = x;
for(i = 0; i < fi->nsymm; ++i) {
for(spos = 0; spos < fi->symm_store[i].size; ++spos) {
fi->symm_store[i].d[spos] = x * fi->coeff[i];
}
}
}
xpos = fi->xpos;
fi->x[xpos] = x;
for(i = 0; i < fi->ncoeff; ++i) {
p = fi->x[xpos] * fi->coeff[i];
y += p;
if(!xpos--) xpos += fi->ncoeff;
if(i < fi->nsymm) {
spos = fi->symm_store[i].pos;
fi->symm_store[i].d[spos] = p;
if(++spos == fi->symm_store[i].size) spos = 0;
fi->symm_store[i].pos = spos;
}
}
if(++fi->xpos == fi->ncoeff) fi->xpos = 0;
for(i = 0; i < fi->nsymm; ++i) {
spos = fi->symm_store[i].pos;
y += fi->symm_store[i].d[spos];
}
return y;
}
/* options for text editors
vim: expandtab:ts=4:sw=4
*/

35
src/libfir/100_fir.h Normal file
View File

@ -0,0 +1,35 @@
/* libfir/src/libfir/100_fir.h
*
* Copyright: ©2014, Laurence Withers.
* Author: Laurence Withers <l@lwithers.me.uk>
* License: GPLv3
*/
struct fir_filter_t;
enum fir_symmetry {
fir_symmetry_none,
fir_symmetry_odd,
fir_symmetry_even,
};
struct fir_filter_t* fir_filter_new(const double* coeff, int ncoeff,
enum fir_symmetry symm);
void fir_filter_free(struct fir_filter_t* fi);
struct fir_filter_t* fir_filter_clone(const struct fir_filter_t* fi);
double fir_filter(struct fir_filter_t* fi, double x);
/* options for text editors
vim: expandtab:ts=4:sw=4
*/

View File

@ -0,0 +1,39 @@
/* libfir/src/libfir/200_common_filters.c
*
* Copyright: ©2014, Laurence Withers.
* Author: Laurence Withers <l@lwithers.me.uk>
* License: GPLv3
*/
struct fir_filter_t*
fir_sinc_lowpass(int npoints, double corner)
{
double* coeff, t;
int i, spoints;
/* find number of points after taking symmetry into account */
spoints = (npoints + 1) / 2;
coeff = alloca(sizeof(double) * spoints);
/* only fill out for t ≤ 0 */
for(i = 0; i < spoints; ++i) {
if((i * 2 + 1) == npoints) {
coeff[i] = 1;
} else {
t = i + 0.5 - npoints * 0.5;
t *= corner * 2;
coeff[i] = sin(t) / t;
}
}
return fir_filter_new(coeff, spoints,
(npoints & 1) ? fir_symmetry_odd : fir_symmetry_even);
}
/* options for text editors
vim: expandtab:ts=4:sw=4
*/

View File

@ -0,0 +1,16 @@
/* libfir/src/libfir/200_common_filters.h
*
* Copyright: ©2014, Laurence Withers.
* Author: Laurence Withers <l@lwithers.me.uk>
* License: GPLv3
*/
struct fir_filter_t* fir_sinc_lowpass(int npoints, double corner);
/* options for text editors
vim: expandtab:ts=4:sw=4
*/

View File

@ -14,7 +14,7 @@ then
libfir="obj/${libfir_BASE}.so.${SOMAJOR}.${SOMICRO}"
libfir_DEP_CFLAGS="" # @TODO@ cflags
libfir_DEP_LIBS="" # @TODO@ libs
SO_EXTRA="${libfir_DEP_CFLAGS} ${libfir_DEP_LIBS} -lc \
SO_EXTRA="${libfir_DEP_CFLAGS} ${libfir_DEP_LIBS} -lc -lm \
-D_GNU_SOURCE -std=gnu99"
echo "Building library ${libfir}..."