问题
I'm trying to have the same FFT with FFTW and Matlab. I use MEX files to check if FFTW is good. I think I have everything correct but :
- I get absurd values from FFTW,
- I do not get the same results when running the FFTW code several times on the same input signal.
Can someone help me get FFTW right?
--
EDIT 1 : I finally figured out what was wrong, BUT... FFTW is very unstable : I get the right spectrum 1 time out of 5 ! How come? Plus, when I get it right, it doesn't have symmetry (which is not a very serious problem but that's too bad).
--
Here is the Matlab code to compare both :
fs = 2000; % sampling rate
T = 1/fs; % sampling period
t = (0:T:0.1); % time vector
f1 = 50; % frequency in Hertz
omega1 = 2*pi*f1; % angular frequency in radians
phi = 2*pi*0.25; % arbitrary phase offset = 3/4 cycle
x1 = cos(omega1*t + phi); % sinusoidal signal, amplitude = 1
%%
mex -I/usr/local/include -L/usr/local/lib/ -lfftw3 mexfftw.cpp
N=256;
S1=mexfftw(x1,N);
S2=fft(x1,N);
plot(abs(S1)),hold,plot(abs(S2),'r'), legend('FFTW','Matlab')
Here is the MEX file :
/*********************************************************************
* mex -I/usr/local/include -L/usr/local/lib/ -lfftw3 mexfftw.cpp
* Use above to compile !
*
********************************************************************/
#include <matrix.h>
#include <mex.h>
#include "fftw3.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
//declare variables
mxArray *sig_v, *fft_v;
int nfft;
const mwSize *dims;
double *s, *fr, *fi;
int dimx, dimy, numdims;
//associate inputs
sig_v = mxDuplicateArray(prhs[0]);
nfft = static_cast<int>(mxGetScalar(prhs[1]));
//figure out dimensions
dims = mxGetDimensions(prhs[0]);
numdims = mxGetNumberOfDimensions(prhs[0]);
dimy = (int)dims[0]; dimx = (int)dims[1];
//associate outputs
fft_v = plhs[0] = mxCreateDoubleMatrix(nfft, 1, mxCOMPLEX);
//associate pointers
s = mxGetPr(sig_v);
fr = mxGetPr(fft_v);
fi = mxGetPi(fft_v);
//do something
double *in;
fftw_complex *out;
fftw_plan p;
in = (double*) fftw_malloc(sizeof(double) * dimy);
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * nfft);
p = fftw_plan_dft_r2c_1d(nfft, s, out, FFTW_ESTIMATE);
fftw_execute(p); /* repeat as needed */
for (int i=0; i<nfft; i++) {
fr[i] = out[i][0];
fi[i] = out[i][1];
}
fftw_destroy_plan(p);
fftw_free(in);
fftw_free(out);
return;
}
回答1:
Matlab uses the fftw library to perform its ffts, on my platform (Mac OS) this leads to issues with the linker as mex replaces the desired library with Matlab's version of fftw. To avoid this static link to the library using mex "-I/usr/local/include /usr/local/lib/libfftw3.a mexfftw.cpp". The input of fftw_plan_dft_r2c_1d is not destroyed so you don't need to duplicate the input (note: not true for fftw_plan_dft_c2r_1d). The output has size nfft/2+1 as the output of a real fft is Hermitian. So to get the full output use:
for (i=0; i<nfft/2+1; i++) {
fr[i] = out[i][0];
fi[i] = out[i][1];
}
for (i=1; i<nfft/2+1; i++) {
fr[nfft-i] = out[i][0];
fi[nfft-i] = out[i][1];
}
回答2:
Should "p = fftw_plan_dft_r2c_1d(nfft, s, out, FFTW_ESTIMATE);"
be "p = fftw_plan_dft_r2c_1d(nfft, in, out, FFTW_ESTIMATE);".
'in' is 16-byte aligned, but 's' may not.
I am not sure whether it will cause a problem. I have a similar code about FFTW, it sometimes gives me correct result and other times NaN. Also, I tried to test my code with python ctypes, and actually it has the same weired behavior.
Finally, I found this post Checking fftw3 with valgrind, and it helps me. For me, the issue is the reservation of heap storage in FFTW which are not freed even after the program terminates.
fftw_cleanup()
resolves my problem. Maybe it can help you too.
来源:https://stackoverflow.com/questions/16946856/matlab-fft-and-fftw