📄 int_fft.c
字号:
/* fix_fft.c - Fixed-point Fast Fourier Transform *//* fix_fft() perform FFT or inverse FFT window() applies a Hanning window to the (time) input fix_loud() calculates the loudness of the signal, for each freq point. Result is an integer array, units are dB (values will be negative). iscale() scale an integer value by (numer/denom). fix_mpy() perform fixed-point multiplication. Sinewave[1024] sinewave normalized to 32767 (= 1.0). Loudampl[100] Amplitudes for lopudnesses from 0 to -99 dB. Low_pass Low-pass filter, cutoff at sample_freq / 4. All data are fixed-point short integers, in which -32768 to +32768 represent -1.0 to +1.0. Integer arithmetic is used for speed, instead of the more natural floating-point. For the forward FFT (time -> freq), fixed scaling is performed to prevent arithmetic overflow, and to map a 0dB sine/cosine wave (i.e. amplitude = 32767) to two -6dB freq coefficients; the one in the lower half is reported as 0dB by fix_loud(). The return value is always 0. For the inverse FFT (freq -> time), fixed scaling cannot be done, as two 0dB coefficients would sum to a peak amplitude of 64K, overflowing the 32k range of the fixed-point integers. Thus, the fix_fft() routine performs variable scaling, and returns a value which is the number of bits LEFT by which the output must be shifted to get the actual amplitude (i.e. if fix_fft() returns 3, each value of fr[] and fi[] must be multiplied by 8 (2**3) for proper scaling. Clearly, this cannot be done within the fixed-point short integers. In practice, if the result is to be used as a filter, the scale_shift can usually be ignored, as the result will be approximately correctly normalized as is. TURBO C, any memory model; uses inline assembly for speed and for carefully-scaled arithmetic. Written by: Tom Roberts 11/8/89 Made portable: Malcolm Slaney 12/15/94 malcolm@interval.com Timing on a Macintosh PowerBook 180.... (using Symantec C6.0) fix_fft (1024 points) 8 ticks fft (1024 points - Using SANE) 112 Ticks fft (1024 points - Using FPU) 11*//* FIX_MPY() - fixed-point multiplication macro. This macro is a statement, not an expression (uses asm). BEWARE: make sure _DX is not clobbered by evaluating (A) or DEST. args are all of type fixed. Scaling ensures that 32767*32767 = 32767. */#define dosFIX_MPY(DEST,A,B) { \ _DX = (B); \ _AX = (A); \ asm imul dx; \ asm add ax,ax; \ asm adc dx,dx; \ DEST = _DX; }#define FIX_MPY(DEST,A,B) DEST = ((long)(A) * (long)(B))>>15#define N_WAVE 1024 /* dimension of Sinewave[] */#define LOG2_N_WAVE 10 /* log2(N_WAVE) */#define N_LOUD 100 /* dimension of Loudampl[] */#ifndef fixed#define fixed short#endifextern fixed Sinewave[N_WAVE]; /* placed at end of this file for clarity */extern fixed Loudampl[N_LOUD];int db_from_ampl(fixed re, fixed im);fixed fix_mpy(fixed a, fixed b);/* fix_fft() - perform fast Fourier transform. if n>0 FFT is done, if n<0 inverse FFT is done fr[n],fi[n] are real,imaginary arrays, INPUT AND RESULT. size of data = 2**m set inverse to 0=dft, 1=idft*/int fix_fft(fixed fr[], fixed fi[], int m, int inverse){ int mr,nn,i,j,l,k,istep, n, scale, shift; fixed qr,qi,tr,ti,wr,wi,t; n = 1<<m; if(n > N_WAVE) return -1; mr = 0; nn = n - 1; scale = 0; /* decimation in time - re-order data */ for(m=1; m<=nn; ++m) { l = n; do { l >>= 1; } while(mr+l > nn); mr = (mr & (l-1)) + l; if(mr <= m) continue; tr = fr[m]; fr[m] = fr[mr]; fr[mr] = tr; ti = fi[m]; fi[m] = fi[mr]; fi[mr] = ti; } l = 1; k = LOG2_N_WAVE-1; while(l < n) { if(inverse) { /* variable scaling, depending upon data */ shift = 0; for(i=0; i<n; ++i) { j = fr[i]; if(j < 0) j = -j; m = fi[i]; if(m < 0) m = -m; if(j > 16383 || m > 16383) { shift = 1; break; } } if(shift) ++scale; } else { /* fixed scaling, for proper normalization - there will be log2(n) passes, so this results in an overall factor of 1/n, distributed to maximize arithmetic accuracy. */ shift = 1; } /* it may not be obvious, but the shift will be performed on each data point exactly once, during this pass. */ istep = l << 1; for(m=0; m<l; ++m) { j = m << k; /* 0 <= j < N_WAVE/2 */ wr = Sinewave[j+N_WAVE/4]; wi = -Sinewave[j]; if(inverse) wi = -wi; if(shift) { wr >>= 1; wi >>= 1; } for(i=m; i<n; i+=istep) { j = i + l; tr = fix_mpy(wr,fr[j]) -fix_mpy(wi,fi[j]); ti = fix_mpy(wr,fi[j]) +fix_mpy(wi,fr[j]); qr = fr[i]; qi = fi[i]; if(shift) { qr >>= 1; qi >>= 1; } fr[j] = qr - tr; fi[j] = qi - ti; fr[i] = qr + tr; fi[i] = qi + ti; } } --k; l = istep; } return scale;}/* window() - apply a Hanning window */void window(fixed fr[], int n){ int i,j,k; j = N_WAVE/n; n >>= 1; for(i=0,k=N_WAVE/4; i<n; ++i,k+=j) FIX_MPY(fr[i],fr[i],16384-(Sinewave[k]>>1)); n <<= 1; for(k-=j; i<n; ++i,k-=j) FIX_MPY(fr[i],fr[i],16384-(Sinewave[k]>>1));}/* fix_loud() - compute loudness of freq-spectrum components. n should be ntot/2, where ntot was passed to fix_fft(); 6 dB is added to account for the omitted alias components. scale_shift should be the result of fix_fft(), if the time-series was obtained from an inverse FFT, 0 otherwise. loud[] is the loudness, in dB wrt 32767; will be +10 to -N_LOUD.*/void fix_loud(fixed loud[], fixed fr[], fixed fi[], int n, int scale_shift){ int i, max; max = 0; if(scale_shift > 0) max = 10; scale_shift = (scale_shift+1) * 6; for(i=0; i<n; ++i) { loud[i] = db_from_ampl(fr[i],fi[i]) + scale_shift; if(loud[i] > max) loud[i] = max; }}/* db_from_ampl() - find loudness (in dB) from the complex amplitude.*/int db_from_ampl(fixed re, fixed im){ static long loud2[N_LOUD] = {0}; long v; int i; if(loud2[0] == 0) { loud2[0] = (long)Loudampl[0] * (long)Loudampl[0]; for(i=1; i<N_LOUD; ++i) { v = (long)Loudampl[i] * (long)Loudampl[i]; loud2[i] = v; loud2[i-1] = (loud2[i-1]+v) / 2; } } v = (long)re * (long)re + (long)im * (long)im; for(i=0; i<N_LOUD; ++i) if(loud2[i] <= v) break; return (-i);}/* fix_mpy() - fixed-point multiplication*/fixed fix_mpy(fixed a, fixed b){ FIX_MPY(a,a,b); return a;}/* iscale() - scale an integer value by (numer/denom)*/int iscale(int value, int numer, int denom){#ifdef DOS asm mov ax,value asm imul WORD PTR numer
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -