快速傅立叶变换算法 FFT

       音频处理里面常用。 就是把波形(时域信号)变换到频域,使得用户更好的分析。频域就是类似于“千千静听”的频谱。这个过程叫“离散傅立叶变换”(DFT)。而FFT是DFT的一种高效快速算法。

代码见下:

#include <iostream>
#include <stdio.h>
#include <math.h>

//**************************************************************************************

#ifndef M_PI
    #define M_PI 3.14159265358979323846
#endif
#define DATA_LEN 64
#define SAMPLE_FREQ 1000 // Hz

unsigned char sin_data[64] = {0x7F,0x8B,0x98,0xA4,0xB0,0xBB,0xC6,0xD0,0xD9,0xE2,
    0xE9,0xEF,0xF5,0xF9,0xFC,0xFE,0xFE,0xFE,0xFC,0xF9,0xF5,0xEF,0xE9,0xE2,0xD9,0xD0,
    0xC6,0xBB,0xB0,0xA4,0x98,0x8B,0x7F,0x73,0x66,0x5A,0x4E,0x43,0x38,0x2E,0x25,0x1C,
    0x15,0x0F,0x09,0x05,0x02,0x00,0x00,0x00,0x02,0x05,0x09,0x0F,0x15,0x1C,0x25,0x2E,
    0x38,0x43,0x4E,0x5A,0x66,0x73};

typedef struct{
    double r;
    double i;
} cplx_t;


//**************************************************************************************

void cplx_exp(cplx_t *x, cplx_t *r)
{
    double expx = exp(x->r);
    r->r = expx*cos(x->i);
    r->i = expx*sin(x->i);
}

// 复数乘法
void cplx_mul(cplx_t *x, cplx_t *y, cplx_t *r)
{
    r->r = x->r*y->r-x->i*y->i;
    r->i = x->r*y->i+x->i*y->r;
}

// 比特反置
void bit_reverse(cplx_t *x, int N)
{
    unsigned int i = 0,j = 0,k = 0;
    
    cplx_t tmp;
    
    int bit_num = log(0.0+N)/log(2.0);  // 比特位数
    
    for (i=0; i<N; i++)
    {
        int t = bit_num;
        k=i;
        j=0;
        while (t--)
        {
            j <<= 1;
            j |= k&1;
            k >>= 1;
        }
        if (j>i)
        {
            tmp = x[i];
            x[i] = x[j];
            x[j] = tmp;
        }
    }
}


void fft(cplx_t *x, int N)
{
    cplx_t u,d,p,W,tmp;
    int i=0,j=0,k=0,l=0;
    
    double M = floor(log(0.0+N)/log(2.0));  // zhiqiu 换底公式
    if (log(0.0+N)/log(2.0)-M > 0)
    {
        printf("The length of x (N) must be a power of two!!!\n");
        return;
    }
    
    bit_reverse(x,N);
    
    for (i = 0; i < M; i++)
    {
        l = 1<<i;
        for (j = 0; j < N; j += 2*l)
        {
            for (k = 0; k < l; k++)
            {
                tmp.r = 0.0;
                tmp.i = -2*M_PI*k/2/l;
                cplx_exp(&tmp,&W);
                cplx_mul(&x[j+k+l],&W,&p);
                u.r = x[j+k].r+p.r;
                u.i = x[j+k].i+p.i;
                d.r = x[j+k].r-p.r;
                d.i = x[j+k].i-p.i;
                x[j+k] = u;
                x[j+k+l] = d;
            }
        }
    }
}

void ifft(cplx_t *x, int N)
{
    unsigned int i = 0;
    for (i = 0;i < N; i++)
        x[i].i = -x[i].i;
    fft(x,N);
    for (i = 0;i < N; i++)
    {
        x[i].r = x[i].r/(N+0.0);
        x[i].i = -x[i].i/(N+0.0);
    }
}



//**************************************************************************************

