Browse Source

cmath4.c, use FFTW3 for cx_fft() and cx_ifft()

pre-master-46
dwarning 13 years ago
committed by rlar
parent
commit
51c7f17186
  1. 4
      configure.ac
  2. 330
      src/maths/cmaths/cmath4.c

4
configure.ac

@ -715,6 +715,10 @@ AC_MSG_RESULT([Checking mathematical features of the system:])
# Look for math library:
AC_CHECK_LIB([m], [sqrt])
AC_CHECK_HEADERS([float.h limits.h values.h ieeefp.h])
AC_CHECK_HEADERS([fftw3.h])
AC_CHECK_LIB([fftw3], [fftw_plan_dft_1d],
[AC_DEFINE([HAVE_LIBFFTW3], [], [Have fft routines in libfftw3])
LIBS="$LIBS -lfftw3"])
# Check for a few mathematical functions:
AC_CHECK_FUNCS([erfc logb scalb scalbn asinh acosh atanh finite])

330
src/maths/cmaths/cmath4.c

@ -35,6 +35,9 @@ extern bool cx_degrees;
extern void vec_new(struct dvec *d);
bool doubledouble(double *, int, double *);
#ifdef HAVE_LIBFFTW3
#include "fftw3.h"
#endif
void *
@ -507,15 +510,25 @@ cx_group_delay(void *data, short int type, int length, int *newlength, short int
void *
cx_fft(void *data, short int type, int length, int *newlength, short int *newtype, struct plot *pl, struct plot *newpl, int grouping)
{
int i, N, M, fpts, order;
int i, fpts, order;
double span, scale, maxt;
double *indata, *xscale;
double *time = NULL, *xtime = NULL, *win = NULL;
ngcomplex_t *outdata;
double *reald = NULL;
double *xscale;
double *time = NULL, *win = NULL;
ngcomplex_t *outdata = NULL;
struct dvec *sv;
char window[BSIZE_SP];
#ifdef HAVE_LIBFFTW3
fftw_complex *inc;
double *ind;
fftw_complex *out = NULL;
fftw_plan plan_forward = NULL;
#else
int N, M;
double *datax = NULL;
double *realdata;
#endif
if (grouping == 0)
grouping = length;
@ -529,80 +542,79 @@ cx_fft(void *data, short int type, int length, int *newlength, short int *newtyp
return (NULL);
}
#ifdef HAVE_LIBFFTW3
if (type == VF_COMPLEX)
fpts = length;
else
fpts = length/2 + 1;
#else
/* size of fft input vector is power of two and larger or equal than spice vector */
N = 1;
M = 0;
while (N < 2*length) {
while (N < length) {
N <<= 1;
M++;
}
/* output vector has length of N/2 */
if (type == VF_COMPLEX)
fpts = N;
else
fpts = N/2;
#endif
*newlength = fpts;
*newtype = VF_COMPLEX;
indata = (double *) data;
outdata = alloc_c(fpts);
time = alloc_d(length);
xscale = TMALLOC(double, fpts);
xscale = TMALLOC(double, length);
if (pl->pl_scale->v_type == SV_TIME) { /* calculate the frequency from time */
span = pl->pl_scale->v_realdata[length-1] - pl->pl_scale->v_realdata[0];
for (i = 0; i<fpts; i++)
xscale[i] = i*1.0/span*(2*length)/N;
for (i = 0; i<length; i++)
#ifdef HAVE_LIBFFTW3
xscale[i] = i*1.0/span;
#else
xscale[i] = i*1.0/span*length/N;
#endif
for (i = 0; i<pl->pl_scale->v_length; i++)
time[i] = pl->pl_scale->v_realdata[i];
} else if (pl->pl_scale->v_type == SV_FREQUENCY) { /* take frequency from ac data and calculate time */
/* Deal with complex frequency vector */
if (pl->pl_scale->v_type == VF_COMPLEX) {
span = realpart(pl->pl_scale->v_compdata[fpts-1]) - realpart(pl->pl_scale->v_compdata[0]);
for (i = 0; i<fpts; i++)
span = realpart(pl->pl_scale->v_compdata[pl->pl_scale->v_length-1]) - realpart(pl->pl_scale->v_compdata[0]);
for (i = 0; i<pl->pl_scale->v_length; i++)
xscale[i] = realpart(pl->pl_scale->v_compdata[i]);
} else {
span = pl->pl_scale->v_realdata[fpts-1] - pl->pl_scale->v_realdata[0];
for (i = 0; i<fpts; i++)
span = pl->pl_scale->v_realdata[pl->pl_scale->v_length-1] - pl->pl_scale->v_realdata[0];
for (i = 0; i<pl->pl_scale->v_length; i++)
xscale[i] = pl->pl_scale->v_realdata[i];
}
for (i = 0; i < length; i++)
time[i] = i*1.0/span*(2*length)/N;
#ifdef HAVE_LIBFFTW3
time[i] = i*1.0/span;
#else
time[i] = i*1.0/span*length/N;
#endif
span = time[length-1] - time[0];
} else {
span = length;
} else { /* there is no usable plot vector - using simple bins */
for (i = 0; i < fpts; i++)
xscale[i] = i;
for (i = 0; i < length; i++)
time[i] = i*1.0/span;
time[i] = i;
span = time[length-1] - time[0];
}
reald = TMALLOC(double, N);
xtime = TMALLOC(double, 2*length);
/* Now interpolate the data... */
if (!doubledouble(indata, length, reald)) {
fprintf(cp_err, "Error: can't interpolate\n");
goto done;
}
if (!doubledouble(time, length, xtime)) {
fprintf(cp_err, "Error: can't interpolate\n");
goto done;
}
win = TMALLOC(double, 2*length);
win = TMALLOC(double, length);
maxt = time[length-1];
if (!cp_getvar("specwindow", CP_STRING, window))
strcpy(window, "none");
@ -611,7 +623,7 @@ cx_fft(void *data, short int type, int length, int *newlength, short int *newtyp
if (order < 2)
order = 2;
if (fft_windows(window, win, xtime, 2*length, maxt, span, order) == 0)
if (fft_windows(window, win, time, length, maxt, span, order) == 0)
goto done;
/* create a new scale vector */
@ -624,28 +636,138 @@ cx_fft(void *data, short int type, int length, int *newlength, short int *newtyp
sv->v_realdata = xscale;
vec_new(sv);
printf("FFT: Time span: %g s, input length: %d, zero padding: %d\n", span, length, N/2-length);
printf("FFT: Frequency resolution: %g Hz, output length: %d\n", 1.0/span*(2*length)/N, fpts);
if (type == VF_COMPLEX) { /* input vector is complex */
ngcomplex_t *indata = (ngcomplex_t *) data;
#ifdef HAVE_LIBFFTW3
printf("FFT: Time span: %g s, input length: %d\n", span, length);
printf("FFT: Frequency resolution: %g Hz, output length: %d\n", 1.0/span, fpts);
inc = fftw_malloc(sizeof(fftw_complex) * (unsigned int) length);
out = fftw_malloc(sizeof(fftw_complex) * (unsigned int) fpts);
for (i = 0; i < length; i++) {
inc[i][0] = indata[i].cx_real * win[i];
inc[i][1] = indata[i].cx_imag * win[i];
}
plan_forward = fftw_plan_dft_1d(fpts, inc, out, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(plan_forward);
*newlength = fpts;
outdata = alloc_c(fpts);
for (i = 0; i < 2*length; i++)
reald[i] = reald[i] * win[i];
for (i = 2*length; i < N; i++)
reald[i] = 0.0;
scale = (double) fpts;
for (i = 0; i < fpts; i++) {
outdata[i].cx_real = out[i][0]/scale;
outdata[i].cx_imag = out[i][1]/scale;
}
fftw_free(inc);
#else /* Green's FFT */
printf("FFT: Time span: %g s, input length: %d, zero padding: %d\n", span, length, N-length);
printf("FFT: Frequency resolution: %g Hz, output length: %d\n", 1.0/span, N);
datax = TMALLOC(double, 2*N);
for (i = 0; i < length; i++) {
datax[2*i] = indata[i].cx_real * win[i];
datax[2*i+1] = indata[i].cx_imag * win[i];
}
for (i = length; i < N; i++) {
datax[2*i] = 0.0;
datax[2*i+1] = 0.0;
}
fftInit(M);
rffts(reald, M, 1);
ffts(datax, M, 1);
fftFree();
scale = N;
/* Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]). */
*newlength = N;
outdata = alloc_c(N);
scale = (double) N;
for (i = 0; i < N; i++) {
outdata[i].cx_real = datax[2*i]/scale;
outdata[i].cx_imag = datax[2*i+1]/scale;
}
#endif
} else { /* input vector is real */
double *indata = (double *) data;
#ifdef HAVE_LIBFFTW3
printf("FFT: Time span: %g s, input length: %d\n", span, length);
printf("FFT: Frequency resolution: %g Hz, output length: %d\n", 1.0/span, fpts);
ind = fftw_malloc(sizeof(double) * (unsigned int) length);
out = fftw_malloc(sizeof(fftw_complex) * (unsigned int) fpts);
for (i = 0; i < length; i++)
ind[i] = indata[i] * win[i];
plan_forward = fftw_plan_dft_r2c_1d(length, ind, out, FFTW_ESTIMATE);
fftw_execute(plan_forward);
*newlength = fpts;
outdata = alloc_c(fpts);
scale = (double) length;
for (i = 0; i < fpts; i++) {
outdata[i].cx_real = reald[2*i]/scale;
outdata[i].cx_imag = reald[2*i+1]/scale;
outdata[i].cx_real = out[i][0]/scale;
outdata[i].cx_imag = out[i][1]/scale;
}
fftw_free(ind);
#else /* Green's FFT */
printf("FFT: Time span: %g s, input length: %d, zero padding: %d\n", span, length, N-length);
printf("FFT: Frequency resolution: %g Hz, output length: %d\n", 1.0/span, N/2);
realdata = (double *) data;
datax = TMALLOC(double, N);
for (i = 0; i < length; i++)
datax[i] = realdata[i] * win[i];
for (i = length; i < N; i++)
datax[i] = 0.0;
fftInit(M);
rffts(datax, M, 1);
fftFree();
*newlength = N/2;
outdata = alloc_c(N/2);
scale = (double) N;
/* Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]). */
for (i = 0; i < N/2; i++) {
outdata[i].cx_real = datax[2*i]/scale;
outdata[i].cx_imag = datax[2*i+1]/scale;
}
#endif
}
done:
tfree(reald);
tfree(xtime);
#ifdef HAVE_LIBFFTW3
fftw_free(out);
fftw_destroy_plan(plan_forward);
#else
tfree(datax);
#endif
tfree(time);
tfree(win);
@ -657,13 +779,20 @@ void *
cx_ifft(void *data, short int type, int length, int *newlength, short int *newtype, struct plot *pl, struct plot *newpl, int grouping)
{
ngcomplex_t *indata = (ngcomplex_t *) data;
int i, N, M, tpts, order;
double span, scale, maxt;
double *xscale, *win = NULL;
double *outdata;
double *reald = NULL;
int i, tpts;
double span, scale;
double *xscale;
ngcomplex_t *outdata = NULL;
struct dvec *sv;
char window[BSIZE_SP];
#ifdef HAVE_LIBFFTW3
fftw_complex *in;
fftw_complex *out = NULL;
fftw_plan plan_backward = NULL;
#else
int N, M;
double *datax = NULL;
#endif
if (grouping == 0)
grouping = length;
@ -678,6 +807,9 @@ cx_ifft(void *data, short int type, int length, int *newlength, short int *newty
return (NULL);
}
#ifdef HAVE_LIBFFTW3
tpts = length;
#else
/* size of ifft input vector is power of two and larger or equal than spice vector */
N = 1;
M = 0;
@ -685,6 +817,8 @@ cx_ifft(void *data, short int type, int length, int *newlength, short int *newty
N <<= 1;
M++;
}
tpts = N;
#endif
if (pl->pl_scale->v_type == SV_TIME) { /* take the time from transient */
@ -710,7 +844,11 @@ cx_ifft(void *data, short int type, int length, int *newlength, short int *newty
span = pl->pl_scale->v_realdata[tpts-1] - pl->pl_scale->v_realdata[0];
for (i = 0; i<tpts; i++)
#ifdef HAVE_LIBFFTW3
xscale[i] = i*1.0/span;
#else
xscale[i] = i*1.0/span*length/N;
#endif
} else {
@ -726,11 +864,6 @@ cx_ifft(void *data, short int type, int length, int *newlength, short int *newty
span = xscale[tpts-1] - xscale[0];
*newlength = tpts;
*newtype = VF_REAL;
outdata = alloc_d(tpts);
/* create a new scale vector */
sv = alloc(struct dvec);
ZERO(sv, struct dvec);
@ -741,43 +874,70 @@ cx_ifft(void *data, short int type, int length, int *newlength, short int *newty
sv->v_realdata = xscale;
vec_new(sv);
win = TMALLOC(double, tpts);
maxt = xscale[tpts-1];
if (!cp_getvar("specwindow", CP_STRING, window))
strcpy(window, "none");
if (!cp_getvar("specwindoworder", CP_NUM, &order))
order = 2;
if (order < 2)
order = 2;
#ifdef HAVE_LIBFFTW3
if (fft_windows(window, win, xscale, tpts, maxt, span, order) == 0)
goto done;
printf("IFFT: Frequency span: %g Hz, input length: %d\n", 1/span*length, length);
printf("IFFT: Time resolution: %g s, output length: %d\n", span/(tpts-1), tpts);
in = fftw_malloc(sizeof(fftw_complex) * (unsigned int) length);
out = fftw_malloc(sizeof(fftw_complex) * (unsigned int) tpts);
printf("IFFT: Frequency span: %g Hz, input length: %d\n", 1/span*tpts/N*(length-1), length);
for (i = 0; i < length; i++) {
in[i][0] = indata[i].cx_real;
in[i][1] = indata[i].cx_imag;
}
plan_backward = fftw_plan_dft_1d(tpts, in, out, FFTW_BACKWARD, FFTW_ESTIMATE);
fftw_execute(plan_backward);
*newtype = VF_COMPLEX;
*newlength = tpts;
outdata = alloc_c(tpts);
scale = (double) tpts;
for (i = 0; i < tpts; i++) {
outdata[i].cx_real = out[i][0] * scale;
outdata[i].cx_imag = out[i][1] * scale;
}
fftw_free(in);
fftw_destroy_plan(plan_backward);
fftw_free(out);
#else /* Green's IFFT */
printf("IFFT: Frequency span: %g Hz, input length: %d, zero padding: %d\n", 1/span*length, length, N-length);
printf("IFFT: Time resolution: %g s, output length: %d\n", span/(tpts-1), tpts);
reald = TMALLOC(double, 2*N);
/* Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]). */
datax = TMALLOC(double, 2*N);
for (i = 0; i < length; i++) {
reald[2*i] = indata[i].cx_real;
reald[2*i+1] = indata[i].cx_imag;
datax[2*i] = indata[i].cx_real;
datax[2*i+1] = indata[i].cx_imag;
}
for (i = length; i < N; i++) {
reald[2*i] = 0.0;
reald[2*i+1] = 0.0;
datax[2*i] = 0.0;
datax[2*i+1] = 0.0;
}
fftInit(M);
riffts(reald, M, 1);
iffts(datax, M, 1);
fftFree();
scale = length;
for (i = 0; i < tpts; i++)
outdata[i] = reald[i] * scale/MAX(1e-03, win[i]); /* makes dewindowing sense? */
*newtype = VF_COMPLEX;
*newlength = N;
outdata = alloc_c(N);
done:
tfree(reald);
tfree(win);
scale = (double) N;
for (i = 0; i < N; i++) {
outdata[i].cx_real = datax[2*i] * scale;
outdata[i].cx_imag = datax[2*i+1] * scale;
}
tfree(datax);
#endif
return ((void *) outdata);
}

Loading…
Cancel
Save