配置心理學實驗時所須要的自變量是一個麻煩的問題,在這裏,介紹一種簡單快速配置實驗變量的方法。這個方法確保了程序的簡單、可讀,減小了編程出bug的可能。python
呈現一個注視屏,上面有三個框,中間的框裏有注視點,800ms編程
而後左邊或右邊的框中出現一個圓,圓的顏色是紅、綠、藍其中一種,200msapp
接着繼續呈現注視屏,400ms或700msdom
再呈現目標刺激,是一個"*",被試須要當即按下'j'鍵。若是被試在"*"出現前按下按鍵,那麼反饋"請看到*後再按鍵",若是被試超過1000ms都沒有按鍵,那麼反饋"請在*出現1秒內反饋"。反饋信息顯示1000ms函數
最後呈現一個700ms的空屏測試
試次分爲正常試次和探測試次。正常試次按以上流程,探測試次在呈現目標刺激階段時,不呈現"*"。ui
color 線索顏色: 紅、綠、藍this
cloc 線索位置: 左邊 右邊spa
soa :400ms 700ms設計
tloc 目標刺激: 左邊 右邊 不呈現
被試的按鍵:"j"
按鍵反應時
其中,反應時爲-1000表示被試提早按鍵,按鍵爲timeout表示被試超時。
共360試次,其中80%正常試次,20%探測試次。在這兩種試次中,自變量的各類狀況都均勻分佈。
被試id 試次 color cloc soa tloc key RT
ShowFixation1 | 顯示第一個注視屏 | |
ShowCue | 顯示線索屏幕 | |
ShowFixation2 | 顯示第二個線索屏 須要檢測是否提早按鍵 |
返回'timeout'說明被試沒按鍵 返回'j'說明被試提早按鍵 |
ShowTarget | 顯示目標刺激 | 返回('j', 789)表示被試正常按鍵 返回('timeout',0)表示被試超時 返回('q', 765)表示退出實驗 |
ShowTimePre | 顯示反應提早 | |
ShowTimeOut | 顯示反應超時 | |
ShowBlank | 顯示空屏 |
from itertools import * import random colors = ['red', 'blue', 'green'] clocs = ['left', 'right'] soas = [0.4, 0.7] tlocs = ['left', 'right'] # + [0] trails = list(product(colors, clocs, soas, tlocs))* 12 +\ list(product(colors, clocs, soas, [0])) * 6 random.shuffle(trails)
itertools裏的product會生成一個迭代器,這個迭代器會依次返回多個循環器集合的笛卡爾積,至關於嵌套循環。在外面套上list把結果轉換成列表。
例如list(product(['a', 'b', 'c'],[1, 2])),會生成[('a', 1), ('a', 2), ('b', 1), ('b', 2), ('c', 1), ('c', 2)]
執行完上面的操做後,trails裏就有 3*2*2*2*12+3*2*2*1*6=360個元素了。
使用:
color, cloc, soa, tloc = trails[i]
就能夠把每一個試次的自變量配置取出來。
COLOR = {'red': [220, 0, 0], 'green': [0, 165, 0], 'blue': [18, 18, 255], 'white': [255, 255, 255], 'black': [0, 0, 0], 'gray': [127, 127, 127] } CLOC = {'left' : (-224, 0), 'right': (224, 0) } TLOC = {'left' : (-224, -20), 'right': (224, -20), 0 : 0 }
有時候咱們會用嵌套的if和else來區分不一樣變量下的詳細配置,其實這是沒有必要的,使用字典能夠靈活地解決這個問題。
好比設置線索的顏色和位置,能夠這樣寫:
color, cloc, soa, tloc = trails[i] circle = Circle(win, radius=16, edges=32, units = 'pix') circle.setFillColor(colorSpace = 'rgb255', color = COLOR[color]) circle.setLineColor(colorSpace = 'rgb255', color = COLOR[color]) circle.setPos(CLOC[cloc])
把每一個試次的按鍵和反應時都保存到results列表裏
results.append((rKey, RT))
最後經過StoreResult把結果保存到文件。
def StoreResult(name, N, trails, results): fp = open(name + '.txt','w') fp.write("ID\tnum\tcolor\tcloc\tsoa\ttloc\trKey\tRT\n") def w(x): fp.write(str(x) + '\t') def n(): fp.write('\n') def k(x): #trans 1s to 1000ms return "%.0f" % (x * 1000) for i in range(N): color, cloc, soa, tloc = trails[i] rKey, RT = results[i] map(w, [name, i+1, color, cloc, k(soa), tloc, rKey, k(RT)]) n() fp.close()
在這裏,map函數的意思是,分別執行w(name);w(i+1);w(color) ......
# -*- coding: utf-8 -*- """ Created on Tue Apr 12 10:31:15 2016 @author: zbg """ from psychopy.visual import Window, ImageStim, TextStim, BufferImageStim, Rect, Circle from psychopy import core, event, gui, clock import random from itertools import * #定義一些基本常量 fullscr = False COLOR = {'red': [220, 0, 0], 'green': [0, 165, 0], 'blue': [18, 18, 255], 'white': [255, 255, 255], 'black': [0, 0, 0], 'gray': [127, 127, 127] } CLOC = {'left' : (-224, 0), 'right': (224, 0) } TLOC = {'left' : (-224, -20), 'right': (224, -20), 0 : 0 } #準備實驗參數與變量 N = 360 colors = ['red', 'blue', 'green'] clocs = ['left', 'right'] soas = [0.4, 0.7] tlocs = ['left', 'right'] # + [0] trails = list(product(colors, clocs, soas, tlocs))* 12 +\ list(product(colors, clocs, soas, [0])) * 6 random.shuffle(trails) results = [] #程序使用的各類函數 def MakeStimBackGround(win): t = TextStim(win, text = '+', pos = (0, 0), colorSpace = 'rgb255', color = COLOR['white'], units = 'pix', height = 32) cb = Rect(win, width=64, height= 64, units = 'pix') cb.setLineColor(colorSpace = 'rgb255', color = COLOR['black']) cb.setPos((0, 0)) rb = Rect(win, width=64, height= 64, units = 'pix') rb.setLineColor(colorSpace = 'rgb255', color = COLOR['black']) rb.setPos((224, 0)) lb = Rect(win, width=64, height= 64, units = 'pix') lb.setLineColor(colorSpace = 'rgb255', color = COLOR['black']) lb.setPos((-224, 0)) stimBackground = BufferImageStim(win, stim = [t, lb, cb, rb]) return stimBackground def MakeCircle(win): circle = Circle(win, radius=16, edges=32, units = 'pix') return circle def GetSubject(): """ 返回被試的id """ myDlg = gui.Dlg(title="Subject Information") myDlg.addField(u'被試ID:') myDlg.show() if myDlg.OK: thisInfo = myDlg.data else: exit(0) return thisInfo[0] def WaitTheKey(win, key = 'space'): event.clearEvents() while key not in event.getKeys(): pass def ShowTextAndWaitTheKey(win, text = '', wait = 0, key = 'space', pos=(0,-0.0), height = 55, units = "pix"): t =TextStim(win, text ,pos = pos, height = height, units = units) t.draw() event.clearEvents() clk = clock.CountdownTimer(wait) win.flip() while clk.getTime() > 0: pass while key not in event.getKeys(): pass def ShowTextAndWait(win, text = '', wait = 0, pos=(0,-0.0), height = 55, units = "pix"): t =TextStim(win, text ,pos = pos, height = height, units = units) t.draw() clk = clock.CountdownTimer(wait) win.flip() while clk.getTime() > 0: pass def ShowIntro(win): introduce =u""" 指導語 按[空格鍵]繼續 """ ShowTextAndWaitTheKey(win, introduce) def ShowFixation1(win, stimBackground): clk = clock.CountdownTimer(0.8) stimBackground.draw() win.flip() while clk.getTime() > 0: pass def ShowCue(win, color, loc, stimBackground, circle): circle.setFillColor(colorSpace = 'rgb255', color = COLOR[color]) circle.setLineColor(colorSpace = 'rgb255', color = COLOR[color]) circle.setPos(CLOC[loc]) stimBackground.draw() circle.draw() clk = clock.CountdownTimer(0.2) win.flip() while clk.getTime() > 0: pass def ShowFixation2(win, soa, stimBackground): ''' 返回值有 ('timeout') 這個是想要的 (按鍵) 這個表示提早按鍵 ''' event.clearEvents() stimBackground.draw() clk = clock.CountdownTimer(soa) win.flip() while clk.getTime() > 0: pressedKeys = event.getKeys() if len(pressedKeys) > 0: return pressedKeys[0] return 'timeout' def ShowTarget(win, loc, stimBackground): """ 返回(按鍵, 反應時(s)) 狀況分別有: ('f', 反應時) ('j', 反應時) ... ('q', 反應時) 一般表示退出 ('timeout', 0) """ event.clearEvents() if loc == 0: stimBackground.draw() else: t = TextStim(win, text = '*', pos = TLOC[loc], colorSpace = 'rgb255', color = COLOR['black'], units = 'pix', height = 96) stimBackground.draw() t.draw() clk = 0 clk = clock.CountdownTimer(1) win.flip() while clk.getTime() > 0: pressedKeys = event.getKeys() key = set(pressedKeys) & set(['q', 'j']) if len(key) > 0: return (key.pop(), 1 - clk.getTime()) return ('timeout', 0) def ShowTimePre(win): ShowTextAndWait(win, text = u'請看到*後再按鍵', wait = 1) def ShowTimeOut(win): ShowTextAndWait(win, text = u'請在*出現1秒內按鍵', wait = 1) def ShowBlank(win, wait = 0.7): ShowTextAndWait(win, wait = wait) def ShowBreak(win): ShowTextAndWaitTheKey(win, text = u"休息一下", key = 'space', wait = 10) def ShowEnd(win): introduce =u""" 結束了 按[空格鍵]退出 """ ShowTextAndWaitTheKey(win, text = introduce) def StoreResult(name, N, trails, results): fp = open(name + '.txt','w') fp.write("ID\tnum\tcolor\tcloc\tsoa\ttloc\trKey\tRT\n") def w(x): fp.write(str(x) + '\t') def n(): fp.write('\n') def k(x): #trans 1s to 1000ms return "%.0f" % (x * 1000) for i in range(N): color, cloc, soa, tloc = trails[i] rKey, RT = results[i] map(w, [name, i+1, color, cloc, k(soa), tloc, rKey, k(RT)]) n() fp.close() #實驗開始 name = GetSubject() win = Window(fullscr = fullscr, colorSpace = 'rgb255', color = COLOR['gray']) stimBackground = MakeStimBackGround(win) circle = MakeCircle(win) ShowIntro(win) for i in range(N): color, cloc, soa, tloc = trails[i] RT = 0 rKey = 0 ShowFixation1(win, stimBackground) ShowCue(win, color, cloc, stimBackground, circle) key = ShowFixation2(win, soa, stimBackground) if key != 'timeout': ShowTimePre(win) RT = -1 rKey = 0 else: (rKey, RT) = ShowTarget(win, tloc, stimBackground) if tloc == 0 and rKey != 'timeout': ShowTimePre(win) elif tloc !=0 and rKey == 'timeout': ShowTimeOut(win) else: pass ShowBlank(win, 0.7) if rKey == 'q': StoreResult('exp-' + name, i, trails, results) win.close() exit(0) results.append((rKey, RT)) if i % 60 == 59: ShowBreak(win) StoreResult('exp-' + name, N, trails, results) ShowEnd(win) win.close()
引用和轉載請註明本文連接,謝謝!