Added inverse FFT code.

This commit is contained in:
Anne de Jong 2018-02-17 17:01:53 +01:00 committed by Anne de Jong
parent d008110c09
commit 008876dbab
4 changed files with 121 additions and 9 deletions

View File

@ -50,6 +50,69 @@ void Fft_free(Fft* fft) {
feTRACE(15); feTRACE(15);
} }
us Fft_nfft(const Fft* fft) {return fft->nfft;} us Fft_nfft(const Fft* fft) {return fft->nfft;}
void Fft_ifft_single(const Fft* fft,const vc* freqdata,vd* result) {
fsTRACE(15);
dbgassert(fft && freqdata && result,NULLPTRDEREF);
const us nfft = fft->nfft;
dbgassert(result->size == nfft,
"Invalid size for time data rows."
" Should be equal to nfft");
dbgassert(freqdata->size == (nfft/2+1),"Invalid number of rows in"
" result array");
/* Obtain fft_result */
vd fft_result = fft->fft_result;
/* Copy freqdata, to fft_result. */
d* fft_result_ptr = getvdval(&fft_result,0);
*fft_result_ptr = c_real(*getvcval(freqdata,0));
d_copy(&fft_result_ptr[1],
(d*) getvcval(freqdata,1),
nfft-1);
/* Perform backward transform */
npy_rfftb(nfft,
fft_result_ptr,
getvdval(&fft->fft_work,0));
/* Scale by dividing by nfft. Checked with numpy implementation
* that this indeed needs to be done. */
d_scale(fft_result_ptr,1/((d) nfft),nfft);
vd_copy(result,
&fft_result);
feTRACE(15);
}
void Fft_ifft(const Fft* fft,const cmat* freqdata,dmat* timedata) {
fsTRACE(15);
dbgassert(fft && timedata && freqdata,NULLPTRDEREF);
const us nchannels = timedata->n_cols;
dbgassert(timedata->n_cols == freqdata->n_cols,
"Number of columns in timedata and result"
" should be equal.");
for(us col=0;col<nchannels;col++) {
vd timedata_col = dmat_column(timedata,col);
vc freqdata_col = cmat_column((cmat*)freqdata,col);
Fft_ifft_single(fft,&freqdata_col,&timedata_col);
vd_free(&timedata_col);
vc_free(&freqdata_col);
}
check_overflow_xmat(*timedata);
check_overflow_xmat(*freqdata);
feTRACE(15);
}
void Fft_fft_single(const Fft* fft,const vd* timedata,vc* result) { void Fft_fft_single(const Fft* fft,const vd* timedata,vc* result) {
fsTRACE(15); fsTRACE(15);
@ -78,15 +141,19 @@ void Fft_fft_single(const Fft* fft,const vd* timedata,vc* result) {
* at 2 etc. This needs to be shifted properly in the * at 2 etc. This needs to be shifted properly in the
* resulting matrix, as for the complex data, the imaginary * resulting matrix, as for the complex data, the imaginary
* part of the DC component equals zero. */ * part of the DC component equals zero. */
*getvcval(result,0) = *getvdval(&fft_result,0); *getvcval(result,0) = *getvdval(&fft_result,0);
/* For an even fft, the imaginary part of the Nyquist frequency
* bin equals zero.*/
if(likely(nfft%2 == 0)) {
((d*) getvcval(result,nfft/2))[1] = 0;
}
memcpy((void*) getvcval(result,1), memcpy((void*) getvcval(result,1),
(void*) getvdval(&fft_result,1), (void*) getvdval(&fft_result,1),
(nfft-1)*sizeof(d)); (nfft-1)*sizeof(d));
/* Set imaginary part of Nyquist frequency to zero */ /* Set imaginary part of Nyquist frequency to zero */
((d*) getvcval(result,nfft/2))[1] = 0;
check_overflow_vx(fft_result); check_overflow_vx(fft_result);
check_overflow_vx(fft->fft_work); check_overflow_vx(fft->fft_work);

View File

@ -57,19 +57,28 @@ void Fft_fft_single(const Fft* fft,const vd* timedata,vc* result);
*/ */
void Fft_fft(const Fft* fft,const dmat* timedata,cmat* result); void Fft_fft(const Fft* fft,const dmat* timedata,cmat* result);
/**
* Perform inverse fft on a single channel.
*
* @param[in] fft Fft handle.
* @param[in] freqdata Frequency domain input data, to be iFft'th.
* @param[out] result: iFft't data, should have size (nfft).
*/
void Fft_ifft_single(const Fft* fft,const vc* freqdata,vd* result);
/** /**
* Perform inverse FFT * Perform inverse FFT
* *
* @param[in] fft Fft handle * @param[in] fft Fft handle
* @param[in] freqdata Frequency domain data * @param[in] freqdata Frequency domain data
* @param[out] timedata * @param[out] timedata Time domain result
*/ */
void Fft_ifft(const Fft* fft,const cmat* freqdata,dmat* timedata); void Fft_ifft(const Fft* fft,const cmat* freqdata,dmat* timedata);
/** /**
* * Free up resources of Fft handle.
* *
* @param fft * @param fft Fft handle.
*/ */
void Fft_free(Fft* fft); void Fft_free(Fft* fft);

View File

@ -20,6 +20,7 @@ cdef extern from "fft.h":
c_Fft* Fft_alloc(us nfft) c_Fft* Fft_alloc(us nfft)
void Fft_free(c_Fft*) void Fft_free(c_Fft*)
void Fft_fft(c_Fft*,dmat * timedate,cmat * res) nogil void Fft_fft(c_Fft*,dmat * timedate,cmat * res) nogil
void Fft_ifft(c_Fft*,cmat * freqdata,dmat* timedata) nogil
us Fft_nfft(c_Fft*) us Fft_nfft(c_Fft*)
@ -64,6 +65,36 @@ cdef class Fft:
return result return result
def ifft(self,c[::1,:] freqdata):
cdef us nfft = Fft_nfft(self._fft)
cdef us nchannels = freqdata.shape[1]
assert freqdata.shape[0] == nfft//2+1
# result[:,:] = np.nan+1j*np.nan
cdef cmat f = cmat_foreign(freqdata.shape[0],
freqdata.shape[1],
&freqdata[0,0])
timedata = np.empty((nfft,nchannels),
dtype=NUMPY_FLOAT_TYPE,
order='F')
cdef d[::1,:] timedata_view = timedata
cdef dmat t = dmat_foreign(timedata.shape[0],
timedata.shape[1],
&timedata_view[0,0])
Fft_ifft(self._fft,&f,&t)
dmat_free(&t)
cmat_free(&f)
return timedata
cdef extern from "window.h": cdef extern from "window.h":
ctypedef enum WindowType: ctypedef enum WindowType:

View File

@ -8,14 +8,16 @@ Created on Mon Jan 15 19:45:33 2018
import numpy as np import numpy as np
from beamforming import Fft from beamforming import Fft
nfft=6 nfft=9
print('nfft:',nfft) print('nfft:',nfft)
print(nfft) print(nfft)
nchannels = 1 nchannels = 4
t = np.linspace(0,1,nfft+1)[:-1] t = np.linspace(0,1,nfft+1)[:-1]
# print(t) # print(t)
x1 = 1+np.sin(2*np.pi*t)+3.2*np.cos(2*np.pi*t)+np.sin(7*np.pi*t) #x1 = 1+np.sin(2*np.pi*t)+3.2*np.cos(2*np.pi*t)+np.sin(7*np.pi*t)
#x1 = np.sin(2*np.pi*t)
x1 = 1+0*t
x = np.vstack([x1.T]*nchannels).T x = np.vstack([x1.T]*nchannels).T
# Using transpose to get the strides right # Using transpose to get the strides right
x = np.random.randn(nchannels,nfft).T x = np.random.randn(nchannels,nfft).T
@ -28,6 +30,9 @@ print(X)
fft = Fft(nfft) fft = Fft(nfft)
Y = fft.fft(x) Y = fft.fft(x)
print('Fftpack fft') print('Beamforming fft')
print(Y) print(Y)
x2 = fft.ifft(Y)
print('normdiff:',np.linalg.norm(x2-x))
print('end python script') print('end python script')