読者です 読者をやめる 読者になる 読者になる

すこしふしぎ.

VR/HI系院生による技術ブログ.まったりいきましょ.(友人ズとブログリレー中.さぼったら焼肉おごらなきゃいけない)

【python】スペクトログラムを表示【サウンドプログラミング】

こんばんは,1000chです. 週末に論文締め切りがあったりバイトの締め目標があったりで,なぜか最近やたら忙しいです. こーゆーのってなぜか重なるものですよね... しかしリレー形式を取ってる以上さぼる訳にはいきませんね. さーてがんばって書かないと(現在1:26)

スペクトログラム

今日のテーマはスペクトログラムです. matplotlibを使ってスペクトログラムを表示してみます. こんなんですね.

f:id:ism1000ch:20140716014749p:plain

スペクトログラムとは,簡単に言うとスペクトルの時間変化を表した図です. (短時間)フーリエ変換を行うと,指定区間の周波数特性(=スペクトル)が求められますよね. しかし通常音データは時間により周波数特性が変化するので,それを表示するにはちょっと工夫が必要になると. そこで出てくるのがスペクトログラムになります.

スペクトル自体が周波数と強度の2次元であるため,そこに時間軸が追加されると3次元データとなってしまうわけですが, スペクトログラムでは強度を濃度で表すことで,平面上にそのデータを表示します. なのでまあ,正確なデータ表示というよりは,全体的な傾向を俯瞰するための図である,と捉えておくと良いでしょう.

pythonでスペクトログラムの表示

毎度のことながらこちらが非常に参考になります.

Pythonでサウンドスペクトログラム - 人工知能に関する断想録

曰く,numpyやらscipyにはスペクトログラムに関する関数はないとのこと.残念. 愚直にやるのであれば,自分でフレーム区切って適宜fftを行い,そのデータを濃度表示すればいいんですかね?

ともあれ,matplotlibにはスペクトログラム描画用の関数があるようなのでこちらを利用してみましょう. 公式はこちら.

mlab.specgram - matplotlib

# definition
matplotlib.mlab.specgram(x, NFFT=256, Fs=2, detrend=<function detrend_none at 0x2635de8>, window=<function window_hanning at 0x2635b90>, noverlap=128, pad_to=None, sides='default', scale_by_freq=None)

いろいろオプションがありますが,詳細は公式をみてみてください.

  • x:信号データ
  • NFFT:fftするデータ数
  • Fs:サンプリングレート(デフォルト2→ナイキストレートが1ということ?)
  • window:窓関数の指定.ハニングとかハミングとか
  • noverlap:重なるサンプル数

くらいが指定できればまぁ使えるんじゃないかな. 返り値は

  • pxx : 2darray.スペクトログラム解析結果?
  • freqs : 1darray.最も強い周波数列?
  • t: 1darray.各ピリオドグラムの時間

てな感じでしょうか.ちょっちよくわかんないです

ということで早速スペクトログラムを表示してみましょう. 周波数特性が時間的に変化しているデータが欲しいので,audacityでこんなの作りました.

ジェネレータからチャープを選んでC3からC5まで変化させています.

スペクトログラム描画のプログラムはこんな感じ.

#coding:utf-8

import scipy.io.wavfile as wio
import matplotlib.pyplot as plt


if __name__ == '__main__':
    rate, data = wio.read("charp_a3_a5.wav")
    pxx, freq, bins, t = plt.specgram(data,Fs = rate)
    plt.show()
    

お気づきかもしれませんが,返り値のタプルに要素が増えてますねw(ハマった) 公式通りで動かないのでggったらこんなコードが書いてあり,これだときちんと動作するようです.

さて注目しておきたいのは,plt.specgram関数を呼んだ後にplt.plot的な描画処理を呼ばなくて良いというところでしょうか. どうやらスペクトログラムの解析と同時に,現在のグラフに描画までしてくれるみたいです. この状態でplt.showを呼ぶとスペクトログラムが表示されます. 今回のデータではこんな感じでした.

f:id:ism1000ch:20140716013804p:plain

選んだ周波数的に低い成分ばかりですが,なんとなく右肩上がりになってるのがわかりますね.ちょいちょい切れ目っぽいのがありますが,これは窓関数化してることに起因したりするのでしょうか?本来なら奇麗になるはずなのでは?と思うのですが,ちょっと原因不明です.

ともあれこれで,音データを可視化することができるようになった,と言えるでしょう. 様々な音のスペクトログラムをのぞいてみると,面白いかもしれません. 特に人の声は特徴的で面白いはず!

まとめ

  • スペクトログラムってなに
  • スペクトログラム描画しよう with python

おまけ

調べてたらSoXなるコマンドライン上での信号処理ツールを知りました.

SoX

日本語解説はこちら.

SoX — Sound eXchange の各種マニュアルページの日本語訳

まだきちんと読んでないですが,サウンドデータの変換や,エフェクト掛けなどをコマンドライン上でできるツールっぽいです.

おもしろそうなので拾ってみました.とりあえずbrew叩いたら入ってきたのでよしとします.

brew install sox

でこれ使うと冒頭のようなかっこいいスペクトログラムを簡単に表示できます.

sox file_name -n spectrogram

ディレクトリ内にspectrogram.pngが生成されるはず. 先程のcharpを描画してみるとこうなりました.

f:id:ism1000ch:20140716022002p:plain

か,かっこええ(`・ω・´)

ネオンっぽく見えるのがイカしてます. というかmatplotlibで描画したやつより見やすいですねw

そのうちこちらも触って遊べたらなーと思います.