硬汉嵌入式论坛

 找回密码
 立即注册
查看: 2966|回复: 12
收起左侧

FFT求得的相位一直在变化

[复制链接]

22

主题

45

回帖

111

积分

初级会员

积分
111
发表于 2020-6-11 11:19:39 | 显示全部楼层 |阅读模式
请教各位大虾。小弟我通过ADC和DMA双缓冲模式在20ms内采样交流电压256个点。做完fft变换后,通过atan2(b,a)求得的相位一直在0~360之间变化。(b和a是fft处理后数组的第2个点的虚部和实部)。这是软件哪里有问题没有处理好么?检查了好几遍不知该如何入手解决此问题。附上我的fft处理的程序:
  1. <blockquote>//DSP运算函数
复制代码


回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115667
QQ
发表于 2020-6-11 11:46:09 | 显示全部楼层
等我发布案例,最近没顾上整了,忙于ThreadX

FFT加窗插值修正后,求解多次谐波频率,幅值,相位的精度杠杠的
http://www.armbbs.cn/forum.php?m ... id=97787&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

22

主题

45

回帖

111

积分

初级会员

积分
111
 楼主| 发表于 2020-6-11 13:11:08 | 显示全部楼层
eric2013 发表于 2020-6-11 11:46
等我发布案例,最近没顾上整了,忙于ThreadX

FFT加窗插值修正后,求解多次谐波频率,幅值,相位的精度杠 ...

硬汉哥,我现在对精度的要求还不是特别高。就是软件处理上有疑问。求相位的时候是不是要取多个周期的波形来求啊?我现在的相位角会在0~360之间变化
回复

使用道具 举报

22

主题

45

回帖

111

积分

初级会员

