授業で、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データのプロット) の横軸も、 単位が時間になるように直すべきかもしれない (横軸、縦軸の説明は必須で、即答するためには、 説明がしやすいものにしておくのが望ましい)。
桂田 祐史