見出し画像

TouchDesignerで心理学実験システム.003:条件を変えたタスクの繰り返し

3. 実験シーケンステーブルの作成とタスクの繰り返し

前回の記事の続きです。TouchDesignerで心理学実験・認知実験などを実装する方法をストループ課題を題材に説明していきます。第一回目はコチラ

前回は、実験条件からの視覚刺激生成部分を作りました。実際の実験シーケンスでは、異なる条件でタスクを繰り返し行うことになります。実験条件はある規則性で順序を設計したり、ランダムな順序にする事が多いので、そのようなテーブルを用意します。

実験順序テーブルは表計算ソフトウエア等でcsv, tsvファイルを作成して読み込み事もできますが、ここではpythonスクリプトを実行してテーブルを作成する方法で作ります。今回も空のbaseコンポーネントを作りその中で作成していきます。

操作動画は前半と後半に分けています。

pythonスクリプトからtableDATを更新する

tableDATがテーブルの入れ物になります。textDATに書いたpythonスクリプトからテーブルの中身を更新します。tableDATの名前がtrialTableとしたとき、trialTableのデータはpythonコードからop(‘trialTable’)でアクセスする事ができます。

#行の追加
op(‘trialTable’).appendRow(['index', 'letter', 'color'])
#セルへのアクセス
op(‘trialTable’)[0.0]

pythonスクリプトはtextDAT (Gen_Paradigm) に書いていきます。

名称未設定

Gen_Sequenceのスクリプト内容はこちら。

import random

#シーケンスをいれておくテーブルを初期化
trialTable = op('trialTable')       
trialTable.clear()

#系列に名前をつけておく。あとで便利
trialTable.appendRow(['index', 'letter', 'color'])
   
text_list = ['RED', 'GREEN', 'BLUE']
color_list = ['RED', 'GREEN', 'BLUE']

#一時的にシーケンスを入れておくリスト
trialseq = []

#text_list, color_list の全組み合わせを3個づつ
#ここを外部から指定してもいいですね。
for _index in range(3):
   for txt in text_list:
       for col in color_list:
           trialseq.append([txt,col ])

#一時的なシーケンスの順序をランダム化
random.shuffle(trialseq)

#tableDATにシーケンスのデータを入れる
index = 1
for seq in trialseq:
   newRow = [index, seq[0], seq[1] ]
   trialTable.appendRow(newRow)
   index += 1

このスクリプトは右クリック→Run Scriptで実行できます。実行すると、trialTableの中身が更新されることが確認できます。また、他のスクリプトから、op(‘Gen_Sequence’).run()のように実行できるので、後ほど他の処理とともに、このシーケンス生成スクリプトを実行できます。

画像2

ボタントリガーでpythonスクリプトを実行する。

こちらのGen_Sequenceスクリプトbaseコンポーネントの外からのトリガーで実行したい場合、方法はいくつかありますが、今回は簡単にButtonコンポーネントを使ってトリガーしてみます。

図のように、inCHOPとそのデフォルトインプットとして、テスト用にButtonコンポーネントをつなげます。その後、inCHOPの値変化で関数実行トリガーするために、chopExcuteCHOP (chopexec1)を用意して、CHOPパラメータでchopexec1を指定、Off to OnをONにします。

画像3

これで、値が0→1に変化した時にonOffToOn関数が呼ばれます。ここに、op('Gen_Sequence').run()を記述することで、Gen_Sequenceスクリプトを実効することができます。

def onOffToOn(channel, sampleIndex, val, prev):
   op('Gen_Sequence').run()
   return

ここまでで、Gen_Sequenceスクリプトを実行して実験条件のテーブルを更新することができます。

実験条件テーブルからの読み出し

このtrialTableに記載されている実験条件をindex順に読み出して、既に作成した刺激生成のモジュールにつないで、指定する実験条件の視覚刺激を作ることになります。

