【问题标题】:How do I plot the spectrum of a wav file using FFT?如何使用 FFT 绘制 wav 文件的频谱?
【发布时间】:2013-08-11 01:17:45
【问题描述】:

注意:这不是重复的,除了相关问题,我还有特定的要求。

首先,我想绘制音频文件 (.wav) 的频谱,就像 audacity 所做的那样(类似:How to draw a frequency spectrum from a Fourier transform)。

到目前为止,我能够读写 wav 文件。但我的问题是我不确切知道需要传递给 FFT 函数的值。顺便说一句,我在 C# 中使用 Exocortex 进行 FFT。 FFT 函数要求我传递一个具有正确大小(512、1024 ......

具体问题:

  1. Exocortex 库中的 Complex(类)有两个值,即 Real 和 Imaginary。我有一组样本,那么哪些应该是真实的,哪些应该是虚构的?
  2. 我有 wav 文件,所以长度应该是可变的。如何将其传递给 FFT 函数?我是否应该选择一个大小(512/1024/等),将整个样本划分为该大小,然后将其全部传递给 FFT?
  3. 我怎么知道应该在 x 轴上列出哪些频率?
  4. 如何绘制 FFT 数据? (我希望 x 轴为频率,y 轴为分贝)

如果您不明白我的意思,请尝试使用 Audacity,导入音频文件,然后单击分析 > 绘制频谱。这些是想要重建的东西。请详细回答我的问题,因为我真的很想学习这个。我对此只有一点背景。我只是数字信号处理的新手。另外,请尽可能不要将我引导到其他 FFT 网站,因为他们没有具体回答我的问题。


编辑:

我已经阅读并了解了如何对音频数据进行 FFT,但仅限于 2 的幂。那么如何在长度不是 2 的幂的音频文件中执行相同的操作?根据一些我需要使用“窗口”。我也对其进行了一些搜索,发现它只需要稍后处理一部分波形。请记住,我想获取音频文件的 FFT,而不是其中的一部分。那我现在该怎么办?请帮忙:(

【问题讨论】:

  • 关于你的笔记 - 1. 你对一个问题的要求太多了。这是更多的数学内容,您将在专门针对它的论坛中获得更好(和更多)的答案。 2. 如果您的文件包含许多不是 2 的幂的样本,则需要用零填充它以使其大小为 2 的幂。这是 FFT 的限制。 3. 基本上使用一个窗口对您的部分数据执行 FFT(如果这是您需要的)。但它更深入,有不同的窗口具有不同的效果。
  • 您尝试生成的内容称为spectrogram。你最好询问如何绘制频谱图而不是询问频谱。

标签: c# audio signal-processing fft


【解决方案1】:

签名是

public static void  FFT( float[] data, int length, FourierDirection direction )
  1. 您传递一个复数数组,以对表示。由于您只有实数(样本),因此您应该将样本放在数组中的偶数位置 - data[0]、data[2]、data[4] 等。奇数位置应为 0,data[1] = data[3] = 0...
  2. 长度是要计算 FFT 的样本数量,它应该正好是数据数组长度的一半。您可以对整个 WAV 或其中的一部分进行 FFT - 取决于您希望看到的内容。 Audacity 将绘制文件选定部分的功率谱,如果您希望这样做,请传递整个 WAV 或选定部分。
  3. FFT 将只显示高达采样率一半的频率。因此,您的值应该在 0 到采样率的一半之间。值的数量取决于您拥有的样本数量(样本数量会影响计算的精度)
  4. Audacity 绘制功率谱。您应该获取收到的数组中的每个复数对并计算其 ABS。 ABS 定义为 sqrt(r^2+i^2)。每个 ABS 值将对应一个频率。

这是一个工作代码的示例:

float[] data = new float[8];
data[0] = 1; data[2] = 1; data[4] = 1; data[6] = 1;
Fourier.FFT(data, data.Length/2, FourierDirection.Forward);

我给它 4 个样本,都一样。所以我希望只在频率为 0 时得到一些东西。事实上,在运行它之后,我得到了

数据[0] == 1,数据[2] == 1,数据[4] == 1,数据[6] == 1

其他都是0。

如果我想使用复杂数组重载

Complex[] data2 = new Complex[4];
data2[0] = new Complex(1,0);
data2[1] = new Complex(1, 0);
data2[2] = new Complex(1, 0);
data2[3] = new Complex(1, 0);
Fourier.FFT(data2,data2.Length,FourierDirection.Forward);

请注意这里的第二个参数等于数组的长度,因为每个数组成员都是一个复数。我得到了和以前一样的结果。

我想我之前错过了复杂的重载。除非您的数据已经成对出现,否则我似乎不太容易出错并且使用起来更自然。

【讨论】:

  • 在计算平方根时不需要Abs()sort() 的结果永远不会是负数。
  • 当然。我的措辞可能很糟糕。我的意思是说他应该计算 ABS,而 sqrt 是计算它的方法。并不意味着您需要应用另一个腹肌。我会修改我的答案。谢谢。
  • 假设我有 float[] fArray; 具有正确的实数和虚数顺序,然后我将它传递给 Exocortex.DSP.Fourier.FFT(fArray, fArray.Length / 2, FourierDirection.Forward); 它会引发 IndexOutOfRangeException。我做错了什么?
  • @user2666785 - 我用一个小数组对此进行了测试,FFT 似乎可以工作。你做了什么,哪里抛出了异常?另外,我刚刚注意到有一个重载确实使用复数而不是成对的浮点数。我会尽快更新我的答案
  • 感谢您的回复@Vadim 我很感激。在我调用 Fourier.FFT() (在先前的评论中)方法的行上引发了异常。我只是传递了整个数组(实数和虚数连续排列)和数组的长度/2。你能告诉我你做的代码吗?我真的很难理解这一点:(
猜你喜欢
  • 1970-01-01
  • 2013-03-12
  • 2015-02-03
  • 2017-01-10
  • 1970-01-01
  • 1970-01-01
  • 2020-08-30
  • 1970-01-01
  • 2012-05-25
相关资源
最近更新 更多