授業で、Mathematica を用いて、WAVE ファイル “guitar-5-3.wav” を読み込み、適当な時点からの1秒分のデータ (項数 をサンプリング周波数と同じにとった) を離散Fourier変換して、 , , , をプロットする、という実験を行った ([1] の第4章)。
Python を使ってそれと同じことをしてみよう。
次のプログラムでは、 グラフ描画のために matplotlib というモデュールを用いている 1。
http://nalab.mind.meiji.ac.jp/~mk/fourier/testwavemodule3.py
1 # testwavemodule3.py 2 # encoding: utf-8 3 # http://nalab.mind.meiji.ac.jp/~mk/lecture/fourier-2017/testwavemodule3.py 4 # これは Python 3.x 用のプログラム 5 6 import wave 7 import numpy as np 8 import matplotlib.pyplot as plt 9 10 fname = 'guitar-5-3.wav' 11 wfile = wave.open(fname, 'r') 12 13 numch = wfile.getnchannels() 14 samplewidth = wfile.getsampwidth() 15 samplerate = wfile.getframerate() 16 numsamples = wfile.getnframes() 17 18 print("チャンネル数 = ", numch) 19 print("サンプル幅 (バイト数) = ", samplewidth) 20 print("サンプリングレート(Hz) =", samplerate) 21 print("サンプル数 =", numsamples) 22 print("録音時間 =", numsamples / samplerate) 23 24 # すべてのフレームを読み込む (bytesオブジェクトになる) 25 buf = wfile.readframes(numsamples) 26 wfile.close() 27 28 # numpy の ndarray に変換する 29 if samplewidth == 2: 30 data = np.frombuffer(buf, dtype='int16') 31 data = data / 32768.0 32 elif samplewidth == 4: 33 data = np.frombuffer(buf, dtype='int32') 34 data = data / 2147483648.0 35 36 # ステレオの場合は左チャンネルだけを取り出す 37 # (0 から最後まで2つおきに、つまり 0,2,4,.. 番目を取り出す) 38 if numch == 2: 39 #l_channel = data[0::2] 40 #r_channel = data[1::2] 41 data = data[0::2] 42 43 # 62000番目から1秒分 (samplerate 個) 取り出し、離散フーリエ変換する 44 start = 62000 45 N = samplerate 46 c = np.fft.fft(data[start:start+N]) 47 c = abs(c) 48 49 plt.subplot(2,1,1) 50 plt.title('data') 51 plt.plot(range(start, start+N), data[start:start+N]) 52 53 plt.subplot(2,1,2) 54 plt.title('frequency spectrum') 55 # 対数目盛りにするには次の3行をアンコメントする(注釈を外す) 56 #ax = plt.gca() 57 #ax.set_yscale('log') 58 #ax.set_xscale('log') 59 60 plt.plot(c, linestyle='-') 61 #横軸を周波数(Hz)にするには、次の2行をアンコメントする 62 #freqList = np.fft.fftfreq(N, d=1.0/samplerate) 63 #plt.plot(freqList, c, linestyle='-') 64 65 plt.tight_layout() # タイトルの被りを防ぐ 66 plt.show()
57行目で単に
plt.plot(c, linestyle='-') |
Numpy で用意されている numpy.fft.fftfreq() を使って
freqList = np.fft.fftfreq(N, d=1.0/samplerate) plt.plot(freqList, c, linestyle='-') |
同様に、1つめのグラフ (PCMデータのプロット) の横軸も、 単位が時間になるように直すべきかもしれない (横軸、縦軸の説明は必須で、即答するためには、 説明がしやすいものにしておくのが望ましい)。
桂田 祐史