⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 int_fft.c

📁 这是我本人编写的一个32位定点小数运算的函数库。对于没有浮点运算器的场合
💻 C
📖 第 1 页 / 共 2 页
字号:
/*      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 + -