本文介绍了使用苹果FFT和加速框架的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有人使用了苹果FFT 的iPhone应用程序还没有或不知道在哪里可以找到一个示例应用程序,以如何使用它?我知道苹果有一些样本code贴,但我真的不知道如何实现它变成一个实际的项目。


解决方案

我刚刚得到了FFT code为iPhone项目的工作:


  • 创建一个新的项目

  • 删除除了main.m文件和xxx_info.plist所有文件

  • 将项目设置和搜索PCH并试图加载一个.PCH停止它(看到我们刚才删除了它)

  • 复制粘贴到任何你在main.m文件有code例如

  • 删除行#包含的碳。碳是OSX。

  • 删除所有的框架,并添加加速框架

您可能还需要去除的info.plist告诉该项目加载厦门国际银行的条目,但我90%肯定你不必与理会。

注:程序输出到控制台,结果出来为0.000,这不是一个错误 - 它只是非常非常快的。

这code是真的愚蠢模糊;它慷慨地评论,但意见并不真正让生活变得更容易。

在基本上它的心脏是:

  vDSP_fft_zrip(SETU preAL,&安培; A,步幅,log2n,FFT_FORWARD);
vDSP_fft_zrip(SETU preAL,&安培; A,步幅,log2n,FFT_INVERSE);

FFT n个真正的彩车,然后反向回到我们开始的地方。
IP代表就地,这意味着与放大器; A被覆盖
这是这一切的特殊包装说大话的原因 - 这样我们就可以挤压的返回值在同一个空间作为发送值

要给予一定的角度(如,如:为什么我们要使用此功能摆在首位),比方说,我们要对麦克风输入进行基音检测,我们已经设定,让一些回调得到每次触发麦克风在1024彩车得到的时间。假设麦克风采样率为44.1kHz的,所以这是〜44帧/秒。

所以,我们的时间窗口是什么的1024个样本的时间长度为,即1/44秒。

所以,我们包了从麦克风1024辆彩车,设置log2n = 10(2 ^ 10 = 1024),precalculate一些骨架(SETU preAL)和:

  vDSP_fft_zrip(SETU preAL,&安培; A,步幅,log2n,FFT_FORWARD);

现在A将含有N / 2复数。这些重新present N / 2频点:


  • 斌[1] .idealFreq = 44Hz - 也就是说,我们可以可靠地检测的最低频率是该窗口中的一个完整的波,即44Hz波


  • 斌[2] .idealFreq = 2 * 44Hz


  • 等。


  • 滨[512] .idealFreq = 512 * 44Hz - 我们可以检测到的最高频率(也称为奈奎斯特频率),每一个点对重新$ P $内psents一挥手,即512完整的波窗口,即512 * 44Hz,或N / 2 *斌[1] .idealFreq


  • 其实,有一个额外斌,斌[0]这通常被称为直流偏移。恰巧,滨[0]和Bin [N / 2]总是有复杂的组件0,因此A [0] .realp用于存储斌[0]和A [0] .imagp用于存储斌[ N / 2]


和各复数的量值为能量的周围频率振动量。

所以,你可以看到,它不会是因为它没有足够的近细粒度一个非常伟大的音调检测。有一个狡猾的手段,<一个href=\"http://stackoverflow.com/questions/4633203/extracting-$p$pcise-frequencies-from-fft-bins-using-phase-change-between-frames\">Extracting从FFT箱使用帧之间的相位变化precise频率,以获得$ ​​P $ pcise频率给定仓。

好了,现在到code:

请注意在vDSP_fft_zrip的'IP'='到位',即输出将覆盖A(R意味着它需要真正的投入)

只看vDSP_fft_zrip的文档,

this is probably the hardest thing to understand. We are using the same container (&A) all the way through the process. so in the beginning we want to fill it with n real numbers. after the FFT it is going to be holding n/2 complex numbers. we then throw that into the inverse transform, and hopefully get out our original n real numbers.

now the structure of A its setup for complex values. So vDSP needs to standardise how to pack real numbers into it.

so first we generate n real numbers: 1, 2, ..., n

for (i = 0; i < n; i++)
    originalReal[i] = (float) (i + 1);

Next we pack them into A as n/2 complex #s:

// 1. masquerades n real #s as n/2 complex #s = {1+2i, 3+4i, ...}
// 2. splits to
//   A.realP = {1,3,...} (n/2 elts)
//   A.compP = {2,4,...} (n/2 elts)
//
vDSP_ctoz(
          (COMPLEX *) originalReal,
          2,                            // stride 2, as each complex # is 2 floats
          &A,
          1,                            // stride 1 in A.realP & .compP
          nOver2);                      // n/2 elts

