FFTを使ったスペクトルの強度を色をで表現しました。
これは評価のため5500Hzの正弦波を測定したグラフです。
縦軸: サンプリング周波数44100HzをFFT長1024でFFT処理をしました。 縦軸の512が22050Hzになります。そして5500Hzの正弦波では、縦軸の4分の1の高さになります。正しそうです。今度は肉声で試して見ます。
「科捜研の女」で見るような画像です。「あいうえお」と喋りました。
ソースです。
import sys
import numpy as np
from PyQt5 import QtWidgets
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph as pg
#音声関係のライブラリ
import pyaudio
class DrawFFT:
def __init__(self):
self.FFT_LEN = 1024
self.RATE= 44100 #サンプリング周波数
# スペクトル表示バッファ
self.tick_max_x = 200
self.spct = np.full((self.tick_max_x, int(self.FFT_LEN / 2)), -150 )
self.window = pg.GraphicsLayoutWidget(size=(500, 450), show=True)
# 画像オブジェクト作成 & 画像をセット
self.image = pg.ImageItem(border="y")
self.image.setImage(self.spct)
# カラーマップ取得・セット
cmap = pg.colormap.getFromMatplotlib("jet")
bar = pg.ColorBarItem( cmap=cmap, values=(-150, 0))
bar.setImageItem(self.image)
# 画像を格納するボックス作成 & 画像オブジェクトをセット
self.view_box = pg.ViewBox()
# self.view_box.setAspectLocked(lock=True)
self.view_box.addItem(self.image)
# プロットオブジェクト作成、view_boxをセット
self.plot = pg.PlotItem(viewBox=self.view_box)
# ウィンドウにplotを追加
self.window.addItem(self.plot)
# ウィンドウ表示
self.window.show()
# PCM録音設定
#音声データの格納場所(プロットデータ)
self.fft_data=np.zeros(self.FFT_LEN)
self.fft_cnt = 0
self.received = False
self.win_hamming = np.hamming(self.FFT_LEN)
# self.CHUNK=1024 #1回の受信で読み取るデータ量
self.audio=pyaudio.PyAudio()
self.stream=self.audio.open(format=pyaudio.paInt16,
channels=1,
rate=self.RATE,
input=True,
frames_per_buffer=self.FFT_LEN,
stream_callback=self.callback)
self.stream.start_stream()
#アップデート時間設定
self.timer=QtCore.QTimer()
self.timer.timeout.connect(self.update)
self.timer.start(20)
def callback(self, in_data, frame_count, time_info, status):
self.fft_data=np.frombuffer(in_data, dtype="int16")/32768.0
self.received = True
return (in_data,pyaudio.paContinue)
def update(self):
if self.received == True:
fft = np.fft.fft(self.fft_data * self.win_hamming)
f = fft[0 : int(self.FFT_LEN / 2)]
power_sp = 20 * np.log10(np.abs(f))
# print(power_sp.max(), power_sp.min())
if self.fft_cnt >= self.tick_max_x:
temp =self.spct[1:]
self.spct = np.insert(temp, -1, power_sp, axis=0)
else:
self.spct[self.fft_cnt] = power_sp
self.fft_cnt += 1
self.image.setImage(self.spct)
self.received = False
# デストラクタ
def __del__(self):
print('terminated.')
self.stream.stop_stream()
self.stream.close()
self.audio.terminate()
if __name__=="__main__":
plotwin=DrawFFT()
if (sys.flags.interactive!=1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
手こずったのがupdate()でどうやって再描画するのか?何度か試行錯誤した結果、
self.image.setImage(self.spct) これだけでOK。
次に一番手こずったのが、表示データを移動するところです。
temp =self.spct[1:]
self.spct = np.insert(temp, -1, power_sp, axis=0)
self.spct[1]からself.spct[199]の199個のデータをtempにコピーします。
次にtempに1データ追加した結果をself.spctに代入します。
最初はnp.append()でやっていました。エラーになったりして思ったように動きません。いりいろ試した結果、np.insert()で解決しました。
numpyとPyQtGraphの組み合わせは本当に高速だと関心しきりです。
|