name: FourierTransform : public AlgorithmBase
synopsis:

>     g++ [flags ...] file ... -l /isip/tools/lib/$ISIP_BINARY/lib_algo.a

>     #include <FourierTransform.h>

>     FourierTransform(ALGORITHM algorithm = DEF_ALGORITHM);
>     boolean setAlgorithm(ALGORITHM algorithm);
>     ALGORITHM getAlgorithm();

quick start:

>     VectorFloat in_vec;
>     VectorComplexFloat out_vec;
>     FourierTransform df;
>     df.setAlgorithm(FourierTransform::FORWARD);
>     in_vec.assign(L"1.0, 2,0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0");
>     df.compute(out_vec, in_vec);

description:
The FourierTransform class is used to calculate the forward and inverse fourier transform. User can select different algorithm implementation, like discrete fourier (DF), split radix (SR) fast fourier transform, etc. The input data and output data are stored in vector objects. The input data can be of either real or complex types.
The Discrete Cosine Transform (DCT) is widely used for speech and image processing, since the DCT has the energy compaction capability and also approaches the statistically orthogonal transformation in decorrelating a signal. The DCT is a close relative of the DFT, but is more computationally efficient for signals that are real and even. For example, in a typical MFCC frontend for speech recognition, we apply an IDCT_II transformation to filterbank coefficients to get an approximation of the cepstrum, which in reality simply represents an orthogonal and compact representation of the log magnitude spectrum.
Since these algorithms have numerous options, we list them separately. The options available for the algorithm choice denoted DFT are:
The options available for the algorithm choice denoted FFT are:
The options available for the algorithm choice denoted DCT are:
The references for the algorithms described in the previous three tables are:

1. S. Orfanidis, Introduction to Signal Processing, Prentice-Hall, Upper Saddle River, New Jersey, USA, pp. 495, ISBN 0-13-209172-0, 1996.
2. This technique is a variation of the Goertzel algorithm. A good starting point for details is this description of the Goertzel algorithm, located within the Ptolemy toolkit.
3. J.G.Proakis, D.G.Manolakis, Digital Signal Processing - Principles, Algorithms, and Applications, 2nd Edition, Macmillan Publishing Company, New York, pp. 727-730, 1992.
4. J.G.Proakis, D.G.Manolakis, Digital Signal Processing - Principles, Algorithms, and Applications, 2nd Edition, Macmillan Publishing Company, New York, pp. 727-730, 1992.
5. C.S. Burrus and T.W. Parks, DFT/FFT and Convolution Algorithms - Theory and Implementation, 2nd Edition, John Wiley and Sons, New York, New York, USA, 1985.
6. R.N.Bracewell, "The Fast Hartley Transform," Proceedings of the IEEE, vol. 72 no. 8, pp. 1010-1018, August 1984.
7. H. Guo, G.A. Sitton and C.S. Burrus, "The Quick Discrete Fourier Transform," Proceedings of the International Conference on Acoustics, Speech, and Signal Processsing, pp. 453-456, Adelaide, Australia, April 1994.
8. A. Saidi, "Decimation In Time Frequency FFT Algorithm," Proceedings of the International Conference on Acoustics, Speech, and Signal Processsing, pp. 453-456, Adelaide, Australia, April 1994.

Two good references for the DCT algorithms are:

- K. Rao, and P. Yip, Discrete Cosine Transform: Algorithms, Advantages and Applications, Academic Press, San Diego, California, USA, pp. 15, 1990.
- X. Huang, A. Acero, and H. Hon, Spoken Language Processing, Prentice Hall PTR, Upper Saddle River, New Jersey, USA, pp. 228, 2001.

The interface in this class allows the user a great deal of flexibility in configuring the resolution of the transform. For example, the length of the input and output can be set independently. The table below summarizes the behavior for all possible combinations of inputs and outputs:
See the programming examples below for more insight into how to configure these options. We recommend users being by using the default settings, and then explore options systematically from there.
dependencies:

