lasp/beamforming/c/aps.c

251 lines
7.0 KiB
C

// aps.c
//
// Author: J.A. de Jong -ASCEE
//
// Description:
//
//////////////////////////////////////////////////////////////////////
#include "aps.h"
#include "ps.h"
#include "ascee_alg.h"
typedef struct AvPowerSpectra_s {
us os; /**< Counter set to the position where
* the next time block should be taken
* from */
us nfft, nchannels;
us oo;
us naverages; /* Counter that counts the number of
* averages taken for the computation
* of this averaged power spectra. */
dmat buffer; /**< Buffer storage of some of the
* previous samples. Number of rows is
* equal to nfft. */
cmat ps_storage; /**< Here we store the averaged
* results for each Cross-power
* spectra computed so far. */
cmat ps_single; /**< This is the work area for a
* PowerSpectra computation on a
* single block */
PowerSpectra* ps; /**< Pointer to underlying
* PowerSpectra calculator. */
} AvPowerSpectra;
AvPowerSpectra* AvPowerSpectra_alloc(const us nfft,
const us nchannels,
const d overlap_percentage,
const WindowType wt) {
fsTRACE(15);
/* Check nfft */
if(nfft % 2 != 0 || nfft > ASCEE_MAX_NFFT) {
WARN("nfft should be even");
feTRACE(15);
return NULL;
}
/* Check overlap percentage */
if(overlap_percentage >= 100) {
WARN("Overlap percentage >= 100!");
feTRACE(15);
return NULL;
}
if(overlap_percentage < 0) {
WARN("Overlap percentage should be positive!");
feTRACE(15);
return NULL;
}
/* Compute and check overlap offset */
us oo = (us) (((d) nfft)-overlap_percentage*((d) nfft)/100);
iVARTRACE(15,oo);
if(oo == 0) {oo++;}
PowerSpectra* ps = PowerSpectra_alloc(nfft,nchannels,wt);
if(!ps) {
WARN(ALLOCFAILED "ps");
feTRACE(15);
return NULL;
}
AvPowerSpectra* aps = a_malloc(sizeof(AvPowerSpectra));
if(!aps) {
WARN("Allocation of AvPowerSpectra memory failed");
PowerSpectra_free(ps);
feTRACE(15);
return NULL;
}
aps->nchannels = nchannels;
aps->nfft = nfft;
aps->ps = ps;
aps->naverages = 0;
aps->oo = oo;
aps->os = oo;
/* Allocate vectors and matrices */
aps->buffer = dmat_alloc(nfft,nchannels);
aps->ps_storage = cmat_alloc(nfft/2+1,nchannels*nchannels);
aps->ps_single = cmat_alloc(nfft/2+1,nchannels*nchannels);
cmat_set(&aps->ps_storage,0);
feTRACE(15);
return aps;
}
us AvPowerSpectra_getAverages(const AvPowerSpectra* ps) {
return ps->naverages;
}
/**
* Helper function that adds a block of time data to the APS
*
* @param aps AvPowerSpectra handle
* @param block Time data block. Size should be exactly nfft*nchannels.
*/
static void AvPowerSpectra_addBlock(AvPowerSpectra* aps,
const dmat* block) {
fsTRACE(15);
dbgassert(aps && block,NULLPTRDEREF);
dbgassert(block->n_rows == aps->nfft,"Invalid block n_rows");
dbgassert(block->n_cols == aps->nchannels,"Invalid block n_cols");
const us nchannels = aps->nchannels;
const us nfft = aps->nfft;
iVARTRACE(15,nfft);
cmat* ps_single = &aps->ps_single;
cmat* ps_storage = &aps->ps_storage;
c naverages = (++aps->naverages);
cVARTRACE(15,naverages);
/* Scale previous result */
cmat_scale(ps_storage,
(naverages-1)/naverages);
uVARTRACE(15,(us) aps->ps);
PowerSpectra_compute(aps->ps,
block,
ps_single);
/* Add new result, scaled properly */
cmat_add_cmat(ps_storage,
ps_single,1/naverages);
feTRACE(15);
}
cmat* AvPowerSpectra_addTimeData(AvPowerSpectra* aps,
const dmat* timedata) {
fsTRACE(15);
dbgassert(aps && timedata,NULLPTRDEREF);
const us nchannels = aps->nchannels;
const us nfft = aps->nfft;
dbgassert(timedata->n_cols == nchannels,"Invalid time data");
dbgassert(timedata->n_rows >= nfft,"Invalid time data. "
"Should at least have nfft rows");
const us oo = aps->oo;
us* os = &aps->os;
iVARTRACE(15,*os);
us os_timedata = 0;
dmat buffer = aps->buffer;
/* Retrieve the buffer and use it to make the first time block. */
if(*os < oo) {
TRACE(15,"Using saved data from previous run");
dbgassert(false,"not tested")
dmat tmp = dmat_alloc(nfft,nchannels);
dbgassert(0 <= *os,"BUG");
dbgassert(*os <= nfft,"BUG");
/* copy_dmat_rows(&tmp, */
/* &buffer, */
/* *os, /\* Startrow_from *\/ */
/* 0, /\* Startrow to *\/ */
/* nfft - *os /\* nrows *\/ */
/* ); */
/* copy_dmat_rows(&tmp, */
/* timedata, */
/* 0, */
/* nfft - *os, */
/* *os */
/* ); */
AvPowerSpectra_addBlock(aps,&tmp);
os_timedata = oo + *os - nfft;
dbgassert(os_timedata < nfft,"BUG");
dmat_free(&tmp);
}
/* Run until we cannot go any further */
while ((os_timedata + nfft) <= timedata->n_rows) {
dmat tmp = dmat_submat(timedata,
os_timedata, /* Startrow */
0, /* Start column */
nfft, /* Number of rows */
nchannels); /* Number of columns */
/* Process the block of time data */
AvPowerSpectra_addBlock(aps,&tmp);
iVARTRACE(15,os_timedata);
os_timedata += oo;
dmat_free(&tmp);
iVARTRACE(15,os_timedata);
}
/* We copy the last piece of samples from the timedata to the
* buffer */
copy_dmat_rows(&buffer,
timedata,
timedata->n_rows-nfft, /* startrow_from */
0, /* startrow_to */
nfft); /* Number of rows */
*os = os_timedata+nfft-timedata->n_rows;
dbgassert(*os <= nfft,"BUG");
feTRACE(15);
return &aps->ps_storage;
}
void AvPowerSpectra_free(AvPowerSpectra* aps) {
fsTRACE(15);
PowerSpectra_free(aps->ps);
dmat_free(&aps->buffer);
cmat_free(&aps->ps_storage);
cmat_free(&aps->ps_single);
a_free(aps);
feTRACE(15);
}
//////////////////////////////////////////////////////////////////////