我目前正在使用这里的快速傅立叶变换代码:https://github.com/syedhali/EZAudio/tree/master/EZAudioExamples/iOS/EZAudioFFTExample
以下是两个相关方法的代码:
-(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方法,这样我就可以得到以赫兹表示的频率,如下所示:
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);
我已经产生了几个纯正弦音调与奥迪在不同的频率进行测试。我看到的问题是,对于两个相对接近的正弦音调,代码返回的频率是相同的。
例如:在19255 as时产生的正弦音将从FFT中显示为19293.750000Hz。在19330赫兹时产生的正弦音也是如此。在计算中一定有什么不对劲。
任何帮助,我可以修改上述代码,以获得一个更精确的FFT频率读数的纯正弦音调,是非常感谢的。谢谢!
发布于 2014-01-27 01:18:41
你可以得到一个粗略的频率估计,通过拟合一条抛物线曲线到3个FFT仓的峰值附近,然后找出该抛物线的极值。
利用FFT窗口的变换作为插值核,并通过逐次逼近改进插值点的最大值估计,可以得到更好的估计值。(零填充和使用长得多的FFT会给出类似的插值估计。)
一个平稳信号的简单方法是,如果可能的话,只需使用更长的FFT和更多的样本,跨越更长的时间间隔。
发布于 2014-01-26 15:28:11
也许你的采样频率不够高?
发布于 2014-01-27 21:56:29
如果你对输入一无所知的话,FFT是一个很好的获得频谱的方法。如果你知道输入是一个纯正弦波,你可以做得更好。从计算FFT开始,得到一个大致的正弦值。得到最小和最大估计幅度或从FFT -平方得到所有输入,加它们,平方根,得到相位在开始和结束给定估计的频率和幅度。
一般来说,你会发现这个阶段不匹配。这是因为末端的相位是2*Δf * N,f-Δf是对频率的一个更好的估计。请记住,这种方法是超噪声敏感的。该方法之所以有效,是因为输入是一个纯正弦波,而噪声是除了那个以外的一切。使用这种方法迭代爆破很快,你甚至碰到四舍五入的错误(也不是正弦波)。
另一个类似的技巧是减去估计的波。两个正弦之间的差异是两个正弦波的乘积,一个加上频率(在你的例子中是±38.5 kHz),另一个减去频率(Δ_f_ < 100 Hz)。另见外差检测
https://stackoverflow.com/questions/21365231
复制相似问题