- AlgorithmBase
- VectorFloat
- Long
- MemoryManager

public constants:

- define the class name:

      static const String CLASS_NAME = L"FourierTransform";

- define algorithm choices:

      enum ALGORITHM { DFT = 0, FFT, DCT, DEF_ALGORITHM = DFT };

- define implementation choices:

      enum IMPLEMENTATION { CONVENTIONAL = 0, TRIGONOMETRIC, SPLIT_RADIX, RADIX_2, RADIX_4,FAST_HARTLEY, QF, DITF, TYPE_I, TYPE_II, TYPE_III, TYPE_IV, DEF_IMPLEMENTATION = CONVENTIONAL };

- define direction choices:

      enum DIRECTION { FORWARD = 0, INVERSE, DEF_DIRECTION = FORWARD };

- define output mode choices:

      enum OTYPE { FULL = 0, SYMMETRIC, DEF_DIRECTION = FULL };

- define resolution choices:

      enum RESOLUTION { AUTO = 0, FIXED, DEF_RESOLUTION = AUTO };

- define normalization choices:

      enum NORM { NONE = 0, UNIT_ENERGY, DEF_NORM = NONE };

- define static NameMap objects:

      static const NameMap ALGO_MAP = L"DFT, FFT, DCT";

      static const NameMap IMPL_MAP = L"CONVENTIONAL, TRIGONOMETRIC, SPLIT_RADIX, RADIX_2, RADIX_4, FAST_HARTLEY, QF, DITF, TYPE_I, TYPE_II, TYPE_III, TYPE_IV";

      static const NameMap DIRE_MAP = L"FORWARD, INVERSE";

      static const NameMap OUTM_MAP = L"FULL, SYMMETRIC";

      static const NameMap RESO_MAP = L"AUTO, FIXED";

      static const NameMap NORM_MAP = L"NONE, UNIT_ENERGY";

- define i/o related constants:

      static const String DEF_PARAM = L"";

      static const String PARAM_ALGORITHM = L"algorithm";

      static const String PARAM_IMPLEMENTATION = L"implementation";

      static const String PARAM_DIRECTION = L"direction";

      static const String PARAM_OTYPE = L"output_mode";

      static const String PARAM_RESOLUTION = L"resolution";

      static const String PARAM_INPUT_LEN = L"input_length";

      static const String PARAM_OUTPUT_LEN = L"output_length";

      static const String PARAM_ORDER = L"order";

      static const String PARAM_NORMALIZATION = L"normalization";

- define default value(s) of the class data:

      static const IMPLEMENTATION DEF_FFT = SPLIT_RADIXR;

      static const long DEF_LENGTH = -1;

      static const long DEF_ORDER = 1024;

- define default argument(s):

      static const AlgorithmData::COEF_TYPE DEF_COEF_TYPE = AlgorithmData::SIGNAL;

error codes:

- error code indicating FourierTransform class general error:

      static const long ERR = 70800;

      static const long ERR_INIT = 70801;

      static const long ERR_OUTLEN = 70802;

      static const long ERR_OUTMODE = 70803;

protected data:

- algorithm name:

      ALGORITHM algorithm_d;

- implementation type:

      IMPLEMENTATION implementation_d;

- direction type:

      DIRECTION direction_d;

- output mode type:

      OTYPE otype_d;

- resolution type:

      RESOLUTION resolution_d;

- parameters related to fourier transform specification:

      Long ilen_d;

      Long olen_d;

      Long order_d;

- normalization name:

      NORM normalization_d;

- data buffers related to fourier transform computation:

      VectorFloat wd_real_d;

      VectorFloat wd_imag_d;

      VectorFloat tempd_d;

- parameters storing implementation type and transform order used last time

      IMPLEMENTATION prev_implementation_d;

      Long prev_order_d;

- parameters related to the Decimation In Time Frequency (DITF) transformation:

      VectorFloat ditf_trans_factor_indices_d;

      VectorFloat ditf_indices_d;

