iPhone加速框架FFT与Matlab FFT

时间:2012-05-30 16:34:50

标签: iphone objective-c matlab fft accelerate-framework

我没有太多的数学背景,但我正在研究的项目的一部分需要单个向量的FFT。 matlab函数fft(x)可以准确地满足我的需要,但在尝试设置Accelerate Framework fft函数后,我得到了完全不准确的结果。如果有人对Accelerate Framework fft有更多的专业知识/经验,我可以真正使用一些帮助来试图弄清楚我做错了什么。我根据我在谷歌上发现的一个例子来建立我的fft设置,但是没有教程或任何产生不同结果的东西。

EDIT1:根据目前为止的答案更改了一些内容。它似乎在进行计算,但它不会以任何接近matlab的方式输出它们

这是matlab的fft文档:http://www.mathworks.com/help/techdoc/ref/fft.html

**注意:例如,x阵列将是{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} in两个例子

Matlab代码:

x = fft(x)

Matlab输出:

x =

   1.0e+02 *

  Columns 1 through 4

   1.3600            -0.0800 + 0.4022i  -0.0800 + 0.1931i  -0.0800 + 0.1197i

  Columns 5 through 8

  -0.0800 + 0.0800i  -0.0800 + 0.0535i  -0.0800 + 0.0331i  -0.0800 + 0.0159i

  Columns 9 through 12

  -0.0800            -0.0800 - 0.0159i  -0.0800 - 0.0331i  -0.0800 - 0.0535i

  Columns 13 through 16

  -0.0800 - 0.0800i  -0.0800 - 0.1197i  -0.0800 - 0.1931i  -0.0800 - 0.4022i

Apple Accelerate Framework:http://developer.apple.com/library/mac/#documentation/Accelerate/Reference/vDSPRef/Reference/reference.html#//apple_ref/doc/uid/TP40009464

目标C代码:

int log2n = log2f(16);

FFTSetupD fftSetup = vDSP_create_fftsetupD (log2n, kFFTRadix2);     

DSPDoubleSplitComplex fft_data;
fft_data.realp = (double *)malloc(8 * sizeof(double));
fft_data.imagp = (double *)malloc(8 * sizeof(double));

vDSP_ctoz((COMPLEX *) ffx, 2, &fft_data, 1, nOver2); //split data (1- 16) into odds and evens

vDSP_fft_zrip (fftSetup, &fft_data, 1, log2n, kFFTDirection_Forward); //fft forward

vDSP_fft_zrip (fftSetup, &fft_data, 1, log2n, kFFTDirection_Inverse); //fft inverse

vDSP_ztoc(&fft_data, 2, (COMPLEX *) ffx, 1, nOver2); //combine complex back into real numbers

目标C输出:

ffx现在包含:

272.000000
-16.000000
-16.000000
-16.000000
0.000000
0.000000
0.000000
0.000000
0.000000
10.000000
11.000000
12.000000
13.000000
14.000000
15.000000
16.000000

3 个答案:

答案 0 :(得分:14)

一个大问题:C数组从0开始索引,与基于1的MATLAB数组不同。所以你需要改变你的循环

for(int i = 1; i <= 16; i++)

for(int i = 0; i < 16; i++)

第二个大问题 - 你正在混合单精度(float)和双精度(double)例程。您的数据为double,因此您应该使用vDSP_ctozD,而非vDSP_ctozvDSP_fft_zripD而不是vDSP_fft_zrip等。

需要注意的另一件事是:不同的FFT实现使用DFT公式的不同定义,特别是在比例因子方面。看起来MATLAB FFT包含1 / N缩放校正,大多数其他FFT都没有。


这是一个完整的工作示例,其输出与Octave(MATLAB clone)匹配:

#include <stdio.h>
#include <stdlib.h>
#include <Accelerate/Accelerate.h>

