Skip to content
Snippets Groups Projects
lib_fft.c 12.23 KiB
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <limits.h>
#include <float.h>
#include <assert.h>
#include "genfft.h"
#include "kiss_fft.h"


void fft(int n, REAL *real, REAL *imag);
void ifft(int n, REAL *real, REAL *imag);
void realifft(int n, REAL *real);
void realfft(int n, REAL *real);

void ccdft(complex *cdata, int n, int sign);
void rcdft(REAL *rdata, complex *cdata, int n, int sign);
void crdft(complex *cdata, REAL *rdata, int n, int sign);

int npfar (int nmin);
int npfa (int nmin);
void pfarc (int isign, int n, REAL rz[], complex cz[]);
void pfa2rc (int isign, int idim, int n1, int n2, REAL rz[], complex cz[]);
void pfacr (int isign, int n, complex cz[], REAL rz[]);
void pfa2cr (int isign, int idim, int n1, int n2, complex cz[], REAL rz[]);
void pfacc (int isign, int n, complex z[]);
void pfamcc (int isign, int n, int nt, int k, int kt, complex z[]);

#ifndef NINT
#define NINT(x) ((int)((x)>0.0?(x)+0.5:(x)-0.5))
#endif

/**
*
*   DESCRIPTION: Local FFT implementation
*
*   USAGE:
*	     void rc1_fft(REAL *data, complex *cdata, int n, int sign)
*        void rcm_fft(REAL *data, complex *cdata, int n1, int n2, int sign)
*        void cr1_fft(complex *cdata, REAL *data, int n, int sign)
*        void crm_fft(complex *cdata, REAL *data, int n1, int n2, int sign)
*        void cc1_fft(complex *cdata, int n, int sign)
*        void ccm_fft(complex *cdata, int n1, int n2, int sign)
*
*   INPUT:  see the documentation in the files without '_'
*
*   OUTPUT: see the documentation in the files without '_'
*
*   AUTHOR:
*           Jan Thorbecke (janth@xs4all.nl)
*           The Netherlands
*
*----------------------------------------------------------------------
*  REVISION HISTORY:
*  VERSION        AUTHOR          DATE         COMMENT
*    1.0       Jan Thorbecke    Feb  '94    Initial version 
*    1.1       Jan Thorbecke    June '94    faster Mayer local FFT 
*    2.0       Jan Thorbecke    July '97    make it more general
*
***********************************************************************/

void rc1_fft(REAL *data, complex *cdata, int n, int sign)
{
	int    j;
	REAL *datft;

	if (NINT(pow(2.0, (double)NINT(log((double)n)/log(2.0)))) != n) {
		if (npfar(n) == n) pfarc(sign,n,data,cdata);
		else rcdft(data,cdata,n,sign);
	}
	else {
		datft = (REAL *)malloc(n*sizeof(REAL));
		if (datft == NULL) fprintf(stderr,"rc1_fft: memory allocation error\n");
	
		for (j = 0; j < n; j++) datft[j] = (REAL)data[j];
		realfft(n, datft);
		cdata[0].i = 0.0;
		for (j = 0; j < n/2; j++) {
			cdata[j].r = (REAL)datft[j]; 
			cdata[j+1].i = sign*(REAL)datft[n-j-1]; 
		}
		cdata[n/2].r = datft[n/2];
		cdata[n/2].i = 0.0; 
	
		free(datft);
	}

	return;
}

void rcm_fft(REAL *data, complex *cdata, int n1, int n2, int ldr, int ldc, int sign)
{
	int    j, i;
	REAL *datft;

	if (NINT(pow(2.0, (double)NINT(log((double)n1)/log(2.0)))) != n1) {
		if (npfar(n1) == n1) {
			if (ldr == n1 && ldc == n2) {
				pfa2rc(sign, 1, n1, n2, data, cdata);
			}
			else {
				for (i = 0; i < n2; i++) {
					pfarc(sign, n1, &data[i*ldr], &cdata[i*ldc]);
				}
			}
		}
		else {
			for (i = 0; i < n2; i++) {
				rcdft(&data[i*ldr], &cdata[i*ldc], n1, sign);
			}
		}
	}
	else {
		datft = (REAL *)malloc(n1*sizeof(REAL));
		if (datft == NULL) fprintf(stderr,"rcm_fft: memory allocation error\n");
	
		for (i = 0; i < n2; i++) {
			for (j = 0; j < n1; j++) datft[j] = (REAL)data[i*ldr+j];
			realfft(n1, datft);
			cdata[i*ldc].i = 0.0;
			for (j = 0; j < n1/2; j++) {
				cdata[i*ldc+j].r = (REAL)datft[j]; 
				cdata[i*ldc+j+1].i = sign*(REAL)datft[n1-j-1]; 
			}
			cdata[i*ldc+n1/2].r = (REAL)datft[n1/2]; 
			cdata[i*ldc+n1/2].i = 0.0; 
		}
	
		free(datft);
	}

	return;
}

