psychopy心理學編程 快速配置自變量

 

配置心理學實驗時所須要的自變量是一個麻煩的問題,在這裏,介紹一種簡單快速配置實驗變量的方法。這個方法確保了程序的簡單、可讀,減小了編程出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()

引用和轉載請註明本文連接,謝謝!

psychopy 實驗程序購買 https://item.taobao.com/item.htm?spm=a230r.1.14.6.Q6E2OW&id=530690095131&ns=1&abbucket=15#detail

相關文章
相關標籤/搜索