- parameters related to the Quick Fourier (QF) transformation:

      VectorFloat qf_comp_real_coeff_d;

      VectorFloat qf_comp_imag_coeff_d;

      VectorFloat qf_comp_temp_d;

- workspace related pointers for Quick Fourier (QF) transformation:

      VectorFloat qf_ws_d;  // Workspace

      long qf_sc_d;         // Secant table address

      long qf_nc_d;         // Current QFT length

      long qf_ic_d;         // Current secant inc.

      long qf_mc_d;         // Current output pruning

      long qf_nn_d;         // Pruned QFT input length

      long qf_mm_d;         // Pruned QFT output length

      long qf_ii_d;         // Current QFT recursion level

      long qf_input_d;      // dct/dst calling arguments

      long qf_output_d;     // dct/dst calling arguments

- static memory manager:

      static MemoryManager mgr_d;

required public methods:

- static methods:

      static const String& name();

      static boolean diagnose(Integral::DEBUG debug_level);

- debug methods: setDebug method is inherited from base class

      boolean debug(const unichar* message) const;

- destructor/constructor(s) methods:

      ~FourierTransform();

      FourierTransform(ALGORITHM algorithm = DEF_ALGORITHM);

      FourierTransform(const FourierTransform& arg);

- assign methods:

      boolean assign(const FourierTransform& arg);

- operator= methods:

      FourierTransform& operator= (const FourierTransform& arg);

- i/o methods:

      long sofSize() const;

      boolean read(Sof& sof, long tag, const String& name = CLASS_NAME);

      boolean write(Sof& sof, long tag, const String& name = CLASS_NAME) const;

      boolean readData(Sof& sof, const String& pname = DEF_PARAM, long size = SofParser::FULL_OBJECT, boolean param = true, boolean nested = false);

      boolean writeData(Sof& sof, const String& pname = DEF_PARAM) const;

- equality methods:

      boolean eq(const FourierTransform& arg) const;

- memory management methods:

      static void* operator new(size_t size);

      static void* operator new[](size_t size);

      static void operator delete(void* ptr);

      static void operator delete[](void* ptr);

      static boolean setGrowSize(long grow_size);

      boolean clear(Integral::CMODE ctype = Integral::DEF_CMODE);

class-specific public methods:

- set methods:

      boolean setAlgorithm(ALGORITHM algorithm);

      boolean setImplementation(IMPLEMENTATION implementation);

      boolean setDirection(DIRECTION direction);

      boolean setOutputType(OTYPEE otype);

      boolean setResolution(RESOLUTION resolution);

      boolean setInputLength(boolean input_len = DEF_LENGTH);

      boolean setOutputLength(boolean output_len = DEF_LENGTH);

      boolean setOrder(long order);

      boolean setNormalization(NORM normalization);

      boolean set(ALGORITHM algorithm = DFT, IMPLEMENTATION implementation = CONVENTIONAL, DIRECTION direction = FORWARD, OTYPE otype = FULL, RESOLUTION resolution = AUTO, long order = DEF_ORDER, NORM normalization = DEF_NORM);

- get methods:

      ALGORITHM getAlgorithm() const;

      IMPLEMENTATION getImplementation() const;

      DIRECTION getDirection() const;

      OTYPE getOutputType() const;

      RESOLUTION getResolution() const;

      boolean getInputLength() const;

      boolean getOutputLength() const;

      long getOrder() const;

      NORM getNormalization() const;

      boolean get(ALGORITHM& algorithm, IMPLEMENTATION& implementation, DIRECTION& direction, OTYPE& otype, RESOLUTION& resolution, long& order, NORM& normalization) const;