int main(void)
{
    const int log2n = 4;
    const int n = 1 << log2n;
    const int nOver2 = n / 2;

    FFTSetupD fftSetup = vDSP_create_fftsetupD (log2n, kFFTRadix2);

    double *input;

    DSPDoubleSplitComplex fft_data;

    int i;

    input = malloc(n * sizeof(double));
    fft_data.realp = malloc(nOver2 * sizeof(double));
    fft_data.imagp = malloc(nOver2 * sizeof(double));

    for (i = 0; i < n; ++i)
    {
       input[i] = (double)(i + 1);
    }

    printf("Input\n");

    for (i = 0; i < n; ++i)
    {
        printf("%d: %8g\n", i, input[i]);
    }

    vDSP_ctozD((DSPDoubleComplex *)input, 2, &fft_data, 1, nOver2);

    printf("FFT Input\n");

    for (i = 0; i < nOver2; ++i)
    {
        printf("%d: %8g%8g\n", i, fft_data.realp[i], fft_data.imagp[i]);
    }

    vDSP_fft_zripD (fftSetup, &fft_data, 1, log2n, kFFTDirection_Forward);

    printf("FFT output\n");

    for (i = 0; i < nOver2; ++i)
    {
        printf("%d: %8g%8g\n", i, fft_data.realp[i], fft_data.imagp[i]);
    }

    for (i = 0; i < nOver2; ++i)
    {
        fft_data.realp[i] *= 0.5;
        fft_data.imagp[i] *= 0.5;
    }

    printf("Scaled FFT output\n");

    for (i = 0; i < nOver2; ++i)
    {
        printf("%d: %8g%8g\n", i, fft_data.realp[i], fft_data.imagp[i]);
    }

    printf("Unpacked output\n");

    printf("%d: %8g%8g\n", 0, fft_data.realp[0], 0.0); // DC
    for (i = 1; i < nOver2; ++i)
    {
        printf("%d: %8g%8g\n", i, fft_data.realp[i], fft_data.imagp[i]);
    }
    printf("%d: %8g%8g\n", nOver2, fft_data.imagp[0], 0.0); // Nyquist

    return 0;
}

输出是:

Input
0:        1
1:        2
2:        3
3:        4
4:        5
5:        6
6:        7
7:        8
8:        9
9:       10
10:       11
11:       12
12:       13
13:       14
14:       15
15:       16
FFT Input
0:        1       2
1:        3       4
2:        5       6
3:        7       8
4:        9      10
5:       11      12
6:       13      14
7:       15      16
FFT output
0:      272     -16
1:      -16 80.4374
2:      -16 38.6274
3:      -16 23.9457
4:      -16      16
5:      -16 10.6909
6:      -16 6.62742
7:      -16  3.1826
Scaled FFT output
0:      136      -8
1:       -8 40.2187
2:       -8 19.3137
3:       -8 11.9728
4:       -8       8
5:       -8 5.34543
6:       -8 3.31371
7:       -8  1.5913
Unpacked output
0:      136       0
1:       -8 40.2187
2:       -8 19.3137
3:       -8 11.9728
4:       -8       8
5:       -8 5.34543
6:       -8 3.31371
7:       -8  1.5913
8:       -8       0

与Octave相比,我们得到:

octave-3.4.0:15> x = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ]
x =

    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16

octave-3.4.0:16> fft(x)
ans =

 Columns 1 through 7:

   136.0000 +   0.0000i    -8.0000 +  40.2187i    -8.0000 +  19.3137i    -8.0000 +  11.9728i    -8.0000 +   8.0000i    -8.0000 +   5.3454i    -8.0000 +   3.3137i

 Columns 8 through 14:

    -8.0000 +   1.5913i    -8.0000 +   0.0000i    -8.0000 -   1.5913i    -8.0000 -   3.3137i    -8.0000 -   5.3454i    -8.0000 -   8.0000i    -8.0000 -  11.9728i

 Columns 15 and 16:

    -8.0000 -  19.3137i    -8.0000 -  40.2187i

octave-3.4.0:17>

请注意,9到16的输出只是一个复共轭镜像或底部的8个项,与实际输入FFT的预期情况一样。

另请注意,我们需要将vDSP FFT缩放2倍 - 这是因为它是一个真实到复数的FFT,它基于N / 2点复数到复数FFT因此,输出按N / 2缩放,而正常的FFT将按N缩放。

答案 1 :(得分:4)

我认为它也可能是阵列打包问题。我刚看了他们的示例代码,我发现他们一直在调用像

这样的转换例程
vDSP_ctoz

以下是apple:http://developer.apple.com/library/ios/#documentation/Performance/Conceptual/vDSP_Programming_Guide/SampleCode/SampleCode.html#//apple_ref/doc/uid/TP40005147-CH205-CIAEJIGF

的代码示例链接

我不认为这是完整的答案,但我也同意Paul R.

顺便说一句,好奇地,如果你去Wolfram Alpha,他们给出了一个完全不同的FFT回答{1,2,3,4,5,6,7,8,9,10,11,12,13 ,14,15,16}

答案 2 :(得分:0)

在MATLAB中,看起来你正在做16个实数{1 + 0i,2 + 0i,3 + 0i等...}的fft,而在Accelerate中,你正在做8个复数值的fft {1 + 2i,3 + 4i,5 + 6i等......}