积分
111
 楼主| 发表于 2020-6-11 13:12:05 | 显示全部楼层
  1. void DSP_Process(void)
  2. {               
  3.                 u16 i=0,a=0;
  4.                 //初始化scfft结构体,设定FFT相关参数
  5.                 arm_cfft_radix4_init_f32(&scfft,FFT_LENGTH,0,1);
  6.           float GLYS_A=0,GLYS_B=0,GLYS_C=0;
  7.                 float PowerA=0,PowerB=0,PowerC=0;
  8.           if(Conv_flag)//DMA有准备好的数据了
  9.                 {
  10.                            a=DMA_GetCurrentMemoryTarget(DMA2_Stream0);
  11.                                  if(a == DMA_Memory_0)
  12.                                  {
  13.                                          ADC_ConvertedValueptr = uAD_Buff_B;
  14.                                  }
  15.                                  else
  16.                                  {
  17.                                          ADC_ConvertedValueptr = uAD_Buff_A;
  18.                                  }
  19.                                 for(i=0;i<FFT_LENGTH;i++)
  20.                                 {
  21.                                                 ADC_Three_V[0][i]=ADC_ConvertedValueptr[i*6];
  22.                                                 ADC_Three_V[1][i]=ADC_ConvertedValueptr[1+i*6];
  23.                                                 ADC_Three_V[2][i]=ADC_ConvertedValueptr[2+i*6];
  24.                                                 True_Three_V[0][i]=(VDDA_VAL*(ADC_Three_V[0][i]-VOLTAGE_Zero-Voltage_A_Devi))/4096/R2*R1;
  25.                                                 True_Three_V[1][i]=(VDDA_VAL*(ADC_Three_V[1][i]-VOLTAGE_Zero-Voltage_B_Devi))/4096/R2*R1;
  26.                                                 True_Three_V[2][i]=(VDDA_VAL*(ADC_Three_V[2][i]-VOLTAGE_Zero-Voltage_C_Devi))/4096/R2*R1;
  27.                                                 fft_inputbuf_V[0][2*i]=True_Three_V[0][i];        //实部
  28.                                                 fft_inputbuf_V[0][2*i+1]=0;//虚部全部为0
  29.                                                 fft_inputbuf_V[1][2*i]=True_Three_V[1][i];        //实部
  30.                                                 fft_inputbuf_V[1][2*i+1]=0;//虚部全部为0
  31.                                                 fft_inputbuf_V[2][2*i]=True_Three_V[2][i];        //实部
  32.                                                 fft_inputbuf_V[2][2*i+1]=0;//虚部全部为0                       
  33.                                                 ADC_Three_I[0][i]=ADC_ConvertedValueptr[3+i*6];
  34.                                                 ADC_Three_I[1][i]=ADC_ConvertedValueptr[4+i*6];
  35.                                                 ADC_Three_I[2][i]=ADC_ConvertedValueptr[5+i*6];
  36.                                                 True_Three_I[0][i]=(VDDA_VAL*(ADC_Three_I[0][i]-VOLTAGE_Zero-Current_A_Devi))/4096/R3*3000;
  37.                                                 True_Three_I[1][i]=(VDDA_VAL*(ADC_Three_I[1][i]-VOLTAGE_Zero-Current_B_Devi))/4096/R3*3000;
  38.                                                 True_Three_I[2][i]=(VDDA_VAL*(ADC_Three_I[2][i]-VOLTAGE_Zero-Current_C_Devi))/4096/R3*3000;
  39.                                                 fft_inputbuf_I[0][2*i]=True_Three_I[0][i];        //实部
  40.                                                 fft_inputbuf_I[0][2*i+1]=0;//虚部全部为0
  41.                                                 fft_inputbuf_I[1][2*i]=True_Three_I[1][i];        //实部
  42.                                                 fft_inputbuf_I[1][2*i+1]=0;//虚部全部为0
  43.                                                 fft_inputbuf_I[2][2*i]=True_Three_I[2][i];        //实部
  44.                                                 fft_inputbuf_I[2][2*i+1]=0;//虚部全部为0
  45.                                 }               
  46.                                 //电压电流有效值
  47.                                 arm_rms_f32(True_Three_V[0],FFT_LENGTH,&VARms);
  48.                                 arm_rms_f32(True_Three_V[1],FFT_LENGTH,&VBRms);   
  49.                                 arm_rms_f32(True_Three_V[2],FFT_LENGTH,&VCRms);   
  50.                                 arm_rms_f32(True_Three_I[0],FFT_LENGTH,&IARms);  
  51.                                 arm_rms_f32(True_Three_I[1],FFT_LENGTH,&IBRms);   
  52.                                 arm_rms_f32(True_Three_I[2],FFT_LENGTH,&ICRms);
  53.                                 //电压数据FFT计算(基4)
  54.                                 arm_cfft_radix4_f32(&scfft,fft_inputbuf_V[0]);
  55.                                 arm_cfft_radix4_f32(&scfft,fft_inputbuf_V[1]);
  56.                                 arm_cfft_radix4_f32(&scfft,fft_inputbuf_V[2]);               
  57.                                 //电流数据FFT计算(基4)
  58.                                 arm_cfft_radix4_f32(&scfft,fft_inputbuf_I[0]);
  59.                                 arm_cfft_radix4_f32(&scfft,fft_inputbuf_I[1]);
  60.                                 arm_cfft_radix4_f32(&scfft,fft_inputbuf_I[2]);       
  61. //        MaxVA=(float)(sqrt(fft_inputbuf_V[0][2]*fft_inputbuf_V[0][2]+fft_inputbuf_V[0][3]*fft_inputbuf_V[0][3]))/128;
  62.                                 //角度
  63.                                 jiaodu_VA=JiaoDu_Process(fft_inputbuf_V[0]);
  64.                                 if(jiaodu_VA<0)
  65.                                 jiaodu_VA+=360.0;
  66.                                 jiaodu_VB=JiaoDu_Process(fft_inputbuf_V[1]);
  67.                                 if(jiaodu_VB<0)
  68.                                 jiaodu_VB+=360.0;                               
  69.                                 jiaodu_VC=JiaoDu_Process(fft_inputbuf_V[2]);
  70.                                 if(jiaodu_VC<0)
  71.                                 jiaodu_VC+=360.0;               
  72.                                 jiaodu_IA=JiaoDu_Process(fft_inputbuf_I[0]);
  73.                                 jiaodu_IB=JiaoDu_Process(fft_inputbuf_I[1]);
  74.                                 jiaodu_IC=JiaoDu_Process(fft_inputbuf_I[2]);
  75.                                
  76.                                 //功率因素
  77.                                 GLYS_A=Factor_Process(fft_inputbuf_V[0],fft_inputbuf_I[0]);
  78.                                 GLYS_B=Factor_Process(fft_inputbuf_V[1],fft_inputbuf_I[1]);
  79.                                 GLYS_C=Factor_Process(fft_inputbuf_V[2],fft_inputbuf_I[2]);
  80.                                
  81.                                
  82.                                 PowerA=VARms*IARms*GLYS_A;
  83.                                 PowerB=VARms*IARms*GLYS_B;
  84.                                 PowerC=VARms*IARms*GLYS_C;
  85.                                
  86.                                 Tol_Power=PowerA+PowerB+PowerC;
  87.                                 Tol_QPower=VARms*IARms+VARms*IARms+VARms*IARms;
  88.                                 Tol_Factor=(GLYS_A+GLYS_B+GLYS_C)/3;
  89.                                 Conv_flag=0;
  90.            }
  91. }


  92. float Factor_Process(float *fft_Data_V,float *fft_Data_I)
  93. {
  94.             float Real_V,Imaginary_V,hudu_V,Real_C,Imaginary_C,hudu_C,GLYS;
  95.                         Real_V      = fft_Data_V[2];         //timeout3=15
  96.                         Imaginary_V = fft_Data_V[3];
  97.                   hudu_V = atan2(Imaginary_V , Real_V);
  98.                         Real_C      = fft_Data_I[2];
  99.                         Imaginary_C = fft_Data_I[3];
  100.                         hudu_C = atan2(Imaginary_C , Real_C);
  101.                         GLYS=cos(hudu_V-hudu_C); //功率因素       
  102.       return GLYS;
  103. }

  104. float JiaoDu_Process(float *fft_Data)
  105. {
  106.                   float Real,Imaginary,hudu,jiaodu;
  107.                         Real      = fft_Data[2];         //timeout3=15
  108.                         Imaginary = fft_Data[3];
  109.                   hudu = atan2(Imaginary , Real);
  110.                         jiaodu = (float)(hudu* 180 / Pi);
  111.       return jiaodu;
  112. }
