将FFT转换为频谱图

时间:2009-11-05 11:33:37

标签: c++ fft spectrogram intel-ipp

我有一个音频文件,我正在遍历文件并在每一步获取512个样本,然后通过FFT传递它们。

我有数据输出,因为块514浮动很长(使用IPP的ippsFFTFwd_RToCCS_32f_I),实数和虚数组件交错。

我的问题是,一旦拥有这些复杂数字,我该如何处理?目前我正在为每个值做

const float realValue   = buffer[(y * 2) + 0];
const float imagValue   = buffer[(y * 2) + 1];
const float value       = sqrt( (realValue * realValue) + (imagValue * imagValue) );

这提供了一些稍微有用的东西,但我更倾向于在0到1的范围内获取值。上面的问题是峰值最终会回到9或更多。这意味着事情会恶化饱和,然后光谱图的其他部分几乎不会出现,尽管当我通过试听的频谱图运行音频时它们看起来非常强大。我完全承认我不是100%确定FFT返回的数据是什么(除了它代表我传入的512个样本长块的频率值)。特别是我的理解是缺乏compex数字代表什么。

非常感谢任何建议和帮助!

编辑:只是为了澄清。我的一个大问题是,如果不知道比例是什么,返回的FFT值是没有意义的。有人能指出我制定这种规模吗?

Edit2:通过执行以下操作,我得到了非常好看的结果:

size_t count2   = 0;
size_t max2     = kFFTSize + 2;
while( count2 < max2 )
{
    const float realValue   = buffer[(count2) + 0];
    const float imagValue   = buffer[(count2) + 1];
    const float value   = (log10f( sqrtf( (realValue * realValue) + (imagValue * imagValue) ) * rcpVerticalZoom ) + 1.0f) * 0.5f;
    buffer[count2 >> 1] = value;
    count2 += 2;
}

在我看来,这甚至看起来比我看过的大多数其他频谱图实现都要好。

我正在做的事情是否有任何重大错误?

5 个答案:

答案 0 :(得分:11)

使所有FFT可见的通常做法是采用幅度的对数。

因此,输出缓冲区的位置会告诉您检测到的频率。复数的幅度(L2范数)告诉您检测到的频率有多强,相位(反正切)为您提供的信息在图像空间中比音频空间更重要。由于FFT是离散的,因此频率从0到奈奎斯特频率。在图像中,第一项(DC)通常是最大的,因此如果这是您的目标,那么它是用于标准化的良好候选者。我不知道音频是否也是如此(我对此表示怀疑)

答案 1 :(得分:7)

对于512个样本的每个窗口,您可以像计算FFT的幅度一样计算FFT的幅度。每个值代表信号中存在的相应频率的大小。

mag
 /\
 |
 |      !         !
 |      !    !    !
 +--!---!----!----!---!--> freq
 0          Fs/2      Fs

现在我们需要弄清楚频率。

由于输入信号具有实数值,因此FFT围绕中间(奈奎斯特分量)对称,第一项是DC分量。知道信号采样频率Fs,奈奎斯特频率为Fs / 2。因此,对于索引k,相应的频率为k*Fs/512

因此,对于长度为512的每个窗口,我们得到指定频率的幅度。连续窗口的那组形成了频谱图。

答案 2 :(得分:6)

就这样,人们知道我在整个问题上做了很多工作。我发现的主要事情是FFT在完成后需要归一化。

要执行此操作,您需要将窗口矢量的所有值平均得到一个小于1的值(如果使用矩形窗口,则为1)。然后,将该数字除以FFT变换后的频率仓数。

最后,您将FFT返回的实际数除以归一化数。您的振幅值现在应该在-Inf到1范围内。记录等,请随意。您仍将使用已知范围。

答案 3 :(得分:5)

我认为你会发现一些有用的东西。

前向FT将在输出中提供比输入中更大的数字。您可以将其视为某个频率的所有强度都显示在一个地方而不是通过数据集分布。这有关系吗?可能不是因为您可以随时扩展数据以满足您的需求。我曾经写过一个基于整数的FFT / IFFT对,每次传递都需要重新调整以防止整数溢出。

您输入的真实数据会转换为几乎复杂的内容。事实证明,缓冲区[0]和缓冲区[n / 2]是真实且独立的。对它进行了很好的讨论here

输入数据是随时间变化的声强度值,等间距。据说它们在时域中足够恰当。据说FT的输出在频域,因为水平轴是频率。垂直刻度仍然是强度。虽然输入数据不明显,但输入中也存在相位信息。尽管所有的声音都是正弦的,但没有任何东西可以修复正弦波的相位。此阶段信息在频域中显示为单个复数的阶段,但通常我们不关心它(通常我们也会这样做!)。这取决于你在做什么。计算

const float value = sqrt((realValue * realValue) + (imagValue * imagValue));

检索强度信息但丢弃相位信息。取对数基本上只会抑制大峰值。

希望这有用。

答案 4 :(得分:1)

如果您得到奇怪的结果,那么要检查的一件事是FFT库的文档,以查看输出是如何打包的。一些例程使用打包格式,其中实/虚值是交错的,或者它们可以从N / 2元素开始并环绕。

为了进行健全性检查,我建议创建具有已知特征的样本数据,例如Fs / 2,Fs / 4(Fs =采样频率),并将FFT例程的输出与您期望的结果进行比较。尝试以相同的频率创建正弦和余弦,因为它们在频谱中应具有相同的幅度,但具有不同的相位(即realValue / imagValue将有所不同,但是平方和应该相同。

如果你打算使用FFT,那么你真的需要知道它在数学上是如何工作的,否则你可能会遇到其他奇怪的问题,比如别名。