我目前正在使用此处的FFT代码:https://github.com/syedhali/ezaudio/tree/master/ezaudioexamples/ios/ezaudiofftexample
这是来自2种相关方法的代码:
-(void)createFFTWithBufferSize:(float)bufferSize withAudioData:(float*)data {
// Setup the length
_log2n = log2f(bufferSize);
// Calculate the weights array. This is a one-off operation.
_FFTSetup = vDSP_create_fftsetup(_log2n, FFT_RADIX2);
// For an FFT, numSamples must be a power of 2, i.e. is always even
int nOver2 = bufferSize/2;
// Populate *window with the values for a hamming window function
float *window = (float *)malloc(sizeof(float)*bufferSize);
vDSP_hamm_window(window, bufferSize, 0);
// Window the samples
vDSP_vmul(data, 1, window, 1, data, 1, bufferSize);
free(window);
// Define complex buffer
_A.realp = (float *) malloc(nOver2*sizeof(float));
_A.imagp = (float *) malloc(nOver2*sizeof(float));
}
-(void)updateFFTWithBufferSize:(float)bufferSize withAudioData:(float*)data {
// For an FFT, numSamples must be a power of 2, i.e. is always even
int nOver2 = bufferSize/2;
// Pack samples:
// C(re) -> A[n], C(im) -> A[n+1]
vDSP_ctoz((COMPLEX*)data, 2, &_A, 1, nOver2);
// Perform a forward FFT using fftSetup and A
// Results are returned in A
vDSP_fft_zrip(_FFTSetup, &_A, 1, _log2n, FFT_FORWARD);
// Convert COMPLEX_SPLIT A result to magnitudes
float amp[nOver2];
float maxMag = 0;
for(int i=0; i<nOver2; i++) {
// Calculate the magnitude
float mag = _A.realp[i]*_A.realp[i]+_A.imagp[i]*_A.imagp[i];
maxMag = mag > maxMag ? mag : maxMag;
}
for(int i=0; i<nOver2; i++) {
// Calculate the magnitude
float mag = _A.realp[i]*_A.realp[i]+_A.imagp[i]*_A.imagp[i];
// Bind the value to be less than 1.0 to fit in the graph
amp[i] = [EZAudio MAP:mag leftMin:0.0 leftMax:maxMag rightMin:0.0 rightMax:1.0];
}
我已经修改了上面的updatefftwithbuffersize方法,以便我可以在这样的hz中获得频率:
for(int i=0; i<nOver2; i++) {
// Calculate the magnitude
float mag = _A.realp[i]*_A.realp[i]+_A.imagp[i]*_A.imagp[i];
if(maxMag < mag) {
_i_max = i;
}
maxMag = mag > maxMag ? mag : maxMag;
}
float frequency = _i_max / bufferSize * 44100;
NSLog(@"FREQUENCY: %f", frequency);
我已经在不同的频率测试时生成了一些纯粹的正弦音调。我看到的问题是,对于两个不同的正弦音调,代码返回相同的频率,这些音调相对接近。
例如:19255Hz产生的正弦音色将从FFT出现为19293.750000Hz。19330Hz产生的正弦音调也会因此。计算中必须关闭某些东西。
在如何修改上述代码以获取更精确的FFT频率读取纯正弦音调方面的任何帮助。谢谢!
您可以通过将抛物线曲线拟合到峰值幅度bin周围的3 fft bin尺寸,然后找到该抛物线的极端。
,可以获得粗略的频率估计。可以通过使用FFT窗口的转换作为插值内核来创建更好的估计,并进行连续的近似以完善插值点的最大值的估计值。(零填充和使用更长的FFT将为您提供类似类型的插值估计。)
固定信号的简便方法是,如果可能的话,只需使用更长的fft,其中包含更多跨越时间间隔的样本。
您在这里遇到了许多问题:
1)您的频率轴间距是f
2)您的信号非常接近Nyquist频率(即20KHz/44.1kHz几乎是0.5),当您接近Nyquist限制时,如果需要准确的结果,您需要非常小心。(也就是说,在20kHz时,您只记录每个完整振荡周期的两个数据点。)
3)由于20KHz处于人类听力的边缘(对于大多数人来说),因此许多麦克风并不真正担心。这是iPhone的测量。
也许您的采样频率不够高?
如果您对输入一无所知,则FFT是获得频谱的一个很好的方法。如果您知道输入是纯正弦波,那么您可以做得更好。首先计算FFT,以了解正弦的位置。获取最小值和最大值以估计幅度[或从FFT - 平方所有输入中获取幅度,添加它们,取平方根],考虑到估计的频率和振幅,在开始和结束时获得相位。
通常,您会发现阶段不匹配。那是因为末端的相位被2 *Δ f * N. f - Δ f 是对频率的更好估计。请记住,这种方法对超级噪声敏感。该方法之所以起作用,是因为输入是纯正弦波,而噪声只是一切。使用此方法迭代迅速炸毁;您甚至遇到了四舍五入错误(也不是正弦)
另一个类似的技巧是减去估计的波。两种罪之间的差异是两种罪的乘积,一个添加了频率(在您的情况下,±38.5 kHz),一个频率减去频率(Δ_F_,小于100 Hz)。另请参见杂差检测