// file: $isip/class/algo/FourierTransform/ft_07.cc
// version: $Id: ft_07.cc 8165 2002-05-31 21:57:33Z picone $
//

// isip include files
//
#include "FourierTransform.h"

// method: dfInit
//
// arguments:
//  long order: (input) new order
//
// return: a boolean value indicating status
//
// creates lookup tables for sin and cosine terms. note that space is
// allocated in this method only when the order changes.
//
boolean FourierTransform::dfInit(long order_a) {

  // if previous implementation and order are the same as
  // the current ones and the current transform object
  // is valid, then we are done
  //
  if (is_valid_d && (prev_implementation_d == CONVENTIONAL) && (prev_order_d == order_a)) {

    // exit gracefully
    //
    return true;
  }

  // refresh the previous implementation type and transform order
  //
  prev_implementation_d = CONVENTIONAL;
  prev_order_d = order_a;
  
  // assign the order
  //
  order_d = order_a;

  // after this method the twiddle factors will be valid
  //
  is_valid_d = true;
  
  // allocate space
  //
  wd_real_d.setLength(order_d * order_d);
  wd_imag_d.setLength(order_d * order_d);

  // loop over all data samples
  //
  double scale_factor = Integral::TWO_PI / order_d;
  double t;
  long m = 0;

  for (long k = 0; k < order_d; k++) {
    for (long n = 0; n < order_d; n++) {
      
      // compute the argument
      //
      t = scale_factor * n * k;
      wd_imag_d(m) = sin(t);
      wd_real_d(m) = cos(t);

      // increment counters
      //
      m++;
    }
  }

  // exit gracefully
  //
  return true;
}

// method: dfReal
//
// arguments:
//  VectorFloat& output: (output) output data vector 
//  const VectorFloat& input: (input) input data vector
//
// return: a boolean value indicating status
//
// this method implements a real discrete fourier transform using a
// table lookup. output data vector length of output vector will
// always be 2*order_d memory is allocated internally, not by the
// calling program. 
//
//  S. Orfanidis, Introduction to Signal Processing, Prentice-Hall,
//  Upper Saddle River, New Jersey, USA, pp. 495, ISBN0-13-209172-0,
//  1996.
//
boolean FourierTransform::dfReal(VectorFloat& output_a,
				 const VectorFloat& input_a) {

  // assign the order
  //  L: input data length, N: DFT points, A: N*L matrix
  //
  long L = input_a.length();
  long N = (olen_d == DEF_LENGTH) ? L : (long)olen_d;

  order_d = (direction_d == FORWARD) ? N : L;

  // check if the lookup table has been initialized
  //
  if (!dfInit(order_d)) {
    return Error::handle(name(), L"dfReal", ERR_INIT, __FILE__, __LINE__);
  }

  // declare local variables
  //
  long m;

  // allocate memory for output vector
  //
  output_a.setLength((long)order_d * 2);
  
  // loop over all frequency samples
  //    
  for (long k = 0; k < order_d; k++) {
    
    // increment the table index
    //
    m = (long)order_d * k;

    // declare local accumulators
    //
    float sumr = 0.0;
    float sumi = 0.0;

    // loop over the data
    //
    for (long n = 0; n < L; n++) {

      // compute the real part
      //
      sumr += (wd_real_d(m) * input_a(n));
      
      // compute the imaginary part
      //
      sumi -= (wd_imag_d(m) * input_a(n));

      // increment the table index
      //
      m++;
    }
    
    // put the output data in an interlaced format
    //
    output_a(2 * k) = sumr;
    output_a(2 * k + 1) = sumi;
  }
  
  // exit gracefully
  //
  return true;
}

// method: dfComplex
//
// arguments:
//  VectorFloat& output: (output) output data vector
//  const VectorFloat& input: (input) input data vector
//
// return: a boolean value indicating status
//
// this method implements a complex discrete fourier transform
//
boolean FourierTransform::dfComplex(VectorFloat& output_a,
				    const VectorFloat& input_a) {
  
  // assign the order
  //  L: input data length, N: DFT points, A: N*L matrix
  //
  long L = input_a.length() / 2;
  long N = (olen_d == DEF_LENGTH) ? L : (long)olen_d;

  order_d = (direction_d == FORWARD) ? N : L;

  // check if the lookup table has been initialized
  //
  if (!dfInit(order_d)) {
    return Error::handle(name(), L"dfComplex", ERR_INIT, __FILE__, __LINE__);
  }

  // declare local variables
  //
  long m;

  // allocate memory for output vector
  //
  output_a.setLength(2 * order_d);
  
  // loop over all frequency samples
  //
  for (long k = 0; k < order_d; k++) {
    
    // increment the table index
    //
    m = (long)order_d * k;

    // declare local accumulators
    //
    float sumr = 0.0;
    float sumi = 0.0;
    
    // loop over the data
    //
    for (long n = 0; n < L; n++) {
      
      // compute the real part
      //
      sumr += ((wd_real_d(m) * input_a(2 * n)) +
	       (wd_imag_d(m) * input_a(2 * n + 1)));
      
      // compute the imaginary part
      //
      sumi += ((wd_real_d(m) * input_a(2 * n + 1)) -
	       (wd_imag_d(m) * input_a(2 * n)));
      
      // increment the table index
      //
      m++;
    }
    
    // put the output data in an interlaced format
    //
    output_a(2 * k) = sumr;
    output_a(2 * k + 1) = sumi;
  }

  // exit gracefully
  //
  return true;
}