void cr1_fft(complex *cdata, REAL *data, int n, int sign)
{
	int    j;
	REAL *datft;

	if (NINT(pow(2.0, (double)NINT(log((double)n)/log(2.0)))) != n) {
		if (npfar(n) == n) pfacr(sign,n,cdata,data);
		else crdft(cdata,data,n,sign);
	}
	else {
		datft = (REAL *)malloc(n*sizeof(REAL));
		if (datft == NULL) fprintf(stderr,"cr1_fft: memory allocation error\n");

		for (j = 0; j < n/2; j++) {
			datft[j] = (REAL)cdata[j].r;
			datft[n-1-j] = (REAL)cdata[j+1].i;
		}
		datft[n/2] = (REAL)cdata[n/2].r;

		realifft(n, datft);
	
		if (sign == -1) {
			for (j = 0; j < n; j++) data[j] = (REAL)datft[j];
		}
		else if (sign == 1) {
			for (j = 1; j < n; j++) data[j] = (REAL)datft[n-j];
			data[0] = (REAL)datft[0];
		}
	
		free(datft);
	}
	
	return;
}

void crm_fft(complex *cdata, REAL *data, int n1, int n2, int ldc, int ldr, int sign)
{
	int    j, i;
	REAL *datft;

	/* non-power of 2 uses FFT from SU for prime numbers or default fft */
	if (NINT(pow(2.0, (double)NINT(log((double)n1)/log(2.0)))) != n1) {
		if (npfar(n1) == n1) {
			if (ldr == n1 && ldc == n2) {
				pfa2cr(sign, 1, n1, n2, cdata, data);
			}
			else {
				for (i = 0; i < n2; i++) {
					pfacr(sign, n1, &cdata[i*ldc], &data[i*ldr]);
				}
			}
		}
		else {
			for (i = 0; i < n2; i++) {
				crdft(&cdata[i*ldc], &data[i*ldr], n1, sign);
			}
		}
	}
	else {
		datft = (REAL *)malloc(n1*sizeof(REAL));
		if (datft == NULL) fprintf(stderr,"crm_fft: memory allocation error\n");
	
		for (i = 0; i < n2; i++) {
			for (j = 0; j < n1/2; j++) {
				datft[j] = (REAL)cdata[i*ldc+j].r;
				datft[n1-1-j] = (REAL)cdata[i*ldc+j+1].i;
			}
			datft[n1/2] = (REAL)cdata[i*ldc+n1/2].r;
	
			realifft(n1, datft);
	
			if (sign == -1) {
				for (j = 0; j < n1; j++) data[i*ldr+j] = (REAL)datft[j];
			}
			else if (sign == 1) {
				for (j = 1; j < n1; j++) data[i*ldr+j] = (REAL)datft[n1-j];
				data[i*ldr] = (REAL)datft[0];
			}
		}
	
		free(datft);
	}

	return;
}


void cc1_fft(complex *cdata, int n, int sign)
{
	int    j, id, max_threads;
	REAL  *real, *imag;
	static kiss_fft_cfg st[MAX_NUMTHREADS]; 
    static int nprev[MAX_NUMTHREADS];

#ifdef _OPENMP
    //max_threads = omp_get_max_threads();
    id = omp_get_thread_num();
#else 
    //max_threads = 1;
    id = 0;
#endif  


	if (NINT(pow(2.0, (double)NINT(log((double)n)/log(2.0)))) != n) {
		if (npfa(n) == n) pfacc(sign, n, cdata);
		else { /* use kiss_fft */
    		if (n != nprev[id]) {
        		if (nprev[id] != 0) free(st[id]);
				st[id] = kiss_fft_alloc( n ,0 ,0, 0);
        		nprev[id] = n;
			}
    		kiss_fft(st[id] ,cdata, n, sign);
		}
	}
	else {
    	if (n != nprev[id]) {
        	if (nprev[id] != 0) free(st[id]);
			st[id] = kiss_fft_alloc( n ,0 ,0, 0);
        	nprev[id] = n;
		}
    	kiss_fft(st[id] ,cdata, n, sign);

/*
		real = (REAL *)malloc(n*sizeof(REAL));
		if (real == NULL) fprintf(stderr,"cc1_fft: memory allocation error\n");
		imag = (REAL *)malloc(n*sizeof(REAL));
		if (imag == NULL) fprintf(stderr,"cc1_fft: memory allocation error\n");
	
		for (j = 0; j < n; j++) {
			real[j] = (double)cdata[j].r;
			imag[j] = (double)cdata[j].i;
		}

		if (sign < 0) fft(n, real, imag);
		else ifft(n, real, imag);

		for (j = 0; j < n; j++) {
			cdata[j].r = (REAL)real[j];
			cdata[j].i = (REAL)imag[j];
		}

		free(real);
		free(imag);
*/
	}

	return;
}

