/* * Copyright (c) 1983-2023 Trevor Wishart and Composers Desktop Project Ltd * http://www.trevorwishart.co.uk * http://www.composersdesktop.com * 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 * */ #include #include #include #include #include #include /*RWD*/ // int fft_(),fftmx(),reals_(); /* *----------------------------------------------------------------------- * 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); */ int fft_(float *a, float *b, int nseg, int n, int nspn, int isn) /* a: pointer to array 'anal' */ /* b: pointer to array 'banal' */ { int exit_status; int nfac[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=0; /* work space pointers */ float *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(FINISHED); nspn=abs(nf*nspn); ntot=abs(nspn*nseg); if(isn*ntot == 0){ sprintf(errstr,"zero in FFT parameters %d %d %d %d",nseg, n, nspn, isn); return(DATA_ERROR); } 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 = max((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) { sprintf(errstr,"FFT parameter n has more than 15 factors : %d", n); return(DATA_ERROR); } if(kt!=0){ j = kt; while(j) nfac[++m]=nfac[j--]; } maxf = nfac[m-kt]; if(kt > 0) maxf = max(nfac[kt],maxf); /* allocate workspace - assume no errors! */ at = (float *) calloc(maxf,sizeof(float)); ck = (float *) calloc(maxf,sizeof(float)); bt = (float *) calloc(maxf,sizeof(float)); sk = (float *) calloc(maxf,sizeof(float)); np = (int *) calloc(maxp,sizeof(int)); /* decrement pointers to allow FORTRAN type usage in fftmx */ at--; bt--; ck--; sk--; np--; /* call fft driver */ if((exit_status = fftmx(a,b,ntot,nf,nspn,isn,m,&kt,at,ck,bt,sk,np,nfac))<0) return(exit_status); /* restore pointers before releasing */ at++; bt++; ck++; sk++; np++; /* release working storage before returning - assume no problems */ (void) free(at); (void) free(sk); (void) free(bt); (void) free(ck); (void) free(np); return(FINISHED); } /* *----------------------------------------------------------------------- * subroutine: fftmx * called by subroutine 'fft' to compute mixed-radix fourier transform *----------------------------------------------------------------------- */ int fftmx(float *a,float *b,int ntot,int n,int nspan,int isn,int m,int *kt, float *at,float *ck,float *bt,float *sk,int *np,int nfac[]) { int i,inc, j,jc,jf, jj, k, k1, k2, k3=0, k4, kk,klim,ks,kspan, kspnn, lim, maxf,mm, nn,nt; double aa, aj, ajm, ajp, ak, akm, akp, bb, bj, bjm, bjp, bk, bkm, bkp, c1, c2=0.0, c3=0.0, c72, cd, dr, rad, sd, s1, s2=0.0, s3=0.0, s72, s120; double xx; /****** ADDED APRIL 1991 *********/ inc=abs(isn); nt = inc*ntot; ks = inc*nspan; /******************* REPLACED MARCH 29: *********************** rad = atan((double)1.0); **************************************************************/ rad = 0.785398163397448278900; /******************* REPLACED MARCH 29: *********************** s72 = rad/0.625; c72 = cos(s72); s72 = sin(s72); **************************************************************/ c72 = 0.309016994374947451270; s72 = 0.951056516295153531190; /******************* REPLACED MARCH 29: *********************** s120 = sqrt((double)0.75); **************************************************************/ s120 = 0.866025403784438707600; /* scale by 1/n for isn > 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] = (float)(a[j] * ak); b[j] = (float)(b[j] * ak); } } kspan = ks; nn = nt - inc; jc = ks/n; /* sin, cos values are re-initialized each lim steps */ lim = 32; klim = lim * jc; i = 0; jf = 0; maxf = m - (*kt); maxf = nfac[maxf]; if((*kt) > 0) maxf = max(nfac[*kt],maxf); /* * 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] = (float)((a[kk]) - ak); b[k2] = (float)((b[kk]) - bk); a[kk] = (float)((a[kk]) + ak); b[kk] = (float)((b[kk]) + 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 = min((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] = (float)((c1 * ak) - (s1 * bk)); b[k2] = (float)((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 = min( 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] = (float)(ak + aj); b[kk] = (float)(bk + bj); ak += (-0.5 * aj); bk += (-0.5 * bj); aj = (a[k1] - a[k2]) * s120; bj = (b[k1] - b[k2]) * s120; a[k1] = (float)(ak - bj); b[k1] = (float)(bk + aj); a[k2] = (float)(ak + bj); b[k2] = (float)(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 = min( 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] = (float)(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] = (float)(bkp + bjp); bjp = (float)(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] = (float)((akp*c1) - (bkp*s1)); b[k1] = (float)((akp*s1) + (bkp*c1)); a[k2] = (float)((ajp*c2) - (bjp*s2)); b[k2] = (float)((ajp*s2) + (bjp*c2)); a[k3] = (float)((akm*c3) - (bkm*s3)); b[k3] = (float)((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] = (float)akp; b[k1] = (float)bkp; a[k2] = (float)ajp; b[k2] = (float)bjp; a[k3] = (float)akm; b[k3] = (float)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 = min( 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] = (float)(aa + akp + ajp); b[kk] = (float)(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] = (float)(ak - bj); a[k4] = (float)(ak + bj); b[k1] = (float)(bk + aj); b[k4] = (float)(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] = (float)(ak - bj); a[k3] = (float)(ak + bj); b[k2] = (float)(bk + aj); b[k3] = (float)(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.0f; sk[jf] = 0.0f; for(j=1; j jf) jj -= jf; }while(k < jf); k = jf - j; a[k1] = (float)(ak - bj); b[k1] = (float)(bk + aj); a[k2] = (float)(ak + bj); b[k2] = (float)(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 = min( 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] = (float)((c2*ak) - (s2 * b[kk])); b[kk] = (float)((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 = min( 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] = (float)ak; bk = b[kk]; b[kk] = b[k2]; b[k2] = (float)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] = (float)ak; bk = b[kk]; b[kk] = b[k2]; b[k2] = (float)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(FINISHED); 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(FINISHED);; } /* *----------------------------------------------------------------------- * 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); */ int reals_(float *a, float *b, int n, int isn) /* a refers to an array of floats 'anal' */ /* 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){ sprintf(errstr,"zero in reals parameters in FFT : %d : %d ",n,isn); return(DATA_ERROR);; } 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-initialized 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] = (float)((em-bb)*0.5); b[j] = (float)((em+bb)*0.5); a[k] = (float)((aa-re)*0.5); a[j] = (float)((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 = ((float)ml) * dr * rad; cn = cos(sn); if(isn>0) cn = -cn; sn = sin(sn); } } return(FINISHED); }