// file: $PDSP/class/fourier_transform/v3.0/ft_rad2_1.cc
//

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

#include "fourier_transform_constants.h"

// method: rad2_complex_cc
//
// this method performs a radix-2 cooley-tukey decimation-in-frequency
// algorithm.  the code follows the exact structure of that in the book:
//
// J.G.Proakis, D.G.Manolakis, "Digital Signal Processing - Principles,
// Algorithms, and Applications" 2nd Edition, Macmillan Publishing Company,
// New York, pp. 731-732, 1992.
// 
// arguments:
//  float_8* output_a: (output) output data array 
//			length of output array will always be 2*N
//			memory is allocated internally, not by the calling
//			program.
//  float_8* input_a: (input) input data array
//			length of input array is 2*N
//			input data memory should be allocated by the
//			calling program.
//
// return: a logical_1 value indicating status
//
// implements a complex discrete fourier transform
//
logical_1 Fourier_transform::rad2_complex_cc(float_8* output_a,
						      float_8* input_a){
  
  // declare local variables
  //
  int_4 i,j,k,l,m,i1,i2;
  int_4 n1,n2;
  float_8 real_twid,imag_twid;
  float_8 tempr,tempi,temp; 
  
  // initialize the lookup tables
  //
  if (rad2_init_cc(N_d) == ISIP_FALSE) {
    error_handler_cc((char_1*)"rad2_complex_cc",
		     (char_1*)"error initializing the algorithm");
    return ISIP_FALSE;
  }
  
  // copy input data to temporary memory so that the input data is retained
  // after calculations. note that the comple input data is in an interlaced
  // format. after this operation, output_a will contain th real part of the
  // input and rad2_temp_d will contain the imaginary part.
  //
  for (k = 0; k < N_d; ++k) {
    output_a[k] = input_a[k*2];
    rad2_temp_d[k] = input_a[k*2 + 1];
  }
  
  // check the order
  //
  if (is_power_cc((int_4&)m, (int_4)2) == ISIP_FALSE) {
    error_handler_cc((char_1*)"rad2_real_cc",
		     (char_1*)"order must be a power of two");
    return ISIP_FALSE;
  }
  
  // actual dif radix-2 computation
  //
  n2 = N_d;  
  for (i = 0; i < m; ++i) {

    // looping  through each stage
    //
    n1 = n2;
    n2 = n2 >> 1;
    i1 = 0;
    i2 = (int_4)((N_d)/n1);
    
    for (j = 0; j < n2; ++j) {

      // loop through each butterfly
      //
      real_twid = rad2_wr_d[i1];
      imag_twid = rad2_wi_d[i1];
      i1 = i1 + i2;
      
      for (k = j; k < N_d; k += n1) {

	// perform the butterfly computation; computation within square braces
	// in eqn (9.3.34) multiplied by the twiddle factor
	//
	l = k + n2;
        tempr = output_a[k] - output_a[l];
        output_a[k] = output_a[k] + output_a[l];
        tempi = rad2_temp_d[k] - rad2_temp_d[l];
        rad2_temp_d[k] = rad2_temp_d[k] + rad2_temp_d[l];
        output_a[l] = (real_twid * tempr) + (imag_twid * tempi);
        rad2_temp_d[l] =  (real_twid * tempi) - (imag_twid * tempr);
      }
    }
  }

  // procedure for bit reversal
  //
  j = 0;
  n1 = N_d - 1;
  n2 = N_d >> 1;

  for (i = 0; i < n1 ; ++i) {
    if (i < j) {
      temp = output_a[j];
      output_a[j] = output_a[i];
      output_a[i] = temp;
      temp = rad2_temp_d[j];
      rad2_temp_d[j] = rad2_temp_d[i];
      rad2_temp_d[i] = temp;
    }
    k = n2;
    while (k <= j) {
	j -= k;
	k = k >> 1;
      }
    j += k;
  }

  // interlace the output and store in the output_a array
  //
  for (k = N_d - 1; k >= 0; --k) {
    output_a[k*2+1] = rad2_temp_d[k];
    output_a[k*2] = output_a[k];
  }
    
  // exit gracefully
  //
  return ISIP_TRUE;
}