- computational methods:

      boolean compute(VectorComplexFloat& output, const VectorFloat& input, AlgorithmData::COEF_TYPE input_coef_type = DEF_COEF_TYPE, long chan = DEF_CHANNEL_INDEX);

      boolean compute(VectorFloat& output, const VectorComplexFloat& input, AlgorithmData::COEF_TYPE input_coef_type = AlgorithmData::SPECTRUM);

      boolean compute(VectorComplexFloat& output, const VectorComplexFloat& input, AlgorithmData::COEF_TYPE input_coef_type = DEF_COEF_TYPE, long chan = DEF_CHANNEL_INDEX);

      boolean compute(VectorFloat& output, const VectorFloat& input, AlgorithmData::COEF_TYPE input_coef_type = DEF_COEF_TYPE, long chan = DEF_CHANNEL_INDEX);

- AlgorithmBase interface contract methods:

      boolean assign(const AlgorithmBase& arg);

      boolean eq(const AlgorithmBase& arg) const;

      const String& className() const;

      boolean apply(Vector<AlgorithmData>& output, const Vector< CircularBuffer<AlgorithmData> >& input);

      boolean setParser(SofParser* parser);

private methods:

- common i/o methods:

      boolean readDataCommon(Sof& sof, const String& pname, long size, boolean param, boolean nested);

      boolean writeDataCommon(Sof& sof, const String& pname) const;

- miscellaneous math methods:

      boolean isPower(long& exponent, long base, long value);

- algorithm checking methods:

  method to check the order of the algorithm and assign a default algorithm if the chosen algorithm does not support the provided order

      boolean validateImplementation() const;

- algorithm-specific computation methods:

      boolean computeForward(VectorComplexFloat& output, const VectorFloat& input);

      boolean computeForward(VectorComplexFloat& output, const VectorComplexFloat& input);

      boolean computeForward(VectorFloat& output, const VectorFloat& input);

      boolean computeInverse(VectorComplexFloat& output, const VectorComplexFloat& input);

      boolean computeInverse(VectorFloat& output, const VectorComplexFloat& input);

      boolean computeInverse(VectorFloat& output, const VectorFloat& input);

      boolean computeInverse(VectorComplexFloat& output, const VectorFloat& input);

- algorithm-specific methods:

  the init methods are called to set up the lookup tables for each algorithm as needed. the real and complex computation methods generate fourier transform coefficients for real and complex input respectively

      boolean dfInit(long order);

      boolean dfReal(VectorFloat& output, const VectorFloat& input);

      boolean dfComplex(VectorFloat& output, const VectorFloat& input);

      boolean triInit(long order);

      boolean triReal(VectorFloat& output, const VectorFloat& input);

      boolean triComplex(VectorFloat& output, const VectorFloat& input);

      boolean srInit(long order);

      boolean srReal(VectorFloat& output, const VectorFloat& input);

      boolean srComplex(VectorFloat& output, const VectorFloat& input);

      boolean rad2Init(long order);

      boolean rad2Real(VectorFloat& output, const VectorFloat& input);

      boolean rad2Complex(VectorFloat& output, const VectorFloat& input);

      boolean rad4Init(long order);

      boolean rad4Real(VectorFloat& output, const VectorFloat& input);

      boolean rad4Complex(VectorFloat& output, const VectorFloat& input);

      boolean fhInit(long order);

      boolean fhReal(VectorFloat& output, const VectorFloat& input, boolean isReal = true);

      boolean fhComplex(VectorFloat& output, const VectorFloat& input);

      boolean qfInit(long order);

      boolean qfReal(VectorFloat& output, const VectorFloat& input);

      boolean qfComplex(VectorFloat& output, const VectorFloat& input);

      boolean ditfInit(long order);

      boolean ditfReal(VectorFloat& output, const VectorFloat& input);

      boolean ditfComplex(VectorFloat& output, const VectorFloat& input);

      boolean dct1Init(long order);

      boolean dct1Real(VectorFloat& output, const VectorFloat& input);

      boolean dct1Complex(VectorFloat& output, const VectorFloat& input);

      boolean dct2Init(long order);

      boolean dct2Real(VectorFloat& output, const VectorFloat& input);

      boolean dct2Complex(VectorFloat& output, const VectorFloat& input);

      boolean dct3Init(long order);

      boolean dct3Real(VectorFloat& output, const VectorFloat& input);

      boolean dct3Complex(VectorFloat& output, const VectorFloat& input);

      boolean dct4Init(long order);

      boolean dct4Real(VectorFloat& output, const VectorFloat& input);

      boolean dct4Complex(VectorFloat& output, const VectorFloat& input);

      boolean dct_real_cc(VectorFloat& output, const VectorFloat& input);

      boolean dst_real_cc(VectorFloat& output, const VectorFloat& input);

