/* =======================================================================
   ************************* RectangularToPolar **************************
   ======================================================================= */

/* This routine converts the rectangular real and imaginary coefficients generated
   by a DFT into polar mag and phase. */ 

#define M_PI 3.14159265358979323846

void RectangularToPolar( imaginary, real, mag, phase, dft_num_freqs, dft_num_points)
   double *imaginary, *real, *mag, *phase;
   long dft_num_freqs, dft_num_points; 
   {
   int i;

/* Compute the DC component. */

   mag[0] = real[0]/dft_num_points;
   phase[0] = 0;

/* Convert to polar form. */

   for ( i = 1; i < dft_num_freqs; i++ ) 
      {
      imaginary[i] *= 2.0/dft_num_points;
      real[i] *= 2.0/dft_num_points;

      mag[i] = sqrt(imaginary[i]*imaginary[i]+real[i]*real[i]);

/* Standard way -> atan(-b/a). */

      phase[i] = atan2(-imaginary[i], real[i])*180.0/M_PI;
      }
   }


/* =======================================================================
   ******************************* CalcDFT *******************************
   ======================================================================= */

/* CalcDFT performs discrete fourier analysis. y_time_data is the raw time 
   domain data to be used as input. Output consists of 5 arrays (imaginary,
   real, mag, phase and freq). dft_num_points is the number of elements in 
   the y_time_data, dft_fund_freq is the fundamental frequency of the 
   analysis.  dft_num_freqs is number of harmonics to calculate. The arrays 
   (y_time_data, imaginary, real, mag, phase and freq) must all be allocated 
   by the caller. y_time_data is a one-dimensional array of size dft_num_points
   while imaginary, real, mag, phase and freq are one dimensional arrays of 
   size dft_num_freqs. The y_time_data array must be reasonably distributed 
   over at least one full period of the fundamental frequency for the fourier 
   transform to be useful. Also, dft_num_freqs is always <= 1/2*dft_num_points. */

void CalcDFT( y_time_data, dft_num_points, dft_fund_freq, dft_num_freqs, 
   imaginary, real, mag, phase, freq)
   double *y_time_data; 
   long dft_num_points, dft_num_freqs; 
   double dft_fund_freq; 
   double *imaginary, *real, *mag, *phase, *freq; 
   {
   long i, j;

/* We are assuming that the caller has provided exactly one period of the 
   fundamental frequency. Clear output arrays */

   for ( i = 0; i < dft_num_freqs; i++ ) 
      {
      real[i] = 0;
      imaginary[i] = 0;
      }

   for (i = 0; i < dft_num_points; i++ ) 
      {
      for ( j = 0; j < dft_num_freqs; j++ ) 
         {
         imaginary[j] += (y_time_data[i]*sin(j*2.0*M_PI*i/((double) dft_num_points)));
         real[j] += (y_time_data[i]*cos(j*2.0*M_PI*i/((double) dft_num_points)));
         }
      }

/* Construct the frequency values, which are just multiples of the fundamental. */

   for ( i = 0; i < dft_num_freqs; i++ ) 
      freq[i] = i * dft_fund_freq;

   RectangularToPolar(imaginary, real, mag, phase, dft_num_freqs, dft_num_points);
   }
