Run a simple experimentΒΆ

This example demonstrates much of the basic functionality built into the ExperimentController class.

simple experiment
=======================
Generate sample stimuli
=======================

This shows how to generate some simple stimuli. It will also play a couple
of sample stimuli.

exp_name: testExp
date: 2023-07-25 19_08_13.771916
file: /home/circleci/project/examples/simple_experiment.py
participant: foo
session: 001
2023-07-25 19:08:13,772 - INFO    - Expyfun: Using version 2.0.0.dev0 (requested dev)
2023-07-25 19:08:13,772 - INFO    - Expyfun: Setting up sound card using pyglet backend with 2 playback channels
2023-07-25 19:08:13,953 - WARNING - Expyfun: Mismatch between reported stim sample rate (24414.0625) and device sample rate (44100.0). Experiment Controller will resample for you, but this takes a non-trivial amount of processing time and may compromise your experimental timing and/or cause artifacts.
2023-07-25 19:08:13,953 - INFO    - Expyfun: Setting up screen
2023-07-25 19:08:13,983 - EXP     - Expyfun: Set screen visibility True
2023-07-25 19:08:13,991 - INFO    - Initialized [800 600] window on screen XlibScreen(display=<pyglet.canvas.xlib.XlibDisplay object at 0x7f1a95b502b0>, x=0, y=0, width=1400, height=900, xinerama=0) with DPI 69.73
2023-07-25 19:08:13,991 - INFO    - Expyfun: Initializing dummy triggering mode
2023-07-25 19:08:13,993 - INFO    - Expyfun: Initialization complete
2023-07-25 19:08:13,993 - EXP     - Expyfun: Participant: foo
2023-07-25 19:08:13,993 - EXP     - Expyfun: Session: 001
2023-07-25 19:08:13,994 - EXP     - Expyfun: Set screen visibility False
2023-07-25 19:08:13,994 - EXP     - Expyfun: Set screen visibility True
2023-07-25 19:08:14,481 - WARNING - Expyfun: Resampling 0.5 seconds of audio
2023-07-25 19:08:14,489 - EXP     - Expyfun: Loading 44100 samples to buffer
2023-07-25 19:08:14,490 - EXP     - Expyfun: Stamp trial ID to ec_id  : 2
2023-07-25 19:08:14,490 - EXP     - Expyfun: Stamp trial ID to ttl_id : [0, 0]
2023-07-25 19:08:14,490 - EXP     - Stamping TTL triggers: [4 4]
2023-07-25 19:08:14,531 - EXP     - Expyfun: Starting stimuli: flipping screen and playing audio
2023-07-25 19:08:14,532 - EXP     - Stamping TTL triggers: [1]
2023-07-25 19:08:14,542 - EXP     - Expyfun: Audio stopped and reset.
2023-07-25 19:08:14,542 - EXP     - Expyfun: Trial OK
2023-07-25 19:08:14,746 - WARNING - Expyfun: Resampling 0.5 seconds of audio
2023-07-25 19:08:14,753 - EXP     - Expyfun: Loading 44100 samples to buffer
2023-07-25 19:08:14,753 - EXP     - Expyfun: Stamp trial ID to ec_id  : 0
2023-07-25 19:08:14,754 - EXP     - Expyfun: Stamp trial ID to ttl_id : [0, 0]
2023-07-25 19:08:14,754 - EXP     - Stamping TTL triggers: [4 4]
2023-07-25 19:08:14,795 - EXP     - Expyfun: Starting stimuli: flipping screen and playing audio
2023-07-25 19:08:14,796 - EXP     - Stamping TTL triggers: [1]
2023-07-25 19:08:14,806 - EXP     - Expyfun: Audio stopped and reset.
2023-07-25 19:08:14,806 - EXP     - Expyfun: Trial OK
2023-07-25 19:08:15,010 - WARNING - Expyfun: Resampling 0.5 seconds of audio
2023-07-25 19:08:15,017 - EXP     - Expyfun: Loading 44100 samples to buffer
2023-07-25 19:08:15,017 - EXP     - Expyfun: Stamp trial ID to ec_id  : 0
2023-07-25 19:08:15,017 - EXP     - Expyfun: Stamp trial ID to ttl_id : [0, 0]
2023-07-25 19:08:15,018 - EXP     - Stamping TTL triggers: [4 4]
2023-07-25 19:08:15,058 - EXP     - Expyfun: Starting stimuli: flipping screen and playing audio
2023-07-25 19:08:15,059 - EXP     - Stamping TTL triggers: [1]
2023-07-25 19:08:15,070 - EXP     - Expyfun: Audio stopped and reset.
2023-07-25 19:08:15,070 - EXP     - Expyfun: Trial OK
2023-07-25 19:08:15,274 - WARNING - Expyfun: Resampling 0.5 seconds of audio
2023-07-25 19:08:15,280 - EXP     - Expyfun: Loading 44100 samples to buffer
2023-07-25 19:08:15,281 - EXP     - Expyfun: Stamp trial ID to ec_id  : 1
2023-07-25 19:08:15,281 - EXP     - Expyfun: Stamp trial ID to ttl_id : [0, 0]
2023-07-25 19:08:15,281 - EXP     - Stamping TTL triggers: [4 4]
2023-07-25 19:08:15,322 - EXP     - Expyfun: Starting stimuli: flipping screen and playing audio
2023-07-25 19:08:15,323 - EXP     - Stamping TTL triggers: [1]
2023-07-25 19:08:15,333 - EXP     - Expyfun: Audio stopped and reset.
2023-07-25 19:08:15,333 - EXP     - Expyfun: Trial OK
2023-07-25 19:08:15,538 - WARNING - Expyfun: Resampling 0.5 seconds of audio
2023-07-25 19:08:15,544 - EXP     - Expyfun: Loading 44100 samples to buffer
2023-07-25 19:08:15,545 - EXP     - Expyfun: Stamp trial ID to ec_id  : 1
2023-07-25 19:08:15,545 - EXP     - Expyfun: Stamp trial ID to ttl_id : [0, 0]
2023-07-25 19:08:15,545 - EXP     - Stamping TTL triggers: [4 4]
2023-07-25 19:08:15,586 - EXP     - Expyfun: Starting stimuli: flipping screen and playing audio
2023-07-25 19:08:15,587 - EXP     - Stamping TTL triggers: [1]
2023-07-25 19:08:15,598 - EXP     - Expyfun: Audio stopped and reset.
2023-07-25 19:08:15,598 - EXP     - Expyfun: Trial OK
2023-07-25 19:08:15,820 - WARNING - Expyfun: Resampling 3.22 seconds of audio
2023-07-25 19:08:15,864 - EXP     - Expyfun: Loading 284226 samples to buffer
2023-07-25 19:08:15,867 - EXP     - Expyfun: Stamp trial ID to ec_id  : multi-tone
2023-07-25 19:08:15,867 - EXP     - Expyfun: Stamp trial ID to ttl_id : [0, 1]
2023-07-25 19:08:15,867 - EXP     - Stamping TTL triggers: [4 8]
2023-07-25 19:08:15,908 - EXP     - Expyfun: Starting stimuli: flipping screen and playing audio
2023-07-25 19:08:15,909 - EXP     - Stamping TTL triggers: [1]
2023-07-25 19:08:15,926 - WARNING - ec.trial_ok called before stimulus had stopped
2023-07-25 19:08:15,926 - EXP     - Expyfun: Trial OK
2023-07-25 19:08:15,931 - INFO    - Expyfun: Exiting
2023-07-25 19:08:15,933 - EXP     - Expyfun: Audio stopped and reset.