examples:

- This example demonstrates how to use this class to compute a forward and reverse transform:

      // isip include files
      //
      #include <FourierTransform.h>

      // main program starts here
      //
      int main(int argc, const char **argv) {

        FourierTransform df;
        FourierTransform fft_sr;
        VectorComplexFloat real_in_vec;
        VectorComplexFloat freq_vec;
        VectorComplexFloat inverse_vec;

        real_in_vec.assign(L"1, 2, 3, 4, 5, 6, 7, 8");

        // setup the the forword complex transform
        //
        df.setDirection(FourierTransform::FORWARD);
        df.setOrder(real_in_vec.length());

        if (!df.compute(freq_vec, real_in_vec)) {
          Error::handle(df.name(), L"compute", Error::TEST, __FILE__,
      		  __LINE__);
        }

        real_in_vec.debug(L"real_in_vec");
        df.debug(L"df");
        freq_vec.debug(L"freq_vec");

        // now setup the the inverse complex transform
        //
        fft_sr.setDirection(FourierTransform::INVERSE);

        // calculate the inverse transform
        //
        if (!fft_sr.compute(inverse_vec, freq_vec)) {
          Error::handle(fft_sr.name(), L"compute", Error::TEST, __FILE__,
      		  __LINE__);
        }

        // print a separating line
        //
        Console::put(L"\n");

        freq_vec.debug(L"freq_vec");
        fft_sr.debug(L"fft_sr");
        real_in_vec.debug(L"");

        // exit gracefully
        //
        Integral::exit();

      }

- This example demonstrates how users can set the input and output orders manually to achieve a variety of resolutions:

      // isip include files
      //
      #include <FourierTransform.h>

      // main program starts here
      //
      int main(int argc, const char **argv) {

        FourierTransform dft;
        VectorComplexFloat real_in_vec;
        VectorComplexFloat freq_vec;
        VectorComplexFloat inverse_vec;

        real_in_vec.assign(L"1, 2, 3, 4, 5, 6, 7, 8");

        // setup the the forward complex DFT
        //
        dft.setAlgorithm(FourierTransform::DFT);
        dft.setImplementation(FourierTransform::CONVENTIONAL);
        dft.setDirection(FourierTransform::FORWARD);

        // extend the input signal by zero-padding
        //
        dft.setInputLength((long)10);

        // compute the DFT
        //
        if (!dft.compute(freq_vec, real_in_vec)) {
          Error::handle(dft.name(), L"compute", Error::TEST, __FILE__,
      		  __LINE__);
        }

        // print the input and the output
        //
        real_in_vec.debug(L"real_in_vec");
        dft.debug(L"dft");
        freq_vec.debug(L"freq_vec");

        // set the output length to 12
        //
        dft.setOutputLength((long)12);

        // compute the DFT
        //
        if (!dft.compute(freq_vec, real_in_vec)) {
          Error::handle(dft.name(), L"compute", Error::TEST, __FILE__,
      		  __LINE__);
        }

        // print the input and the output
        //
        real_in_vec.debug(L"real_in_vec");
        dft.debug(L"dft");
        freq_vec.debug(L"freq_vec");

        // exit gracefully
        //
        Integral::exit();
      }

notes:

- While computing the Fourier transform, the memory is allocated by the calling program for the input vector. For the output vector, the memory is allocated internally, not by the calling program.