授之以渔: 几个例子弄清复立叶变换的应用

[复制链接]
xuyiyi 发表于 2010-8-30 21:44 | 显示全部楼层
继续听课~~~
 楼主| highgear 发表于 2010-8-30 22:28 | 显示全部楼层
6 问题 B 的解答
现在大家已经知道了, DFT 可以单独的计算各个谐波。这道题,同样可以用 DFT 来做, 当然也可以用 FFT 来做。 50Hz 55hz 相差 5Hz, 所以必须采用 5Hz 的分辨率。采样频率为800Hz,
周期T800 = 1.25ms;
5Hz周期T5 = 200 ms. 因此,5hz 数据窗口的长度为 N = T5 / T800 = 160,这样50Hz, 55Hz就分别是1011次谐波。



定义常数:
#define N 160
#define LOG2_N 8
计算 cos, sin系数。注意 (1<<(14 + LOG2_N)) / N 的作用

  1.     for (int i=0; i<N; i++) {
  2.         ui.W[i].R = (int16) (::cos( 2*3.1415927*i/N) * (1<<(14 + LOG2_N)) / N + 0.5);
  3.         ui.W[i].I = (int16) (::sin(-2*3.1415927*i/N) * (1<<(14 + LOG2_N)) / N + 0.5);
  4.         ui.Voltage[i] = 0;
  5.     }

计算:

  1. void UI_Calculate(int16 voltage)
  2. {
  3.     int16 d;
  4.     int i;
  5.     d = voltage - ui.Voltage[ui.Index];
  6.     ui.Voltage[ui.Index] = voltage;
  7.     i = (ui.Index * 10) % N;
  8.     ui.U10_Acc.R += (d * ui.W[i].R) >> (13 + LOG2_N - 16);
  9.     ui.U10_Acc.I += (d * ui.W[i].I) >> (13 + LOG2_N - 16);
  10.     ui.U10.R = (int16) (ui.U10_Acc.R >> 16);
  11.     ui.U10.I = (int16) (ui.U10_Acc.I >> 16);

  12.     i = (ui.Index * 11) % N;
  13.     ui.U11_Acc.R += (d * ui.W[i].R) >> (13 + LOG2_N - 16);
  14.     ui.U11_Acc.I += (d * ui.W[i].I) >> (13 + LOG2_N - 16);
  15.     ui.U11.R = (int16) (ui.U11_Acc.R >> 16);
  16.     ui.U11.I = (int16) (ui.U11_Acc.I >> 16);

  17.     ui.Index = (ui.Index + 1) % N;
  18. }
注意  (13 + LOG2_N - 16) 的作用。
演示主程序:

  1. int _tmain(int argc, _TCHAR* argv[])
  2. {
  3.     UI_Init();
  4.     float Hz50 = 2 * PI * 50 / 800;
  5.     float Hz55 = 2 * PI * 55 / 800;
  6.     for (int i=0; i<1000; i++) {
  7.         UI_Calculate((int16) (::sin(Hz50*i)*8000 + ::sin(Hz55*i)* 4000));
  8.     }
  9.     printf("50Hz: %d\n",  Magnitude(ui.U10));
  10.     printf("55Hz: %d\n",  Magnitude(ui.U11));
  11.     ::getchar();
  12.     return 0;
  13. }     


结果:
50Hz: 8000
55Hz: 4000



 
 楼主| highgear 发表于 2010-8-30 22:44 | 显示全部楼层
上面的例子有一个问题就是 N=160,这对于小ram容量的 mcu 来说, 不太合适。我们可以做一些改动。一是改变采样频率, 二是保持采样频率不变,跳过几个点,变相的改变采样频率。这里我们可以每采样5次,计算一次, 这样 N =160/5=32.

#define N 32
#define LOG2_N 5



 for (int i=0; i<1000; i++) {
    if ((i % 5) == 0)
       UI_Calculate((int16) (::sin(Hz50*i)*8000 + ::sin(Hz55*i)* 4000));
 }

得到了一样的结果,而数据buffer 为 32, 可以计算出上到 15 次谐波。

 
 楼主| highgear 发表于 2010-8-30 22:57 | 显示全部楼层
