人工知能に関する断創録

このブログでは人工知能のさまざまな分野について調査したことをまとめています(更新停止: 2019年12月31日)

Pythonでサウンドスペクトログラム

Pythonで音声信号処理(2011/05/14)

今回は、さまざまな音声のスペクトログラム(spectrogram)を求めてみたいと思います。科学捜査班が声紋分析で使っているやつですね。こういうの。

f:id:aidiary:20111001111243p:plain

名前がスペクトログラムってくらいなのでフーリエ変換で求めるスペクトル(spectrum)と関係があります。スペクトルは、離散フーリエ変換(2011/6/11)でも紹介しましたが、音声波形の短時間(512サンプルなど)の波形データの中にどのような周波数成分がどれだけ含まれるかを表した図です。スペクトルは、横軸が周波数で縦軸が強度(振幅の2乗)となっています。スペクトルのグラフには、時間が入ってこないのが特徴的。時間はFFTをかける波形の位置で決まるので時間はFFTする前にあらかじめ固定されています。ちなみに、元の波形は横軸が時間なので時間領域、スペクトルは横軸が周波数なので周波数領域といいます。この時間領域と周波数領域を相互に変換するのがフーリエ変換、逆フーリエ変換でした

f:id:aidiary:20111001121934p:plain

スペクトルは、時間軸がないので「波形の時間経過に伴ってスペクトルがどのように変化するか」を見たい場合は、別の手法が必要になります。そのひとつが前回紹介した短時間離散フーリエ変換(2011/7/16)を使ったアニメーションです。そして、もうひとつの方法が、今回紹介するスペクトログラムです。スペクトログラムを使うとスペクトルの時間変化が一枚の画像で表せます。

f:id:aidiary:20111001111243p:plain

スペクトログラムは、横軸が時間で縦軸が周波数になります。そして、色(白黒画像の場合は濃淡)で周波数の強度を表します。こうすれば、時間、周波数、強度という3つの情報を1つの図にまとめることができます。これは便利!

Pythonでサウンドスペクトログラム

Pythonでスペクトログラムを描画してみようと思ったけど、今までフーリエ変換で利用してきたnumpyやscipyにはスペクトログラムを描画する機能はないようです。Pythonのグラフ描画ライブラリであるmatplotlibの中にspecgram()という関数があったので使ってみます。以下のプログラムで使っているWAVEファイルは、正弦波の合成(2011/6/7)からダウンロードできます。

#coding:utf-8
import wave
from pylab import *

if __name__ == "__main__":
    # WAVEファイルから波形データを取得
    wf = wave.open("data/sine.wav", "rb")
    data = wf.readframes(wf.getnframes())
    data = frombuffer(data, dtype="int16")
    length = float(wf.getnframes()) / wf.getframerate()  # 波形長さ(秒)
    
    # FFTのサンプル数
    N = 512
    
    # FFTで用いるハミング窓
    hammingWindow = np.hamming(N)

    # スペクトログラムを描画
    pxx, freqs, bins, im = specgram(data, NFFT=N, Fs=wf.getframerate(), noverlap=0, window=hammingWindow)
    axis([0, length, 0, wf.getframerate() / 2])
    xlabel("time [second]")
    ylabel("frequency [Hz]")

    show()

実行すると、下図のようにカラフルなスペクトログラムが表示されます。赤いほど強度が強く、青いほど強度が弱いことを意味しています。このサイン波は基本周波数250Hzなので250Hzの部分が赤くなっていることがわかります。3倍、5倍、7倍・・・のところがうっすら線になっているのはなぜだろう?一応、窓関数を使っているけど成分が出てしまったのかな?

f:id:aidiary:20111001121935p:plain

いろいろな波のスペクトログラム

ここで、いろんな音のスペクトログラムを調べてみました。離散フーリエ変換(2011/6/11)で作ってみた三角波矩形波、のこぎり波、ギター(A4)、和音のスペクトログラムです。

まずは、三角波。基本周波数の250Hzの3倍、5倍、7倍・・・の成分も含まれていることがわかります。また、音量は変わっていないので時間がたっても強度(色)の変化はありません。

f:id:aidiary:20111001121936p:plain

次、四角波。これも三角波と同様に奇数倍の成分も含まれますが、三角波と比べて赤色が強いままなことがわかります。

f:id:aidiary:20111001121937p:plain

次、のこぎり波。これは、2倍、3倍、4倍・・・の成分が含まれています。

f:id:aidiary:20111001122442p:plain

次、ギターの音。音量がだんだん弱くなっているので時間が経つとスペクトルの強度もだんだん薄くなっています。

f:id:aidiary:20111001122443p:plain

次、正弦波の合成(2011/6/7)で作った和音。和音は3つの周波数の音が含まれます。C→D→E→F→G→A→Bとだんだん音を高くしているので階段状になっています。

f:id:aidiary:20111001122444p:plain

最後に、人間の声で「あいうえお」としゃべった音声。人間の声の場合は、スペクトログラムから抽出されるフォルマントという特徴量で母音が識別できるとのこと。あとで音声認識のときに使います。

f:id:aidiary:20111001123201p:plain

soxでサウンドスペクトログラム

matplotlib以外にもスペクトログラムを表示するソフトはたくさんあります。上のプログラムは、モノラル音声にしか対応していないなど使い勝手が悪いです。コマンドラインのツールとして非常に便利なsox(Sound eXchange)でスペクトログラムを求めてみます。使い方は、非常に簡単。

    sox aiueo.wav -n spectrogram

だけ。カレントディレクトリにspectrogram.pngというファイルができています。matplotlibより美しいです。soxは、他にも便利な機能満載なのであとで紹介したいと思います。

f:id:aidiary:20111001124129p:plain