ftp.nice.ch/pub/next/science/physics/gck.2.01.s.tar.gz#/gckc.2.0.1/gck_fft.c

This is gck_fft.c in view mode; [Download] [Up]

/* ******************************************************************** */
/* *                           GCK                                    * */
/* *               A Circuit Simulation Program                       * */
/* *                    by Tanju Cataltepe                            * */
/* *                    (c) Copyright 1989                            * */
/* ******************************************************************** */
/* (c) Copyright 1989, Tanju Cataltepe */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>			
#include <ctype.h>
#include <time.h>

#ifdef Macintosh
#include <console.h> 
#include <Files.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#endif

#include <math.h>
#include <float.h>
#include "gck.h"
#include "gck_vars.h"
#include "gck_protos.h"
#include "gck_errors.h"


fftMRec *get_fft_mrec(fftRec *tmpP)
{
fftMRec *tmpM;
fftMRec *newptr;

tmpM = baseOfMFFT;

while (tmpM != NULL) {
  if ((tmpP->vo1 == tmpM->vo1) && (tmpP->vo2 == tmpM->vo2))
    break;
  tmpM = tmpM->next;
  }

if (tmpM != NULL)
  return(tmpM);
else {
  newptr = (fftMRec *) c_malloc(sizeof(fftMRec));
  newptr->vo1 = tmpP->vo1;
  newptr->vo2 = tmpP->vo2;
  newptr->next = baseOfMFFT;
  baseOfMFFT = newptr;
  newptr->fft_length = 0;
  newptr->base = (fftClist *) c_malloc(sizeof(fftClist));
  newptr->current = newptr->base;
  newptr->current->depth = 0;
  newptr->current->next = NULL;
  return(newptr);
  }
}

void readFFT()
{
  /*.FFT [Window windowname] V(n1, n2) I(name) ... [> filename] */
  fftRec *tmpP, *lastP;
  aWord tmpW;
  nameString tmpN;
  long i, j, k, m;
  long counter;

  i = 2;
  GetWORD(tmpW,i);

  while (tmpW[0] != NULL_CHAR) {
    switch (tmpW[0]) {

    case 'W':
      i++;
      GetWORD(tmpW,i);
      if (strncmp(tmpW,"RECT",4) == 0)
        fft_window = WINDOW_RECTANGULAR;
      else if (strncmp(tmpW,"BART",4) == 0)
        fft_window = WINDOW_TRIANGULAR;
      else if (strncmp(tmpW,"TRIA",4) == 0)
        fft_window = WINDOW_TRIANGULAR;
      else if (strncmp(tmpW,"HANN",4) == 0)
        fft_window = WINDOW_HANN;
      else if (strncmp(tmpW,"HAMM",4) == 0)
        fft_window = WINDOW_HAMMING;
      else if (strncmp(tmpW,"BLAC",4) == 0)
        fft_window = WINDOW_BLACKMAN;
      else
        errorReport(ERROR_WINDOW_NOT_FOUND,tmpW,ERR_VOID,0);
      break;
    case '>':	/* new option */
      fft_to_file = TRUE;
      if (tmpW[1] == NULL_CHAR) {
        i++;
        GetWord(fft_filename,i);
        }
      else {
        GetWord(tmpW,i);
        strcpy(fft_filename,&tmpW[1]);
        }
      break;
    /* Windowing On Another Card ! */
    case 'V':
      tmpP = (fftRec *)c_malloc(sizeof(fftRec));
      tmpP->outType = branchVoltage;
      strcpy(tmpN,"\0");
      if (tmpW[1] != '(') {
        m = 1;
        switch(tmpW[1]) {
          case 'M':	tmpP->fptype = FP_MAGN;		break;
          case 'R':	tmpP->fptype = FP_REAL;			break;
          case 'I':		tmpP->fptype = FP_IMAG;			break;
          case 'P':	tmpP->fptype = FP_PHASE;		break;
          case 'D':	tmpP->fptype = FP_DB;	m = 2;	break;
          }
        }
      else {
        tmpP->fptype = FP_MAGN;
        m = 0;
        }
      j = 3;
      while ((tmpW[j - 1 + m] != ',') && (tmpW[j - 1 + m] != ')')) {
        tmpN[j - 3] = tmpW[j - 1 + m];
        j++;
      }
      tmpN[j - 3] = NULL_CHAR;
      tmpP->n1 = nodeRecordFromList(tmpN,REQUEST_NODE);
      if (tmpW[j - 1 + m] == ')') /* Remembering Ayse! */
        tmpP->n2 = nodeRecordFromList("0",REQUEST_NODE);
      else {
        strcpy(tmpN,"\0");
        k = j + 1;
        while (tmpW[k - 1 + m] != ')') {
          tmpN[k - j - 1] = tmpW[k - 1 + m];
          k++;
          }
        tmpN[k - j - 1] = NULL_CHAR;
      
        tmpP->n2 = nodeRecordFromList(tmpN,REQUEST_NODE);
        }
      if (baseOfFFT == NULL) {
        baseOfFFT = tmpP;
        lastP = tmpP;
      } else {
        lastP->next = tmpP;
        lastP = tmpP;
      }
      break;

    case 'I':
      tmpP = (fftRec *)c_malloc(sizeof(fftRec));
      tmpP->outType = branchCurrent;
      strcpy(tmpN,"\0");
      if (tmpW[1] != '(') {
        m = 1;
        switch(toupper(tmpW[1])) {
          case 'M':            tmpP->fptype = FP_MAGN;            break;
          case 'R':            tmpP->fptype = FP_REAL;            break;
          case 'I':            tmpP->fptype = FP_IMAG;            break;
          case 'P':            tmpP->fptype = FP_PHASE;            break;
          case 'D':            tmpP->fptype = FP_DB;            m = 2;            break;
          }
        }
      else {
        tmpP->fptype = FP_MAGN;
        m = 0;
        }
      j = 3;
      while (tmpW[j - 1 + m] != ')') {
        tmpN[j - 3] = tmpW[j - 1 + m];
        j++;
      }
      tmpN[j - 3] = NULL_CHAR;
      strcpy(tmpP->name,tmpN);
      if (baseOfFFT == NULL) {
        baseOfFFT = tmpP;
        lastP = tmpP;
      } else {
        lastP->next = tmpP;
        lastP = tmpP;
      }
      break;

    default:
      errorReport(ERROR_BAD_FFTSPEC, progName, ERR_VOID, 0);
      break;
    }
    i++;
    GetWORD(tmpW,i);

  }
}


