我没有太多的数学背景,但我正在研究的项目的一部分需要单个向量的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
答案 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_ctoz
和vDSP_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
的代码示例链接
我不认为这是完整的答案,但我也同意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等......}