使用 FFT 获取频率分量
Posted
技术标签:
【中文标题】使用 FFT 获取频率分量【英文标题】:Getting Frequency Components with FFT 【发布时间】:2013-07-01 23:02:58 【问题描述】:所以我能够解决我的上一个问题,但我已经遇到了下一个问题。
所以我想制作一个简单的频谱图,但为了做到这一点,我想了解 FFT 库的工作原理以及它们实际计算和返回的内容。 (FFT 和信号处理是我一有时间就会进入的第一主题,但现在,我只有晚上的时间进行一些编程练习。;))
这里我只是总结了最重要的部分:
int framesPerSecond;
int samplesPerSecond;
int samplesPerCycle; // right now i want to refresh the spectogram every
DoubleFFT_1D fft;
WAVReader audioIn;
double audioL[], audioR[];
double fftL[], fftR[];
.....
framesPerSecond = 30;
audioIn= new WAVReader("Strobe.wav");
int samplesPerSecond = (int)audioIn.GetSampleRate();
samplesPerCycle = (int)(audioIn.GetSampleRate()/framesPerSecond);
audioL = new double[samplesPerCycle*2];
audioR = new double[samplesPerCycle*2];
fftL = new double[samplesPerCycle];
fftR = new double[samplesPerCycle];
for(int i = 0; i < samplesPerCycle; i++)
// don't even know why,...
fftL[i] = 0;
fftR[i] = 0;
fft = new DoubleFFT_1D(samplesPerCycle);
.....
for(int i = 0; i < samplesPerCycle; i++)
audioIn.GetStereoSamples(temp);
audioL[i]=temp[0];
audioR[i]=temp[1];
fft.realForwardFull(audioL); //still stereo
fft.realForwardFull(audioR);
System.out.println("Check");
for(int i = 0; i < samplesPerCycle; i++)
//storing the magnitude in the fftL/R arrays
fftL[i] = Math.sqrt(audioL[2*i]*audioL[2*i] + audioL[2*i+1]*audioL[2*i+1]);
fftR[i] = Math.sqrt(audioR[2*i]*audioR[2*i] + audioR[2*i+1]*audioR[2*i+1]);
所以问题是,如果我想知道采样信号中有哪些频率,我该如何计算它们? (当我想打印 fftL / fftR 数组时,我会在数组的两端得到一些指数形式。)
谢谢:)
【问题讨论】:
How can I get DFT/FFT output frequencies in Hertz?、How to get Frequency from FFT result、et al ... 的可能重复项 我发现了这些主题,但它没有足够的帮助。在阵列的前几个插槽中写入音频样本然后在位置 2i nd 2i+1 处获取 RE 和 IM 部分,我通常是否正确? (我得到了类似这里显示的东西,但我有点怀疑,这就是我想要的。cnx.org/content/m12554/latest/?collection=col10253/1.7) 那么您需要在 FFT 之前有一个窗口函数,并且您需要计算前 N/2 个 bin 的 FFT 输出的 幅度,然后找到峰值。你对哪一部分有困难? 我不想找到峰值,我想计算每个频率的幅度(或多或少对于 ech 频率区域,如 400 到 800 赫兹、800 到 1600 赫兹之间,......所以我想我已经计算了幅度,对吗?我在计算各个频率范围的值时遇到问题。(就像在频谱图中显示的那样)所以我实际上不知道如何处理我的 fftR 和 fftL 数组,其中包含量级。(我也不知道,我的 fftL-Array 的索引 i 是什么意思。) 好的,那么只需将感兴趣频率上的 bin 幅度相加即可。 【参考方案1】:所以我添加了 Window 功能,但并没有真正改变。 (这有点好,但就像你看不到一样,我认为某处存在问题。我只是发布我计算数组和打印它们的部分:
short temp[] = new short[2];
for(int i = 0; i < samplesPerCycle; i++)
audioIn.GetStereoSamples(temp);
double multiplier = 0.5*(1 - Math.cos(2*Math.PI*i/(samplesPerCycle-1)));
audioL[i]=multiplier*temp[0];
audioR[i]=multiplier*temp[1];
fft.realForwardFull(audioL);
fft.realForwardFull(audioR);
for(int i = 0; i < samplesPerCycle; i++)
fftL[i] = Math.sqrt(audioL[2*i]*audioL[2*i] + audioL[2*i+1]*audioL[2*i+1]);
fftR[i] = Math.sqrt(audioR[2*i]*audioR[2*i] + audioR[2*i+1]*audioR[2*i+1]);
if(fftL[i] > maxValue)
maxValue = fftL[i];
if(fftR[i] > maxValue)
maxValue = fftR[i];
repaint();
我在这里画它们
double dx = (double)this.getWidth()/samplesPerCycle;
for(int i = 0; i < samplesPerCycle; i++)
g.drawLine((int)(i*dx), this.getHeight(), (int)(i*dx),this.getHeight()-(int)((this.getHeight()*fftL[i])/maxValue));
这些是我得到的结果: http://www.pic-upload.de/view-19926382/FFTResult.jpg.html
我在这里错过了什么重要的事情吗?
【讨论】:
以上是关于使用 FFT 获取频率分量的主要内容,如果未能解决你的问题,请参考以下文章