为什么我的iPhone FFT频率值不正确?

时间:2014-03-28 15:52:04

标签: ios objective-c signal-processing fft accelerate-framework

我一直在尝试使用Apple的加速框架中的FFT来获取精确的频率,但我在弄清楚为什么我的值超出真实频率时遇到了麻烦。

我一直在使用这篇文章http://www.dspdimension.com/admin/pitch-shifting-using-the-ft/作为我实施的基础,经过努力达到我现在的目标之后,我完全被难倒了。

到目前为止,我已收到音频 - >汉宁窗口 - > FFT - >相位计算 - >奇怪的最终输出。我觉得某个地方的数学会有问题,但我现在真的没有想法了。

输出比应该低很多,例如,我输入440Hz并输出190Hz,或输入880Hz,输出400Hz。在大多数情况下,这些结果是一致的,但并非总是如此,并且似乎并不是任何事物之间的任何共同因素......

这是我的代码:

enum
{
    sampleRate  = 44100,
    osamp       = 4,
    samples     = 4096,
    range       = samples * 7 / 16,
    step        = samples / osamp
};

NSMutableArray *fftResults;

static COMPLEX_SPLIT    A;
static FFTSetup         setupReal;
static uint32_t         log2n, n, nOver2;
static int32_t          stride;

static float            expct = 2*M_PI*((double)step/(double)samples);
static float            phase1[range];
static float            phase2[range];
static float            dPhase[range];

- (void)fftSetup
{
    // Declaring integers
    log2n = 12;
    n = 1 << log2n;
    stride = 1;
    nOver2 = n / 2;

    // Allocating memory for complex vectors
    A.realp = (float *) malloc(nOver2 * sizeof(float));
    A.imagp = (float *) malloc(nOver2 * sizeof(float));

    // Allocating memory for FFT
    setupReal = vDSP_create_fftsetup(log2n, FFT_RADIX2);

    // Setting phase
    memset(phase2, 0, range * sizeof(float));

}
        // For each sample in buffer...
        for (int bufferCount = 0; bufferCount < audioBufferList.mNumberBuffers; bufferCount++)
        {
            // Declaring samples from audio buffer list
            SInt16 *samples = (SInt16*)audioBufferList.mBuffers[bufferCount].mData;


            // Creating Hann window function
            for (int i = 0; i < nOver2; i++)
            {
                double hannMultiplier = 0.5 * (1 - cos((2 * M_PI * i) / (nOver2 -  1)));

                // Applying window to each sample
                A.realp[i] = hannMultiplier * samples[i];
                A.imagp[i] = 0;
            }

            // Applying FFT
            vDSP_fft_zrip(setupReal, &A, stride, log2n, FFT_FORWARD);

            // Detecting phase
            vDSP_zvphas(&A, stride, phase1, stride, range);

            // Calculating phase difference
            vDSP_vsub(phase2, stride, phase1, stride, dPhase, stride, range);

            // Saving phase
            memcpy(phase2, phase1, range * sizeof(float));

            // Extracting DSP outputs
            for (size_t j = 0; j < nOver2; j++)
            {
                NSNumber *realNumbers = [NSNumber numberWithFloat:A.realp[j]];
                NSNumber *imagNumbers = [NSNumber numberWithFloat:A.imagp[j]];

                [real addObject:realNumbers];
                [imag addObject:imagNumbers];

            }

            // Combining real and imaginary parts
            [resultsCombined addObject:real];
            [resultsCombined addObject:imag];

            // Filling FFT output array
            [fftResults addObject:resultsCombined];
        }

    }


    int fftCount = [fftResults count];
    NSLog(@"FFT Count: %d",fftCount);

    // For each FFT...
    for (int i = 0; i < fftCount; i++)
    {
        // Declaring integers for peak detection
        float peak = 0;
        float binNumber = 0;

        // Declaring integers for phase detection
        float deltaPhase;

        static float trueFrequency[range];


        for (size_t j = 1; j < range; j++)
        {
            // Calculating bin magnitiude
            float realVal   = [[[[fftResults objectAtIndex:i] objectAtIndex:0] objectAtIndex:j] floatValue];
            float imagVal   = [[[[fftResults objectAtIndex:i] objectAtIndex:1] objectAtIndex:j] floatValue];
            float magnitude = sqrtf(realVal*realVal + imagVal*imagVal);

            // Peak detection
            if (magnitude > peak)
            {
                peak = magnitude;
                binNumber = (float)j;
            }

            // Getting phase difference
            deltaPhase = dPhase[j];

            // Subtract expected difference
            deltaPhase -= (float)j*expct;

            // Map phase difference into +/- pi interval
            int qpd = deltaPhase / M_PI;

            if (qpd >= 0)
                qpd += qpd&1;
            else
                qpd -= qpd&1;

            deltaPhase -= M_PI * (float)qpd;

            // Getting bin deviation from +/i interval
            float deltaFrequency = osamp * deltaPhase / (2 * M_PI);

            // Calculating true frequency at the j-th partial
            trueFrequency[j] = (j * (sampleRate/samples)) + (deltaFrequency * (sampleRate/samples));

        }

        UInt32 mag;
        mag = binNumber;

        // Extracting frequency at bin peak
        float f = trueFrequency[mag];

        NSLog(@"True frequency = %fHz", f);

        float b = roundf(binNumber*(sampleRate/nOver2));

        NSLog(@" Bin frequency = %fHz", b);

    }

1 个答案:

答案 0 :(得分:0)

请注意,预期的相位差(即使对于以bin为中心的频率)取决于FFT对的窗口偏移或重叠,以及FFT结果的bin编号或频率。例如如果您将窗口偏移很少(1个样本),则2个FFT之间的展开相位差将小于具有较大偏移的相位差。在相同的偏移处,如果频率较高,则两个FFT的相同二进制位之间的预期相位差将更大(或者它将包含更多)。