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

[复制链接]
xuyiyi 发表于 2010-8-30 07:49 | 显示全部楼层
请继续! 顶!
 楼主| highgear 发表于 2010-8-30 08:06 | 显示全部楼层

*

本帖最后由 highgear 于 2010-8-30 08:28 编辑

(5) 问题 A 的解答
在上面的代码 CalculateHarmonic(Complex* X, int harmonic) 中可以看出dft 的各次谐波计算是独立的, 不依赖其它次谐波。而且,问题 A 不需要计算2次(100hz),3次(150hz)等等谐波,这是 dft 的优点之一。首先,定义两个复数的结构:


  1. typedef short int16;
  2. typedef int int32;
  3. typedef struct SComplex
  4. {
  5. int16 R;
  6. int16 I;
  7. } Complex;
  8. typedef struct SComplex32
  9. {
  10. int32 R;
  11. int32 I;
  12. } Complex32;


接着, 定义两个常数以及电压电流的结构:


  1. #define N 16       //每周期采样点数
  2. #define LOG2_N 4   // log2(N)

  3. struct UI {
  4. Complex  U;         //电压的结果
  5. Complex  I;   //电流的结果
  6.   int16  Voltage[N]; //先前的 N 个电压
  7. int16  Current[N];   //先前的 N 个电流
  8. Complex32 UAcc;  //电压的累加器
  9. Complex32 IAcc;   //电流的累加器
  10. int   Index;  //迭代索引计数器, 8-BIT MCU 可以为 char, 如果 N < 256.
  11. Complex  W[N];  //N 点的 cos, sin 系数
  12. } ui;

初始化,cos, sin 系数数组应该事先计算好:


  1. void UI_Init()
  2. {
  3. for (int i=0; i<N; i++) {
  4.   ui.W[i].R = (int16) (::cos( 2*3.1415927*i/N) * (1<<14) + 0.5); //应离线计算!!!
  5.   ui.W[i].I = (int16) (::sin(-2*3.1415927*i/N) * (1<<14) + 0.5);
  6.   ui.Voltage[i] = 0;
  7.   ui.Current[i] = 0;
  8. }
  9. ui.UAcc.R = 0; ui.UAcc.I = 0;
  10. ui.IAcc.R = 0; ui.IAcc.I = 0;
  11. ui.Index = 0;
  12. }

下面的代码不断递推, 可以求出电压和电流的复数:


  1. void UI_Calculate(int16 voltage, int16 current)
  2. {
  3. int16 d;
  4. d = voltage - ui.Voltage[ui.Index];
  5. ui.Voltage[ui.Index] = voltage;
  6. ui.UAcc.R += (d * ui.W[ui.Index].R) >> (13 + LOG2_N - 16);
  7. ui.UAcc.I += (d * ui.W[ui.Index].I) >> (13 + LOG2_N - 16);
  8. ui.U.R = (int16) (ui.UAcc.R >> 16);
  9. ui.U.I = (int16) (ui.UAcc.I >> 16);
  10. d = current - ui.Current[ui.Index];
  11. ui.Current[ui.Index] = current;
  12. ui.IAcc.R += (d * ui.W[ui.Index].R) >> (13 + LOG2_N - 16);
  13. ui.IAcc.I += (d * ui.W[ui.Index].I) >> (13 + LOG2_N - 16);
  14. ui.I.R = (int16) (ui.IAcc.R >> 16);
  15. ui.I.I = (int16) (ui.IAcc.I >> 16);

  16. ui.Index = (ui.Index + 1) & (N-1);
  17. }

  

上面的计算dft计算使用的是 16-bit, 32-bit 的定点运算,这里需要把电压和电流单位化。比如系统最大电压幅值为 Vmax = 400V,最大电流幅值 Imax = 20A, 在数字系统中统一归一化:  Q15 = 2^15 = 32768. 即 Vmax,Imax在数字系统对应Q15 = 32768. 因此,演示主程序中的:
     8000 ---〉8000/Q15 * Vmax  =  97.66V
     4000 ---〉4000/Q15 * Imax  =   2.441A

至于功率,很简单, 用电压乘以电流的轭(用 j 来代替复数i, 以免混淆):
     P + jQ = U*I’ = (ui.U.R + j ui.U.I) * (ui.I.R – j ui.I.I)