void SetUpFFT()
{
  fftRec *tmp;
  branchRec *b;

  /* the following may be a conflict, since it is now performed "twice." */
  tmp = baseOfFFT;
  while (tmp != NULL) {
    switch (tmp->outType) {

    case branchVoltage:
      if (tmp->n1 == 0)
        tmp->vo1 = GND;
      else
        tmp->vo1 = &vv_x[ID_nindex[tmp->n1]];
      if (tmp->n2 == 0)
        tmp->vo2 = GND;
      else
        tmp->vo2 = &vv_x[ID_nindex[tmp->n2]];
      break;

    case branchCurrent:
      GetBranchByName(&b, tmp->name);
      tmp->vo1 = &vv_x[b->ID.UU.n[0]];
      tmp->vo2 = GND;
      break;
    }
    /* create some space for the list of numbers ... */
    /* must determine whether data space has been created for this entry yet */
    tmp->data = get_fft_mrec(tmp);
    tmp = tmp->next;
  }
}


void RunFFT()
{
  fftMRec *tmp;
  fftClist	*holder;

  if (baseOfMFFT == NULL)
    return;
  tmp = baseOfMFFT;

  while (tmp != NULL) {
    holder = tmp->current;
    /* should place parameters in appropriate bins... */
    holder->x[holder->depth].re = (*tmp->vo1 - *tmp->vo2);
    holder->x[holder->depth].im = (double) 0.0;
    tmp->fft_length++;
    holder->depth++;
    
    if (holder->depth == FFT_ARRAY_SIZE) {
      tmp->current = (fftClist *) c_malloc(sizeof(fftClist));
      holder->next = tmp->current;
      tmp->current->depth = 0;
      tmp->current->next = NULL;
      }
    tmp = tmp->next;
  }
}


void process_fft()
{
  fftMRec *tmp;
  gck_complex *x;
  long length;
  long position;
  fftClist *clistptr;
  fftClist *c2;

  if (baseOfMFFT == NULL)
    return;
  tmp = baseOfMFFT;

  while (tmp != NULL) {
   x = (gck_complex *) c_malloc(sizeof(gck_complex) * tmp->fft_length);
   /* here rdh stress */
   clistptr = tmp->base;
   position = 0;
   for (length = 0; length < tmp->fft_length; length++) {
     x[length].re = clistptr->x[position].re;
     x[length].im = clistptr->x[position].im;
     position++;
     if (position == FFT_ARRAY_SIZE) {
       c2 = clistptr->next;
       free(clistptr);
       clistptr = c2;
       position = 0;
       }
     }

   window_data(x,tmp->fft_length);
   compute_fft(x,tmp->fft_length);
   tmp->result = x;
   tmp = tmp->next;
  }
}


