01.短時間フーリエ解析

Created: 2018/08/24
Last Update: 2018/08/24
  1. イントロダクション

    音声解析には歴史があり、いろいろな手法が既に知られています。 ここでは、まず最初にフーリエ変換を利用して解析を行います。

    フーリエ変換では、信号が無限にくり返していることが仮定されています。 しかし、実際の音楽や音声信号では、音は一定で鳴り続けるのではなく、時間が経つと変化してしまいます。 こういった信号に対して、フーリエ解析をかける手法として、短時間フーリエ変換があります。 この手法は、信号の一部分を窓関数で切り出してきて、その一部の信号が無限にくり返しているものとして フーリエ解析をかけるといったものです。 こうすることで、信号に含まれる周波数成分の時系列変化が解析できます。

  2. pythonを使った音声解析

    それでは、実際に短時間フーリエ変換を用いて解析を試してみます。 ここではpythonを用いることとします。

    python3にnumpy, matplotlib, soundfileを入れて、次のコードを試します。

    
    #!/usr/bin/env python
    
    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.colors import LogNorm
    import soundfile as sf
    
    NFFT = 4096
    overlap = int(NFFT * 3 / 4)
    
    window = np.hamming(NFFT)
    
    def readwav(filename):
        spec = []
        with sf.SoundFile(filename, 'r') as f:
            print('sound file %d samples %f sec'%(f.frames, f.frames/f.samplerate))
            time_x = []
            fftfreq = np.fft.rfftfreq(NFFT, 1/f.samplerate)
            for pos in range(0, f.frames, NFFT-overlap):
                f.seek(pos)
                data = f.read(NFFT)
                if data.shape[0] %lt; NFFT:
                    break
                if data.ndim > 1:
                    windowed = window * data[:,1]
                else:
                    windowed = window * data
    
                fft_result = np.fft.rfft(windowed)
                fft_data = np.abs(fft_result)
    
                spec.append(fft_data)
                time_x.append(pos/f.samplerate)
    
        spec = np.array(spec).T
        time_x = np.array(time_x)
        X,Y = np.meshgrid(time_x, fftfreq)
    
        plt.pcolormesh(X, Y, spec, norm=LogNorm())
        plt.xlabel("time[s]")
        plt.ylabel("frequency[Hz]")
        plt.yscale('log')
        plt.ylim((20, 20000))
        plt.colorbar(orientation='horizontal')
        plt.show()
    
    if __name__ == '__main__':
        import sys
    
        argv = sys.argv
        argc = len(argv)
    
        if argc < 2:
            print('Usage: python %s input.wav'%argv[0])
            quit()
    
        readwav(argv[1])
    
  3. 解析の例

  4. 短時間フーリエ変換の特性

    短時間フーリエ変換を用いた解析では、解析に用いるサンプル数(ここではNFFT=4096)と窓関数(ここではハミング窓) によって得られるスペクトラムの見え方が変わります。

    NFFT=4096という大きめの解析幅を用いているので、混合sin波やスイープ信号はうまく捉えられています。 しかしながら、楽曲の解析においては低音領域においてまだ分離が十分ではなく、4096/44100=90msの時間分解能もまた十分とは言えず、ぼんやりとした結果が得られています。

    このことを解決しようとするのが次の手法です。

もくじへ戻る