用于从FFT结果中获取频率的Java代码

时间:2012-06-17 08:54:47

标签: java signal-processing fft

我有一个包含直接来自麦克风的音频样本的双打数组,采样率为44100.我想得到基频(样本包含幅度)。在自相关页面的维基百科上,我找到了基于Wiener-Khinchin定理的解决方案的描述,我通过互联网进行了更多的研究完成了算法,最后我编写了以下代码,但我不确定它是否正确:

private double determineFrequency(double[] signal) {
 //Get a FastFourierTransformer instance (Apache library)
 FastFourierTransformer fft = new FastFourierTransformer(DftNormalization.STANDARD);

 //The size of the array used by the fft must be a power of two, wrapping 
 //the original array in a bigger one padded to zero
 //NOTE: Here I assume that the input array is smaller than 8192
 double[] paddedSignal = new double[8192];
 System.arraycopy(signal, 0, paddedSignal, 0, signal.length);

 //First fft (forward) to switch from amplitude domain to the frequency domain
 Complex[] transformed = fft.transform(paddedSignal, TransformType.FORWARD);

 // Calculate the conjugate of the complex array
 for (int i=0; i<transformed.length; i++)
  transformed[i] = transformed[i].conjugate();

 //Second fft (inverse) to complete the autocorrelation
 transformed = fft.transform(transformed, TransformType.INVERSE);

 //Calculate the array of corresponding real values to switch 
 // from the frequency domain to the amplitude domain
 double[] autocorrelationMatrix = new double[transformed.length];
 for (int i=0; i<transformed.length; i++) {
  if (Double.isNaN(transformed[i].abs()) || Double.isInfinite(transformed[i].abs()))
   autocorrelationMatrix[i] = 0;
  else
   autocorrelationMatrix[i] = transformed[i].abs();
 }

 //Get the index of the max amplitude
 Integer indexOfMax = Utils.indexOfMax(autocorrelationMatrix);

 return transformed[indexOfMax].getReal()*audioFormat.getSampleRate()/transformed.length; 
}

1 个答案:

答案 0 :(得分:0)

您在自相关域中找到了最大值,然后使用它来读取频域。这不会起作用,只不过你可以使用时域中的索引来学习有关频域的信息。

相反,

return autocorrelationMatrix[indexOfMax].getReal()*audioFormat.getSampleRate()/autocorrelationMatrix.length;

那就是说,你可能会发现更容易避免额外的IFFT。相反,只需从频域中提取最大绝对值。这将对采样率/变换长度的分辨率起作用,并且可以在最大FFT bin的相位辅助下进行细化。