void ccm_fft(complex *cdata, int n1, int n2, int ld1, int sign)
{
	int    i, j;
	REAL  *real, *imag;

	if (NINT(pow(2.0, (double)NINT(log((double)n1)/log(2.0)))) != n1) {
		if (npfa(n1) == n1) pfamcc(sign, n1, n2, 1, ld1, cdata);
		else {
			for (i = 0; i < n2; i++) cc1_fft(&cdata[i*ld1],n1,sign);
		}
	}
	else {
		for (i = 0; i < n2; i++) cc1_fft(&cdata[i*ld1],n1,sign);
/*
		real = (REAL *)malloc(n1*sizeof(REAL));
		if (real == NULL) fprintf(stderr,"ccm_fft: memory allocation error\n");
		imag = (REAL *)malloc(n1*sizeof(REAL));
		if (imag == NULL) fprintf(stderr,"ccm_fft: memory allocation error\n");
	
		for (i = 0; i < n2; i++) {
			for (j = 0; j < n1; j++) {
				real[j] = (REAL)cdata[i*ld1+j].r;
				imag[j] = (REAL)cdata[i*ld1+j].i;
			}
	
			if (sign < 0) fft(n1, real, imag);
			else ifft(n1, real, imag);
	
			for (j = 0; j < n1; j++) {
				cdata[i*ld1+j].r = (REAL)real[j];
				cdata[i*ld1+j].i = (REAL)imag[j];
			}

		}

		free(real);
		free(imag);
*/
	}

	return;
}

void ccdft(complex *cdata, int n, int sign)
{
	int i, j, k; 
	REAL scl, sumr, sumi;
	complex *tmp;
	static REAL *csval;
	static int nprev=0;

	if (nprev != n) {
		scl = 2.0*M_PI/(REAL)n;
		if (csval) free(csval);
		csval = (REAL *) malloc(2*n*sizeof(REAL));
		for (i=0; i<n; i++) {
			csval[2*i] = cos(scl*i);
			csval[2*i+1] = sin(scl*i);
		}
		nprev = n;
	}

	tmp = (complex *) malloc(n*sizeof(complex));

	for (i=0; i<n; i++) {
		sumr = sumi = 0.0;
		for (j=0; j<n; j++) {
			k = 2*((i*j)%n);
			sumr += cdata[j].r*csval[k]-sign*cdata[j].i*csval[k+1];
			sumi += cdata[j].i*csval[k]+sign*cdata[j].r*csval[k+1];
		}
		tmp[i].r = sumr;
		tmp[i].i = sumi;
	}

	for (i=0; i<n; i++) cdata[i] = tmp[i];
	free(tmp);

	return;
}

void rcdft(REAL *rdata, complex *cdata, int n, int sign)
{
	int i, j, k, nc, id, max_threads; 
	double scl, sumr, sumi;
	static double *csval[MAX_NUMTHREADS];
    static int nprev[MAX_NUMTHREADS];

#ifdef _OPENMP
    //max_threads = omp_get_max_threads();
    id = omp_get_thread_num();
#else 
    //max_threads = 1;
    id = 0;
#endif  

	if (nprev[id] != n) {
		scl = (2.0*M_PI)/((double)n);
		if (csval[id]) free(csval[id]);
		nc = (n+2)/2;
		csval[id] = (double *) malloc(2*n*nc*sizeof(double));
		for (i=0; i<nc; i++) {
	    	#pragma ivdep
			for (j=0; j<n; j++) {
				csval[id][2*i*j] = cos(scl*(i*j));
				csval[id][2*i*j+1] = sin(scl*(i*j));
			}
		}
		nprev[id] = n;
	}

	nc = (n+2)/2;
	for (i=0; i<nc; i++) {
		sumr = sumi = 0.0;
	    #pragma ivdep
		for (j=0; j<n; j++) {
			sumr += rdata[j]*csval[id][2*i*j];
			sumi += sign*rdata[j]*csval[id][2*i*j+1];
		}
		cdata[i].r = (REAL)sumr;
		cdata[i].i = (REAL)sumi;
	}

	return;
}

