如何让iOS加速FFT产生频率幅度?

时间:2014-09-22 21:32:52

标签: ios iphone signal-processing fft accelerate-framework

我使用此代码(基于Apple的audioRouch示例):

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值(左起第1条黑线)看起来没问题,正确表示y = sin(x)+ 1垂直偏移。

但是为什么第二条黑线代表了正弦方程中唯一存在的频率没有幅度= 1并且不完全保持在1Hz?

有人能指点我使用vDSP函数将FFT结果从输入信号转换为幅度单位吗?

1 个答案:

答案 0 :(得分:2)

简答:

您似乎正在使用我在这个地方的答案中的代码:https://stackoverflow.com/a/19966776/468812 它很棒,但是:

您无法避免信号中的这些额外频率。

您生成的信号(正弦波)是无限信号。 如果你&#34;裁剪它&#34;和&#34;只使用一段信号&#34;它介绍了&#34;削波噪声&#34;在两端。

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

请参阅this article,google:光谱泄漏,窗口功能。