Ios 使用纯正弦音调的FFT更精确的频率
我目前使用的FFT代码如下: 以下是两种相关方法的代码:Ios 使用纯正弦音调的FFT更精确的频率,ios,objective-c,audio,signal-processing,fft,Ios,Objective C,Audio,Signal Processing,Fft,我目前使用的FFT代码如下: 以下是两种相关方法的代码: -(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
-(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];
}
-(void)createFFTWithBufferSize:(float)bufferSize与audiodata:(float*)数据{
//设置长度
_log2n=log2f(缓冲区大小);
//计算权重数组。这是一次性操作。
_FFT设置=vDSP_创建_FFT设置(_log2n,FFT_RADIX2);
//对于FFT,numsample必须是2的幂,即始终为偶数
int nOver2=缓冲区大小/2;
//用汉明窗口函数的值填充*窗口
float*window=(float*)malloc(sizeof(float)*bufferSize);
vDSP_hamm_窗口(窗口,缓冲区大小,0);
//将样品开窗
vDSP_vmul(数据,1,窗口,1,数据,1,缓冲区大小);
免费(窗口);
//定义复杂缓冲区
_A.realp=(float*)malloc(nOver2*sizeof(float));
_A.imagp=(浮动*)malloc(11月2日*sizeof(浮动));
}
-(void)updateFFTWithBufferSize:(float)带音频数据的bufferSize:(float*)数据{
//对于FFT,numsample必须是2的幂,即始终为偶数
int nOver2=缓冲区大小/2;
//包装样品:
//C(re)->A[n],C(im)->A[n+1]
vDSP_ctoz((复杂*)数据,2号和1号,11月2日);
//使用FFT设置和
//结果以
vDSP_fft_zrip(_fft设置,&u A,1,_log2n,fft前向);
//将结果转换为量级
浮动放大器[nOver2];
float maxMag=0;
对于(int i=0;i maxMag?mag:maxMag;
}
对于(int i=0;i可能您的采样频率不够高?您可以通过将抛物线曲线拟合到峰值震级仓周围的3个FFT仓震级,然后找到该抛物线的极值来获得粗略的频率估计
通过使用FFT窗口的变换作为插值核,并进行逐次逼近以细化插值点最大值的估计,可以创建更好的估计值。(零填充和使用更长的FFT将提供类似类型的插值估计值。)
平稳信号的简单方法是,如果可能的话,只需使用更长的FFT和更长时间间隔内的更多样本。这里出现了许多问题:
1) 你的频率轴间距是fmax/N,或者大约80Hz,所以你不会得到比这更好的分辨率
2) 你的信号非常接近(即,20KHz/44.1KHz几乎为0.5),当你接近奈奎斯特极限时,如果你想要得到准确的结果,你需要非常小心。(也就是说,在20KHz时,每个完整振荡周期只记录大约两个数据点。)
3) 由于20KHz处于人类听力的边缘(对大多数人来说更高),许多话筒并不真正担心它。iPhone的一种测量方法。如果你对输入一无所知,FFT是获得频谱的一种非常好的方法。如果您知道输入是纯正弦波,您可以做得更好。从计算FFT开始,大致了解正弦的位置。获取最小值和最大值以估计振幅[或从FFT中获取值-将所有输入平方,相加,取平方根],在给定估计频率和振幅的情况下,获取开始和结束处的相位
通常,您会发现相位不匹配。这是因为末端的相位差为2*Δf*N。f-Δf是对频率的更好估计。请记住,这种方法对噪声非常敏感。这种方法之所以有效,是因为输入是一个纯正弦波,而噪声是除此之外的一切。使用这种方法迭代地快速爆炸;您甚至会遇到舍入错误(也不是正弦曲线)
另一个类似的技巧是减去估计的波浪。两个正弦之间的差值是两个正弦的乘积,一个加上频率(在您的情况下为±38.5 kHz),另一个减去频率(Δ_f_,小于100 Hz)。另请参见正弦音调的声音为44.1 kHz,据我所知,这与我产生的频率有关,因为其中一半的频率比我产生的声音高。考虑到无限长的时间,这就足够了。如果您在固定时间段内需要更好的频率分辨率,则确实需要增加采样频率。由于我的声音的采样率为44.1KHz,因此频率分辨率看起来将在20000/256个音箱左右,即78.125。这就是为什么我不能得到一个特定的频率,只有一个在78范围内。还有其他方法可以更具体地描述正弦音吗?如果你能列出相关的数字,比如:缓冲区大小、分辨率等,那会很有帮助。我想目前我的缓冲区大小是512。我将在哪里/如何增加它?您的频率分辨率将受到采样频率和缓冲区大小的限制。您好,Codeman,您能给我发送增加缓冲区大小的修改代码吗(我面临着类似的问题,我已经工作了一个月了)我将如何增加我的缓冲区大小?这是我可以在代码中手动更改的吗?@codeman:是的,FFT对接受多少点没有实际限制。如果你想通过262.144分而不是512分,它仍然有效。不过,频率分辨率*时间分辨率=2,因此填充该缓冲区将花费512倍的时间。
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);