void crdft(complex *cdata, REAL *rdata, int n, int sign)
{
	int i, j, k, nc, id, max_threads; 
	double scl, sumr;
	static double *csval[MAX_NUMTHREADS];
    static int nprev[MAX_NUMTHREADS];

#ifdef _OPENMP
    //max_threads = omp_get_max_threads();
    id = omp_get_thread_num();
#else 
    //max_threads = 1;
    id = 0;
#endif  
	if (nprev[id] != n) {
		scl = (2.0*M_PI)/((double)n);
		if (csval[id]) free(csval[id]);
		nc = (n+2)/2;
		csval[id] = (double *) malloc(2*n*nc*sizeof(double));
		for (i=0; i<n; i++) {
	    	#pragma ivdep
			for (j=0; j<nc; j++) {
				csval[id][2*i*j] = cos(scl*(i*j));
				csval[id][2*i*j+1] = sin(scl*(i*j));
			}
		}
		nprev[id] = n;
	}

	nc = (n+2)/2;
	scl = (2.0*M_PI)/((double)n);
	#pragma ivdep
	for (i=0; i<n; i++) {
		sumr = 0.0;
		#pragma ivdep
		for (j=0; j<nc; j++) {
			sumr += cdata[j].r*csval[id][2*i*j]-sign*cdata[j].i*csval[id][2*i*j+1];
//            sumr += cdata[j].r*cos(scl*i*j)-sign*cdata[j].i*sin(scl*i*j);

		}
		rdata[i] = (REAL)2.0*sumr-cdata[0].r;
	}

/* there is something strange here but adding these values for even
   transformation numbers solves it ??? */
    if (!(n & 01)) {
        scl = n*0.25;
        for (i=0; i<nc-1; i++) {
            rdata[2*i] -= scl;
            rdata[2*i+1] += scl;
        }
    }

	return;
}

/*
void dc1_fft(double *data, dcomplex *cdata, int n, int sign)
{
	int    j;
	double *datft;

	if (NINT(pow(2.0, (double)NINT(log((double)n)/log(2.0)))) != n) {
		if (npfar(n) == n) pfarc(sign,n,data,cdata);
		else rcdft(data,cdata,n,sign);
	}
	else {
		fprintf(stderr,"Using double dc1_fft \n");
		datft = (double *)malloc(n*sizeof(double));
		if (datft == NULL) fprintf(stderr,"rc1_fft: memory allocation error\n");
	
		for (j = 0; j < n; j++) datft[j] = (double)data[j];
		realfft(n, datft);
		cdata[0].i = 0.0;
		for (j = 0; j < n/2; j++) {
			cdata[j].r = (double)datft[j]; 
			cdata[j+1].i = sign*(double)datft[n-j-1]; 
		}
		cdata[n/2].r = datft[n/2];
		cdata[n/2].i = 0.0; 
	
		free(datft);
	}

	return;
}


void cd1_fft(dcomplex *cdata, double *data, int n, int sign)
{
	int    j;
	double *datft;

	if (NINT(pow(2.0, (double)NINT(log((double)n)/log(2.0)))) != n) {
		if (npfar(n) == n) pfacr(sign,n,cdata,data);
		else crdft(cdata,data,n,sign);
	}
	else {
		fprintf(stderr,"Using double cd1_fft \n");
		datft = (double *)malloc(n*sizeof(double));
		if (datft == NULL) fprintf(stderr,"cr1_fft: memory allocation error\n");

		for (j = 0; j < n/2; j++) {
			datft[j] = (double)cdata[j].r;
			datft[n-1-j] = (double)cdata[j+1].i;
		}
		datft[n/2] = (double)cdata[n/2].r;

		realifft(n, datft);
	
		if (sign == -1) {
			for (j = 0; j < n; j++) data[j] = (double)datft[j];
		}
		else if (sign == 1) {
			for (j = 1; j < n; j++) data[j] = (double)datft[n-j];
			data[0] = (double)datft[0];
		}
	
		free(datft);
	}
	
	return;
}

*/