如何从傅立叶变换中绘制频谱

时间:2012-05-19 09:50:36

标签: transform fft frequency spectrum

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

我将这首歌(大约2000万个样本)一次分成4096个样本。这些块将产生2049(N / 2 + 1)个复数(正弦和余弦 - >实部和虚部)。所以现在我有成千上万个2049阵列,如何组合它们?

让我们说我做了5000次FFT,产生了5000个2049-复数数组。我是否加上5000阵列的所有值,然后采用组合2049阵列的大小?然后,我是否使用歌曲采样率/ 2对x轴进行扫描(例如:对于44100hz文件为22050)?

任何信息都将适用

4 个答案:

答案 0 :(得分:2)

您使用的是什么应用程序?我假设您不是手动执行此操作,因此这是一个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

答案 1 :(得分:2)

我可能在这方面不正确,但就我所知,你有2种方法可以获得整首歌的光谱。

1)对整首歌曲进行单次FFT,这将为您提供极佳的频率分辨率,但实际上效率不高,无论如何您都不需要这种分辨率。

2)将其划分为小块(如4096样本块,正如您所说),获取每个块的FFT并平均光谱。您将在频率分辨率上妥协,但使计算更易于管理(并且还会降低频谱的方差)。 Wilhelmsen链接描述了如何用C ++计算FFT,我认为有一些库已经存在,比如FFTW(但我从未设法编译它,公平=)。)

要获得幅度谱,请将每个容器的所有块的能量(幅度的平方)平均。要以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的帖子将为您提供有关此事的大量信息=)

答案 2 :(得分:2)

哇,我刚刚写了一篇关于此的文章。

我甚至把它变成了一篇博文here

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

答案 3 :(得分:1)

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