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