psychopy心理学编程 快速配置自变量

我与影子孤独终老i 提交于 2019-12-10 05:18:57

 

配置心理学实验时所需要的自变量是一个麻烦的问题,在这里,介绍一种简单快速配置实验变量的方法。这个方法确保了程序的简单、可读,减少了编程出bug的可能。

实验过程

呈现一个注视屏,上面有三个框,中间的框里有注视点,800ms

然后左边或右边的框中出现一个圆,圆的颜色是红、绿、蓝其中一种,200ms

接着继续呈现注视屏,400ms或700ms

再呈现目标刺激,是一个"*",被试需要立即按下'j'键。如果被试在"*"出现前按下按键,那么反馈"请看到*后再按键",如果被试超过1000ms都没有按键,那么反馈"请在*出现1秒内反馈"。反馈信息显示1000ms

最后呈现一个700ms的空屏

试次分为正常试次和探测试次。正常试次按以上流程,探测试次在呈现目标刺激阶段时,不呈现"*"。

自变量

color 线索颜色: 红、绿、蓝

cloc 线索位置: 左边 右边

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

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!