void print_fft()
{
  fftRec *tmp;
  long length;
  long stages;
  long counter;
  long index;
  register double frequency_step;
  double z;
  double value;
  FILE *fft_file;

  if (fft_to_file) {
    fft_file = fopen(fft_filename,"w");
    if (fft_file == NULL)
      errorReport(ERROR_FILE_FFT_CANNOT_OPEN,fft_filename,ERR_VOID,0);
    }
  else {
    fft_file = stdout;
    }


  if (baseOfFFT == NULL)
    return;
  length = baseOfFFT->data->fft_length;
  /* frequency step fixed April 13, 1992 RdH */
  z = ((double) deltaT * (double) NoOfTicks / (double) samplesOn);
  frequency_step = (double) (1.0 / (z * (double) length));
  stages = get_max_stages(length);
  for (counter = 0; counter < (length / 2); counter++) {
    fprintf(fft_file,"% .5E%c",(counter * frequency_step),TAB_CHAR);
    tmp = baseOfFFT;
    if (fft_must_reorder)
      index = bit_reversed_index(counter,stages);
    else
      index = counter;
    while (tmp != NULL) {
       switch (tmp->fptype) {
        case FP_REAL:
          fprintf(fft_file,"% .5E",tmp->data->result[index].re);
          break;
        case FP_IMAG:
          fprintf(fft_file,"% .5E",tmp->data->result[index].im);
          break;
        case FP_MAGN:
          value = (double)
          	(sqrt(pow(tmp->data->result[index].re,2.0) + pow(tmp->data->result[index].im,2.0)));
          fprintf(fft_file,"% .5E",value);
          break;
        case FP_PHASE:
          value = atan2(tmp->data->result[index].im,tmp->data->result[index].re);
          fprintf(fft_file,"% .5E",value);
          break;
        case FP_DB:
          value = (double)
          	(20.0 * log10(sqrt(pow(tmp->data->result[index].re,2.0)
          	+ pow(tmp->data->result[index].im,2.0))));
          fprintf(fft_file,"% .5E",value);
          break;
         }
       if (tmp->next != NULL)
         fprintf(fft_file,"%c",TAB_CHAR);
       tmp = tmp->next;
       }
    fprintf(fft_file,"\n");
    }
}


long bit_reversed_index(index,stages)
long index;
long stages;
{
long		result;
long		stage;
long		hold;

result = 0;
for (stage = 0; stage < stages; stage++) {
  hold = (index >> stage) & 0x01;
  result += (hold << (stages - stage - 1));
  }


return(result);
}


long get_max_stages(N)
long N;
{
long i;

for (i = 0; i < 30; i++) {
  if (((N >> i) & 0x01) == 1)
    break;
  }

return((long) i);
}