もう一つinCHOP (in2)を用意します。これは、テーブルのIndexを指定するbaseコンポーネントへの2つ目の入力となります。(inCHOPの2番目につないでいるconstantCHOPは、入力がなかった時のデフォルト値になります。in2nullCHOPをつないで、名前をCURRENT_INDEXにしてあります。この値をop(‘CURRENT_INDEX’)[0]のように参照することで、selectDATで指定する行を取り出します。なお、nullCHOPはこの実装ではなくても作れますが、後々オペレーターをつなぎ直すときに便利なので使っています。

画像4

ここでもselectDATを用いることで、対応するIndexの実験条件を取り出します。このテーブル形式は前回作成した刺激作成用のテーブルの形式になります。最後にselectDATからoutDATへ接続して実験条件のテーブルを出力します。

今回作成したbaseコンポーネント(base_sequenceTable)を上の階層から使用するために、buttonコンポーネントの出力を第1入力に接続、ConstantCHOP (channel名をIndexにしておく)を第2入力に接続し、base_sequenceTableからの出力を前回作成した、base_vstimにつなぐことで指定したIndexに対応する実験条件の視覚刺激を生成できるようになりました。

画像5

画像6

ここまでで、ボタンを押すとテーブルの更新を行い、constantCHOPのIndex値を変えると対応する視覚刺激をつくる部分ができました。

なおサンプルのモジュールでは、これをシーケンス状況を見やすいように、contiainerにしたモジュールも用意してあり、下記にように全体のシーケンス数とシーケンステーブルの内容が’確認できるようになっています。

画像7

ここまでできたら、前回作成した視覚刺激部分(base_vstim)とさらにその先の画面遷移の視覚刺激部分(base_trialscreem)をつなげていくことで、indexで指定した条件で、実験タスクが行われる事が確認できます。

画像8

実験順序指定Indexを自動でカウントアップする

後半の動画

しかし、今のままではIndexを手動で更新しないと実験タスクの内容が変わりません。そこで、実験タスクをする度にIndexをカウントアップするようにしましょう。(この辺の実装方法は色々あると思うので、参考程度に見てください)

今回は下記のように作ります。
- 実験タスクの開始は実験者または実験者参加者がマニュアルでスタート
- 実験トライアルのIndexは自動的にカウントアップする。

そこで、まず前回作ったtimerCHOPOn DoneDo nothingにします。これで、実験はtimeCHOPstartを押さないと開始しません。

画像9

また、timerCHOPoutputパラメータでDoneOnになっていることを確認します。これで、timerで1回シーケンスが完了した時に、Doneチャンネルに1が出力されます。次にtimeCHOPの出力をselectCHOPへつないで’Done’だけ取り出します。そしてそれをcountCHOPへ接続します。ここで、timeCHOPでシーケンスが終わる度にcountCHOPでカウントアップさせることができます。最後にrenameCHOPでチャンネル名をIndexに変更した後に、今回作成したbase_sequenceTableの入力へ接続します。

画像10

これで、timeCHOPでシーケンスが一回終わる度にIndexがインクリメントされて、次のタスクで使用される条件の視覚刺激が用意されるようになります。

初期化ボタンを実験開始ボタンの追加

オペレーションのために、
- Initボタン:実験順序シーケンスの初期化(count upを0に戻す)
- Startボタン:実験タスクを(1回ずつ)開始する。
のためのボタンを配置します。

ここではbuttonコンポーネントから接続したnullCHOPの値(0→1)を使います。InitボタンcountCHOPresetpulseボタンへ参照させて、Startボタンは、timerCHOPStartボタンへ参照させます。なお、buttonコンポーネントのparameterButton Typeは「Momentary」にしておきましょう。

画像11

これで、
- Initボタンを押すとカウントが0へ初期化される。(実験順序Indexは0へ)
- Startボタンを押すと、タイマーが開始されて、実験タスクが開始する

という挙動が完成しました。ここまで操作ステップごとに書くと長いですが、一度作ってしまえば、使い回しが出来る構成です。

ソースコードはコチラ

またおなじ内容のQiita記事はこちら(準備中)


次は、実験トライアル毎の実験参加者反応(キーボード回答・反応時間)の取得する部分を作っていきます。


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