介绍完 DFT, 下面轮到FFT. 我现在发现变速不变调不适合作为 FFT 的例子, 因为变速不变调涉及了很多其他的概念, 验证程序用 matlab 做的, 虽然不长, 但是用了 matlab 里 FFT, IFFT 的命令, 所以没有典型性。而DFT/FFT与逆变换 IDFT/IFFT 的定点 c/c++ 程序都是我自己做的, 可以更详细的讲解。

FFT 容我这两天设想一个经典的例子, 另外开一个帖子讲解。
xuyiyi 发表于 2010-8-30 23:01 | 显示全部楼层
再顶!

期待highgear老师讲课。
martial 发表于 2010-8-31 11:02 | 显示全部楼层
公式都不记得了,再学习一遍
luowei2651 发表于 2010-8-31 11:54 | 显示全部楼层
来听课的
c51avr 发表于 2010-8-31 14:04 | 显示全部楼层
hbsun2007 发表于 2010-8-31 14:34 | 显示全部楼层
jiabin1024 发表于 2010-8-31 15:32 | 显示全部楼层
顶一下highgear大师!讲的太经典了
开始的梦想 发表于 2010-8-31 15:58 | 显示全部楼层
期待。。。
望断云山 发表于 2010-8-31 20:17 | 显示全部楼层
lxyppc 发表于 2010-8-31 20:59 | 显示全部楼层
murphy_zhu 发表于 2010-8-31 22:57 | 显示全部楼层
yeah ,get a chair ,and listen to the couch carefully in the chair!
 楼主| highgear 发表于 2010-8-31 23:35 | 显示全部楼层
本帖最后由 highgear 于 2010-8-31 23:42 编辑

总结:

傅里叶变换的实质是把一个信号通过正交分解(e^(jωt) = cos(ωt) + j sin(ωt)  ), 分解成无数的正弦信号, 而这些无数的正弦信号还可以重新被合成为原来的信号。就像白光通过三棱镜分解成光谱, 再通过三棱镜可以被还原成白光一样,  傅里叶变换就是那个三棱镜, 或者说三棱镜就是一个傅里叶变换。

                         e^(jωt) = cos(ωt) + j sin(ωt)

可以看做钟表的指针以的角速度 ω 旋转时, 指针在纵横两个方向上的投影, 在横轴上的投影就是 sin(ωt) . 假设两个不同时间的钟表叠放在一起, 你坐在其中的一个秒指针上, 你会发现另一块表的秒指针是静止的, 并且在你的指针上的投影是固定的。现在设想一下很多块表的秒指针以不同的速率旋转, 而你所乘坐的秒指针可以控制旋转速率, 那么你会发现, 总可以使某一个秒指针看上去是静止的, 即在你的指针上的投影是常数,与速度无关。

傅里叶变换出来的是什么? 以离散的傅里叶变换DFT/FFT 来说明,对N点的数据做傅里叶变换,得到了 N/2 个复数, 这每一个复数实际上代表了一个正弦波, 假设 采样频率为 F, 那么基本频率为   ω0 = 2*PI*F/N

这 N/2 个复数:
      Y[0] = x0 + j y0 :  ω  = 0,  即 DC.
      Y[1] = x1 + j y1 = r1* e^(j a1)  :   ω  =     ω0, 代表正弦波 r1* sin(    ω0 * t  + a1)
      Y[2] = x2 + j y2 = r2* e^(j a2)  :   ω  = 2* ω0, 代表正弦波 r2* sin(2* ω0 * t  + a2)
    ....
      Y[k] = xk + j yk = rk* e^(j ak)  :   ω  = k* ω0,   代表正弦波 rk* sin(k* ω0 * t  + ak)
    ...
      Y[N/2 - 1] =


所以, 这些复数的意义在于正弦波的代表, 不是一般意义上的复数。把上面的正弦波叠加在一起, 又可以得到原来的波形。
原野之狼 发表于 2010-8-31 23:39 | 显示全部楼层
testcode 发表于 2010-9-1 08:05 | 显示全部楼层
本帖最后由 testcode 于 2010-9-1 08:07 编辑

听课~~~

另,有没有关于ZOOM FFT应用的例子?
jack_icc 发表于 2010-9-1 08:13 | 显示全部楼层
123jj 发表于 2010-9-1 08:27 | 显示全部楼层
好文,帮顶
jasonell 发表于 2010-9-1 10:55 | 显示全部楼层
学过2年的课程,可惜工作不搭边,现在都忘了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部