見出し画像

複数のPC上でPsychopyを使った実験プログラムから同期した反応時間を得る & 実験プログラムを同期させて動かす

参考資料:
 Razavi, M., Yamauchi, T., Janfaza, V., Leontyev, A., Longmire-Monford, S., & Orr, J. M. (2020). Multimodal-Multisensory Experiments: Design and Implementation. 
 LabRecorder(https://github.com/labstreaminglayer/App-LabRecorder
 Lab Streaming Layer(https://labstreaminglayer.readthedocs.io/index.html
 pyxdf(https://github.com/xdf-modules/pyxdf

初めに

 いったい何人の日本人がタイトル通りのことをやる必要に迫られるか分からないが,資料として残す。
 自分の状況としては,会話実験を行い,会話中に各参加者が行うキー押し・発話の時間を同期させたデータが欲しかった。まず,実験プログラムをPsychopyで作成したのだが,使えるPCがWindowsであったために一つのパソコンに繋いだ複数のキーボードそれぞれを個別に指定してデータを取ることが出来なかった(Mac/Linuxでは可能)。加えて,それぞれの参加者の発話を個別に録音する必要があった。そこでタイトルの通り,複数のPC上でPsychopyで作成した実験プログラムを動かしてキー押し時間と録音開始時間を同期させたデータを取った。
 後,Psychopyはビルダー使う前提で話が進みます。

1. 準備

 PsychopyとLabRecorderをパソコンn台にインストールする。パソコンn台はそれぞれLANに接続する。LabRecorderは,Lab Streaming Layer(LSL)に付帯するデフォルトの記録プログラムで,ネットワーク上のすべてのストリーム間の時間を同期させることができる。データはXDFファイルフォーマットで出て来る。
 後,実験プログラムを適当にPsychopyで作成する。

2. LabRecorder

 早速ダウンロードして,開いてみると以下ような画面が表示される。

画像1

 LSLに対応したアイトラッキングや脳波測定のための機器がつないであると,「Record From Streams」の欄に表示され,保存したいものを選択してStartを押すことですぐに時間を同期させたデータが取れるそうだが,残念なことにPsychopy単体では何も出てこない。Psychopyで取得したデータをLabRecorderで記録するためには,コーダーを弄る必要がある。

3. Psychopy側の準備

 実験プログラムで,教示を表示するなどの実際に反応を取得する前にある適当なルーチンに,コーダーコンポーネントを追加し,「実験開始時」タブに以下のようなコードを書く。

from pylsl import StreamInfo, StreamOutlet
from pathlib import Path
import os, sys, subprocess, time
sys.path.append('./lib/')
info_Taptime1 = StreamInfo(name = 'Taptime1', type = 'Markers',
                     channel_count = 1, channel_format = 'string',
                     source_id = 'Taptime123')
outlet_Taptime1 = StreamOutlet(info_Taptime1)

 このコードによって,実験プログラム開始時にLSL上にストリームを作ることが出来るようになった。つまり,このコードはデータを同期させ記録したい全てのプログラムに追加しておく必要がある。
name:作成するストリームの名前
type:、そのチャンネルで伝送されるコンテンツを表す
channel_count:ストリーム内のチャンネルの数,最低1
channel_format:ストリーム内のチャンネルは全て同じフォーマットでないとダメ,今回は関係ないが接続した複数機器のフォーマットが違ったら対応する分だけストリームを作る必要がある(ということだと思う)
source_id:利用可能な場合,プログラムがオンラインに戻った後にストリームを自動的に再取得できる

 次に,先ほど追加したコーダーコンポーネントの「ルーチン終了時」タブに,以下のようなコードを書く。

currentTime = expInfo['data']
LabRecorderCLI_path = ".\LabRecorder\LabRecorderCLI.exe"
Path("./stream").mkdir(parents = True, exist_ok = True)
Dataset_path = ".\stream\\"
save_path = Dataset_path + currentTime + ".xdf"
XDF_save_command = LabRecorderCLI_path + " " + save_path + " " + "'searchstr'"
XDF_Record = os.popen(XDF_save_command)

 このコードによって,実験プログラムの裏でLabRecorderを起動してストリームの記録を開始することが可能になった。このコードは,LabRecorderをインストールしたPC上で動かすプログラム一つに含まれていればよい(当然,保険のために全てのプログラムにあってもいいと思う。自分は手元のパソコンの性能が微妙だったため,一番マシなPCで動かすプログラムだけに追加した)。
 ここで大事なのは,LabRecorderを起動して記録を開始する前にストリームを作っておく必要があることである。記録開始後にストリームを作っても,それは保存されない。

 最後に,Psychopyで取得したデータをストリームに流すためのコードを書く。自分は,反応を取得するルーチンにコーダーコンポーネントを追加し,以下のコードをフレーム毎のタブに書いた。

keys_1 = event.getKeys('s')
outlet_Taptime1.push_chunk([keys_1])

 このコードによって,sキーを押した時間がストリーム上に流される。このコードは,それぞれのプログラム上で,ストリームの作成・記録開始後に書く必要がある。

4.  データの確認

 以上のコードを追加した実験プログラムをLANに接続した複数PC上で同時に実行すると,実験プログラムが存在するフォルダにstreamという名前のフォルダが生成され,その中に反応時間等のデータが入ったxdfファイルが保存される。自分はxdfファイルの閲覧にpyxdfを用いた。

data, header = pyxdf.load_xdf('test.xdf', select_streams = 2)
data

 select_stereamsで指定することで,記録した複数のストリームの内から該当ストリーム上のデータを見ることが出来る。数字はストリームを作成した順番になっているっぽい(?)。

5. 同期させて動かす

 パソコンAからpush_chunkでストリームに流して,パソコンB・Cでpull_chunkで受け取る。そんだけ。Psychopyで録音長まわしすると遅延がバカにならないので,複数試行あるときは試行毎にパソコンAへの入力を受けてパソコンB・Cで録音が開始&終了するプログラムを書いた方がいいことが分かった。

この記事が気に入ったらサポートをしてみませんか?