# Author: Dan McCloy <drmccloy@uw.edu>
#
# License: BSD (3-clause)

import os
import sys
from os import path as op
import numpy as np

from expyfun import (ExperimentController, get_keyboard_input, set_log_level,
                     building_doc)
from expyfun.io import read_hdf5
import expyfun.analyze as ea

print(__doc__)

set_log_level('INFO')

# set configuration
noise_db = 45  # dB for background noise
stim_db = 65  # dB for stimuli
min_resp_time = 0.1
max_resp_time = 2.0
max_wait = np.inf
feedback_dur = 2.0
isi = 0.2
running_total = 0

# make the stimuli if necessary and then load them
fname = 'equally_spaced_sinewaves.hdf5'
if not op.isfile(fname):
    # This sys.path wrangling is only necessary for Sphinx automatic
    # documentation building
    sys.path.insert(0, os.getcwd())
    from generate_simple_stimuli import generate_stimuli
    generate_stimuli()
stims = read_hdf5(fname)
orig_rms = stims['rms']
freqs = stims['freqs']
fs = stims['fs']
trial_order = stims['trial_order']
num_trials = len(trial_order)
num_freqs = len(freqs)

if num_freqs > 8:
    raise RuntimeError('Too many frequencies, not enough buttons.')

# keep only sinusoids, order low-high, convert to list of arrays
wavs = [stims[k] for k in sorted(stims.keys()) if k.startswith('stim_')]

# instructions
instructions = ('You will hear tones at {0} different frequencies. Your job is'
                ' to press the button corresponding to that frequency. Please '
                'press buttons 1-{0} now to hear each tone.').format(num_freqs)

instr_finished = ('Okay, now press any of those buttons to start the real '
                  'thing. There will be background noise.')

