【问题标题】:How to get iOS Accelerate FFT results in frequency magnitudes?如何获得 iOS Accelerate FFT 结果的频率幅度?
【发布时间】:2014-09-22 21:32:51
【问题描述】:

我使用此代码(基于 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);

}

在最简单的可能 - 1Hz 正弦波上计算 FFT(上移 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)];

    }

我得到的结果是:

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

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

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

【问题讨论】:

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


    【解决方案1】:

    简答:

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

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

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

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

    参见this article,google:Spectral Leakage,窗函数。

    【讨论】:

      猜你喜欢
      • 2012-05-05
      • 1970-01-01
      • 2019-09-05
      • 2011-12-02
      • 1970-01-01
      • 2011-09-06
      • 2014-05-04
      • 1970-01-01
      • 2011-05-20
      相关资源
      最近更新 更多