2014-09-22 89 views
0

我用这个代码(基于苹果的audioRouch样品):如何获得iOS在FFT频率上加速FFT结果?

void FFTHelper::ComputeFFT(Float32* inAudioData, Float32* outFFTData) 
{ 
    if (inAudioData == NULL || outFFTData == NULL) return; 

    // Generate a split complex vector from the real data 
    vDSP_ctoz((COMPLEX *)inAudioData, 2, &mDspSplitComplex, 1, mFFTLength); 

    // Take the fft and scale appropriately 
    vDSP_fft_zrip(mSpectrumAnalysis, &mDspSplitComplex, 1, mLog2N, kFFTDirection_Forward); 
    vDSP_vsmul(mDspSplitComplex.realp, 1, &mFFTNormFactor, mDspSplitComplex.realp, 1, mFFTLength); 
    vDSP_vsmul(mDspSplitComplex.imagp, 1, &mFFTNormFactor, mDspSplitComplex.imagp, 1, mFFTLength); 

    // Zero out the nyquist value 
    mDspSplitComplex.imagp[0] = 0.0; 

    // Complex vector magnitudes squared; single precision. 
    // Calculates the squared magnitudes of complex vector A. 
    vDSP_zvmags(&mDspSplitComplex, 1, outFFTData, 1, mFFTLength); 

} 

为了计算上尽可能简单的FFT - 1Hz的正弦波(1个单位移):

Float32 waveFreq   = 1.0; 
    int  samplesCount  = 1024; 
    Float32 samplesPerSecond = 1000;  //sample rate 
    Float32 dt = 1/samplesPerSecond; 
    Float32 sd = M_PI * 2.0 * waveFreq; 

    FFTHelper *mFFTHelper = new FFTHelper(samplesCount); 

    Float32 NyquistMaxFreq = samplesPerSecond/2.0; 
    Float32 fftDataSize  = samplesCount/2.0; 

    Float32 *sinusoidOriginal = (Float32 *)malloc(sizeof(Float32) * samplesCount); 
    Float32 *outFFTData = (Float32 *)malloc(sizeof(Float32) * fftDataSize); 

    // 2. Generate sin samples: 
    for (int i = 0; i < samplesCount; i++) { 

     Float32 x = dt * i; 
     sinusoidOriginal[i] = sin(sd * x) + 1; 
     [originalPlot addVector2D:GLVector2DMake(x, sinusoidOriginal[i])]; 
    } 

    mFFTHelper->ComputeFFT(sinusoidOriginal, outFFTData); 

    for (int i = 0; i < fftDataSize; i++) { 

      Float32 hz = ((Float32)i/(Float32)fftDataSize) * NyquistMaxFreq; 
      GLfloat mag = outFFTData[i]; 
      [fftPlot addVector2D:GLVector2DMake(hz, 0)]; 
      [fftPlot addVector2D:GLVector2DMake(hz, mag)]; 

    } 

结果我得到的是:

enter image description here

黑线是来自FTT的绘图仪结果,水平定位在它们的频率上。 DC值(左起第一条黑线)看起来正常,正确表示y = sin(x)+1垂直偏移。

但为什么第二条黑线表示窦性方程中存在的唯一频率,没有大小= 1,并且不完全保持在1Hz?

任何人都可以指向我的vDSP函数将FFT结果转换为输入信号的幅度单位吗?

回答

2

简短的回答:

你似乎使用的代码从这个地方我的回答:https://stackoverflow.com/a/19966776/468812 ,它的伟大,但:

你不能避免在信号中的这些额外的频率。

您生成的信号(正弦波)是一个无限信号。 如果你“裁剪它”和“只使用一段信号”,它会在两端引入“剪切噪声”。

但是,您可以通过在FFT之前采用较大的输入块和using windowing来最小化噪声。 Accelerate Framework提供了一些很好且简单的窗口函数。 (例如Hann Function,vDSP_hann_window) 另外 - 使用更大的输入块。更大的输入更精确的是频率检测。

请参阅this article,谷歌:频谱泄漏,窗口功能。