快速傅里叶变换
一、功能
计算复序列的快速傅里叶变换。
二、方法简介
序列x(n)(n=0,1,...,N−1)x(n)(n=0,1,...,N−1)的离散傅里叶变换定义为
X(k)=N−1∑n=0x(n)WnkN,k=0,1,...,N−1X(k)=N−1∑n=0x(n)WnkN,k=0,1,...,N−1
其中WnkN=e−j2πnkNWnkN=e−j2πnkN,将序列x(n)x(n)按序号nn的奇偶分成两组,即
x1(n)=x(2n)x2(n)=x(2n+1)}n=0,1,...,N2−1
因此,x(n)的傅里叶变换可写成
X(k)=N/2−1∑n=0x(2n)W2nkN+N/2−1∑n=0x(2n+1)W(2n+1)kN=N/2−1∑n=0x1(n)WnkN/2+WkNN/2−1∑n=0x2(n)WnkN/2
由此可得X(k)=X1(k)+WkNX2(k),k=0,1,...,N2,式中
X1(k)=N/2−1∑n=0x(2n)W2nkNX2(k)=N/2−1∑n=0x(2n+1)W(2n+1)kN
他们分别是x1(n)和x2(n)的N/2点DFT。上面的推导表明:一个N点DFT被分解为两个N/2点DFT,这两个N/2点DFT又可合成一个N点DFT。但上面给出的公式仅能得到X(k)的前N/2点的值,要用X1(k)和X2(k)来表达X(k)的后半部分的值,还必须运用权系数WN的周期性与对称性,即
Wn(k+N/2)N/2=WnkN/2,W(k+N/2)N=−WkN
因此,X(k)的后N/2点的值可表示为
X(k+N2)=X1(k+N2)+Wk+N/2NX2(k+N2)=X1(k)−WkNX2(k), k=0,1,...,N2−1
通过上面的推导可以看出,N点的DFT可以分解为两个N/2点DFT,每个N/2点DFT又可以分解为两个N/4点DFT。依此类推,当N为2的整数次幂时(N=2M),由于每分解一次降低一阶幂次,所以通过M次分解,最后全部成为一系列2点DFT运算。以上就是按时间抽取的快速傅里叶变换(FFT)算法。
序列X(k)的离散傅里叶反变换定义为
x(n)=1NN−1∑k=0X(k)W−nkN,n=0,1,...,N−1
它与离散傅里叶正变换的区别在于将WN改变为W−1N,并多了一个除以N的运算。因为WN和W−1N对于推导按时间抽取的快速傅里叶变换算法并无实质性区别,因此可将FFT和快速傅里叶反变换(IFFT)算法合并在同一程序中。
三、使用说明
是用C语言实现快速傅里叶变换(FFT)的方法如下:
/************************************
x ---一维数组,长度为n,开始时存放要变换数据的实部,最后存放变换结果的实部。
y ---一维数组,长度为n,开始时存放要变换数据的虚部,最后存放变换结果的虚部。
n ---数据长度,必须是2的整数次幂。
sign ---当sign=1时,子函数计算离散傅里叶正变换;当sign=-1时,子函数计算离散傅里叶反变换
************************************/
#include "math.h"
void fft(double *x, double *y, int n, int sign)
{
int i, j, k, l, m, n1, n2;
double c, c1, e, s, s1, t, tr, ti;
for(j = 1, i=1; i < 16; i++) {
m = i;
j = 2 * j;
if(j == n)
break;
}
n1 = n - 1;
for(j = 0, i = 0; i < n1; i++) {
if(i < j) {
tr = x[j];
ti = j[j];
x[j] = x[i];
y[j] = j[i];
x[i] = tr;
y[i] = ti;
}
k = n / 2;
while(k < (j + 1)) {
j = j - k;
k = k / 2;
}
j = j + k;
}
n1 = 1;
for(l = 1; l <= m; l++) {
n1 = 2 * n1;
n2 = n1 / 2;
e = 3.14159265359 / n2;
c = 1.0;
s = 0.0;
c1 = cos(e);
s1 = -sign * sin(e);
for(j = 0; j < n2; j++) {
for(i = j; i < n; i += n1) {
k = i + n2;
tr = c * x[k] - s * y(k);
ti = c * y[k] + s * x[k];
x[k] = x[i] - tr;
y[k] = y[i] - ti;
x[i] = x[i] + tr;
y[i] = y[i] + ti;
}
t = c;
c = c * c1 - s * s1;
s = t * s1 + s * c1;
}
}
if(sign == -1) {
for(i = 0; i < n; i++) {
x[i] /= n;
y[i] /= n;
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!