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; };