复制代码


回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115667
QQ
发表于 2020-6-11 13:20:29 | 显示全部楼层

你这种干求不行的。相位当然是乱跳。
回复

使用道具 举报

22

主题

45

回帖

111

积分

初级会员

积分
111
 楼主| 发表于 2020-6-11 13:25:35 | 显示全部楼层
eric2013 发表于 2020-6-11 13:20
你这种干求不行的。相位当然是乱跳。

是要选个点做参考么?硬汉哥求指点
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115667
QQ
发表于 2020-6-11 13:31:55 | 显示全部楼层
h418452224 发表于 2020-6-11 13:25
是要选个点做参考么?硬汉哥求指点

最简单情况下,如果波形的频率是固定的,至少跳动非常微小的情况下,采样率是此周期的整数倍,一个周期有100个点就行,采集几个周期求FFT,这种情况求解出来的还算准。

如果频率是跳转的范围,就不行了。
回复

使用道具 举报

22

主题

45

回帖

111

积分

初级会员

积分
111
 楼主| 发表于 2020-6-11 13:38:33 | 显示全部楼层
eric2013 发表于 2020-6-11 13:31
最简单情况下,如果波形的频率是固定的,至少跳动非常微小的情况下,采样率是此周期的整数倍,一个周期有 ...

好的,好的。我试试看
回复

使用道具 举报

22

主题

45

回帖

111

积分

初级会员

积分
111
 楼主| 发表于 2020-6-11 18:47:04 | 显示全部楼层
eric2013 发表于 2020-6-11 13:31
最简单情况下,如果波形的频率是固定的,至少跳动非常微小的情况下,采样率是此周期的整数倍,一个周期有 ...

硬汉哥。(采集几个周期求FFT)有什么比较简便的思路么?小弟我刚刚试着实现采4个周期。程序for循环了4遍。这部分看着好臃肿啊
回复

使用道具 举报

22

主题

45

回帖

111

积分

初级会员

积分
111
 楼主| 发表于 2020-6-11 19:53:06 | 显示全部楼层
eric2013 发表于 2020-6-11 13:31
最简单情况下,如果波形的频率是固定的,至少跳动非常微小的情况下,采样率是此周期的整数倍,一个周期有 ...

虽然程序臃肿,但是还是可以用。可是结果算出来的相位角还是会在0~360之间规律的变化
回复

使用道具 举报

1

主题

71

回帖

74

积分

初级会员

积分
74
发表于 2020-6-12 11:25:25 | 显示全部楼层
对的,你的adc 定时器 有误差,不能锁定初始采样的相位,0-360,缓慢连续变化,就没有问题
回复

使用道具 举报

98

主题

356

回帖

650

积分

金牌会员

积分
650
发表于 2020-6-12 13:16:20 | 显示全部楼层
仿真算一下相互之间的相位差,只要相位差不变,算法就没问题,最终的功率应该也是稳定的。
回复

使用道具 举报

2

主题

8

回帖

14

积分

新手上路

积分
14
发表于 2020-9-3 22:02:56 | 显示全部楼层
老哥,我最近也在做这个,有空交流一下哇
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-5-10 23:45 , Processed in 0.300765 second(s), 24 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表