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

 

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

 

转载于:https://my.oschina.net/zbaigao/blog/683526

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值