用Python和PsychoPy从零搭建一个n-back工作记忆测试游戏(附完整代码)

发布时间:2026/6/1 23:13:17

用Python和PsychoPy从零搭建一个n-back工作记忆测试游戏(附完整代码) 用Python和PsychoPy构建n-back工作记忆测试从实验设计到代码实现九宫格中的绿色方块快速闪烁你需要记住它前几次出现的位置——这就是经典的n-back测试心理学研究中衡量工作记忆的黄金标准。作为认知神经科学领域最常用的实验范式之一n-back任务不仅被用于评估注意力、记忆保持能力还在脑机接口、认知训练等前沿领域发挥着重要作用。本文将带你用Python的PsychoPy库从零搭建一个可定制、可扩展的n-back测试系统。1. 实验原理与PsychoPy环境搭建n-back任务的核心在于要求被试者持续监控并回忆前n次刺激出现的位置或内容。当n1时只需记忆前一次刺激而n3则需在脑海中维持三个连续刺激的记忆栈。这种阶梯式难度设计使其成为研究工作记忆负荷的理想工具。PsychoPy作为开源的心理学实验构建工具其优势在于精确的时间控制刺激呈现时间可精确到毫秒级跨平台一致性在Windows、macOS和Linux上保持相同表现丰富的刺激类型支持文本、图像、视频等多种刺激形式数据记录完备自动记录反应时、正确率等关键指标安装PsychoPy只需一行命令pip install psychopy pandas openpyxl提示建议使用Python 3.8及以上版本某些PsychoPy功能在旧版本中可能受限2. 实验界面设计与刺激呈现我们先构建九宫格的基本视觉元素。九宫格位置采用像素坐标表示中心为原点(0,0)from psychopy import visual, event, core # 窗口设置 win visual.Window(size(1000, 618), colorwhite, unitspix) # 九宫格位置参数 positions [ (-150, 150), (0, 150), (150, 150), (-150, 0), (0, 0), (150, 0), (-150, -150),(0, -150),(150, -150) ] cube_size 145 # 方块尺寸刺激序列生成需要确保相邻刺激不重复这通过以下算法实现import random def generate_sequence(length30, num_positions9): sequence [] while len(sequence) length: pos random.randint(0, num_positions-1) if not sequence or pos ! sequence[-1]: sequence.append(pos) return sequence刺激呈现的核心逻辑是循环遍历序列在每个位置显示绿色方块1秒def show_stimulus(position, duration1.0): for i in range(9): color green if i position else #afafaf cube visual.Rect(win, widthcube_size, heightcube_size, pospositions[i], fillColorcolor) cube.draw() win.flip() core.wait(duration)3. 实验流程控制与用户交互完整的n-back实验包含以下几个阶段指导语阶段解释任务要求位置记忆阶段展示九宫格位置编号测试阶段呈现刺激序列并收集反应结果反馈阶段显示正确率和反应时数据保存阶段记录实验数据到Excel关键的用户交互代码如下# 指导语显示 def show_instruction(text, y_offset0, is_titleFalse): text_stim visual.TextStim(win, texttext, pos(0, y_offset), height50 if is_title else 20, colorblack, boldTrue) text_stim.draw() win.flip() event.waitKeys() # 显示位置编号 def show_position_numbers(): for i, pos in enumerate(positions): cube visual.Rect(win, widthcube_size, heightcube_size, pospos, fillColor#afafaf) cube.draw() num visual.TextStim(win, textstr(i1), pospos, heightcube_size/2) num.draw() win.flip() event.waitKeys()4. 数据收集与结果分析n-back实验通常关注两个核心指标指标类型具体测量数据分析意义准确率正确判断次数/总测试次数反映工作记忆容量反应时从问题呈现到按键反应的时间反映认知处理速度数据记录采用pandas库实现import pandas as pd def save_to_excel(data, filenamenback_results.xlsx): df pd.DataFrame(data) try: existing pd.read_excel(filename) combined pd.concat([existing, df], ignore_indexTrue) combined.to_excel(filename, indexFalse) except FileNotFoundError: df.to_excel(filename, indexFalse)实验主循环中我们随机选择n值1-3并记录每次测试结果data {trial: [], n: [], correct: [], response_time: []} for trial in range(30): show_stimulus(sequence[trial]) # 每6次测试提问一次 if (trial 1) % 6 0: n random.randint(1, 3) question f前{n}次绿色方块出现的位置是 show_instruction(question, y_offset150) timer core.Clock() keys event.waitKeys(keyList[str(i) for i in range(1, 10)]) rt timer.getTime() correct (int(keys[0]) - 1) sequence[trial - n] feedback 正确 if correct else 错误 show_instruction(f{feedback} 反应时间{rt:.3f}秒) data[trial].append(trial//6 1) data[n].append(n) data[correct].append(correct) data[response_time].append(rt) save_to_excel(data)5. 高级功能扩展与优化建议基础版本实现后可以考虑以下增强功能自适应难度根据被试表现动态调整n值多模态刺激增加声音或图像刺激脑电同步通过并行端口发送事件标记网络部署使用PsychoJS实现浏览器版本反应时分析的改进方法# 剔除异常反应时如200ms或3000ms clean_rt [rt for rt in data[response_time] if 0.2 rt 3.0] # 计算各n水平的平均反应时 n_levels sorted(set(data[n])) rt_by_n {n: [] for n in n_levels} for n, rt in zip(data[n], data[response_time]): rt_by_n[n].append(rt) avg_rt {n: sum(rts)/len(rts) for n, rts in rt_by_n.items()}窗口关闭前的数据完整性检查def validate_data(data): required_fields [trial, n, correct, response_time] if not all(field in data for field in required_fields): raise ValueError(缺失必要数据字段) if len(data[trial]) ! len(data[correct]): raise ValueError(数据长度不一致) return True6. 常见问题排查与调试技巧遇到问题时可以尝试以下调试方法视觉刺激不显示检查窗口单位pix/cm/deg是否与坐标匹配确认draw()和flip()被正确调用反应键无响应验证keyList参数是否包含所有有效键检查键盘焦点是否在实验窗口时间控制不精确避免使用time.sleep()改用core.wait()关闭不必要的后台进程记录调试信息的实用代码# 在关键操作前后添加时间戳 debug_log [] trial_start core.getTime() # ...执行操作... debug_log.append(fTrial {trial}: {core.getTime() - trial_start:.3f}s) # 保存日志文件 with open(debug_log.txt, w) as f: f.write(\n.join(debug_log))实验结束后记得正确释放资源win.close() core.quit()

相关新闻