代码之家  ›  专栏  ›  技术社区  ›  Tyler Hilbert

FFT:当采样数小于fs/2时,如何找到单边谱

  •  0
  • Tyler Hilbert  · 技术社区  · 6 年前

    我正在编写一段代码,找出歌曲在任何给定时间播放的频率(音符)(注:目前我正在测试它,只捕捉歌曲的第一秒)。为此,我将音频文件的第一秒钟分成8个不同的块。然后,我对每个块执行FFT,并用以下代码绘制它:

    % Taking a second of an audio file and breaking it into n many chunks and
    % figuring out what frequencies make up each of those chunks
    clear all;
    
    % Read Audio
    fs = 44100;         % sample frequency (Hz)
    full = audioread('song.wav');
    
    % Perform fft and get frequencies
    chunks = 8;         % How many chunks to break wave into
    for i = 1:chunks
        beginningChunk = (i-1)*fs/chunks+1
        endChunk = i*fs/chunks
        x = full(beginningChunk:endChunk);
        y = fft(x);
        n = length(x);     % number of samples in chunk
        amp = abs(y)/n;    % amplitude of the DFT
        %%%amp = amp(1:fs/2/chunks); % note this is my attempt that I think is wrong
        f = (0:n-1)*(fs/n);     % frequency range
        %%%f = f(1:fs/2/chunks); % note this is my attempt that I think is wrong
    
        figure(i);
        plot(f,amp)
        xlabel('Frequency')
        ylabel('amplitude')
    end
    

    当我这样做时,我得到的图形如下所示: enter image description here enter image description here

    看起来我画的点太多了,因为在图的最右边,频率的幅度上升了,所以我想我用的是双面谱。我想我只需要使用1:fs/2的样本,问题是我没有足够大的矩阵来获取那么多的点。我试着从1:fs/2/chunk开始,但我不相信这些值是正确的,所以我把它们注释掉了。当样本数少于fs/2时,如何找到单侧光谱?

    当我绘制所有图表时,我注意到给出的频率几乎完全相同。这让我很惊讶,因为我认为我把这些音块做得足够小,只有在准确的时间发生的频率才能被捕捉到,因此我会得到当前播放的音符。如果有人知道我如何更好地挑出每次演奏的音符,我将不胜感激。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Cris Luengo    6 年前

    对于单侧FT,只需获取FFT算法输出的前一半。另一半(否定频率)是多余的,因为你的输入是实值的。

    1/8秒相当长。请注意,如果我没记错的话,相关频率约为160-1600 Hz(音乐不是我的专长)。这些将位于FT的最左侧区域。计算的最高频率(去掉FFT的右半部分后)是采样频率的一半,44.1/2 kHz。最低频率和采样之间的距离由变换的长度给出(44.1 kHz/采样数)。