int main(int argc, const char * argv[])
{
    int i;
    cplx_t x[DATA_LEN];
    for (i=0;i<DATA_LEN;i++)
    {
        x[i].r = sin_data[i];
        x[i].i = 0;
    }
    
    printf("Before...\nReal\t\tImag\n");
    for (i=0; i<DATA_LEN; i++)
        printf("%f\t%f\n",x[i].r,x[i].i);
    
    fft(x, DATA_LEN);
    
    printf("\nAfter FFT...\nReal\t\tImag\n");
    for (i=0; i<DATA_LEN; i++)
        printf("%f\t%f\n",x[i].r,x[i].i);
    
    printf("\n频率\t\t幅度\t\t相位\n");
    for (i=0; i<DATA_LEN; i++)
    {
        double fudu = sqrt(x[i].r*x[i].r+x[i].i*x[i].i);
        double xiangwei = atan(x[i].i/x[i].r)*180.0/M_PI;
        if (i == 0)
            fudu /= DATA_LEN;
        else
            fudu /= DATA_LEN/2;
        printf("%f\t%f\t%f\n", (double)SAMPLE_FREQ/DATA_LEN*i, fudu, xiangwei);
    }
    
    ifft(x, DATA_LEN);
    
    printf("\nAfter IFFT...\nReal\t\tImag\n");
    for (i=0; i<DATA_LEN; i++)
        printf("%f\t%f\n",x[i].r,x[i].i);
    
    return 0;
}


运行结果:

Before...
Real		Imag
127.000000	0.000000
139.000000	0.000000
152.000000	0.000000
164.000000	0.000000
176.000000	0.000000
187.000000	0.000000
198.000000	0.000000
208.000000	0.000000
217.000000	0.000000
226.000000	0.000000
233.000000	0.000000
239.000000	0.000000
245.000000	0.000000
249.000000	0.000000
252.000000	0.000000
254.000000	0.000000
254.000000	0.000000
254.000000	0.000000
252.000000	0.000000
249.000000	0.000000
245.000000	0.000000
239.000000	0.000000
233.000000	0.000000
226.000000	0.000000
217.000000	0.000000
208.000000	0.000000
198.000000	0.000000
187.000000	0.000000
176.000000	0.000000
164.000000	0.000000
152.000000	0.000000
139.000000	0.000000
127.000000	0.000000
115.000000	0.000000
102.000000	0.000000
90.000000	0.000000
78.000000	0.000000
67.000000	0.000000
56.000000	0.000000
46.000000	0.000000
37.000000	0.000000
28.000000	0.000000
21.000000	0.000000
15.000000	0.000000
9.000000	0.000000
5.000000	0.000000
2.000000	0.000000
0.000000	0.000000
0.000000	0.000000
0.000000	0.000000
2.000000	0.000000
5.000000	0.000000
9.000000	0.000000
15.000000	0.000000
21.000000	0.000000
28.000000	0.000000
37.000000	0.000000
46.000000	0.000000
56.000000	0.000000
67.000000	0.000000
78.000000	0.000000
90.000000	0.000000
102.000000	0.000000
115.000000	0.000000

After FFT...
Real		Imag
8128.000000	0.000000
0.000000	-4079.961454
0.000000	0.000000
0.000000	-2.073634
0.000000	0.000000
-0.000000	0.912016
0.000000	0.000000
-0.000000	1.409742
0.000000	0.000000
0.000000	1.173062
0.000000	0.000000
0.000000	0.039072
0.000000	0.000000
0.000000	4.791678
0.000000	0.000000
0.000000	0.161168
0.000000	0.000000
0.000000	1.343569
0.000000	0.000000
0.000000	4.934246
0.000000	0.000000
0.000000	1.217879
0.000000	0.000000
0.000000	-3.948687
0.000000	0.000000
-0.000000	6.362596
0.000000	0.000000
0.000000	1.672291
0.000000	0.000000
-0.000000	2.117931
0.000000	0.000000
0.000000	-0.236919
0.000000	0.000000
0.000000	0.236919
0.000000	0.000000
-0.000000	-2.117931
0.000000	0.000000
0.000000	-1.672291
0.000000	0.000000
-0.000000	-6.362596
0.000000	0.000000
-0.000000	3.948687
0.000000	0.000000
0.000000	-1.217879
0.000000	0.000000
-0.000000	-4.934246
0.000000	0.000000
0.000000	-1.343569
0.000000	0.000000
-0.000000	-0.161168
0.000000	0.000000
0.000000	-4.791678
0.000000	0.000000
-0.000000	-0.039072
0.000000	0.000000
0.000000	-1.173062
0.000000	0.000000
-0.000000	-1.409742
0.000000	0.000000
-0.000000	-0.912016
0.000000	0.000000
0.000000	2.073634
0.000000	0.000000
-0.000000	4079.961454