with ExperimentController('testExp', verbose=True, screen_num=0,
                          window_size=[800, 600], full_screen=False,
                          stim_db=stim_db, noise_db=noise_db, stim_fs=fs,
                          participant='foo', session='001',
                          version='dev', output_dir=None) as ec:

    # define usable buttons / keys
    live_keys = [x + 1 for x in range(num_freqs)]

    # do training, or not
    ec.set_visible(False)
    long_resp_time = max_resp_time + 1
    if building_doc:
        max_wait = max_resp_time = min_resp_time = train = feedback_dur = 0
        long_resp_time = 0
    else:
        train = get_keyboard_input('Run training (0=no, 1=yes [default]): ',
                                   1, int)
    ec.set_visible(True)

    if train:
        not_yet_pressed = live_keys[:]

        # show instructions until all buttons have been pressed at least once
        ec.screen_text(instructions)
        ec.flip()
        while len(not_yet_pressed) > 0:
            pressed, timestamp = ec.wait_one_press(live_keys=live_keys)
            for p in pressed:
                p = int(p)
                ec.load_buffer(wavs[p - 1])
                ec.play()
                ec.wait_secs(len(wavs[p - 1]) / float(ec.fs))
                ec.stop()
                if p in not_yet_pressed:
                    not_yet_pressed.pop(not_yet_pressed.index(p))
        ec.flip()  # clears the screen
        ec.wait_secs(isi)

    # show instructions finished screen
    ec.screen_prompt(instr_finished, live_keys=live_keys, max_wait=max_wait)
    ec.wait_secs(isi)

    ec.call_on_next_flip(ec.start_noise())
    ec.screen_text('OK, here we go!', wrap=False)
    screenshot = ec.screenshot()
    ec.wait_one_press(max_wait=feedback_dur, live_keys=None)
    ec.wait_secs(isi)

    single_trial_order = trial_order[range(len(trial_order) // 2)]
    mass_trial_order = trial_order[len(trial_order) // 2:]
    # run the single-tone trials
    for stim_num in single_trial_order:
        ec.load_buffer(wavs[stim_num])
        ec.identify_trial(ec_id=stim_num, ttl_id=[0, 0])
        ec.write_data_line('one-tone trial', stim_num + 1)
        ec.start_stimulus()
        pressed, timestamp = ec.wait_one_press(max_resp_time, min_resp_time,
                                               live_keys)
        ec.stop()  # will stop stim playback as soon as response logged
        ec.trial_ok()

        # some feedback
        if pressed is None:
            message = 'Too slow!'
        elif int(pressed) == stim_num + 1:
            running_total += 1
            message = ('Correct! Your reaction time was '
                       '{}').format(round(timestamp, 3))
        else:
            message = ('You pressed {0}, the correct answer was '
                       '{1}.').format(pressed, stim_num + 1)
        ec.screen_prompt(message, max_wait=feedback_dur)
        ec.wait_secs(isi)

    # create 100 ms pause to play between stims and concatenate
    pause = np.zeros(int(ec.fs / 10))
    concat_wavs = wavs[mass_trial_order[0]]
    for num in mass_trial_order[1:len(mass_trial_order)]:
        concat_wavs = np.r_[concat_wavs, pause, wavs[num]]
    concat_dur = len(concat_wavs) / float(ec.fs)
    # run mass trial
    ec.screen_prompt('Now you will hear {0} tones in a row. After they stop, '
                     'wait for the "Go!" prompt, then you will have {1} '
                     'seconds to push the buttons in the order that the tones '
                     'played in. Press one of the buttons to begin.'
                     ''.format(len(mass_trial_order), max_resp_time),
                     live_keys=live_keys, max_wait=max_wait)
    ec.load_buffer(concat_wavs)
    ec.identify_trial(ec_id='multi-tone', ttl_id=[0, 1])
    ec.write_data_line('multi-tone trial', [x + 1 for x in mass_trial_order])
    ec.start_stimulus()
    ec.wait_secs(len(concat_wavs) / float(ec.stim_fs) if not building_doc else
                 0)
    ec.screen_text('Go!', wrap=False)
    ec.flip()
    pressed = ec.wait_for_presses(long_resp_time, min_resp_time,
                                  live_keys, False)
    answers = [str(x + 1) for x in mass_trial_order]
    correct = [press == ans for press, ans in zip(pressed, answers)]
    running_total += sum(correct)
    ec.call_on_next_flip(ec.stop_noise())
    ec.screen_prompt('You got {0} out of {1} correct.'
                     ''.format(sum(correct), len(answers)),
                     max_wait=feedback_dur)
    ec.trial_ok()

    # end experiment
    ec.screen_prompt('All done! You got {0} correct out of {1} tones. Press '
                     'any key to close.'.format(running_total, num_trials),
                     max_wait=max_wait)

ea.plot_screen(screenshot)

Total running time of the script: ( 0 minutes 2.251 seconds)

Gallery generated by Sphinx-Gallery