void compute_fft(fft_x,N)
gck_complex *fft_x;
long N;
{
long butterfly;
long butterfly_first_position;
long butterfly_index_spacing;
long max_butterflies;
long max_stages;
long stage;
long element_position;
register double ti;
register double tj;
long 	inner_loop;
long 	inner_loop_upper_limit;
double alpha;
long outer_loop;
long step_factor;
long twiddle;
long loop;
double twi[2],twj[2];
gck_complex *twiddle_array;
gck_complex *xn,*hold;
boolean can_fft;
double junk1;
long junk2;
register long k,n;

if (PRINT_PAINFUL)
  fprintf(stderr,"N is %ld \n",N);

k = 0;
for (n = 0; n < 30; n++) {	/* 30 because a long has 32 bits */
  if (((N >> n) & 0x01) == (long) 1)
    k++;
  }
if (k == 1)
  can_fft = TRUE;
else
  can_fft = FALSE;

if (can_fft) {
  if (PRINT_PAINFUL)
    fprintf(stderr,"Performing FFT ... \n");
  twiddle_array = (gck_complex *) c_malloc(sizeof(gck_complex) * N);
  max_stages = get_max_stages(N);
  max_butterflies = (N >> 1);
  butterfly_index_spacing = (N >> 1); /* initial spacing */
  for (stage = 0; stage < max_stages; stage++) {
    if (stage != 0) {
      element_position = 0;
      /* compute twiddle factor... */
      step_factor = (1 << (stage - 1) * 1);
      for (outer_loop = 0; outer_loop < (1 << (stage * 1)); outer_loop++) {
        inner_loop_upper_limit = (N / (step_factor << 1));
        for (inner_loop = 0; inner_loop < inner_loop_upper_limit; inner_loop++) {
          twiddle = (step_factor * (outer_loop % 2) * inner_loop);			
          alpha = (-2.0 * PI * (double) twiddle) / ((double) N);
          twiddle_array[element_position].re = cos(alpha);
          twiddle_array[element_position].im = sin(alpha);
          element_position++;
          }
        }
      }
    /* twiddle_all_elements() */
    if (stage != 0) {
      for (element_position = 0; element_position < N; element_position++) {
        ti = fft_x[element_position].re;
        tj = fft_x[element_position].im;
        fft_x[element_position].re = (ti * twiddle_array[element_position].re)
          - (tj * twiddle_array[element_position].im);
        fft_x[element_position].im = (ti * twiddle_array[element_position].im)
          + (tj * twiddle_array[element_position].re);
        }
      }
  
    /* must butterfly all next */
    for (butterfly = 0; butterfly < max_butterflies; butterfly++) {
      butterfly_first_position = butterfly / butterfly_index_spacing;
      butterfly_first_position *= (butterfly_index_spacing << 1);
      butterfly_first_position += (butterfly % butterfly_index_spacing);
      /* radix_2_butterfly(butterfly_first_position,butterfly_index_spacing); */
      for (loop = 0; loop < 2; loop++) {
        element_position = butterfly_first_position + (loop * butterfly_index_spacing);
        twi[loop] = fft_x[element_position].re;
        twj[loop] = fft_x[element_position].im;
        }
  
    /* Oppenheim and Schafer, Discrete Time Signal Processing, Figure 9.6, page 591 */
      element_position = butterfly_first_position;
      fft_x[element_position].re  	=	twi[0] + twi[1];
      fft_x[element_position].im 	=	twj[0] + twj[1];
      element_position += butterfly_index_spacing;
      fft_x[element_position].re 	=	twi[0] - twi[1];
      fft_x[element_position].im 	=	twj[0] - twj[1];
      }
    butterfly_index_spacing >>= 1;
    }
  /* bit reversal performed during printout...*/
  free(twiddle_array);
}
else {
  if (PRINT_NORMAL) {
    fprintf(stderr,"*Warning:  Performing DFT ... This may take a while.\n");
    }
  fft_must_reorder = FALSE;

 /* now, a DFT */

 /* Equation 8.61, Oppenheim and Schafer, Discrete-Time Signal Processing */

  twiddle_array = (gck_complex *) c_malloc(sizeof(gck_complex) * N);
  xn = (gck_complex *) c_malloc(sizeof(gck_complex) * N);

  for (k = 0; k < N; k++) {
    xn[k].re = fft_x[k].re;
    xn[k].im = fft_x[k].im;
    alpha = (-2.0 * PI * (double) k) / ((double) N);
    twiddle_array[k].re = cos(alpha);
    twiddle_array[k].im = sin(alpha);
    }

  for (k = 0; k < N; k++) {
    ti = 0.0;    tj = 0.0;
    for (n = 0; n < N; n++) {
      element_position = (k * n) % N;
      ti += xn[n].re * twiddle_array[element_position].re - xn[n].im * twiddle_array[element_position].im;
      tj += xn[n].re * twiddle_array[element_position].im + xn[n].im * twiddle_array[element_position].re;
      }
    fft_x[k].re = ti;
    fft_x[k].im = tj;
    }

  free(xn);
  free(twiddle_array);
  }
}

void window_data(fft_x,N)
gck_complex *fft_x;
long N;
{
long n;
long spare;
double scalar;

  if ((PRINT_PAINFUL) && (fft_window != WINDOW_RECTANGULAR))
    fprintf(stderr,"Windowing Data ... \n");

  switch(fft_window) {
    case WINDOW_RECTANGULAR:
      /* Whew, that was easy. */
      break;
    case WINDOW_TRIANGULAR:
      if (((double) N / 2.0) - (double) (long) (N / 2) == 0.5)
        spare = 1;
      else
        spare = 0;
      for (n = 0; n <= (N/2); n++) {
        scalar = 2.0 * (double) n / N;
        fft_x[n].re *= scalar;
        }
      for (n = (N/2) + spare; n < N; n++) {
        scalar = 2.0 - 2.0 * (double) n / N;
        fft_x[n].re *= scalar;
        }
      break;
    case WINDOW_HANN:
      for (n = 0; n < N; n++) {
        scalar = 0.50 - 0.50 * cos(TWOPI * (double) n / (double) N);
        fft_x[n].re *= scalar;
        }
      break;
    case WINDOW_HAMMING:
      for (n = 0; n < N; n++) {
        scalar = 0.54 - 0.46 * cos(TWOPI * (double) n / (double) N);
        fft_x[n].re *= scalar;
        }
      break;
    case WINDOW_BLACKMAN:
      for (n = 0; n < N; n++) {
        scalar = 0.42 - 0.50 * cos(TWOPI * (double) n / (double) N) + 0.08 * cos(2.0 * TWOPI * (double) n / (double) N);
        fft_x[n].re *= scalar;
        }
      break;
    }
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.