P是有功功率, Q是无功功率;
功率因数为:cos(theta) = P / sqrt(P*P +Q*Q)     



  1. visual c++下的演示主程序 :
  2. #include "stdafx.h"
  3. #include "Math.h"
  4. #include "stdio.h"
  5. #include "UI.h"
  6. #define Magnitude(c) ((int) sqrtf(c.R*c.R + c.I*c.I))
  7. #define PI 3.14159265f
  8. int _tmain(int argc, _TCHAR* argv[])
  9. {
  10. int16 voltage, current;
  11. Complex PQ;
  12. UI_Init();
  13. for (int i=0; i<1000; i++) {
  14.   voltage = (int16) (::sin(2*PI*i/N)*8000);    //模拟采样电压
  15.   current = (int16) (::sin(2*PI*i/N + PI/3)* 4000);  //模拟采样电流
  16.   UI_Calculate(voltage, current);
  17. }
  18. PQ.R = (ui.U.R * ui.I.R + ui.U.I * ui.I.I) >> 15;
  19. PQ.I = (ui.U.I * ui.I.R - ui.U.R * ui.I.I) >> 15;
  20. printf("Voltage: %d\n",  Magnitude(ui.U));
  21. printf("Cuurent: %d\n",  Magnitude(ui.I));
  22. printf("Power Factor: %d\n", PQ.R * 1000 / Magnitude(PQ));
  23. ::getchar();
  24. return 0;
  25. }

结果
Voltage: 8000
Cuurent: 3999
Power Factor: 500


machunshui 发表于 2010-8-30 08:26 | 显示全部楼层
顶一下。
要搞清楚,还是要先静下心来看书。
itelectron 发表于 2010-8-30 08:39 | 显示全部楼层
望断云山 发表于 2010-8-30 10:47 | 显示全部楼层
专程前来学习,并非偶然路过。
123jj 发表于 2010-8-30 10:55 | 显示全部楼层
学习,学习,继续跟highgear老师学习。
宇宙飞船 发表于 2010-8-30 12:15 | 显示全部楼层
对于没有数字信号处理基础的电工,既使放出应用代码,变换数学公式,也没有能力去弄懂博立叶变换的原理。
除非楼主有能力用初等数学夹杂在一起讲解。但是这需要楼主确彻地精通博立叶变换。
雪山飞狐D 发表于 2010-8-30 12:21 | 显示全部楼层
要想正真理解,关键是对系统响应的物理过程的理解
btiger2000 发表于 2010-8-30 12:29 | 显示全部楼层
路过,学习!
望断云山 发表于 2010-8-30 13:12 | 显示全部楼层
飞船何不一句话点爆傅里叶变换?:lol
宇宙飞船 发表于 2010-8-30 14:35 | 显示全部楼层
要具备一些数学基础知识。好比如连欧姆定律,方程组还不会解的情况下,谈何学习模拟基础电路。
本飞船一句话点破是对于已有基础的电工,并非针对任何没有基础的电子菜鸟。
但是21IC这里已经有一些基础的电工,给飞船的感觉是很“串”----广东话。
做任何事都要负出代价的,“串”过之后所负出的代价,那就是在今后自学过程中负出的痛苦时间。
xuyiyi 发表于 2010-8-30 14:41 | 显示全部楼层
这么漂亮的楼,怎么看见一只苍蝇在飞?

谁放进来的?拖出去砍了~~~ :@
超级马夹 发表于 2010-8-30 14:56 | 显示全部楼层
垃圾堆中当然有苍蝇了,在“我们的--AVR”上好象没有发现苍蝇。
因为那里很干净纯正。
yewuyi 发表于 2010-8-30 15:36 | 显示全部楼层
呵呵,还有人开课啊。。。


BBS有希望了。。。
TCL 发表于 2010-8-30 18:23 | 显示全部楼层
使用FFT的话,不仅是考考知识,主要是在考耐心.
搞好了,不仅能区分50和55HZ的信号.能从1万个人的声音中找到一个人的声音.简单的就是现在的电话和电视的声音比以前的声音清楚,就是用了FFT技术
TCL 发表于 2010-8-30 18:26 | 显示全部楼层
我到现在还是用汇编语言,搞懂FFT就简单了许多!
xuyiyi 发表于 2010-8-30 18:37 | 显示全部楼层
LS又是神仙,能从1万个人的声音中找到一个人的声音.  ;P
yuyi21ic 发表于 2010-8-30 18:59 | 显示全部楼层
哈哈,正好我这学期选修课选了一门数字信号处理,看来用的上喽!!!得好好看看!
lymum 发表于 2010-8-30 19:28 | 显示全部楼层
我是来听课的
odqqdo 发表于 2010-8-30 19:48 | 显示全部楼层
楼主有没有C代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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