如何获得 iOS Accelerate FFT 结果的频率幅度?
Posted
技术标签:
【中文标题】如何获得 iOS Accelerate FFT 结果的频率幅度?【英文标题】:How to get iOS Accelerate FFT results in frequency magnitudes? 【发布时间】:2014-09-22 21:32:51 【问题描述】:我使用此代码(基于 Apple 的 audioRouch 示例):
void FFTHelper::ComputeFFT(Float32* inAudioData, Float32* outFFTData)
if (inAudioData == NULL || outFFTData == NULL) return;
// Generate a split complex vector from the real data
vDSP_ctoz((COMPLEX *)inAudioData, 2, &mDspSplitComplex, 1, mFFTLength);
// Take the fft and scale appropriately
vDSP_fft_zrip(mSpectrumAnalysis, &mDspSplitComplex, 1, mLog2N, kFFTDirection_Forward);
vDSP_vsmul(mDspSplitComplex.realp, 1, &mFFTNormFactor, mDspSplitComplex.realp, 1, mFFTLength);
vDSP_vsmul(mDspSplitComplex.imagp, 1, &mFFTNormFactor, mDspSplitComplex.imagp, 1, mFFTLength);
// Zero out the nyquist value
mDspSplitComplex.imagp[0] = 0.0;
// Complex vector magnitudes squared; single precision.
// Calculates the squared magnitudes of complex vector A.
vDSP_zvmags(&mDspSplitComplex, 1, outFFTData, 1, mFFTLength);
在最简单的可能 - 1Hz 正弦波上计算 FFT(上移 1 个单位):
Float32 waveFreq = 1.0;
int samplesCount = 1024;
Float32 samplesPerSecond = 1000; //sample rate
Float32 dt = 1 / samplesPerSecond;
Float32 sd = M_PI * 2.0 * waveFreq;
FFTHelper *mFFTHelper = new FFTHelper(samplesCount);
Float32 NyquistMaxFreq = samplesPerSecond/2.0;
Float32 fftDataSize = samplesCount/2.0;
Float32 *sinusoidOriginal = (Float32 *)malloc(sizeof(Float32) * samplesCount);
Float32 *outFFTData = (Float32 *)malloc(sizeof(Float32) * fftDataSize);
// 2. Generate sin samples:
for (int i = 0; i < samplesCount; i++)
Float32 x = dt * i;
sinusoidOriginal[i] = sin(sd * x) + 1;
[originalPlot addVector2D:GLVector2DMake(x, sinusoidOriginal[i])];
mFFTHelper->ComputeFFT(sinusoidOriginal, outFFTData);
for (int i = 0; i < fftDataSize; i++)
Float32 hz = ((Float32)i / (Float32)fftDataSize) * NyquistMaxFreq;
GLfloat mag = outFFTData[i];
[fftPlot addVector2D:GLVector2DMake(hz, 0)];
[fftPlot addVector2D:GLVector2DMake(hz, mag)];
我得到的结果是:
黑线是来自 FTT 的绘图仪结果,在其频率处水平定位。 DC 值(左起第 1 条黑线)看起来没问题,正确表示 y = sin(x) + 1 垂直偏移量。
但是为什么代表正弦方程中唯一频率的第二条黑线没有幅度 = 1 并且不完全保持在 1Hz?
谁能指点我使用 vDSP 函数将 FFT 结果从输入信号转换为幅度单位?
【问题讨论】:
【参考方案1】:简答:
您似乎正在使用我在这个地方的回答中的代码:https://***.com/a/19966776/468812 这很棒,但是:
您无法避免信号中出现这些额外频率。
您生成的信号(正弦波)是无限信号。 如果你“裁剪它”并且“只使用一个信号”,它会在两端引入“削波噪声”。
但是您可以通过在 FFT 之前获取更大的输入块和 using windowing 来最小化噪声。 Accelerate Framework 提供了一些良好且简单的窗口函数。 (例如Hann Function、vDSP_hann_window) 另外 - 使用更大的输入块。输入越大,频率检测越精确。
参见this article,google:Spectral Leakage,窗函数。
【讨论】:
以上是关于如何获得 iOS Accelerate FFT 结果的频率幅度?的主要内容,如果未能解决你的问题,请参考以下文章
Apple 的 Accelerate vDSP:如何从 FFT 中获取复数向量的参数
使用 Apple Accelerate 框架选择实数和复数 2D FFT