频率		幅度		相位
0.000000	127.000000	0.000000
15.625000	127.498795	-90.000000
31.250000	0.000000	nan
46.875000	0.064801	-90.000000
62.500000	0.000000	nan
78.125000	0.028501	-90.000000
93.750000	0.000000	nan
109.375000	0.044054	-90.000000
125.000000	0.000000	nan
140.625000	0.036658	90.000000
156.250000	0.000000	nan
171.875000	0.001221	90.000000
187.500000	0.000000	nan
203.125000	0.149740	90.000000
218.750000	0.000000	nan
234.375000	0.005036	90.000000
250.000000	0.000000	nan
265.625000	0.041987	90.000000
281.250000	0.000000	nan
296.875000	0.154195	90.000000
312.500000	0.000000	nan
328.125000	0.038059	90.000000
343.750000	0.000000	nan
359.375000	0.123396	-90.000000
375.000000	0.000000	nan
390.625000	0.198831	-90.000000
406.250000	0.000000	nan
421.875000	0.052259	90.000000
437.500000	0.000000	nan
453.125000	0.066185	-90.000000
468.750000	0.000000	nan
484.375000	0.007404	-90.000000
500.000000	0.000000	nan
515.625000	0.007404	90.000000
531.250000	0.000000	nan
546.875000	0.066185	90.000000
562.500000	0.000000	nan
578.125000	0.052259	-90.000000
593.750000	0.000000	nan
609.375000	0.198831	90.000000
625.000000	0.000000	nan
640.625000	0.123396	-90.000000
656.250000	0.000000	nan
671.875000	0.038059	-90.000000
687.500000	0.000000	nan
703.125000	0.154195	90.000000
718.750000	0.000000	nan
734.375000	0.041987	-90.000000
750.000000	0.000000	nan
765.625000	0.005036	90.000000
781.250000	0.000000	nan
796.875000	0.149740	-90.000000
812.500000	0.000000	nan
828.125000	0.001221	90.000000
843.750000	0.000000	nan
859.375000	0.036658	-90.000000
875.000000	0.000000	nan
890.625000	0.044054	90.000000
906.250000	0.000000	nan
921.875000	0.028501	90.000000
937.500000	0.000000	nan
953.125000	0.064801	90.000000
968.750000	0.000000	nan
984.375000	127.498795	-90.000000

After IFFT...
Real		Imag
127.000000	-0.000000
139.000000	-0.000000
152.000000	-0.000000
164.000000	-0.000000
176.000000	0.000000
187.000000	-0.000000
198.000000	0.000000
208.000000	-0.000000
217.000000	-0.000000
226.000000	-0.000000
233.000000	0.000000
239.000000	-0.000000
245.000000	-0.000000
249.000000	0.000000
252.000000	0.000000
254.000000	-0.000000
254.000000	-0.000000
254.000000	0.000000
252.000000	0.000000
249.000000	0.000000
245.000000	-0.000000
239.000000	0.000000
233.000000	-0.000000
226.000000	0.000000
217.000000	-0.000000
208.000000	0.000000
198.000000	0.000000
187.000000	0.000000
176.000000	-0.000000
164.000000	0.000000
152.000000	-0.000000
139.000000	0.000000
127.000000	0.000000
115.000000	0.000000
102.000000	0.000000
90.000000	0.000000
78.000000	-0.000000
67.000000	0.000000
56.000000	-0.000000
46.000000	0.000000
37.000000	0.000000
28.000000	0.000000
21.000000	-0.000000
15.000000	0.000000
9.000000	-0.000000
5.000000	-0.000000
2.000000	-0.000000
0.000000	0.000000
0.000000	-0.000000
-0.000000	-0.000000
2.000000	-0.000000
5.000000	-0.000000
9.000000	0.000000
15.000000	-0.000000
21.000000	0.000000
28.000000	-0.000000
37.000000	0.000000
46.000000	-0.000000
56.000000	-0.000000
67.000000	-0.000000
78.000000	0.000000
90.000000	-0.000000
102.000000	0.000000
115.000000	-0.000000



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值