Changed Fft API to also be able to compute for one channel

This commit is contained in:
Anne de Jong 2018-02-10 21:14:17 +01:00 committed by Anne de Jong
parent 63b45d8dfe
commit 85636ce946
8 changed files with 113 additions and 92 deletions

View File

@ -164,7 +164,7 @@ cmat* AvPowerSpectra_addTimeData(AvPowerSpectra* aps,
const us oo = aps->oo;
us* os = &aps->os;
iVARTRACE(15,*os);
us os_timedata = 0;
dmat buffer = aps->buffer;

View File

@ -483,7 +483,7 @@ static inline cmat cmat_submat(cmat* parent,
* @param to : Vector to write to
* @param from : Vector to read from
*/
static inline void vd_copy(vd* to,vd* from) {
static inline void vd_copy(vd* to,const vd* from) {
dbgassert(to && from,NULLPTRDEREF);
dbgassert(to->size==from->size,SIZEINEQUAL);
d_copy(to->ptr,from->ptr,to->size);
@ -494,7 +494,7 @@ static inline void vd_copy(vd* to,vd* from) {
* @param to : Vector to write to
* @param from : Vector to read from
*/
static inline void vc_copy(vc* to,vc* from) {
static inline void vc_copy(vc* to,const vc* from) {
dbgassert(to && from,NULLPTRDEREF);
dbgassert(to->size==from->size,SIZEINEQUAL);
c_copy(to->ptr,from->ptr,to->size);

View File

@ -13,19 +13,12 @@
typedef struct Fft_s {
us nfft;
us nchannels;
vd fft_work;
} Fft;
Fft* Fft_alloc(const us nfft,const us nchannels) {
Fft* Fft_alloc(const us nfft) {
fsTRACE(15);
if(nchannels > ASCEE_MAX_NUM_CHANNELS) {
WARN("Too high number of channels! Please increase the "
"ASCEE_MAX_NUM_CHANNELS compilation flag");
return NULL;
}
Fft* fft = a_malloc(sizeof(Fft));
if(fft==NULL) {
WARN("Fft allocation failed");
@ -33,7 +26,6 @@ Fft* Fft_alloc(const us nfft,const us nchannels) {
}
fft->nfft = nfft;
fft->nchannels = nchannels;
/* Initialize foreign fft lib */
fft->fft_work = vd_alloc(2*nfft+15);
@ -52,55 +44,73 @@ void Fft_free(Fft* fft) {
a_free(fft);
feTRACE(15);
}
us Fft_nchannels(const Fft* fft) {return fft->nchannels;}
us Fft_nfft(const Fft* fft) {return fft->nfft;}
void Fft_fft_single(const Fft* fft,const vd* timedata,vc* result) {
fsTRACE(15);
dbgassert(fft && timedata && result,NULLPTRDEREF);
const us nfft = fft->nfft;
dbgassert(timedata->size == nfft,
"Invalid size for time data rows."
" Should be equal to nfft");
dbgassert(result->size == (nfft/2+1),"Invalid number of rows in"
" result array");
vd fft_result = vd_alloc(nfft);
vd_copy(&fft_result,timedata);
/* Perform fft */
npy_rfftf(nfft,fft_result.ptr,fft->fft_work.ptr);
/* Fftpack stores the data a bit strange, the resulting array
* has the DC value at 0,the first cosine at 1, the first sine
* at 2 etc. This needs to be shifted properly in the
* resulting matrix, as for the complex data, the imaginary
* part of the DC component equals zero. */
*getvcval(result,0) = *getvdval(&fft_result,0);
memcpy((void*) getvcval(result,1),
(void*) getvdval(&fft_result,1),
(nfft-1)*sizeof(d));
/* Set imaginary part of Nyquist frequency to zero */
((d*) getvcval(result,nfft/2))[1] = 0;
check_overflow_vx(fft_result);
check_overflow_vx(fft->fft_work);
vd_free(&fft_result);
feTRACE(15);
}
void Fft_fft(const Fft* fft,const dmat* timedata,cmat* result) {
fsTRACE(15);
dbgassert(fft && timedata && result,NULLPTRDEREF);
dbgassert(timedata->n_rows == fft->nfft,"Invalid size for time data rows."
" Should be equal to nfft");
dbgassert(timedata->n_cols == fft->nchannels,"Invalid size for time data cols."
" Should be equal to nchannels");
const us nfft = fft->nfft;
const us nchannels = timedata->n_cols;
dbgassert(timedata->n_cols == result->n_cols,
"Number of columns in timedata and result"
" should be equal.");
vd fft_result = vd_alloc(fft->nfft);
for(us col=0;col<fft->nchannels;col++) {
for(us col=0;col<nchannels;col++) {
vd timedata_col = dmat_column((dmat*) timedata,col);
vd_copy(&fft_result,&timedata_col);
vc result_col = cmat_column(result,col);
Fft_fft_single(fft,&timedata_col,&result_col);
vd_free(&timedata_col);
npy_rfftf(fft->nfft,fft_result.ptr,fft->fft_work.ptr);
/* Fftpack stores the data a bit strange, the resulting array
* has the DC value at 0,the first cosine at 1, the first sine
* at 2 etc. This needs to be shifted properly in the
* resulting matrix, as for the complex data, the imaginary
* part of the DC component equals zero. */
check_overflow_vx(fft_result);
check_overflow_vx(fft->fft_work);
vc resultcol = cmat_column(result,col);
*getvcval(&resultcol,0) = *getvdval(&fft_result,0);
memcpy((void*) getvcval(&resultcol,1),
(void*) getvdval(&fft_result,1),
(nfft-1)*sizeof(d));
/* Set imaginary part of Nyquist frequency to zero */
((d*) getvcval(&resultcol,nfft/2))[1] = 0;
check_overflow_xmat(*timedata);
/* Free up storage of the result column */
vc_free(&resultcol);
vc_free(&result_col);
}
check_overflow_xmat(*timedata);
check_overflow_xmat(*result);
/* print_vd(&fft->fft_work); */
vd_free(&fft_result);
feTRACE(15);
}

View File

@ -21,19 +21,10 @@ typedef struct Fft_s Fft;
* Construct an Fft object
*
* @param nfft Nfft size
* @param nchannels Number of channels
*
* @return Pointer to Fft handle, NULL on error
*/
Fft* Fft_alloc(const us nfft,const us nchannels);
/**
* Returns the number of channels for this Fft instance
*
* @return nchannels
*/
us Fft_nchannels(const Fft*);
Fft* Fft_alloc(const us nfft);
/**
* Returns the nfft for this Fft instance
*
@ -41,18 +32,36 @@ us Fft_nchannels(const Fft*);
*/
us Fft_nfft(const Fft*);
/**
* Compute the fft of a single channel.
*
* @param[in] fft Fft handle.
*
* @param[in] timedata Input time data pointer, should have size nfft
* @param[out] result Pointer to result vector should have size
* nfft/2+1
*/
void Fft_fft_single(const Fft* fft,const vd* timedata,vc* result);
/**
* Compute the fft of the data matrix, first axis is assumed to be
* the time axis.
*
* @param[in] timedata Input time data pointer, such that
* data[i*nfft+j) is the i-th channel from data stream j.
*
* @param[out] result: Fft't data, size should be (nfft/2+1)*nchannels
*/
void Fft_fft(const Fft*,const dmat* timedata,cmat* result);
* @param[in] fft Fft handle.
* @param[in] timedata Input time data. First axis is assumed to be
* the time, second the channel number.
*
* @param[out] result: Fft't data, should have size (nfft/2+1) *
* nchannels
*/
void Fft_fft(const Fft* fft,const dmat* timedata,cmat* result);
/**
*
*
* @param fft
*/
void Fft_free(Fft* fft);
#endif // FFT_H

View File

@ -5,7 +5,7 @@
// Description:
//
//////////////////////////////////////////////////////////////////////
/* #define TRACERPLUS 1000 */
#define TRACERPLUS (-5)
#include "ps.h"
#include "fft.h"
#include "ascee_alloc.h"
@ -33,7 +33,7 @@ PowerSpectra* PowerSpectra_alloc(const us nfft,
}
/* ALlocate space */
Fft* fft = Fft_alloc(nfft,nchannels);
Fft* fft = Fft_alloc(nfft);
if(fft == NULL) {
WARN("Fft allocation failed");
return NULL;
@ -76,7 +76,7 @@ void PowerSpectra_compute(const PowerSpectra* ps,
dbgassert(ps && timedata && result,NULLPTRDEREF);
const us nchannels = Fft_nchannels(ps->fft);
const us nchannels = timedata->n_rows;
const us nfft = Fft_nfft(ps->fft);
uVARTRACE(15,nchannels);
const d win_pow = ps->win_pow;

View File

@ -7,28 +7,27 @@ cdef extern from "cblas.h":
# If we touch this variable: we get segfaults when running from
# Spyder!
#openblas_set_num_threads(8)
# openblas_set_num_threads(8)
# print("Number of threads: ",
# openblas_get_num_threads())
def cls():
clearScreen()
cls()
# cls()
cdef extern from "fft.h":
ctypedef struct c_Fft "Fft"
c_Fft* Fft_alloc(us nfft,us nchannels)
c_Fft* Fft_alloc(us nfft)
void Fft_free(c_Fft*)
void Fft_fft(c_Fft*,dmat * timedate,cmat * res) nogil
us Fft_nchannels(c_Fft*)
us Fft_nfft(c_Fft*)
cdef class Fft:
cdef:
c_Fft* _fft
def __cinit__(self, us nfft,us nchannels):
self._fft = Fft_alloc(nfft,nchannels)
def __cinit__(self, us nfft):
self._fft = Fft_alloc(nfft)
if self._fft == NULL:
raise RuntimeError('Fft allocation failed')
@ -39,9 +38,8 @@ cdef class Fft:
def fft(self,d[::1,:] timedata):
cdef us nfft = Fft_nfft(self._fft)
cdef us nchannels = Fft_nchannels(self._fft)
cdef us nchannels = timedata.shape[1]
assert timedata.shape[0] ==nfft
assert timedata.shape[1] == nchannels
result = np.empty((nfft//2+1,nchannels),
dtype=NUMPY_COMPLEX_TYPE,
@ -67,22 +65,25 @@ cdef class Fft:
cdef extern from "window.h":
ctypedef enum WindowType:
Hann = 0
Hamming = 1
Rectangular = 2
Bartlett = 3
Blackman = 4
hann = 0
hamming = 1
rectangular = 2
bartlett = 3
blackman = 4
Hann
Hamming
Rectangular
Bartlett
Blackman
# Export these constants to Python
hann = Hann
hamming = Hamming
rectangular = Rectangular
bartlett = Bartlett
blackman = Blackman
cdef extern from "ps.h":
ctypedef struct c_PowerSpectra "PowerSpectra"
c_PowerSpectra* PowerSpectra_alloc(const us nfft,
const us nchannels,
const WindowType wt)
void PowerSpectra_compute(const c_PowerSpectra* ps,
const dmat * timedata,
cmat * result)
@ -156,7 +157,7 @@ cdef extern from "aps.h":
void AvPowerSpectra_free(c_AvPowerSpectra*)
us AvPowerSpectra_getAverages(const c_AvPowerSpectra*);
cdef class AvPowerSpectra:
cdef:
@ -180,7 +181,9 @@ cdef class AvPowerSpectra:
def __dealloc__(self):
if self.aps:
AvPowerSpectra_free(self.aps)
def getAverages(self):
return AvPowerSpectra_getAverages(self.aps)
def addTimeData(self,d[::1,:] timedata):
"""!
Adds time data, returns current result
@ -223,7 +226,6 @@ cdef class AvPowerSpectra:
cmat_free(&res)
dmat_free(&td)
return result
def getFreq(self, d fs):

View File

@ -26,7 +26,7 @@ X = np.fft.rfft(x,axis=0)
print('Numpy fft')
print(X)
fft = Fft(nfft,nchannels)
fft = Fft(nfft)
Y = fft.fft(x)
print('Fftpack fft')
print(Y)

View File

@ -16,9 +16,9 @@ int main() {
iVARTRACE(15,getTracerLevel());
Fft* fft = Fft_alloc(100000,8);
Fft* fft = Fft_alloc(100000);
Fft_fft(fft,NULL,NULL);
/* Fft_fft(fft,NULL,NULL); */
Fft_free(fft);