IOS和FFT(vDSP_fft_zrip):频率低于appr。切断100赫兹 - 为什么?

时间:2015-06-19 09:45:41

标签: ios audio core-audio

我使用Novocaine框架进行音高检测。一切运行良好 - 只有图形FFT表示,有一些麻烦。

当我使用音频文件进行输入时,FFT工作正常 - 低于100 Hz的频率可以完美显示。

相反,当我使用麦克风作为输入时,100 Hz以下的频率根本没有显示 - 我无法弄清楚原因!见下面的截图:

正确显示更高的频率(例如1000 Hz)!

这里是FFT程序的源代码:



- (NSMutableArray*)performFFT: (float*) data  withFrames: (int) numSamples {
    // 1. init
    float bufferSize = numSamples;
    uint32_t maxFrames = numSamples;
    displayData = (float*)malloc(maxFrames*sizeof(float));
    bzero(displayData, maxFrames*sizeof(float));
    int log2n = log2f(maxFrames);
    int n = 1 << log2n;
    assert(n == maxFrames);
    float nOver2 = maxFrames/2;
    
    
    A.realp = (float*)malloc(nOver2 * sizeof(float));
    A.imagp = (float*)malloc(nOver2 * sizeof(float));
    fftSetup = vDSP_create_fftsetup(log2n, FFT_RADIX2);
    
    // 2. calcuate
    bufferSize = numSamples;
    float ln = log2f(numSamples);
    vDSP_ctoz((COMPLEX*)data, 2, &A, 1, numSamples/2);
    
    //fft
    vDSP_fft_zrip(fftSetup, &A, 1, ln, FFT_FORWARD);
    
    // Absolute square (equivalent to mag^2)
    vDSP_zvmags(&A, 1, A.realp, 1, numSamples/2);
    // make imaginary part to zero in order to filter them out in the following loop
    bzero(A.imagp, (numSamples/2) * sizeof(float));
    
    //convert complex split to real
    vDSP_ztoc(&A, 1, (COMPLEX*)displayData, 2, numSamples/2);
    
    // Normalize
    float scale = 1.f/displayData[0];
    vDSP_vsmul(displayData, 1, &scale, displayData, 1, numSamples);
    
    
    //scale fft
    Float32 mFFTNormFactor = 1.0/(2*numSamples);
    vDSP_vsmul(A.realp, 1, &mFFTNormFactor, A.realp, 1, numSamples/2);
    vDSP_vsmul(A.imagp, 1, &mFFTNormFactor, A.imagp, 1, numSamples/2);

...
}
&#13;
&#13;
&#13;

对于更多图形问题,我使用 displayData

由于我对较低的频率感兴趣(有一个单独的音调检测算法工作正常),我将采样率降低到11.025(而不是44100)。

在诺沃卡因内,我拨打以下电话:

1)输入

&#13;
&#13;
[audioManager setInputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels) {
            
            // frequency analysis
            vDSP_rmsqv(data, 1, &magnitude, numFrames*numChannels);
            self->ringBuffer->AddNewInterleavedFloatData(data, numFrames, numChannels);
...
}
&#13;
&#13;
&#13;

2)输出:

&#13;
&#13;
[audioManager setOutputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels)
     { 
   self->ringBuffer->FetchInterleavedData(data, numFrames, numChannels);
   ....
   [fft performFFT:data withFrames:numFrames];
   ...
   }
&#13;
&#13;
&#13;

有人有想法吗?

2 个答案:

答案 0 :(得分:1)

这是因为内置麦克风是一个电容式麦克风,并配有一个高通滤波器,用于消除信号上的直流偏置。

可以禁用HPF。直流偏置不是什么大问题,因为它只会在FFT的#2中出现。

[[AVAudioSession sharedInstance] setMode: AVAudioSessionModeMeasurement error:NULL];

另请注意,FFT的窗口化也会影响FFT的低频区间的精度。对于任何给定频率,窗口中至少需要2 * PI样本。

答案 1 :(得分:0)

音高与频谱频率不同。低音调声音通常由谐波和泛音能量组成,并且在基频处没有太多能量。因此,FFT也找不到多少。在找到这些类型的富含谐波的声音的音高时,自相关稍微好一些。

除此之外,iPhone麦克风对低频能量的敏感度不如中高音频(在线audio response graphs)。

另请注意,FFT缓冲器需要按比例更长,以获得低频内容的等效百分比(以美分为单位的回音间距)。低频分辨率通常需要远远超过iOS音频单元提供的任何单个缓冲区的FFT。