频谱图的频率范围

Posted

技术标签:

【中文标题】频谱图的频率范围【英文标题】:frequency range of the spectogram 【发布时间】:2013-10-26 04:57:44 【问题描述】:

我能够使用来自https://code.google.com/p/musicg/ 的音乐库来可视化频谱图,但我发现了一些我不太了解的奇怪事情。 我尝试使用采样率为 22050 的 wav 文件,并使用 blackmann 窗口使用 1024 个具有 50% 重叠的样本执行 fft。 计算的结果是二维数组(spectrogram[time][frequency]=intensity)。 我的问题是,如果第二个维度称为频率,为什么它的大小只有 256?它与频率宽度bin有关吗?那么我如何确定频率? 当我尝试使用 512 个样本时,大小减少到一半(128)。

那么我们应该对频谱图进行归一化吗?

这是我从 musicg 得到的代码

short[] amplitudes=wave.getSampleAmplitudes();

    int numSamples = amplitudes.length;
    int pointer=0;
    // overlapping
    if (overlapFactor>1)

        int numOverlappedSamples=numSamples*overlapFactor;
        int backSamples=fftSampleSize*(overlapFactor-1)/overlapFactor;
        int fftSampleSize_1=fftSampleSize-1;
        short[] overlapAmp= new short[numOverlappedSamples];
        pointer=0;
        for (int i=0; i<amplitudes.length; i++)
            overlapAmp[pointer++]=amplitudes[i];
            if (pointer%fftSampleSize==fftSampleSize_1)
                // overlap
                i-=backSamples;
            
        
        numSamples=numOverlappedSamples;
        amplitudes=overlapAmp;
    
    // end overlapping

    numFrames=numSamples/fftSampleSize;
    framesPerSecond=(int)(numFrames/wave.length()); 

    // set signals for fft (windowing)
    WindowFunction window = new WindowFunction();
    window.setWindowType("BLACKMAN");
    double[] win=window.generate(fftSampleSize);

    double[][] signals=new double[numFrames][];
    for(int f=0; f<numFrames; f++) 
        signals[f]=new double[fftSampleSize];

        int startSample=f*fftSampleSize;
        for (int n=0; n<fftSampleSize; n++)

            signals[f][n]=amplitudes[startSample+n]*win[n];                         
        
    
    // end set signals for fft

    absoluteSpectrogram=new double[numFrames][];
    // for each frame in signals, do fft on it
    FastFourierTransform fft = new FastFourierTransform();
    for (int i=0; i<numFrames; i++)            
        absoluteSpectrogram[i]=fft.getMagnitudes(signals[i]);
    

    if (absoluteSpectrogram.length>0)

        numFrequencyUnit=absoluteSpectrogram[0].length;
        unitFrequency=(double)wave.getWaveHeader().getSampleRate()/2/numFrequencyUnit;  // frequency could be caught within the half of nSamples according to Nyquist theory

        // normalization of absoluteSpectrogram
        spectrogram=new double[numFrames][numFrequencyUnit];

        // set max and min amplitudes
        double maxAmp=Double.MIN_VALUE;
        double minAmp=Double.MAX_VALUE; 
        for (int i=0; i<numFrames; i++)
            for (int j=0; j<numFrequencyUnit; j++)
                if (absoluteSpectrogram[i][j]>maxAmp)
                    maxAmp=absoluteSpectrogram[i][j];
                
                else if(absoluteSpectrogram[i][j]<minAmp)
                    minAmp=absoluteSpectrogram[i][j];
                
            
        

谢谢

【问题讨论】:

第二维是频率系数。粗略地说,FFT 可以告诉某些特定频率的功率,您可以“猜测”它们之间的功率。为了在频率维度上获得更好的分辨率,您应该使用更大的 FFT 窗口(更多样本)。 那么,我们如何确定频谱图上存在的最低频率和最高频率? 【参考方案1】:

每个 FFT 结果 bin 之间的间距是采样率除以 FFT 长度。对于以 22050 sps 的速率采样并馈送到 1024 的 FFT 长度的数据,得到的频率区间间距约为 21.5 Hz。如果您将 FFT 长度减少到 512,则更大的 bin 间距会导致频谱图垂直轴中的总 bin 在达到不超过采样率的一半之前减少。对于 Blackman 窗口(实际上是任何窗口),每个 bin 的带宽都会有一些重叠。

【讨论】:

以上是关于频谱图的频率范围的主要内容,如果未能解决你的问题,请参考以下文章

无线通信频率分配表

限制 scipy.signal.spectrogram 仅计算特定频率

对于DFT频谱泄漏问题的研究

使用 FFT 进行频谱分析

Qt之调用FFTW3实现音频频谱(原理)

周期信号的频谱的谱线间隔与啥有关