【问题标题】:How to draw a frequency spectrum from a Fourier transform如何从傅里叶变换中绘制频谱
【发布时间】:2012-05-19 09:50:35
【问题描述】:

我想绘制音乐文件的频谱(就像他们在 Audacity 中所做的那样)。因此,我想要 x 轴上的赫兹频率和 y 轴上的振幅(或分贝)。

我一次将歌曲(大约 2000 万个样本)分成 4096 个样本块。这些块将产生 2049 (N/2 + 1) 个复数(正弦和余弦 -> 实部和虚部)。那么现在我有这数千个单独的 2049 数组,我该如何组合它们呢?

假设我执行 FFT 5000 次,得到 5000 个 2049 复数数组。我是否将 5000 个数组的所有值相加,然后取组合 2049 个数组的大小?然后我是否使用歌曲采样率 / 2 来调整 x 轴(例如:22050 用于 44100hz 文件)?

任何信息都会被应用

【问题讨论】:

    标签: transform fft frequency spectrum


    【解决方案1】:

    您为此使用什么应用程序?我假设您不是手动执行此操作,所以这是一个 Matlab 示例:

    >> fbins = fs/N * (0:(N/2 - 1)); % Where N is the number of fft samples

    现在你可以表演了

    >> plot(fbins, abs(fftOfSignal(1:N/2)))

    Stolen

    编辑:查看http://www.codeproject.com/Articles/9388/How-to-implement-the-FFT-algorithm

    【讨论】:

    • 我正在编写自己的 C++ 程序。你能解释一下上面的例子吗? 0: 和 1: meen 是什么,fs 是什么?
    • fs = 采样频率,0:x = 从零到 x 的所有步长,对于 1:N/2 相同。绝对值 = 绝对值。结尾是plot(x,y),所以fbins是x,其余的是y
    • 下次用你的 C 代码删除 pastebin 的链接,我有点好奇你将如何解决这个问题:)
    • 我还在寻找,所以我还不能提供代码。所以任何关于这方面的想法都非常受欢迎!
    • 我更喜欢嵌入式 C,而不是 C++,所以我只是好奇。让我们希望其他人可以提供更多。也许您可以通过描述您正在使用的平台/操作系统来提供帮助
    【解决方案2】:

    哇,我最近写了一篇关于这个的文章。

    我什至把它变成了一篇博客文章here

    我的解释是倾向于频谱图,但像你描述的那样渲染图表同样容易!

    【讨论】:

    • 网站已关闭。显示数据库连接错误
    【解决方案3】:

    我在这方面可能不正确,但据我所知,您有两种方法可以获取整首歌曲的频谱。

    1) 对整首歌曲进行一次 FFT,这将为您提供非常好的频率分辨率,但实际上效率不高,而且您也不需要这种分辨率。

    2)将其分成小块(如您所说的 4096 个样本块),获取每个块的 FFT 并对光谱进行平均。您将在频率分辨率上妥协,但使计算更易于管理(并且还减少了频谱的方差)。 Wilhelmsen 链接描述了如何在 C++ 中计算 FFT,我认为已经有一些库可以做到这一点,比如 FFTW(但我从来没有设法编译它,公平地说 =))。

    要获得幅度谱,请对每个 bin 的所有块的能量(幅度的平方)进行平均。要获得以 dB 为单位的结果,只需 10 * log10 的结果。这当然是假设您对相位谱不感兴趣。我认为这被称为Barlett's method

    我会这样做:

    //  At this point you have the FFT chunks
    
    float sum[N/2+1];
    
    // For each bin
    for (int binIndex = 0; binIndex < N/2 + 1; binIndex++)
    {
        for (int chunkIndex = 0; chunkIndex < chunkNb; chunkIndex++)
        {
            //  Get the magnitude of the complex number
            float magnitude = FFTChunk[chunkIndex].bins[binIndex].real * FFTChunk[chunkIndex].bins[binIndex].real
                +   FFTChunk[chunkIndex].bins[binIndex].im * FFTChunk[chunkIndex].bins[binIndex].im;
    
            magnitude = sqrt(magnitude);
    
            //  Add the energy
            sum[binIndex] += magnitude * magnitude;
        }
    
        //  Average the energy;
        sum[binIndex] /= chunkNb;
    }
    
    //  Then get the values in decibel
    for (int binIndex = 0; binIndex < N/2 + 1; binIndex++)
    {
        sum[binIndex] = 10 * log10f(sum[binIndex]);
    }
    

    希望这能回答你的问题。

    编辑:Goz 的帖子将为您提供有关此事的大量信息 =)

    【讨论】:

    • 我正在尝试为 Java 实现这一点。我不明白的是为什么你只迭代 N/2 而不是 N?
    【解决方案4】:

    通常,您会只取其中一个数组,对应于您感兴趣的音乐的时间点。您将计算每个复杂数组元素的大小的对数。将 N/2 个结果绘制为 Y 值,并将 X 轴从 0 缩放到 Fs/2(其中 Fs 是采样率)。

    【讨论】:

    • 谢谢,但我不只是想要一秒钟左右的频谱,而是想要整首歌。
    • 如果 FFT 的长度为 N,为什么只绘制 N/2?
    • 对于严格的真实数据输入,FFT 结果的后半部分只是前半部分的共轭镜像(例如冗余)。只有当时域数据很复杂(实部和虚部均非零)时,N/2 以上的一半才有用(不同)。
    猜你喜欢
    • 2012-02-14
    • 2016-06-19
    • 2019-09-29
    • 1970-01-01
    • 1970-01-01
    • 2014-11-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多