Dear all,
I am writing the code for 6 blocks object nback (0-1-2-0-1-2). Each image stimulus will show up 0.5 secs following 1.5 secs of black screen and there are 16 image stimuli in each n-back block. I am creating the log file record the key press response, stimulus order etc,. I attached the code below. Right now I met a issue that If I press the key for this image stimuli, the response will only be detected in the following stimuli. For example if the current image is my target and I press the key. After I check the log file later. This response was counted for next stimuli. That means my if statement did not detect the key was pressed in the stimuli I pressed the key. I have tried both event.getKeys and also the new keyboard class. Both have one loop delay. My key press event only could be detected until next iteration but not the current iteration I press the key. Feel free to try my code(I also uploaded the test images). Now I only activate the first 0 back block for testing. My environment is Win10+Psychopy 2023.1.2… Much appreciation about your help.
import csv
import random
from datetime import datetime
from psychopy import visual, core, event
from psychopy.hardware import keyboard
# Define the window and stimuli
win = visual.Window(size=(800, 600), fullscr=False, color=[-1,-1,-1])
images = [visual.ImageStim(win, image='image1.jpg'),
visual.ImageStim(win, image='image2.jpg'),
visual.ImageStim(win, image='image3.jpg'),
visual.ImageStim(win, image='image4.jpg'),
visual.ImageStim(win, image='image5.jpg'),
visual.ImageStim(win, image='image6.jpg')]
def generate_n_back_stimuli(images, n, num_stimuli, num_n_back):
# Generate a list of stimuli with no n-back situations
stimuli = [random.choice(images) for _ in range(0, num_stimuli)]
# Generate a list of indices for the n-back situations
n_back_indices = random.sample(range(2, num_stimuli-2), num_n_back)
# Replace the stimuli at the n-back indices with n-back situations
if n!=0:
for i in n_back_indices:
stimuli[i] = stimuli[i-n]
else:
for i in n_back_indices:
stimuli[i] = visual.ImageStim(win, image='image1.bmp')
return stimuli
# Define the n-back tasks
n_back_tasks = [
{'n': 0, 'stimuli': generate_n_back_stimuli(images, 0, 16, 5)},
#{'n': 1, 'stimuli': generate_n_back_stimuli(images, 1, 16, 5)},
#{'n': 2, 'stimuli': generate_n_back_stimuli(images, 2, 16, 5)},
#{'n': 0, 'stimuli': generate_n_back_stimuli(images, 0, 16, 5)},
#{'n': 1, 'stimuli': generate_n_back_stimuli(images, 1, 16, 5)},
#{'n': 2, 'stimuli': generate_n_back_stimuli(images, 2, 16, 5)},
]
"""
n_back_tasks = [
{'n': 0, 'stimuli': random.sample(images*2, 16)},
{'n': 1, 'stimuli': random.sample(images*2, 16)},
{'n': 2, 'stimuli': random.sample(images*2, 16)},
{'n': 0, 'stimuli': random.sample(images*2, 16)},
{'n': 1, 'stimuli': random.sample(images*2, 16)},
{'n': 2, 'stimuli': random.sample(images*2, 16)},
]
"""
# Define the duration of each n-back task and rest
task_duration = 32.0
stimuli_duration = 0.5
black_screen_duration = 1.5
rest_duration = 5.0
key_resp = keyboard.Keyboard()
key_resp.keys = []
key_resp.rt = []
# Define the keyboard keys
key_1 = '1'
key_5 = '5'
# Define the log file
log_file = f'subject_{datetime.now().strftime("%Y%m%d_%H%M%S")}.csv'
# Wait for the key 5 to be pressed to start the loop
start_text = visual.TextStim(win, text='Welcome to Task', pos=(0, 0),height=0.25)
start_text.draw()
win.flip()
while True:
keys = event.getKeys(keyList=[key_5])
if key_5 in keys:
break
with open(log_file, 'w', newline='') as file:
writer = csv.writer(file)
writer.writerow(['Task Type', 'Stimulus', 'N-Back', 'Stimulus Image', 'Response', 'Accuracy', 'RT', 'Omission Error', 'Commission Error'])
# Run the n-back tasks
correct_responses = 0
total_responses = 0
total_omission_errors = 0
total_commission_errors = 0
for i, task in enumerate(n_back_tasks):
# Show the task type
task_type = visual.TextStim(win, text=f'{task["n"]}-back task', pos=(0, 0),height=0.25)
task_type.draw()
win.flip()
core.wait(rest_duration)
# Show the stimuli
for j, stimulus in enumerate(task['stimuli']):
# Show the stimulus for 0.5 seconds
win.color = [-1, -1, -1]
stimulus.draw()
win.flip()
start_time = core.getTime()
key_resp.clock.reset()
keys=key_resp.getKeys(keyList=['1'], waitRelease=True)
core.wait(stimuli_duration)
#keys = event.getKeys(keyList=[key_1])
#Show a black screen for 1.5 seconds
win.color = [-1, -1, -1]
win.flip()
#kb.clock.reset()
#keys=kb.getKeys([key_1])
core.wait(black_screen_duration)
#core.checkPygletDuringWait=True
#keys = event.getKeys(keyList=[key_1], waitRelease=True)
#keys = event.waitKeys(keyList=[key_1], maxWait=stimuli_duration)
#keys = event.waitKeys(keyList=[key_1], maxWait=stimuli_duration+black_screen_duration)
#keys = event.getKeys(keyList=[key_1])
# Check if the subject pressed the key 1
if keys is not None and key_1 in keys:
total_responses += 1
response = '1'
rt=keys[0].rt
#rt = core.getTime() - start_time
if task['n'] == 0:
if stimulus.image == 'image1.bmp':
accuracy = 'Correct'
correct_responses += 1
elif stimulus.image != 'image1.bmp':
accuracy = 'Incorrect'
total_commission_errors += 1
elif j >= task['n'] and stimulus.image == task['stimuli'][j-task['n']].image:
accuracy = 'Correct'
correct_responses += 1
else:
accuracy = 'Incorrect'
total_commission_errors += 1
else:
response = ''
rt = 2
if task['n'] == 0:
if stimulus.image != 'image1.bmp':
accuracy = 'Correct'
correct_responses += 1
elif stimulus.image == 'image1.bmp':
accuracy = 'Incorrect'
total_omission_errors += 1
elif j >= task['n'] and stimulus.image != task['stimuli'][j-task['n']].image:
accuracy = 'Correct'
correct_responses += 1
else:
accuracy = 'Incorrect'
total_omission_errors += 1
#duration2=(stimuli_duration+black_screen_duration)-(2*stimuli_duration)
#core.wait(black_screen_duration)
#core.wait(duration2)
#core.wait(stimuli_duration)
# Calculate the reaction time
#rt = core.getTime() - start_time
# Show a black screen for 1.5 seconds
#win.color = [-1, -1, -1]
#win.flip()
#core.wait(black_screen_duration)
# Log the data
writer.writerow([f'{task["n"]}-back', j+1, task['n'], stimulus.image, response, accuracy, rt, total_omission_errors, total_commission_errors])
# Rest between tasks
rest = visual.TextStim(win, text='Rest', pos=(0, 0),height=0.25)
rest.draw()
win.flip()
core.wait(rest_duration)
# Calculate the percentage of correct responses
if total_responses > 0:
score = correct_responses / total_responses * 100
else:
score = 0
# Calculate the percentage of omission errors and commission errors
if total_responses > 0:
omission_error_rate = total_omission_errors / total_responses * 100
commission_error_rate = total_commission_errors / total_responses * 100
else:
omission_error_rate = 0
commission_error_rate = 0
# Output the results
print(f'Score: {score:.2f}%')
print(f'Omission Error Rate: {omission_error_rate:.2f}%')
print(f'Commission Error Rate: {commission_error_rate:.2f}%')