我应该如何使用Accelerate框架在iOS上的Swift中计算真实的信号的FFT?
WEB示例
Apple的Accelerate框架似乎提供了有效计算信号FFT的功能。
不幸的是,互联网上的大多数示例,如Swift-FFT-Example和TempiFFT,如果广泛测试并调用Objective C API,就会崩溃。
Apple documentation回答了许多问题,但也引出了其他一些问题(这部分是强制性的吗?为什么我需要这个调用来转换?)。
栈溢出线程
有几个线程用具体的例子来解决FFT的各个方面。特别是FFT Using Accelerate In Swift,DFT result in Swift is different than that of MATLAB和FFT Calculating incorrectly - Swift。它们都没有直接解决“从0开始,正确的方法是什么”的问题?
我花了一天的时间才弄清楚如何正确地做到这一点,所以我希望这篇文章能清楚地解释你应该如何使用苹果的FFT,展示需要避免的陷阱,并帮助开发人员保存宝贵的时间。
1条答案
按热度按时间rqcrx0a61#
TL ; DR:如果您需要一个工作实现来复制here is a gist。
什么是FFT?
快速傅立叶变换是一种算法,它在时域中获取信号--在规则的、通常很小的时间间隔内获取的测量值的集合--并将其转换为在相域中表示的信号(频率的集合)。表示信号沿着时间的能力,因变换而丢失(变换是可逆的,这意味着通过计算FFT不会丢失任何信息,并且您可以应用IFFT来获得原始信号),但是我们得到了区分信号所包含的频率的能力。这通常用来显示你在各种硬件和YouTube视频上正在听的音乐的频谱图。
FFT可以处理complexe numbers。如果你不知道它们是什么,让我们假设它是半径和Angular 的组合。2D平面上的每个点都有一个复数。真实的(你常用的浮点数)可以被看作是一条线上的位置(左边是负数,右边是正数)。
Nb:FFT(FFT(FFT(FFT(X)))= X(取决于FFT实现,最大为常数)。
如何计算真实的信号的FFT。
通常你想计算一个音频信号的小窗口的FFT。为了举例,我们将采用一个小的1024个样本窗口。你也更喜欢使用2的幂,否则事情会变得有点困难。
首先,您需要初始化一些用于计算的常量。
按照apple的文档,我们首先需要创建一个复杂的数组作为我们的输入。不要被教程误导。你通常想要的是复制你的信号作为输入的真实的部,并保持复部为空。
请注意,FFT函数不允许同时使用相同的splitComplex作为输入和输出。如果您遇到崩溃,这可能是原因。这就是为什么我们定义输入和输出。
现在,我们必须小心并“锁定”指向这四个数组的指针,如文档示例所示。如果您只是使用
&forwardInputReal
作为DSPSplitComplex
的参数,则指针可能会在以下行中失效,并且您的应用可能会偶尔崩溃。最后一句:对FFT的调用:
FFT的结果现在在
forwardOutputReal
和forwardOutputImag
中可用。如果你只需要每个频率的振幅,而不关心真实的部和虚部,你可以在输入和输出旁边声明一个额外的数组:
在你的fft计算每个“bin”的振幅后加上: