适用于psychopy2022.2.5版本的Nb-back任务,用于核磁收集数据
仅作为记录与备份,大部分使用AI完成,不进行解答
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from psychopy import visual, core, event, sound, gui
import random
import os
import csv
import time
import numpy as np
########## 收集被试信息 ################
info = {'编号':'',
'性别\n(1-女 2-男)':['1','2'],
'年龄':''}
# title为标题,order为内容顺序
inputDlg = gui.DlgFromDict(info, title = '信息收集', order = ['编号','性别\n(1-女 2-男)','年龄'])
if inputDlg.OK: #单击OK后的操作
pass #占位符
else:
core.quit()
# 打开一个1920*1080分辨率的窗口,灰色背景,非全屏,单位为像素,中心坐标是(0,0)
win = visual.Window((1920,1080), color=(128,128,128),
fullscr=False, units='pix',colorSpace='rgb255')
## 定义注视点和指导语
fix = visual.TextStim(win, text = '+', color = 'white', height = 100, bold = False)
intro_1 = visual.ImageStim(win, image='intro/1.jpg')
intro_2 = visual.ImageStim(win, image='intro/2.jpg')
intro_3 = visual.ImageStim(win, image='intro/3.jpg')
intro_4 = visual.ImageStim(win, image='intro/4.jpg')
intro_5 = visual.ImageStim(win, image='intro/5.jpg')
## 定义刺激图片和刺激音频的路径
positionFolder = 'position/'
letterFolder = 'letter/'
puretoneFolder = 'puretone/'
## 定义试次数和注视点时间变量
nTrials_2 = 17
nTrials_3 = 18
buffertime = 10.000
fixtime = 14.000
## 定义生成2-back的刺激序列的函数
def generate_2_Back_Sequence(nTrials_2):
stimuliSequence = np.random.randint(1, 9, nTrials_2) #取值为左闭右开,即包含下限1不包含上限9
for n in range(3, nTrials_2):
if np.random.rand() > 0.5:
stimuliSequence[n] = stimuliSequence[n - 2]
# 检查当前刺激是否是刺激序列中连续出现的相同刺激,并且出现次数超过了4次。
if n >= 4 and np.sum(stimuliSequence[n-4:n] == stimuliSequence[n]) == 4:
differentStimulus = np.setdiff1d(np.arange(1, 9), stimuliSequence[n])
stimuliSequence[n] = np.random.choice(differentStimulus)
return stimuliSequence
## 定义生成3-back的刺激序列的函数
def generate_3_Back_Sequence(nTrials_3):
stimuliSequence = np.random.randint(1, 9, nTrials_3) #取值为左闭右开,即包含下限1不包含上限9
for n in range(4, nTrials_3):
if np.random.rand() > 0.5:
stimuliSequence[n] = stimuliSequence[n - 3]
# 检查当前刺激是否是刺激序列中连续出现的相同刺激,并且出现次数超过了4次。
if n >= 4 and np.sum(stimuliSequence[n-4:n] == stimuliSequence[n]) == 4:
differentStimulus = np.setdiff1d(np.arange(1, 9), stimuliSequence[n])
stimuliSequence[n] = np.random.choice(differentStimulus)
return stimuliSequence
########### 定义数据储存的文档 ##########
date = time.strftime("_20%y_%m_%d_%H%M", time.localtime()) #获取当前时间
file = 'Nback_data/' + info['编号'] + '_' + date + '.csv' #文档名(含路径)
# 写入表头
with open(file, 'a', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(['编号', '性别', '年龄', 'Trial', 'Condition', 'Load', 'BlockType',
'Stimstart', 'Stimend','RESP', 'RT', 'ACC'])
######### 定义第一个Blcok的内容——2back-Position#################
def block_2_position(win,info):
## 生成刺序列
stimuliSequence = generate_2_Back_Sequence(nTrials_2)
# 定义条件判定空列表
conditions = []
for trials in range(len(stimuliSequence)):
if trials >= 2:
if stimuliSequence[trials] == stimuliSequence[trials - 2]:
condition = 'same'
else:
condition = 'diff'
else:
condition = 'None'
conditions.append(condition)
## 刺激呈现循环
for trials in range(len(stimuliSequence)):
#初始化按键和反应时
resp = None
rt = None
# 刺激呈现0.5s
StimStart = Clock.getTime()
position_path = positionFolder + f'position_{stimuliSequence[trials]}.jpg'
stim = visual.ImageStim(win, position_path)
stim.draw()
win.flip()
core.wait(0.5)
# 空白屏幕1.5s
win.flip()
# 在整个2秒的trial时间内持续检测按键
while Clock.getTime() - StimStart <= 2.000:
keys = event.getKeys(keyList=['1', '4', 'escape'], timeStamped=Clock)
for key, time in keys:
if key in ['1','4']:
resp = 1 if key == '1' else 4
rt = time - StimStart
elif key == 'escape':
win.close()
core.quit()
if resp is None:
rt = 10
resp = 10
# ACC判断
if trials >= 2:
if (conditions[trials] == 'same' and resp == 1) or (conditions[trials] == 'diff' and resp == 4):
acc = 1
else:
acc = 0
else:
acc = None
# 记录trial结束时间
StimEnd = Clock.getTime()
# 将每个trial的结果写入CSV文件
with open(file, 'a', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow([info['编号'], info['性别\n(1-女 2-男)'], info['年龄'], stimuliSequence[trials], conditions[trials],
'2', 'position', StimStart, StimEnd, resp, rt, acc])
######### 定义第二个Blcok的内容——2back-Letter #################
def block_2_letter(win,info):
## 生成刺序列
stimuliSequence = generate_2_Back_Sequence(nTrials_2)
# 定义条件判定空列表
conditions = []
for trials in range(len(stimuliSequence)):
if trials >= 2:
if stimuliSequence[trials] == stimuliSequence[trials - 2]:
condition = 'same'
else:
condition = 'diff'
else:
condition = 'None'
conditions.append(condition)
## 刺激呈现循环
for trials in range(len(stimuliSequence)):
#初始化按键和反应时
resp = None
rt = None
# 刺激呈现0.5s
StimStart = Clock.getTime()
letter_path = letterFolder + f'letter_{stimuliSequence[trials]}.wav'
stim = sound.Sound(letter_path)
stim.play()
core.wait(0.5)
stim = None # 将声音对象设置为None释放资源
# 在整个2秒的trial时间内持续检测按键
while Clock.getTime() - StimStart <= 2.000:
keys = event.getKeys(keyList=['1', '4', 'escape'], timeStamped=Clock)
for key, time in keys:
if key in ['1','4']:
resp = 1 if key == '1' else 4
rt = time - StimStart
elif key == 'escape':
win.close()
core.quit()
if resp is None:
rt = 10
resp = 10
# ACC判断
if trials >= 2:
if (conditions[trials] == 'same' and resp == 1) or (conditions[trials] == 'diff' and resp == 4):
acc = 1
else:
acc = 0
else:
acc = None
# 记录trial结束时间
StimEnd = Clock.getTime()
# 将每个trial的结果写入CSV文件
with open(file, 'a', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow([info['编号'], info['性别\n(1-女 2-男)'], info['年龄'], stimuliSequence[trials], conditions[trials],
'2', 'letter', StimStart, StimEnd, resp, rt, acc])
######### 定义第三个Blcok的内容——2back-Puretone #################
def block_2_puretone(win,info):
## 生成刺序列
stimuliSequence = generate_2_Back_Sequence(nTrials_2)
# 定义条件判定空列表
conditions = []
for trials in range(len(stimuliSequence)):
if trials >= 2:
if stimuliSequence[trials] == stimuliSequence[trials - 2]:
condition = 'same'
else:
condition = 'diff'
else:
condition = 'None'
conditions.append(condition)
## 刺激呈现循环
for trials in range(len(stimuliSequence)):
#初始化按键和反应时
resp = None
rt = None
# 刺激呈现0.5s
StimStart = Clock.getTime()
puretone_path = puretoneFolder + f'puretone_{stimuliSequence[trials]}.wav'
stim = sound.Sound(puretone_path)
stim.play()
core.wait(0.5)
stim = None # 将声音对象设置为None释放资源
# 在整个2秒的trial时间内持续检测按键
while Clock.getTime() - StimStart <= 2.000:
keys = event.getKeys(keyList=['1', '4', 'escape'], timeStamped=Clock)
for key, time in keys:
if key in ['1','4']:
resp = 1 if key == '1' else 4
rt = time - StimStart
elif key == 'escape':
win.close()
core.quit()
if resp is None:
rt = 10
resp = 10
# ACC判断
if trials >= 2:
if (conditions[trials] == 'same' and resp == 1) or (conditions[trials] == 'diff' and resp == 4):
acc = 1
else:
acc = 0
else:
acc = None
# 记录trial结束时间
StimEnd = Clock.getTime()
# 将每个trial的结果写入CSV文件
with open(file, 'a', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow([info['编号'], info['性别\n(1-女 2-男)'], info['年龄'], stimuliSequence[trials], conditions[trials],
'2', 'puretone', StimStart, StimEnd, resp, rt, acc])
######### 定义第四个Blcok的内容——Position#################
def block_3_position(win,info):
## 生成刺序列
stimuliSequence = generate_3_Back_Sequence(nTrials_3)
# 定义条件判定空列表
conditions = []
for trials in range(len(stimuliSequence)):
if trials >= 3:
if stimuliSequence[trials] == stimuliSequence[trials - 3]:
condition = 'same'
else:
condition = 'diff'
else:
condition = 'None'
conditions.append(condition)
## 刺激呈现循环
for trials in range(len(stimuliSequence)):
#初始化按键和反应时
resp = None
rt = None
# 刺激呈现0.5s
StimStart = Clock.getTime()
position_path = positionFolder + f'position_{stimuliSequence[trials]}.jpg'
stim = visual.ImageStim(win, position_path)
stim.draw()
win.flip()
core.wait(0.5)
# 空白屏幕1.5s
win.flip()
# 在整个2秒的trial时间内持续检测按键
while Clock.getTime() - StimStart <= 2.000:
keys = event.getKeys(keyList=['1', '4', 'escape'], timeStamped=Clock)
for key, time in keys:
if key in ['1','4']:
resp = 1 if key == '1' else 4
rt = time - StimStart
elif key == 'escape':
win.close()
core.quit()
if resp is None:
rt = 10
resp = 10
# ACC判断
if trials >= 3:
if (conditions[trials] == 'same' and resp == 1) or (conditions[trials] == 'diff' and resp == 4):
acc = 1
else:
acc = 0
else:
acc = None
# 记录trial结束时间
StimEnd = Clock.getTime()
# 将每个trial的结果写入CSV文件
with open(file, 'a', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow([info['编号'], info['性别\n(1-女 2-男)'], info['年龄'], stimuliSequence[trials], conditions[trials],
'3', 'position', StimStart, StimEnd, resp, rt, acc])
######### 定义第五个Blcok的内容——Letter #################
def block_3_letter(win,info):
## 生成刺序列
stimuliSequence = generate_3_Back_Sequence(nTrials_3)
# 定义条件判定空列表
conditions = []
for trials in range(len(stimuliSequence)):
if trials >= 3:
if stimuliSequence[trials] == stimuliSequence[trials - 3]:
condition = 'same'
else:
condition = 'diff'
else:
condition = 'None'
conditions.append(condition)
## 刺激呈现循环
for trials in range(len(stimuliSequence)):
#初始化按键和反应时
resp = None
rt = None
# 刺激呈现0.5s
StimStart = Clock.getTime()
letter_path = letterFolder + f'letter_{stimuliSequence[trials]}.wav'
stim = sound.Sound(letter_path)
stim.play()
core.wait(0.5)
stim = None # 将声音对象设置为None释放资源
# 在整个2秒的trial时间内持续检测按键
while Clock.getTime() - StimStart <= 2.000:
keys = event.getKeys(keyList=['1', '4', 'escape'], timeStamped=Clock)
for key, time in keys:
if key in ['1','4']:
resp = 1 if key == '1' else 4
rt = time - StimStart
elif key == 'escape':
win.close()
core.quit()
if resp is None:
rt = 10
resp = 10
# ACC判断
if trials >= 3:
if (conditions[trials] == 'same' and resp == 1) or (conditions[trials] == 'diff' and resp == 4):
acc = 1
else:
acc = 0
else:
acc = None
# 记录trial结束时间
StimEnd = Clock.getTime()
# 将每个trial的结果写入CSV文件
with open(file, 'a', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow([info['编号'], info['性别\n(1-女 2-男)'], info['年龄'], stimuliSequence[trials], conditions[trials],
'3', 'letter', StimStart, StimEnd, resp, rt, acc])
######### 定义第六个Blcok的内容——Puretone #################
def block_3_puretone(win,info):
## 生成刺序列
stimuliSequence = generate_3_Back_Sequence(nTrials_3)
# 定义条件判定空列表
conditions = []
for trials in range(len(stimuliSequence)):
if trials >= 3:
if stimuliSequence[trials] == stimuliSequence[trials - 3]:
condition = 'same'
else:
condition = 'diff'
else:
condition = 'None'
conditions.append(condition)
## 刺激呈现循环
for trials in range(len(stimuliSequence)):
#初始化按键和反应时
resp = None
rt = None
# 刺激呈现0.5s
StimStart = Clock.getTime()
puretone_path = puretoneFolder + f'puretone_{stimuliSequence[trials]}.wav'
stim = sound.Sound(puretone_path)
stim.play()
core.wait(0.5)
stim = None # 将声音对象设置为None释放资源
# 在整个2秒的trial时间内持续检测按键
while Clock.getTime() - StimStart <= 2.000:
keys = event.getKeys(keyList=['1', '4', 'escape'], timeStamped=Clock)
for key, time in keys:
if key in ['1','4']:
resp = 1 if key == '1' else 4
rt = time - StimStart
elif key == 'escape':
win.close()
core.quit()
if resp is None:
rt = 10
resp = 10
# ACC判断
if trials >= 3:
if (conditions[trials] == 'same' and resp == 1) or (conditions[trials] == 'diff' and resp == 4):
acc = 1
else:
acc = 0
else:
acc = None
# 记录trial结束时间
StimEnd = Clock.getTime()
# 将每个trial的结果写入CSV文件
with open(file, 'a', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow([info['编号'], info['性别\n(1-女 2-男)'], info['年龄'], stimuliSequence[trials], conditions[trials],
'3', 'puretone', StimStart, StimEnd, resp, rt, acc])
#################### 实验开始,调用函数 ################
# 呈现指导语1
intro_1.draw()
win.flip()
event.waitKeys(keyList='s')
# 呈现指导语2
intro_2.draw()
win.flip()
event.waitKeys( keyList='s')
## 为整个实验创建一个时钟
Clock = core.Clock()
# 创建一个包含这些block函数的列表
blocks_2 = [block_2_position, block_2_letter, block_2_puretone]
blocks_3 = [block_3_position, block_3_letter, block_3_puretone]
# 将每种 block 复制两次,形成 6 个 block 的列表
blocks_2 = blocks_2 * 3
blocks_3 = blocks_3 * 3
## 2-BACK-实验循环-其中9个block,每个block有15个trial
# 每次循环前重新打乱 blocks_2 列表
random.shuffle(blocks_2)
# 清屏
win.flip()
# 重置时钟,呈现10s缓冲
Clock.reset()
while Clock.getTime() < buffertime:
pass
# 第一个基线时长维持14s
fix.draw()
win.flip()
while Clock.getTime() < fixtime + buffertime:
pass
win.flip()
# 依次执行打乱后的block函数
for block in blocks_2:
# 调用block函数
block(win, info)
# block之后的基线时长,维持14s
FixStart = Clock.getTime()
fix.draw()
win.flip()
while Clock.getTime() - FixStart < fixtime:
pass
win.flip()
# 呈现中间语,告诉被试即将进入3-BACK
intro_3.draw()
win.flip()
event.waitKeys(keyList='s')
## 3-BACK-实验循环-其中9个block,每个block有15个trial
# 每次循环前重新打乱 blocks_3 列表
random.shuffle(blocks_3)
# 重置时钟
Clock.reset()
# 清屏,呈现10s缓冲
win.flip()
while Clock.getTime() < buffertime:
pass
# 第一个基线时长维持14s
fix.draw()
win.flip()
while Clock.getTime() < fixtime + buffertime:
pass
win.flip()
# 依次执行打乱后的block函数
for block in blocks_3:
# 调用block函数
block(win, info)
# block之后的基线时长,维持14s
FixStart = Clock.getTime()
fix.draw()
win.flip()
while Clock.getTime() - FixStart < fixtime:
pass
win.flip()
# 呈现结束语
intro_4.draw()
win.flip()
core.wait(1)
# 关闭窗口
win.close()
print('Succeed!')
5813

被折叠的 条评论
为什么被折叠?



