简体   繁体   English

如何获得iOS在频率幅度上的FFT加速结果?

[英]How to get iOS Accelerate FFT results in frequency magnitudes?

I use this code (based on Apple's audioRouch sample): 我使用以下代码(基于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);

}

To compute FFT on the simplest possible - 1Hz sinus wave (shifted up by 1 unit): 要以最简单的方式-1Hz的正弦波 (上移1个单位) 来计算FFT

    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)];

    }

The result I get is: 我得到的结果是:

在此处输入图片说明

Black lines are plotter results from FTT, positioned horizontally at their frequencies. 黑线是FTT的绘图仪结果,以其频率水平放置。 DC value (1st black line from the left) looks OK, correctly represents y = sin(x) + 1 vertical offset. DC值(从左起第1条黑线)看起来不错,正确表示y = sin(x)+ 1垂直偏移。

But why 2nd black line, which represents the only frequency present in sinus equation, does not have magnitude = 1 and does not exactly stay at 1Hz? 但是,为什么第二条黑线(它代表窦性方程中出现的唯一频率) 没有幅度= 1,也不能精确地保持在1Hz?

Can anyone point me to vDSP function to convert FFT results to magnitude units from input signal? 谁能指出我使用vDSP函数将FFT结果从输入信号转换为幅度单位的情况?

Short answer: 简短答案:

You seem to be using the code from my answer from this place: https://stackoverflow.com/a/19966776/468812 And it's great, but: 您似乎正在使用我从以下位置得到的答案中的代码: https : //stackoverflow.com/a/19966776/468812很好,但是:

You can not avoid these extra frequencies in your signal. 您无法避免信号中出现这些多余的频率。

The signal you generate (sin wave) is an infinite signal. 您生成的信号(正弦波)是一个无限大的信号。 And if you "crop it" and "only use a piece of the signal" it introduces "clipping noise" at both ends. 如果“修剪”并且“仅使用一部分信号”,则会在两端引入“削波噪声”。

But you can minimize the noise by taking larger input chunks and using windowing before the FFT. 但是您可以通过占用较大的输入块并在FFT之前使用开窗来将噪声降至最低。 The Accelerate Framework provides some good and simple windowing functions. 加速框架提供了一些良好而简单的窗口功能。 (Ex. Hann Function , vDSP_hann_window ) Also - use larger input chunks. (例如Hann FunctionvDSP_hann_window )另外-使用更大的输入块。 The larger input the more precise is frequency detection. 输入越大,频率检测越精确。

See this article , google: Spectral Leakage, window function. 参见这篇文章 ,谷歌:光谱泄漏,窗口函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM