FFT算法【初识】(一)

(一)离散傅里叶变换(DFT)

DFT是傅里叶变换在时域和频域上都呈现离散的形式,将时域信号的采样变换为在离散时间傅里叶变换(DTFT)频域的采样。在形式上,变换两端(时域和频域上)的序列是有限长的,而实际上这两组序列都应当被认为是离散周期信号的主值序列。即使对有限长的离散信号作DFT,也应该将其看作经过周期延拓成为周期信号再作变换。在实际应用中通常采用快速傅里叶变换以高效计算DFT。

基本性质:线性性质、循环移位特性

(二)快速傅里叶变换(FFT)

1、简介:

FFT算法,是根据DFT的奇、偶、虚、实等特性来对DFT算法进行改进获得的。

FFT在算法竞赛中,常常用于加速多项式的乘法。

【例如】:数组A[x]与数组B[x]相乘得到数组C[x],其中,A[x]的项数为n,系数构成的n维向量为(a0,a1,...,an-1);B[x]的项数 为m,系数构成的m维向量为(b0,b1,b2,...,bm-1);要求C[x]的系数为n+m-1维的向量。

【解】:

for(int i = 0; i < n; ++i)
    for(int j = 0; j < m; ++j){
        c[i+j] += a[i] * b[i];
    }

以上的代码所需要的时间复杂度为O(n^2)。

而利用FFT,则其时间复杂度为O(nlogn)。

2、算法:

DFT的运算:

计算DFT对于X(k)的每个k值,需要进行4N次实数相乘和(4N-2)次相加,对于N个k值,共需4N*N次实数相乘和(4N-2)*N次实数相加。

而DFT运用其中W_{N}^{kn}的周期性和对称性,使之变成一系列迭代运算。

 

【源码】:

// 必须添加 #include<math.h> 的头文件,以保证在以下内容中能正确运用 define M_PI
#define _USE_MATH_DEFINES
#include <math.h>  //该头文件包含了一些常用的数学运算等
#include <stdio.h>  //标准输入输出头文件
#include <stdlib.h>  //标准库头文件
#define PI M_PI   /*PI到机器精度,在 math.h 中定义 */
#define TWOPI (2.0*PI)  //定义了PI的两倍,用2.0而不用2是为了保证其为浮点型数据,保证精度

/*
FFT/IFFT routine. (see pages 507-508 of Numerical Recipes in C)
Inputs:
data[] : array of complex* data points of size 2*NFFT+1.
data[0] is unused,
* the n'th complex number x(n), for 0 <= n <= length(x)-1, is stored as:
data[2*n+1] = real(x(n))
data[2*n+2] = imag(x(n))
if length(Nx) < NFFT, the remainder of the array must be padded with zeros
nn : FFT order NFFT. This MUST be a power of 2 and >= length(x).
isign: if set to 1,
computes the forward FFT
if set to -1,
computes Inverse FFT - in this case the output values have
to be manually normalized by multiplying with 1/NFFT.
Outputs:
data[] : The FFT or IFFT results are stored in data, overwriting the input.
*/

void four1(double data[], int nn, int isign) {
    int n, mmax, m, j, istep, i;
    double wtemp, wr, wpr, wpi, wi, theta;
    double tempr, tempi;
    n = nn << 1;  //将nn左移一位存放于n中,即 nn*2【补充:计算机做乘法运算时不是一个个相加,而是运用移位来实现。>>这个是右移,<<这个是左移。】
    j = 1;
    for (i = 1; i < n; i += 2) {
        if (j > i) {
            tempr = data[j];
            data[j] = data[i];
            data[i] = tempr;
            tempr = data[j+1];
            data[j+1] = data[i+1];
            data[i+1] = tempr;
        }
        m = n >> 1;
        while (m >= 2 && j > m) {
            j -= m;
            m >>= 1;
        }
        j += m;
    }
    mmax = 2;
    while (n > mmax) {
        istep = 2*mmax;
        theta = TWOPI/(isign*mmax);
        wtemp = sin(0.5*theta);
        wpr = -2.0*wtemp*wtemp;
        wpi = sin(theta);
        wr = 1.0;
        wi = 0.0;
        for (m = 1; m < mmax; m += 2) {
            for (i = m; i <= n; i += istep) {
                j =i + mmax;
                tempr = wr*data[j] - wi*data[j+1];
                tempi = wr*data[j+1] + wi*data[j];
                data[j] = data[i] - tempr;
                data[j+1] = data[i+1] - tempi;
                data[i] += tempr;
                data[i+1] += tempi;
            }
            wr = (wtemp = wr)*wpr - wi*wpi + wr;
            wi = wi*wpr + wtemp*wpi + wi;
        }
        mmax = istep;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值