-
Jan Thorbecke authoredJan Thorbecke authored
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;
}
*/