You would really need to look at how A is allocated to get this, maybe look up COMPLEX_SPLIT in the documentation.

A.realp = (float *) malloc(nOver2 * sizeof(float));
A.imagp = (float *) malloc(nOver2 * sizeof(float));

Next we do a pre-calculation.


Quick DSP class for maths bods:Fourier theory takes a long time to get your head around (I've been looking at it on and off for several years now)

A cisoid is:

z = exp(i.theta) = cos(theta) + i.sin(theta)

i.e. a point on the unit circle in the complex plane.

When you multiply complex numbers, the angles add. So z^k will keep hopping around the unit circle; z^k can be found at an angle k.theta

  • Choose z1 = 0+1i, i.e. a quarter turn from the real axis, and notice that z1^2 z1^3 z1^4 each give another quarter turn so that z1^4 = 1

  • Choose z2 = -1, i.e. a half-turn. also z2^4 = 1 but z2 has completed 2 cycles at this point (z2^2 is also = 1). So you could think of z1 as the fundamental frequency and z2 as the first harmonic

  • Similarly z3 = the 'three-quarters of a revolution' point i.e. -i completes exactly 3 cycles, but actually going forwards 3/4 each time is the same as going backwards 1/4 each time

i.e. z3 is just z1 but in the opposite direction -- It's called aliasing

z2 is the highest meaningful frequency, as we chose 4 samples to hold a full wave.

  • z0 = 1+0i, z0^(anything)=1, this is DC offset

You can express any 4-point signal as a linear combination of z0 z1 and z2i.e. You're projecting it onto these basis vectors

but I hear you asking "what does it mean to project a signal onto a cisoid?"

You can think of it this way: The needle spins round the cisoid, so at sample k, the needle is pointing in direction k.theta, and the length is signal[k]. A signal that matches the frequency of the cisoid exactly will bulge the resulting shape in some direction. So if you add up all the contributions, you'll get a strong resultant vector.If the frequency nearly matches, than the bulge will be smaller and will move slowly around the circle.For a signal that doesn't match frequency, the contributions will cancel one another out.

http://complextoreal.com/tutorials/tutorial-4-fourier-analysis-made-easy-part-1/ will help you get an intuitive understanding.

But the gist is; if we have chosen to project 1024 samples onto {z0,...,z512} we would have precalculate z0 thru z512, and that's what this precalculation step is.


Note that if you are doing this in real code you probably want to do this once when the app loads and call the complementary release function once when it quits. DON'T do it lots of times -- it is expensive.

// let's say log2n = 8, so n=2^8=256 samples, or 'harmonics' or 'terms'
// if we pre-calculate the 256th roots of unity (of which there are 256)
// that will save us time later.
//
// Note that this call creates an array which will need to be released
// later to avoid leaking
setupReal = vDSP_create_fftsetup(log2n, FFT_RADIX2);

It's worth noting that if we set log2n to eg 8, you can throw these precalculated values into any fft function that uses resolution <= 2^8. So (unless you want ultimate memory optimisation) just create one set for the highest resolution you're going to need, and use it for everything.

Now the actual transforms, making use of the stuff we just precalculated:

vDSP_fft_zrip(setupReal, &A, stride, log2n, FFT_FORWARD);

At this point A will be containing n/2 complex numbers, only the first one is actually two real numbers (DC offset, Nyquist #) masquerading as a complex number. The documentation overview explains this packing. It is quite neat -- basically it allows the (complex) results of the transform to be packed into the same memory footprint as the (real, but weirdly packaged) inputs.

vDSP_fft_zrip(setupReal, &A, stride, log2n, FFT_INVERSE);

and back again... we will still need to unpack our original array from A. then we compare just to check that we have got back exactly what we started out with, release our precalculated bobbins and done!

But wait! before you unpack, there is one final thing that needs to be done:

// Need to see the documentation for this one...
// in order to optimise, different routines return values
// that need to be scaled by different amounts in order to
// be correct as per the math
// In this case...
scale = (float) 1.0 / (2 * n);

vDSP_vsmul(A.realp, 1, &scale, A.realp, 1, nOver2);
vDSP_vsmul(A.imagp, 1, &scale, A.imagp, 1, nOver2);

这篇关于使用苹果FFT和加速框架的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 04:26