计算复序列的快速傅里叶变换。

序列\(x(n)(n=0,1,…,N-1)\)的离散傅里叶变换定义为

\[X(k)=\sum_{n=0}^{N-1}x(n)W_{N}^{nk}, \qquad k=0,1,…,N-1
\]

其中\(W_{N}^{nk}=e^{-j\frac{2\pi nk}{N}}\),将序列\(x(n)\)按序号\(n\)的奇偶分成两组,即

\[\left.\begin{matrix}\begin{align*}x_{1}(n)=&x(2n)\\ x_{2}(n)=&x(2n+1)\end{align*}\end{matrix}\right\} \qquad n=0,1,…,\frac{N}{2}-1
\]

因此,\(x(n)\)的傅里叶变换可写成

\[\begin{align*}X(k) &= \sum_{n=0}^{N/2-1}x(2n)W^{2nk}_{N} + \sum_{n=0}^{N/2-1}x(2n+1)W^{(2n+1)k}_{N}\\&= \sum_{n=0}^{N/2-1}x_{1}(n)W^{nk}_{N/2} + W_{N}^{k}\sum_{n=0}^{N/2-1}x_{2}(n)W^{nk}_{N/2}\end{align*}
\]

由此可得\(X(k)=X_{1}(k)+W_{N}^{k}X_{2}(k), \qquad k = 0,1,…,\frac{N}{2}\),式中

\[\begin{align*}X_{1}(k)&=\sum_{n=0}^{N/2-1}x(2n)W^{2nk}_{N}\\X_{2}(k)&=\sum_{n=0}^{N/2-1}x(2n+1)W^{(2n+1)k}_{N}\end{align*}
\]

他们分别是\(x_1(n)\)\(x_2(n)\)\(N/2\)点DFT。上面的推导表明:一个\(N\)点DFT被分解为两个\(N/2\)点DFT,这两个\(N/2\)点DFT又可合成一个\(N\)点DFT。但上面给出的公式仅能得到\(X(k)\)的前\(N/2\)点的值,要用\(X_{1}(k)\)\(X_{2}(k)\)来表达\(X(k)\)的后半部分的值,还必须运用权系数\(W_N\)的周期性与对称性,即

\[W_{N/2}^{n(k+N/2)}=W_{N/2}^{nk}, \quad W_{N}^{(k+N/2)}=-W_{N}^{k}
\]

因此,\(X(k)\)的后\(N/2\)点的值可表示为

\[\begin{align*}X(k+\frac{N}{2})&=X_{1}(k+\frac{N}{2})+W_{N}^{k+N/2}X_{2}(k+\frac{N}{2})\\&=X_{1}(k)-W_{N}^{k}X_{2}(k), \ k=0,1,…,\frac{N}{2}-1\end{align*}
\]

通过上面的推导可以看出,\(N\)点的DFT可以分解为两个\(N/2\)点DFT,每个\(N/2\)点DFT又可以分解为两个\(N/4\)点DFT。依此类推,当\(N\)为2的整数次幂时(\(N=2^M\)),由于每分解一次降低一阶幂次,所以通过\(M\)次分解,最后全部成为一系列2点DFT运算。以上就是按时间抽取的快速傅里叶变换(FFT)算法。

序列\(X(k)\)的离散傅里叶反变换定义为

\[x(n)=\frac{1}{N}\sum_{k=0}^{N-1}X(k)W_{N}^{-nk}, \qquad n=0,1,…,N-1
\]

它与离散傅里叶正变换的区别在于将\(W_N\)改变为\(W_N^{-1}\),并多了一个除以\(N\)的运算。因为\(W_N\)\(W_N^{-1}\)对于推导按时间抽取的快速傅里叶变换算法并无实质性区别,因此可将FFT和快速傅里叶反变换(IFFT)算法合并在同一程序中。

是用C语言实现快速傅里叶变换(FFT)的方法如下:

  1. /************************************
  2. x ---一维数组,长度为n,开始时存放要变换数据的实部,最后存放变换结果的实部。
  3. y ---一维数组,长度为n,开始时存放要变换数据的虚部,最后存放变换结果的虚部。
  4. n ---数据长度,必须是2的整数次幂。
  5. sign ---当sign=1时,子函数计算离散傅里叶正变换;当sign=-1时,子函数计算离散傅里叶反变换
  6. ************************************/
  7. #include "math.h"
  8. void fft(double *x, double *y, int n, int sign)
  9. {
  10. int i, j, k, l, m, n1, n2;
  11. double c, c1, e, s, s1, t, tr, ti;
  12. for(j = 1, i=1; i < 16; i++) {
  13. m = i;
  14. j = 2 * j;
  15. if(j == n)
  16. break;
  17. }
  18. n1 = n - 1;
  19. for(j = 0, i = 0; i < n1; i++) {
  20. if(i < j) {
  21. tr = x[j];
  22. ti = j[j];
  23. x[j] = x[i];
  24. y[j] = j[i];
  25. x[i] = tr;
  26. y[i] = ti;
  27. }
  28. k = n / 2;
  29. while(k < (j + 1)) {
  30. j = j - k;
  31. k = k / 2;
  32. }
  33. j = j + k;
  34. }
  35. n1 = 1;
  36. for(l = 1; l <= m; l++) {
  37. n1 = 2 * n1;
  38. n2 = n1 / 2;
  39. e = 3.14159265359 / n2;
  40. c = 1.0;
  41. s = 0.0;
  42. c1 = cos(e);
  43. s1 = -sign * sin(e);
  44. for(j = 0; j < n2; j++) {
  45. for(i = j; i < n; i += n1) {
  46. k = i + n2;
  47. tr = c * x[k] - s * y(k);
  48. ti = c * y[k] + s * x[k];
  49. x[k] = x[i] - tr;
  50. y[k] = y[i] - ti;
  51. x[i] = x[i] + tr;
  52. y[i] = y[i] + ti;
  53. }
  54. t = c;
  55. c = c * c1 - s * s1;
  56. s = t * s1 + s * c1;
  57. }
  58. }
  59. if(sign == -1) {
  60. for(i = 0; i < n; i++) {
  61. x[i] /= n;
  62. y[i] /= n;
  63. }
  64. }
  65. }

版权声明:本文为liam-ji原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/liam-ji/p/11686673.html