Listing 3: Signal<> header file.
#include "IPPPolicy.h" // include the policy class that wraps Intel's IPP library
template <typename T>
class Signal {
public:
typedef IntelIppPolicy<T> IPP;
Signal(int N=0) : m_nSamples(N), m_pSamples(NULL)
{
if (N)
m_pSamples = IPP::malloc(N);
}
~Signal()
{
if (m_pSamples)
IPP::free(m_pSamples);
}
operator T *() {
return m_pSamples;
}
int getNumSamples() {
return m_nSamples;
}
// adjust the length of the array
void resize(int N)
{
if (m_pSamples)
IPP::free(m_pSamples);
m_nSamples = N;
m_pSamples = IPP::malloc(N);
}
// Returns minimum value pIndx is where this point is located.
T min(int *pIndx)
{
T minVal;
IppStatus sts = IPP::minIndx(m_pSamples, m_nSamples, &minVal, pIndx);
if (ippStsOk != sts)
throw std::runtime_error((char*)ippGetStatusString(sts));
return minVal;
}
// Returns minimum value pIndx is where this point is located.
T max(int *pIndx)
{
T maxVal;
IppStatus sts = IPP::maxIndx(m_pSamples, m_nSamples, &maxVal, pIndx);
if (ippStsOk != sts)
throw std::runtime_error((char*)ippGetStatusString(sts));
return maxVal;
}
// Computes and returns the magnitude of the FFT of the signal. The FFT
// of a real-valued signal is a symmetric complex signal: hence the
// length of the return signal will be half (plus 1) of the input signal.
// There isn't enough error checking performed in this method, for
// example one should really verify that the length of the input vector
// is a power-of-2 length.
// Finally, IPP library does provide a higher-level API function that
// computes power spectrum of a signal--the equivalent to this method.
void fftMagnitude(Signal<T> *pMagFFT)
{
IPP::cmplx_type *pFFT = NULL;
// order of the FFT defined to be log2(length of input)
int orderFFT = (int)(std::log((double)m_nSamples) / std::log(2.0));
// this is somewhat inefficient, in a real implementation we'd likely
// initialize this just once and then cache it away.
IPP::fft_spec_type *pFFTSpec = NULL;
IppStatus sts = IPP::allocFFTSpec(&pFFTSpec, orderFFT, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone);
if (ippStsOk != sts)
throw std::runtime_error((char*)ippGetStatusString(sts));
// length of the return signal
int lenFFT = (1<<(orderFFT-1)) + 1;
if (NULL == (pFFT = IPP::cmplxMalloc(lenFFT)))
throw std::bad_alloc("Failed to malloc complex array!");
// ready to compute the FFT now
if (ippStsOk != (sts = IPP::fwdFFT(m_pSamples, (IPP::elem_type *)pFFT, pFFTSpec)))
throw std::runtime_error((char*)ippGetStatusString(sts));
// magnitude of the FFT is the complex modulus
pMagFFT->resize(lenFFT);
if (ippStsOk != (sts = IPP::cmplxModulus(pFFT, pMagFFT->m_pSamples, lenFFT)))
throw std::runtime_error((char*)ippGetStatusString(sts));
// clean up
IPP::free(pFFT);
IPP::freeFFTSpec(pFFTSpec);
}
private:
// the underlying array
T *m_pSamples;
// how many data points in the m_pSamples array
int m_nSamples;
};