Added inverse FFT code.
This commit is contained in:
parent
d008110c09
commit
008876dbab
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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')
|
||||||
|
Loading…
Reference in New Issue
Block a user