教育用GM管開発を振り返って(10)
放射線教育支援サイト「らでぃ」の実験集に掲載した「Pythonで反復計数の実験」のPythonプログラムについて解説する。Pythonやライブラリーのインストール方法や注意点、Pythonの文法の特徴などは「教育用GM管開発を振り返って(9)」に記載した。
「Pythonで反復計数の実験」のプログラム例
10秒間の計数を、キーqの入力で停止するまで繰り返し、計数率を画面表示するとともに、csvファイルに出力する計数の基本プログラムについて解説する。
まず、必要なライブラリーをインポートする。このうち、numpyはPythonのインストールで同時にインストールされるので、ライブラリーとして別途インストールする必要はない。#以下はコメント文である。
import pyaudio #マイク入出力処理 import numpy as np import matplotlib.pyplot as plt #グラフ処理 import cv2 #カメラ画像処理
次に、グローバル変数を宣言し、初期値を決める。閾値の変数thresholdは、パルス波高を予めモニターして数値を決め、キーボードから入力する。
global m, threshold #回数と閾値の変数をグローバルと宣言 m = 1 #測定回数 threshold = input('Threshold?') #閾値を入力
出力ファイルcpm_data.csvを開き、ヘッダーを書き込んでおく。出力ファイルはExcelなどの処理ソフトを利用することを念頭にcsvファイルとした。
with open('cpm_data.csv', mode='w') as fc: #出力ファイルを新規モードで開く fc.write('Time(sec)' + ',' + 'CPM' + '\n') #ヘッダーを書き込む
次に一連の音声入力をストリーミングとしてデータ化し、計数に至るまでを関数化する。CHUNKは入力単位でここでは、1024個ごとにサンプリングする。サンプリング周波数は変えられるが、デフォルトのままにした。録音時間は10秒である。
def streamandcount(): #マイク入力から計数までの処理 #stream CHUNK = 1024 #入出力の長さ FORMAT = pyaudio.paInt16 #2Byte整数 CHANNELS = 2 #ステレオ RATE = 44100 #サンプリング周波数(Hz) RECORD_SECONDS = 10 #録音時間(秒)
ストリーミングをオープンし、CHUNKごとのデータdata-rawをframesというlistに追記していく。
p = pyaudio.PyAudio() stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, #入力のみ frames_per_buffer=CHUNK) #ストリームを開く frames = [] #空のlistを用意
10秒分のデーターを加算して、framesに追記していく。
for i in range(int(RATE * RECORD_SECONDS // CHUNK)): #CHUNK単位で切り捨て data_raw = stream.read(CHUNK) #CHUNK単位で音声信号をサンプリング frames.append(data_raw) #430回分を加算 frames_int16 = np.array(frames) #listをnumpyアレイに変換
ここでストリームを閉じる。
stream.stop_stream() #ストリームを閉じる
stream.close()
p.terminate()
以下は、計数と計数率の画面とファイルへの出力のための演算で、まず、2進数を10進数に変換し、データは片チャンネルだけでよいので、ステレオのLチャンネルのデータだけを抽出する。
#count pulse = 0 #計数を初期化 data = np.frombuffer(frames_int16, dtype='int16') #バイトデータを整数に変換 data_l = data[::2] #ステレオのLチェンネルを取り出す onflag = False #閾値超過フラッグの初期値
データが閾値を超えるとフラッグを立て、閾値を下回るとカウント1を加算し、フラッグを降ろす。閾値を超えたところから下回ったところまでを1カウントとするので、複数パルスでも重複カウントすることはない。
for k in range(len(data_l)): #data_l全体が範囲 dat = data_l[int(k)] #data_lのk番目の値 if int(dat) > int(threshold) and not onflag: #閾値を超えたら pulse = pulse + 1 #1カウントを加算 onflag = True #閾値超過フラッグを立てる if int(dat) <= int(threshold): #閾値以下になったら onflag = False #閾値超過フラッグを降ろす
計数率はCPMで表示することとしたので、10秒のカウント数を6倍して画面に出力する。
cpm = pulse / RECORD_SECONDS * 60 #CPMに換算 print('CPM = ' + str(int(cpm))) #CPMを画面に出力
同時に計数率をファイルに出力する。フォーマットは、回数、計数率となっている。
with open('cpm_data.csv', mode='a') as fc: #出力ファイルを追記モードで開く fc.write(str(10 * m) + ',' + str(cpm) + '\n')
キーボードからqを入力するまで、計数を反復する。プログラムの停止には、キーボードからqを入力する。
while True: #キー入力まで反復する if cv2.waitKey(1) & 0xFF == ord('q'): #qを入力すると break #プログラムが終了 streamandcount() #処理を繰り返す m = m + 1 #回数のカウントを1増やす
Pythonの実行は、Windows Power ShellまたはCMDを開いて、ファイル名を入力することで行う。そうすれば、終了時にも計数率は画面上に残っているので、結果を確認することができる。Pythonファイルをダブルクリックして実行した場合は、画面上に残らないので結果は出力ファイルで確認することになる。学校の授業で、距離の実験や遮へいの実験を行う場合は、条件を変えて10秒率で6回の測定を繰り返すので、6回測定後に一旦停止して、再度再開できるプログラムの方が適している。しかし、キーボード入力でコントロールする方法に確実性がないために、できていない。うまい方法があれば教えてほしい。
(※id:TJOがid:apgmmanから受領したWord原稿を元に再構成、代理投稿したものです)