/* mxfftd.c: double precision version of mxfft.c This file is part of the CDP System. The CDP System is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The CDP System is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the CDP System; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* This program converted from the FORTRAN routines by Singleton in * Section 1.4 of "Programs for Digital Signal Processing", IEEE Press, 1979. * Conversion by Trevor Wishart and Keith Henderson, York Univ. */ #include #include #include void fft_(double *, double *, int, int, int, int); void fftmx(double *, double *, int, int, int, int, int, int*, double *, double *, double *, double *, int *, int[]); void reals_(double *, double *, int, int); /* *----------------------------------------------------------------------- * subroutine: fft * multivariate complex fourier transform, computed in place * using mixed-radix fast fourier transform algorithm. *----------------------------------------------------------------------- * * this is the call from C: * fft_(anal,banal,&one,&N2,&one,&mtwo); * CHANGED TO:- * fft_(anal,banal,one,N2,one,mtwo); */ void fft_(double *a, double *b, int nseg, int n, int nspn, int isn) /* *a, pointer to array 'anal' */ /* *b; pointer to array 'banal' */ { int nfac[/*16*/32]; /* (2023)WAS 16. These are one bigger than needed */ /* because wish to use Fortran array */ /* index which runs 1 to n, not 0 to n */ int m = 0, nf, k, kt, ntot, j, jj, maxf, maxp=-1; /* work space pointers */ double *at, *ck, *bt, *sk; int *np; /* reduce the pointers to input arrays - by doing this, FFT uses FORTRAN indexing but retains compatibility with C arrays */ a--; b--; /* * determine the factors of n */ k=nf=abs(n); if (nf==1) return; nspn=abs(nf*nspn); ntot=abs(nspn*nseg); if (isn*ntot == 0) { printf("\nerror - zero in fft parameters %d %d %d %d", nseg, n, nspn, isn); return; } for (m=0; !(k%16); nfac[++m]=4,k/=16); for (j=3,jj=9; jj<=k; j+=2,jj=j*j) for (; !(k%jj); nfac[++m]=j,k/=jj); if (k<=4) { kt = m; nfac[m+1] = k; if (k != 1) m++; } else { if (k%4==0) { nfac[++m]=2; k/=4; } kt = m; maxp = (kt+kt+2 > k-1 ? kt+kt+2 : k-1); for (j=2; j<=k; j=1+((j+1)/2)*2) if (k%j==0) { nfac[++m]=j; k/=j; } } if (m <= kt+1) maxp = m + kt + 1; if (m+kt > 15) { printf("\nerror - fft parameter n has more than 15 factors : %d", n); return; } if (kt!=0) { j = kt; while (j) nfac[++m]=nfac[j--]; } maxf = nfac[m-kt]; if (kt > 0 && maxf 0 ( reverse transform ) */ if (isn < 0) { s72 = -s72; s120 = -s120; rad = -rad;} else { ak = 1.0/(double)n; for (j=1; j<=nt;j += inc) { a[j] *= (double)ak; b[j] *= (double)ak; } } kspan = ks; nn = nt - inc; jc = ks/n; /* sin, cos values are re-initialised each lim steps */ lim = 32; klim = lim * jc; i = 0; jf = 0; maxf = m - (*kt); maxf = nfac[maxf]; if ((*kt) > 0 && maxf < nfac[*kt]) maxf = nfac[*kt]; /* * compute fourier transform */ lbl40: dr = (8.0 * (double)jc)/((double)kspan); /*************************** APRIL 1991 POW & POW2 not WORKING.. REPLACE ******* cd = 2.0 * (pow2 ( sin((double)0.5 * dr * rad)) ); *******************************************************************************/ xx = sin((double)0.5 * dr * rad); cd = 2.0 * xx * xx; sd = sin(dr * rad); kk = 1; if (nfac[++i]!=2) goto lbl110; /* * transform for factor of 2 (including rotation factor) */ kspan /= 2; k1 = kspan + 2; do { do { k2 = kk + kspan; ak = a[k2]; bk = b[k2]; a[k2] = (a[kk]) - (double)ak; b[k2] = (b[kk]) - (double)bk; a[kk] = (a[kk]) + (double)ak; b[kk] = (b[kk]) + (double)bk; kk = k2 + kspan; } while (kk <= nn); kk -= nn; } while (kk <= jc); if (kk > kspan) goto lbl350; lbl60: c1 = 1.0 - cd; s1 = sd; mm = (k1/2 < klim ? k1/2 :klim); goto lbl80; lbl70: ak = c1 - ((cd*c1)+(sd*s1)); s1 = ((sd*c1)-(cd*s1)) + s1; c1 = ak; lbl80: do { do { k2 = kk + kspan; ak = a[kk] - a[k2]; bk = b[kk] - b[k2]; a[kk] = a[kk] + a[k2]; b[kk] = b[kk] + b[k2]; a[k2] = (double)((c1 * ak) - (s1 * bk)); b[k2] = (double)((s1 * ak) + (c1 * bk)); kk = k2 + kspan; } while (kk < nt); k2 = kk - nt; c1 = -c1; kk = k1 - k2; } while (kk > k2); kk += jc; if (kk <= mm) goto lbl70; if (kk < k2) goto lbl90; k1 += (inc + inc); kk = ((k1-kspan)/2) + jc; if (kk <= (jc+jc)) goto lbl60; goto lbl40; lbl90: s1 = ((double)((kk-1)/jc)) * dr * rad; c1 = cos(s1); s1 = sin(s1); mm = (k1/2 < mm+klim ? k1/2 : mm+klim); goto lbl80; /* * transform for factor of 3 (optional code) */ lbl100: k1 = kk + kspan; k2 = k1 + kspan; ak = a[kk]; bk = b[kk]; aj = a[k1] + a[k2]; bj = b[k1] + b[k2]; a[kk] = (double)(ak + aj); b[kk] = (double)(bk + bj); ak += (-0.5 * aj); bk += (-0.5 * bj); aj = (a[k1] - a[k2]) * s120; bj = (b[k1] - b[k2]) * s120; a[k1] = (double)(ak - bj); b[k1] = (double)(bk + aj); a[k2] = (double)(ak + bj); b[k2] = (double)(bk - aj); kk = k2 + kspan; if (kk < nn) goto lbl100; kk -= nn; if (kk <= kspan) goto lbl100; goto lbl290; /* * transform for factor of 4 */ lbl110: if (nfac[i] != 4) goto lbl230; kspnn = kspan; kspan = kspan/4; lbl120: c1 = 1.0; s1 = 0; mm = (kspan < klim ? kspan : klim); goto lbl150; lbl130: c2 = c1 - ((cd*c1)+(sd*s1)); s1 = ((sd*c1)-(cd*s1)) + s1; /* * the following three statements compensate for truncation * error. if rounded arithmetic is used, substitute * c1=c2 * * c1 = (0.5/(pow2(c2)+pow2(s1))) + 0.5; * s1 = c1*s1; * c1 = c1*c2; */ c1 = c2; lbl140: c2 = (c1 * c1) - (s1 * s1); s2 = c1 * s1 * 2.0; c3 = (c2 * c1) - (s2 * s1); s3 = (c2 * s1) + (s2 * c1); lbl150: k1 = kk + kspan; k2 = k1 + kspan; k3 = k2 + kspan; akp = a[kk] + a[k2]; akm = a[kk] - a[k2]; ajp = a[k1] + a[k3]; ajm = a[k1] - a[k3]; a[kk] = (double)(akp + ajp); ajp = akp - ajp; bkp = b[kk] + b[k2]; bkm = b[kk] - b[k2]; bjp = b[k1] + b[k3]; bjm = b[k1] - b[k3]; b[kk] = (double)(bkp + bjp); bjp = bkp - bjp; if (isn < 0) goto lbl180; akp = akm - bjm; akm = akm + bjm; bkp = bkm + ajm; bkm = bkm - ajm; if (s1 == 0.0) goto lbl190; lbl160: a[k1] = (double)((akp*c1) - (bkp*s1)); b[k1] = (double)((akp*s1) + (bkp*c1)); a[k2] = (double)((ajp*c2) - (bjp*s2)); b[k2] = (double)((ajp*s2) + (bjp*c2)); a[k3] = (double)((akm*c3) - (bkm*s3)); b[k3] = (double)((akm*s3) + (bkm*c3)); kk = k3 + kspan; if (kk <= nt) goto lbl150; lbl170: kk -= (nt - jc); if (kk <= mm) goto lbl130; if (kk < kspan) goto lbl200; kk -= (kspan - inc); if (kk <= jc) goto lbl120; if (kspan==jc) goto lbl350; goto lbl40; lbl180: akp = akm + bjm; akm = akm - bjm; bkp = bkm - ajm; bkm = bkm + ajm; if (s1 != 0.0) goto lbl160; lbl190: a[k1] = (double)akp; b[k1] = (double)bkp; a[k2] = (double)ajp; b[k2] = (double)bjp; a[k3] = (double)akm; b[k3] = (double)bkm; kk = k3 + kspan; if (kk <= nt) goto lbl150; goto lbl170; lbl200: s1 = ((double)((kk-1)/jc)) * dr * rad; c1 = cos(s1); s1 = sin(s1); mm = (kspan < mm+klim ? kspan : mm+klim); goto lbl140; /* * transform for factor of 5 (optional code) */ lbl210: c2 = (c72*c72) - (s72*s72); s2 = 2.0 * c72 * s72; lbl220: k1 = kk + kspan; k2 = k1 + kspan; k3 = k2 + kspan; k4 = k3 + kspan; akp = a[k1] + a[k4]; akm = a[k1] - a[k4]; bkp = b[k1] + b[k4]; bkm = b[k1] - b[k4]; ajp = a[k2] + a[k3]; ajm = a[k2] - a[k3]; bjp = b[k2] + b[k3]; bjm = b[k2] - b[k3]; aa = a[kk]; bb = b[kk]; a[kk] = (double)(aa + akp + ajp); b[kk] = (double)(bb + bkp + bjp); ak = (akp*c72) + (ajp*c2) + aa; bk = (bkp*c72) + (bjp*c2) + bb; aj = (akm*s72) + (ajm*s2); bj = (bkm*s72) + (bjm*s2); a[k1] = (double)(ak - bj); a[k4] = (double)(ak + bj); b[k1] = (double)(bk + aj); b[k4] = (double)(bk - aj); ak = (akp*c2) + (ajp*c72) + aa; bk = (bkp*c2) + (bjp*c72) + bb; aj = (akm*s2) - (ajm*s72); bj = (bkm*s2) - (bjm*s72); a[k2] = (double)(ak - bj); a[k3] = (double)(ak + bj); b[k2] = (double)(bk + aj); b[k3] = (double)(bk - aj); kk = k4 + kspan; if (kk < nn) goto lbl220; kk -= nn; if (kk <= kspan) goto lbl220; goto lbl290; /* * transform for odd factors */ lbl230: k = nfac[i]; kspnn = kspan; kspan /= k; if (k==3) goto lbl100; if (k==5) goto lbl210; if (k==jf) goto lbl250; jf = k; s1 = rad/(((double)(k))/8.0); c1 = cos(s1); s1 = sin(s1); ck[jf] = 1.0; sk[jf] = 0.0; for (j=1; j jf) jj -= jf; } while (k < jf); k = jf - j; a[k1] = (double)(ak - bj); b[k1] = (double)(bk + aj); a[k2] = (double)(ak + bj); b[k2] = (double)(bk - aj); j++; if (j < k) goto lbl270; kk += kspnn; if (kk <= nn) goto lbl250; kk -= nn; if (kk<=kspan) goto lbl250; /* * multiply by rotation factor (except for factors of 2 and 4) */ lbl290: if (i==m) goto lbl350; kk = jc + 1; lbl300: c2 = 1.0 - cd; s1 = sd; mm = (kspan < klim ? kspan : klim); goto lbl320; lbl310: c2 = c1 - ((cd*c1) + (sd*s1)); s1 = s1 + ((sd*c1) - (cd*s1)); lbl320: c1 = c2; s2 = s1; kk += kspan; lbl330: ak = a[kk]; a[kk] = (double)((c2*ak) - (s2 * b[kk])); b[kk] = (double)((s2*ak) + (c2 * b[kk])); kk += kspnn; if (kk <= nt) goto lbl330; ak = s1*s2; s2 = (s1*c2) + (c1*s2); c2 = (c1*c2) - ak; kk -= (nt - kspan); if (kk <= kspnn) goto lbl330; kk -= (kspnn - jc); if (kk <= mm) goto lbl310; if (kk < kspan) goto lbl340; kk -= (kspan - jc - inc); if (kk <= (jc+jc)) goto lbl300; goto lbl40; lbl340: s1 = ((double)((kk-1)/jc)) * dr * rad; c2 = cos(s1); s1 = sin(s1); mm = (kspan < mm+klim ? kspan :mm+klim); goto lbl320; /* * permute the results to normal order---done in two stages * permutation for square factors of n */ lbl350: np[1] = ks; if (!(*kt)) goto lbl440; k = *kt + *kt + 1; if (m < k) k--; np[k+1] = jc; for (j=1; j < k; j++,k--) { np[j+1] = np[j] / nfac[j]; np[k] = np[k+1] * nfac[j]; } k3 = np[k+1]; kspan = np[2]; kk = jc + 1; k2 = kspan + 1; j = 1; if (n != ntot) goto lbl400; /* * permutation for single-variate transform (optional code) */ lbl370: do { ak = a[kk]; a[kk] = a[k2]; a[k2] = (double)ak; bk = b[kk]; b[kk] = b[k2]; b[k2] = (double)bk; kk += inc; k2 += kspan; } while (k2 < ks); lbl380: do { k2 -= np[j++]; k2 += np[j+1]; } while (k2 > np[j]); j = 1; lbl390: if (kk < k2) { goto lbl370; } kk += inc; k2 += kspan; if (k2 < ks) goto lbl390; if (kk < ks) goto lbl380; jc = k3; goto lbl440; /* * permutation for multivariate transform */ lbl400: do { do { k = kk + jc; do { ak = a[kk]; a[kk] = a[k2]; a[k2] = (double)ak; bk = b[kk]; b[kk] = b[k2]; b[k2] = (double)bk; kk += inc; k2 += inc; } while (kk < k); kk += (ks - jc); k2 += (ks - jc); } while (kk < nt); k2 -= (nt - kspan); kk -= (nt - jc); } while (k2 < ks); lbl420: do { k2 -= np[j++]; k2 += np[j+1]; } while (k2 > np[j]); j = 1; lbl430: if (kk < k2) goto lbl400; kk += jc; k2 += kspan; if (k2 < ks) goto lbl430; if (kk < ks) goto lbl420; jc = k3; lbl440: if ((2*(*kt))+1 >= m) return; kspnn = *(np + *(kt) + 1); j = m - *kt; nfac[j+1] = 1; lbl450: nfac[j] = nfac[j] * nfac[j+1]; j--; if (j != *kt) goto lbl450; *kt = *(kt) + 1; nn = nfac[*kt] - 1; jj = 0; j = 0; goto lbl480; lbl460: jj -= k2; k2 = kk; kk = nfac[++k]; lbl470: jj += kk; if (jj >= k2) goto lbl460; np[j] = jj; lbl480: k2 = nfac[*kt]; k = *kt + 1; kk = nfac[k]; j++; if (j <= nn) goto lbl470; /* Determine permutation cycles of length greater than 1 */ j = 0; goto lbl500; lbl490: k = kk; kk = np[k]; np[k] = -kk; if (kk != j) goto lbl490; k3 = kk; lbl500: kk = np[++j]; if (kk < 0) goto lbl500; if (kk != j) goto lbl490; np[j] = -j; if (j != nn) goto lbl500; maxf *= inc; /* Perform reordering following permutation cycles */ goto lbl570; lbl510: j--; if (np[j] < 0) goto lbl510; jj = jc; lbl520: kspan = jj; if (jj > maxf) kspan = maxf; jj -= kspan; k = np[j]; kk = (jc*k) + i + jj; k1 = kk + kspan; k2 = 0; lbl530: k2++; at[k2] = a[k1]; bt[k2] = b[k1]; k1 -= inc; if (k1 != kk) goto lbl530; lbl540: k1 = kk + kspan; k2 = k1 - (jc * (k + np[k])); k = -(np[k]); lbl550: a[k1] = a[k2]; b[k1] = b[k2]; k1 -= inc; k2 -= inc; if (k1 != kk) goto lbl550; kk = k2; if (k != j) goto lbl540; k1 = kk + kspan; k2 = 0; lbl560: k2++; a[k1] = at[k2]; b[k1] = bt[k2]; k1 -= inc; if (k1 != kk) goto lbl560; if (jj) goto lbl520; if (j != 1) goto lbl510; lbl570: j = k3 + 1; nt -= kspnn; i = nt - inc + 1; if (nt >= 0) goto lbl510; return; } /* *----------------------------------------------------------------------- * subroutine: reals * used with 'fft' to compute fourier transform or inverse for real data *----------------------------------------------------------------------- * this is the call from C: * reals_(anal,banal,N2,mtwo); * which has been changed from CARL call * reals_(anal,banal,&N2,&mtwo); */ void reals_(double *a, double *b, int n, int isn) /* *a, a refers to an array of floats 'anal' */ /* *b; b refers to an array of floats 'banal' */ /* See IEEE book for a long comment here on usage */ { int inc, j, k, lim, mm,ml, nf,nk,nh; double aa,ab, ba,bb, cd,cn, dr, em, rad,re, sd,sn; double xx; /******* ADDED APRIL 1991 ******/ /* adjust input array pointers (called from C) */ a--; b--; inc=abs(isn); nf=abs(n); if (nf*isn==0) { printf("\nerror - zero in reals parameters : %d : %d ",n,isn); return; } nk = (nf*inc) + 2; nh = nk/2; /***************************** rad = atan((double)1.0); ******************************/ rad = 0.785398163397448278900; dr = -4.0/(double)(nf); /********************************** POW2 REMOVED APRIL 1991 ***************** cd = 2.0 * (pow2(sin((double)0.5 * dr * rad))); *****************************************************************************/ xx = sin((double)0.5 * dr * rad); cd = 2.0 * xx * xx; sd = sin(dr * rad); /* * sin,cos values are re-initialised each lim steps */ lim = 32; mm = lim; ml = 0; sn = 0.0; if (isn<0) { cn = 1.0; a[nk-1] = a[1]; b[nk-1] = b[1]; } else { cn = -1.0; sd = -sd; } for (j=1;j<=nh;j+=inc) { k = nk - j; aa = a[j] + a[k]; ab = a[j] - a[k]; ba = b[j] + b[k]; bb = b[j] - b[k]; re = (cn*ba) + (sn*ab); em = (sn*ba) - (cn*ab); b[k] = (double)((em-bb)*0.5); b[j] = (double)((em+bb)*0.5); a[k] = (double)((aa-re)*0.5); a[j] = (double)((aa+re)*0.5); ml++; if (ml!=mm) { aa = cn - ((cd*cn)+(sd*sn)); sn = ((sd*cn) - (cd*sn)) + sn; cn = aa;} else { mm +=lim; sn = ((double)ml) * dr * rad; cn = cos(sn); if (isn>0) cn = -cn; sn = sin(sn); } } return; }