我目前正忙着练习,而我的老板要我在java编程的一周结束时准备好FFT。
现在我已经从普林斯顿大学获得了一个FFT代码:http://introcs.cs.princeton.edu/java/97data/FFT.java
我在我的项目中实现并扩展了这段代码,我现在可以先读取信号的二进制输入,然后对这些样本值进行FFT处理,然后提供幅度。
现在我遇到了问题。
我输入了以下final double d = Math.sin(i);
生成的值并循环了8次(这仅用于测试目的,下周我将不得不输入实际值)。
0.0
0.8414709848078965
0.9092974268256817
0.1411200080598672
-0.7568024953079282
-0.9589242746631385
-0.27941549819892586
0.6569865987187891
所以这些价值来自一个纯粹的正弦(我不知道正确的英语单词,但纯粹的正弦,我指的是一个只有一个频率的正弦,例如50赫兹)。
现在输出
0.553732750242242
2.3946469565385193 - 2.0970118573701813i
-1.386684423934684 + 0.9155598966338983i
-0.8810419659226628 + 0.28041399267903344i
-0.8075738836045867
-0.8810419659226628 - 0.28041399267903366i
-1.386684423934684 - 0.9155598966338983i
2.394646956538519 + 2.0970118573701817i
输出的大小
0.553732750242242
3.183047718211326
1.6616689248786416
0.9245901540720989
0.8075738836045867
0.924590154072099
1.6616689248786416
3.183047718211326
现在我实际上期望在每个频率采样点处输出值为0,直到我达到纯正弦被支配的频率,其中输出应该> 0(例如在50Hz)。至少那是我老板给他这个任务时的期望。
要点: 所以这就是我所挣扎的。我已经阅读了另一个询问类似问题的帖子,但对我来说还有一些未解决的问题。我应该对给定的输出数据做什么?如何找到最常出现的频率?
我真的需要一些帮助或解释我的想法是错误的。
感谢您的聆听...
答案 0 :(得分:1)
在应用简单窗函数后计算512点傅里叶变换:
w(i)= ((float)i-(float)(n-1f)/2f)
它在i = 25时给出峰值(结果数组上的最大幅度)。
还增加了输入信息,例如正弦波发生器的频率(50 Hz)和采样率(每个样本1kHz或0.001秒)并添加2PI常数:
初始化现在看起来像这样(作为sin(2xPIxFxi)表示法):
for (int i = 0; i < n; i++)
{
v1[i] = ((float)i-(float)(n-1f)/2f)*
(float)Math.Sin(0.001f* 50f*2f*Math.PI*(float)i);
^ ^ ^ ^
| | | |
| F | |
sampling 2xPi constant sample bin
rate(simulation)
}
和结果峰看起来像:
v2[22] 2145,21852033773
v2[23] 3283,36245333956
v2[24] 6368,06249969329
v2[25] 28160,6579468591 <-- peak
v2[26] 23231,0481898687
v2[27] 1503,8455705291
v2[28] 1708,68502071037
所以我们有
25
现在这些步骤都在频率空间,输入频率为1kHz,因此您可以感知最大500 Hz的谐波信号(采样率的一半)。
25*500 = 12500
结果范围为0到N / 2,其他半镜像,并将可感知的频率范围(500)除以结果范围(N = 512为256)给出
48.83 Hz
错误的大部分必须是开头使用的窗口函数但是v2 [26]的值高于v2 [24],所以实际的选择更接近v2 [26]并且这些的平滑图点数应显示50 Hz 。
忽略结果数组的第一个元素,因为它是关于恒定信号电平或无限波长或零频率。
以下是dft计算代码,以确保fft是否正在返回正确的结果:
//a---->b Fourier Transformation brute-force
__kernel void dft(__global float *aRe,
__global float *aIm,
__global float *bRe,
__global float *bIm)
{
int id=get_global_id(0); // thread id
int s=get_global_size(0); // total threads = 512
double cRe=0.0f;
double cIm=0.0f;
double fid=(double)id;
double fmpi2n=(-2.0*M_PI)*fid/(double)s;
for(int i=0;i<s;i++)
{
double fi=(float)i;
double re=cos(fmpi2n*fi);
double im=sin(fmpi2n*fi);
cRe+=aRe[i]*re-aIm[i]*im;
cIm+=aRe[i]*im+aIm[i]*re;
}
bRe[id]=cRe;
bIm[id]=cIm;
}
并且可以肯定的是,针对逆变换测试结果以检查是否再次实现原始输入信号:
// a--->b inverse Fourier Transformation brute force
__kernel void idft(__global float *aRe,
__global float *aIm,
__global float *bRe,
__global float *bIm)
{
int id=get_global_id(0); // thread id
int s=get_global_size(0); // total threads = 512
double cRe=0.0f;
double cIm=0.0f;
for(int i=0;i<s;i++)
{
double re=cos(2.0*M_PI*((double)id)*((double)i)/(double)s);
double im=sin(2.0*M_PI*((double)id)*((double)i)/(double)s);
cRe+=aRe[i]*re-aIm[i]*im;
cIm+=aRe[i]*im+aIm[i]*re;
}
cRe/=(double)s;
cIm/=(double)s;
bRe[id]=cRe;
bIm[id]=cIm;
}
我知道在快速机器上运行慢速代码很糟糕,但这看起来更简单,并且可以扩展到许多内核(对于包含阵列副本的320core-gpu,为2.4ms)。