Exemple #1
0
    def test_displayNewRound(self):
        next_label = visual.TextStim(window,
                                     units='norm',
                                     text=u'New Round',
                                     pos=[0, 0],
                                     height=0.1,
                                     color='red',
                                     colorSpace='rgb',
                                     alignHoriz='center',
                                     alignVert='center')

        res = displayNewRound(window, next_label, keyboard, False)
        self.assertEqual(res, 0)
Exemple #2
0
def trial(self, clock, window, shapes, keys, text_color, centered, wait_time, warning_time, exp, count, ser):
    """
    Main motor type function
    :param clock: clock used for standardized timing; initialized in the main experimental loop
    :param window: display window
    :param shapes: array of shape objects to be used (not already randomized)
    :param keys: keyboard device
    :param text_color: color for text
    :param centered: true if blocks are to be centered, false otherwise
    :param wait_time: max seconds for trial to wait before continuing if trial is not completed
    :param warning_time: num of seconds left to begin countdown
    :param exp: experiment object for adding trial data
    :param count: number of motor trials during this experiment for file naming
    :param ser: serial port that links to XBee for syncing
    :return: status of trial where 0 = completed but incorrect; 1 = completed and correct; 2 = incomplete
    """

    # Default Value Set Up for Timing #
    global stimulus_beg_time
    stimulus_beg_time = -1
    global in_between_time
    in_between_time = -1
    global total_stimuli_time
    total_stimuli_time = -1

    # Position Tracking File Set Up #
    text_file = open("keys_exp_%d.txt" % count, "w")
    text_file.write("Time\tKey Event\tKey Type\n")

    # Text Values #
    count_label = visual.TextStim(window, units='norm', text=u'', pos=[-0.5,-0.5], height=0.2, color=text_color,
                                  colorSpace='rgb255',alignHoriz='center', alignVert='center')

    second_label = visual.TextStim(window, units='norm', text=u'Press on keyboard.',
                                   pos = [0,0], height=0.1, color=text_color, colorSpace='rgb255',alignHoriz='center',
                                   alignVert='center')

    next_label = visual.TextStim(window, units='norm', text=u'Motor Round', pos=[0,0], height=0.1, color=text_color,
                                colorSpace='rgb',alignHoriz='center', alignVert='center')

    # Display round name
    helper.displayNewRound(window, next_label)

    # Set up default values for tracking mouse click timing
    key_times = [-1, -1, -1]
    key_counter = [0, 0, 0]
    length = len(shapes)
    event.clearEvents()

    # block sequence display #
    print "%f BEGIN BLOCK SEQUENCE" %(clock.getTime())
    global in_between_time
    in_between_time = helper.drawSequence(window, shapes, clock)
    print "%f END BLOCK SEQUENCE" %(clock.getTime())

    # instructions are displayed #
    self.hub.clearEvents('all')
    for nFrames in range(200):
        second_label.draw()
        window.flip()

    # for block interaction #
    beg_time = clock.getTime()
    curr_time = clock.getTime()
    self.hub.clearEvents()

    # changes location of shapes if centered, so that they don't overlap
    if centered and length > 1:
        helper.adjustShapeLoc(shapes)

    # Map the blocks in each corner to the respective keyboard events
    keyMap = mapKeys(shapes)

    # store time right when interactive stimuli is presented for reference
    window.callOnFlip(track_time, clock)

    # draw the interactive stimuli
    [s.draw() for s in shapes]
    window.flip()

    temp_time = -1
    key_char = ''
    no_release = False

    # loop until trial finished or timed out
    while curr_time - beg_time < wait_time:
        # redraw the stimuli every window flip
        [s.draw() for s in shapes]
        count_label.draw()
        window.flip()

        # If the shape is pressed long enough to set it to 0 opacity, then the timing of that setting is recorded.
        events = keys.getKeys()  # iohub device keyboard info
        events2 = event.getKeys(timeStamped=clock)  # event keyboard with event timing based on clock input
        for kbe in events2: # get accurate timing
            key_char = kbe[0]
            temp_time = kbe[1]
            print kbe
        for kbe in events: # use for recording keystrokes and durations
            text_file.write(str(clock.getTime()))
            text_file.write("\t")
            text_file.write(kbe.type)
            text_file.write("\t")
            text_file.write(kbe.char)
            text_file.write("\n")
            if kbe.type == 'KEYBOARD_RELEASE':
                no_release = False
            elif kbe.type == 'KEYBOARD_PRESS':
                no_release = True
        if no_release is True:
            if key_char == keyMap[0]:
                key_counter[0] += 1
                if 0 < key_counter[0] < CHNG_INTERVAL:
                    shapes[0].setOpacity(shapes[0].opacity - ADJ_INTERVAL)
                elif key_counter[0] == CHNG_INTERVAL:
                    shapes[0].setOpacity(OPACITY_THRES)
                elif key_counter[0] == REQUIRED_FRAMES:
                    shapes[0].setOpacity(0.0)
                    key_times[0] = temp_time
            elif key_char == keyMap[1]:
                key_counter[1] += 1
                if 0 < key_counter[1] < CHNG_INTERVAL:
                    shapes[1].setOpacity(shapes[1].opacity - ADJ_INTERVAL)
                elif key_counter[1] == CHNG_INTERVAL:
                    shapes[1].setOpacity(OPACITY_THRES)
                elif key_counter[1] == REQUIRED_FRAMES:
                    shapes[1].setOpacity(0.0)
                    key_times[1] = temp_time
            elif key_char == keyMap[2]:
                key_counter[2] += 1
                if 0 < key_counter[2] < CHNG_INTERVAL:
                    shapes[2].setOpacity(shapes[2].opacity - ADJ_INTERVAL)
                elif key_counter[2] == CHNG_INTERVAL:
                    shapes[2].setOpacity(OPACITY_THRES)
                elif key_counter[2] == REQUIRED_FRAMES:
                    shapes[2].setOpacity(0.0)
                    key_times[2] = temp_time

        # once the round is finished, use previous counters to calculate total time spent and individual click times
        if helper.checkOpacity(shapes):
            finish_time = clock.getTime()
            total_stimuli_time = finish_time - stimulus_beg_time
            print "\n%f\t%f\t%f" %(key_times[0], key_times[1], key_times[2])
            print "%f TOTAL TIME TO FINISH ROUND" %(total_stimuli_time)
            break

        # adjust countdown value, to be displayed with the next flip
        curr_time = clock.getTime()
        if (curr_time - beg_time) >= (wait_time - warning_time - 0.1):
            count_label.setText(int(round(wait_time - (curr_time - beg_time))), 0)

    event.clearEvents()

    # save data in the experiment file
    global stimulus_beg_time
    exp.addData("stimulus_begin_time", stimulus_beg_time)
    exp.addData("in_between_time", in_between_time)
    exp.addData("total_stimuli_time", total_stimuli_time)
    exp.addData("time1", key_times[0])
    exp.addData("time2", key_times[1])
    exp.addData("time3", key_times[2])

    # return status code based on correctness of sequence
    if (curr_time-beg_time) >  wait_time:
        return 2
    if length == 1:
        return 1
    elif length == 2:
        if key_times[1] > key_times[0]:
            return 1  # correct
        else:
            return 0  # not correct
    elif length == 3:
        if key_times[0] < key_times[1] < key_times[2]:
            return 1  # correct
        else:
            return 0  # not correct
    return -1
Exemple #3
0
def trial(self, clock, window, shapes, mouse, text_color, centered, wait_time,
          warning_time, exp, count, ser):
    """
    Main motor type function
    :param clock: clock used for standardized timing; initialized in the main experimental loop
    :param window: display window
    :param shapes: array of shape objects to be used (not already randomized)
    :param mouse: mouse device
    :param text_color: color for text
    :param centered: true if blocks are to be centered, false otherwise
    :param wait_time: max seconds for trial to wait before continuing if trial is not completed
    :param warning_time: num of seconds left to begin countdown
    :param exp: experiment object for adding trial data
    :param count: number of motor trials during this experiment for file naming
    :param ser: serial port that links to XBee for syncing
    :return: status of trial where 0 = completed but incorrect; 1 = completed and correct; 2 = incomplete
    """

    # Default Value Set Up for Timing #
    global stimulus_beg_time
    stimulus_beg_time = -1
    global in_between_time
    in_between_time = -1
    global total_stimuli_time
    total_stimuli_time = -1

    # Position Tracking File Set Up #
    text_file = open("motor_exp_%d.txt" % count, "w")
    text_file.write("Time\tX\tY\tRandom\n")

    # Text Values #
    count_label = visual.TextStim(window,
                                  units='norm',
                                  text=u'',
                                  pos=[-0.5, -0.5],
                                  height=0.2,
                                  color=text_color,
                                  colorSpace='rgb255',
                                  alignHoriz='center',
                                  alignVert='center')

    second_label = visual.TextStim(window,
                                   units='norm',
                                   text=u'Click on blocks',
                                   pos=[0, 0],
                                   height=0.1,
                                   color=text_color,
                                   colorSpace='rgb255',
                                   alignHoriz='center',
                                   alignVert='center')

    next_label = visual.TextStim(window,
                                 units='norm',
                                 text=u'Motor Round',
                                 pos=[0, 0],
                                 height=0.1,
                                 color=text_color,
                                 colorSpace='rgb',
                                 alignHoriz='center',
                                 alignVert='center')

    # Display round name
    helper.displayNewRound(window, next_label)

    # Set up default values for tracking mouse click timing
    mouse_times = [-1, -1, -1]
    mouse_counter = [0, 0, 0]
    length = len(shapes)
    event.clearEvents()

    # block sequence display #
    print "%f BEGIN BLOCK SEQUENCE" % (clock.getTime())
    ser.write("Begin Sequence")
    global in_between_time
    in_between_time = helper.drawSequence(window, shapes, clock)
    ser.write("End Sequence")
    print "%f END BLOCK SEQUENCE" % (clock.getTime())

    # instructions are displayed #
    self.hub.clearEvents('all')
    for nFrames in range(200):
        second_label.draw()
        window.flip()

    # for block interaction #
    beg_time = clock.getTime()
    curr_time = clock.getTime()
    self.hub.clearEvents()

    # changes location of shapes if centered, so that they don't overlap
    if centered and length > 1:
        helper.adjustShapeLoc(shapes)

    # store time right when interactive stimuli is presented for reference
    window.callOnFlip(track_time, clock, mouse)

    # draw the interactive stimuli
    [s.draw() for s in shapes]
    window.flip()

    # set up the initial mouse position
    mouse.getPos()

    # loop until trial finished or timed out
    while curr_time - beg_time < wait_time:
        # redraw the stimuli every window flip
        [s.draw() for s in shapes]
        count_label.draw()
        window.flip()

        # Check for mouse clicks and location; even if not all present, goes off location.
        # First checks if mouse is within a block, then fades that block out according to the specified
        # constant values.
        # If the shape is pressed long enough to set it to 0 opacity, then the timing of that setting is recorded.
        buttons = mouse.getPressed()
        if buttons[0] == 1:
            if shapes[0].contains(mouse):
                mouse_counter[0] += 1
                if 0 < mouse_counter[0] < CHNG_INTERVAL:
                    shapes[0].setOpacity(shapes[0].opacity - ADJ_INTERVAL)
                elif mouse_counter[0] == CHNG_INTERVAL:
                    shapes[0].setOpacity(OPACITY_THRES)
                elif mouse_counter[0] == REQUIRED_FRAMES:
                    shapes[0].setOpacity(0.0)
                    mouse_times[0] = clock.getTime()
            elif shapes[1].contains(mouse):
                mouse_counter[1] += 1
                if 0 < mouse_counter[1] < CHNG_INTERVAL:
                    shapes[1].setOpacity(shapes[1].opacity - ADJ_INTERVAL)
                elif mouse_counter[1] == CHNG_INTERVAL:
                    shapes[1].setOpacity(OPACITY_THRES)
                elif mouse_counter[1] == REQUIRED_FRAMES:
                    shapes[1].setOpacity(0.0)
                    mouse_times[1] = clock.getTime()
            elif shapes[2].contains(mouse):
                mouse_counter[2] += 1
                if 0 < mouse_counter[2] < CHNG_INTERVAL:
                    shapes[2].setOpacity(shapes[2].opacity - ADJ_INTERVAL)
                elif mouse_counter[2] == CHNG_INTERVAL:
                    shapes[2].setOpacity(OPACITY_THRES)
                elif mouse_counter[2] == REQUIRED_FRAMES:
                    shapes[2].setOpacity(0.0)
                    mouse_times[2] = clock.getTime()

        # once the round is finished, use previous counters to calculate total time spent and individual click times
        if helper.checkOpacity(shapes):
            finish_time = clock.getTime()
            total_stimuli_time = finish_time - stimulus_beg_time
            print "\n%f\t%f\t%f" % (mouse_times[0], mouse_times[1],
                                    mouse_times[2])
            print "%f TOTAL TIME TO FINISH ROUND" % (total_stimuli_time)
            break

        num = random.randint(0, 10)
        ser.write(num)  # write random number to Zigbee for syncing
        # gets and saves the mouse position and time A
        mouse_position_time(clock, mouse, text_file, num)

        # adjust countdown value, to be displayed with the next flip
        curr_time = clock.getTime()
        if (curr_time - beg_time) >= (wait_time - warning_time - 0.1):
            count_label.setText(int(round(wait_time - (curr_time - beg_time))),
                                0)

    # save data in the experiment file
    global stimulus_beg_time
    exp.addData("stimulus_begin_time", stimulus_beg_time)
    exp.addData("in_between_time", in_between_time)
    exp.addData("total_stimuli_time", total_stimuli_time)
    exp.addData("time1", mouse_times[0])
    exp.addData("time2", mouse_times[1])
    exp.addData("time3", mouse_times[2])

    # closes the position tracking file at the end A
    text_file.close()

    # return status code based on correctness of sequence
    if (curr_time - beg_time) > wait_time:
        return 2
    if length == 1:
        return 1
    elif length == 2:
        if mouse_times[1] > mouse_times[0]:
            return 1  # correct
        else:
            return 0  # not correct
    elif length == 3:
        if mouse_times[0] < mouse_times[1] < mouse_times[2]:
            return 1  # correct
        else:
            return 0  # not correct
    return -1
Exemple #4
0
def trial(self, clock, window, shapes, text_color, centered, wait_time, warning_time, exp, count, ser):
    """
    Main eye tracking type function
    :param clock: clock used for standardized timing; initialized in the main experimental loop
    :param window: display window
    :param shapes: array of shape objects to be used (not already randomized)
    :param text_color: color for text
    :param centered: true if blocks are to be centered, false otherwise
    :param wait_time: max seconds for trial to wait before continuing if trial is not completed
    :param warning_time: num of seconds left to begin countdown
    :param exp: experiment object for adding trial data
    :param count: number of eye tracking trials during this experiment for file naming
    :param ser: serial port that links to XBee for syncing
    :return: status of trial where 0 = completed but incorrect; 1 = completed and correct; 2 = incomplete
    """

    # Default Value Set Up for Timing #
    global stimulus_beg_time
    stimulus_beg_time = -1
    global in_between_time
    in_between_time = -1
    global total_stimuli_time
    total_stimuli_time = -1

    # Position Tracking File Set Up #
    text_file = open("eye_exp_%d.txt" % count, "w")
    text_file.write("Time\tX\tY\tRandom\n")

    # Eye tracker set up
    tracker=self.hub.devices.tracker
    tracker.runSetupProcedure()
    tracker.setConnectionState(True)
    tracker.setRecordingState(True)

    # Check if eye tracker is returning any data over a short range of time.
    # Quits the trial if the eye tracker if it is not connected or cannot detect eyes.
    connection_counter = 0
    for i in range(100):
        gpos=tracker.getLastGazePosition()
        if not isinstance(gpos,(tuple,list)):
            connection_counter += 1
        time.sleep(0.01)
    if connection_counter > 97:
        print "no connection"
        return

    # Text Values #
    gaze_dot = visual.GratingStim(window,tex=None, mask="gauss", pos=(0,0 ),size=(0.1,0.1),color='green',
                                                    units='norm')

    instructions_text_stim = visual.TextStim(window, units='norm', text=u'Look at blocks',
                          pos=[0,0.2], height=0.1, color=text_color, colorSpace='rgb',alignHoriz='center',
                          alignVert='center')

    count_label = visual.TextStim(window, units='norm', text=u'', pos=[-0.5,-0.5], height=0.2, color=text_color,
                          colorSpace='rgb255',alignHoriz='center', alignVert='center')

    next_label = visual.TextStim(window, units='norm', text=u'Eye Round', pos=[0,0], height=0.1, color=text_color,
                                colorSpace='rgb',alignHoriz='center', alignVert='center')

    # Display round name
    helper.displayNewRound(window, next_label)

    # Set up default values #
    self.hub.clearEvents('all')
    init_time_array = [-1, -1, -1]
    if len(shapes) == 3:
        init_time_array[0] = 0
        init_time_array[1] = 0
        init_time_array[2] = 0
    elif len(shapes) == 2:
        init_time_array[0] = 0
        init_time_array[1] = 0
    elif len(shapes) == 1:
        init_time_array[0] = 0

    time_diff_array = [-1, -1, -1]
    length = len(shapes)

    # block sequence display #
    print "%f BEGIN BLOCK SEQUENCE" %(clock.getTime())
    ser.write("Begin Sequence")
    global in_between_time
    in_between_time = helper.drawSequence(window, shapes, clock)
    ser.write("End Sequence")
    print "%f END BLOCK SEQUENCE" %(clock.getTime())

    # instructions are displayed #
    self.hub.clearEvents('all')
    for nFrames in range(200):
        instructions_text_stim.draw()
        window.flip()

    # for block interaction #
    beg_time = clock.getTime()
    curr_time = clock.getTime()
    self.hub.clearEvents()

    # changes location of shapes if centered, so that they don't overlap #
    if centered and length > 1:
        helper.adjustShapeLoc(shapes)

    # store time right when clicking stimuli is presented for reference
    window.callOnFlip(track_time, clock)

    # draw the interactive stimuli
    [s.draw() for s in shapes]
    window.flip()

    # initialize the block vertices
    shapes_verts = []
    for num in range(len(shapes)):
        shapes_verts.append(helper.pix_conv(window.size[0], window.size[1], shapes[num].width, shapes[num].height, shapes[num].pos[0], shapes[num].pos[1]))
    print shapes_verts

    # loop until trial finished or timed out
    while curr_time - beg_time < wait_time:
        [s.draw() for s in shapes]
        count_label.draw()

        # Get the latest gaze position
        gpos = tracker.getLastGazePosition()

        if not isinstance(gpos,(tuple,list)):
            window.flip()
            continue

        # Check if eye position is within each block.
        # If so, then the time is recorded and the opacity is changed accordingly.
        for num in range(length):
            s = shapes[num]
            if s.opacity == 0.0:
                continue
            if isinstance(gpos,(tuple,list)):
                if shapes_verts[num][0] < gpos[0] < shapes_verts[num][1] and shapes_verts[num][3] < gpos[1] < shapes_verts[num][2]:
                    init_time_array[num] += 1
                    time_diff_array[num] = clock.getTime()
                    if init_time_array[num] == REQUIRED_FRAMES/2:
                        s.setOpacity(0.5)
                    if init_time_array[num] > REQUIRED_FRAMES:
                        s.setOpacity(0.0)
                        init_time_array[num] = clock.getTime()
                    break  # if position is within one block, it could not be in any of the other blocks

                # reset the opacity of the block if the eye looks away for a specified amount time
                # implemented to prevent registering blocks when the eye is just passing over the screen
                elif clock.getTime() - time_diff_array[num] > THRES_TIME_AWAY:
                    init_time_array[num] = 0
                    time_diff_array[num] = -1
                    s.setOpacity(1.0)

        ## EYE TRACKING DISPLAY DOT; NOT NECESSARY FOR ACTUAL IMPLEMENTATION ##
        # if isinstance(gpos,(tuple,list)):
        #     # Adjusting eye tracking values to match norm units to display on the screen
        #     gpos0_adj = (gpos[0]/window.size[1])*2
        #     gpos1_adj = (gpos[1]/window.size[0])*2
        #     gaze_dot.setPos([gpos0_adj, gpos1_adj])
        #     gaze_dot.draw()

        # once the round is finished, use previous counters to calculate total time spent and individual position times
        if helper.checkOpacity(shapes):
            finish_time = clock.getTime()
            total_stimuli_time = finish_time - stimulus_beg_time
            print "\n%f\t%f\t%f" %(init_time_array[0], init_time_array[1], init_time_array[2])
            print "%f TOTAL TIME TO FINISH ROUND" %(total_stimuli_time)
            break

        num = random.randint(0, 10)
        ser.write(num)  # write random number to Zigbee for syncing
        # gets and saves the eye position and time
        eye_position_time(clock, gpos, text_file)

        # adjust count_down, to be displayed with the next flip
        curr_time = clock.getTime()
        if (curr_time - beg_time) >= (wait_time - warning_time - 0.1):
            count_label.setText(int(round(wait_time - (curr_time - beg_time))), 0)

        window.flip()

    # turn off eye tracker
    self.hub.clearEvents('all')
    tracker.setRecordingState(False)
    tracker.setConnectionState(False)

    # save data in the experiment file
    exp.addData("stimulus_begin_time", stimulus_beg_time)
    exp.addData("in_between_time", in_between_time)
    exp.addData("total_stimuli_time", total_stimuli_time)
    exp.addData("time1", init_time_array[0])
    exp.addData("time2", init_time_array[1])
    exp.addData("time3", init_time_array[2])

    # closes the position tracking file at the end A
    text_file.close()

    # return status code based on correctness of sequence
    if (curr_time-beg_time) >  wait_time:
        return 2
    if length == 1:
        return 1
    elif length == 2:
        if init_time_array[1] > init_time_array[0]:
            return 1  # correct
        else:
            return 0  # not correct
    elif length == 3:
        if init_time_array[0] < init_time_array[1] < init_time_array[2]:
            return 1  # correct
        else:
            return 0  # not correct
Exemple #5
0
def trial(self, clock, window, shapes, mouse, keys, text_color, wait_time, warning_time, exp, count, ser):
    """
    Main speech type function
    :param clock: clock used for standardized timing; initialized in the main experimental loop
    :param window: display window
    :param shapes: array of shape objects to be used (not already randomized)
    :param mouse: mouse device
    :param text_color: color for text
    :param wait_time: max seconds for trial to wait before continuing if trial is not completed
    :param warning_time: num of seconds left to begin countdown
    :param exp: experiment object for adding trial data
    :param count: number of speech trials during this experiment for file naming
    :param ser: serial port that links to XBee for syncing
    :return: status of trial where 0 = completed but incorrect; 1 = completed and correct; 2 = incomplete
    """

    # Default Value Set Up for Timing #
    global stimulus_beg_time
    stimulus_beg_time = -1
    global in_between_time
    in_between_time = -1
    global total_stimuli_time
    total_stimuli_time = -1

    # Text values
    count_label = visual.TextStim(window, units='norm', text=u'', pos = [0, -0.6], height=0.2, color=text_color,
                                  colorSpace='rgb255',alignHoriz='center', alignVert='center')

    second_label = visual.TextStim(window, units='norm', text=u'Speak color of blocks',
                                   pos=[0,0.3], height=0.1, color=text_color, colorSpace='rgb255',alignHoriz='center',
                                   alignVert='center')

    done_label = visual.TextStim(window, units='norm', text=u'Done', pos=[0,-0.25], height=0.1, color=text_color,
                                 colorSpace='rgb255',alignHoriz='center', alignVert='center')

    done_button = visual.Rect(window, width=0.5, height=0.25, lineColor=(0, 0, 0), lineWidth=2,
                              lineColorSpace='rgb', pos=(0, -0.25))

    next_label = visual.TextStim(window, units='norm', text=u'Speech Round', pos=[0,0], height=0.1, color=text_color,
                                colorSpace='rgb',alignHoriz='center', alignVert='center')

    BLOCK_LIST = [second_label, done_button, done_label]

    # Display round name
    helper.displayNewRound(window, next_label)

    # Microphone Set Up #
    microphone.switchOn(sampleRate=16000)
    name = "speech_exp_%d.wav" %count
    mic = microphone.AdvAudioCapture(filename=name)
    # todo: can edit marker to output as sync signal; played when recording starts
    # marker currently set to not output any sound on onset of recording
    mic.setMarker(tone=5000, secs=0.015, volume=0.0)

    # Block Sequence Display #
    print "%f BEGIN BLOCK SEQUENCE" %(clock.getTime())
    ser.write("Begin Sequence")
    global in_between_time
    in_between_time = helper.drawSequence(window, shapes, clock)
    ser.write("End Sequence")
    print "%f END BLOCK SEQUENCE" %(clock.getTime())

    # for block interaction #
    self.hub.clearEvents()
    start_time = clock.getTime()
    timeout_counter = 0
    self.hub.clearEvents()

    # store time right when clicking stimuli is presented for reference
    window.callOnFlip(track_speech_time, clock, mouse)
    window.flip()

    # records for length of specified wait time
    mic.record(wait_time, block=False)
    ser.write("Start")
    while mic.recorder.running:
        [s.draw() for s in BLOCK_LIST]
        count_label.draw()
        window.flip()
        timeout_counter += 1

        ## FOR MOUSE-CLICK END: ##
        # buttons, times = mouse.getPressed(getTime=True)
        # if mouse.isPressedIn(done_button, buttons=[0]):
        #     break

        ## FOR KEYBOARD END: ##
        events = keys.getKeys()
        if len(events) != 0:
            break

        # adjust countdown value, to be displayed with the next flip
        if timeout_counter >= ((wait_time - warning_time)*60) and timeout_counter % 60 == 0:
            count_label.setText(((wait_time*60)-timeout_counter)/60)

    # turn off microphone and saves the audio file automatically
    ser.write("Finish")
    microphone.switchOff()
    finish_time = clock.getTime()

    # once the round is finished, use previous counters to calculate total time spent and individual click times
    total_stimuli_time = finish_time - speech_beg_time
    print "\n%f" %(finish_time)
    print "%f TOTAL TIME TO FINISH ROUND" %(total_stimuli_time)

    # save data in the experiment file
    exp.addData("stimulus_begin_time", speech_beg_time)
    exp.addData("in_between_time", in_between_time)
    exp.addData("total_stimuli_time", total_stimuli_time)
    exp.addData("time1", start_time)
    exp.addData("time2", finish_time)

    # return status code based on correctness of sequence
    if timeout_counter == wait_time*60:
        return 2
    if timeout_counter < wait_time*60: # assume finished normally by clicking button
        return 0
    return -1
    def test_displayNewRound(self):
        next_label = visual.TextStim(window, units='norm', text=u'New Round', pos=[0,0], height=0.1, color='red',
                                     colorSpace='rgb',alignHoriz='center', alignVert='center')

        res= displayNewRound(window,next_label,keyboard,False)
        self.assertEqual(res,0)
Exemple #7
0
def trial(self, clock, window, shapes, mouse, keys, text_color, wait_time,
          warning_time, exp, count, ser):
    """
    Main speech type function
    :param clock: clock used for standardized timing; initialized in the main experimental loop
    :param window: display window
    :param shapes: array of shape objects to be used (not already randomized)
    :param mouse: mouse device
    :param text_color: color for text
    :param wait_time: max seconds for trial to wait before continuing if trial is not completed
    :param warning_time: num of seconds left to begin countdown
    :param exp: experiment object for adding trial data
    :param count: number of speech trials during this experiment for file naming
    :param ser: serial port that links to XBee for syncing
    :return: status of trial where 0 = completed but incorrect; 1 = completed and correct; 2 = incomplete
    """

    # Default Value Set Up for Timing #
    global stimulus_beg_time
    stimulus_beg_time = -1
    global in_between_time
    in_between_time = -1
    global total_stimuli_time
    total_stimuli_time = -1

    # Text values
    count_label = visual.TextStim(window,
                                  units='norm',
                                  text=u'',
                                  pos=[0, -0.6],
                                  height=0.2,
                                  color=text_color,
                                  colorSpace='rgb255',
                                  alignHoriz='center',
                                  alignVert='center')

    second_label = visual.TextStim(window,
                                   units='norm',
                                   text=u'Speak color of blocks',
                                   pos=[0, 0.3],
                                   height=0.1,
                                   color=text_color,
                                   colorSpace='rgb255',
                                   alignHoriz='center',
                                   alignVert='center')

    done_label = visual.TextStim(window,
                                 units='norm',
                                 text=u'Done',
                                 pos=[0, -0.25],
                                 height=0.1,
                                 color=text_color,
                                 colorSpace='rgb255',
                                 alignHoriz='center',
                                 alignVert='center')

    done_button = visual.Rect(window,
                              width=0.5,
                              height=0.25,
                              lineColor=(0, 0, 0),
                              lineWidth=2,
                              lineColorSpace='rgb',
                              pos=(0, -0.25))

    next_label = visual.TextStim(window,
                                 units='norm',
                                 text=u'Speech Round',
                                 pos=[0, 0],
                                 height=0.1,
                                 color=text_color,
                                 colorSpace='rgb',
                                 alignHoriz='center',
                                 alignVert='center')

    BLOCK_LIST = [second_label, done_button, done_label]

    # Display round name
    helper.displayNewRound(window, next_label)

    # Microphone Set Up #
    microphone.switchOn(sampleRate=16000)
    name = "speech_exp_%d.wav" % count
    mic = microphone.AdvAudioCapture(filename=name)
    # todo: can edit marker to output as sync signal; played when recording starts
    # marker currently set to not output any sound on onset of recording
    mic.setMarker(tone=5000, secs=0.015, volume=0.0)

    # Block Sequence Display #
    print "%f BEGIN BLOCK SEQUENCE" % (clock.getTime())
    ser.write("Begin Sequence")
    global in_between_time
    in_between_time = helper.drawSequence(window, shapes, clock)
    ser.write("End Sequence")
    print "%f END BLOCK SEQUENCE" % (clock.getTime())

    # for block interaction #
    self.hub.clearEvents()
    start_time = clock.getTime()
    timeout_counter = 0
    self.hub.clearEvents()

    # store time right when clicking stimuli is presented for reference
    window.callOnFlip(track_speech_time, clock, mouse)
    window.flip()

    # records for length of specified wait time
    mic.record(wait_time, block=False)
    ser.write("Start")
    while mic.recorder.running:
        [s.draw() for s in BLOCK_LIST]
        count_label.draw()
        window.flip()
        timeout_counter += 1

        ## FOR MOUSE-CLICK END: ##
        # buttons, times = mouse.getPressed(getTime=True)
        # if mouse.isPressedIn(done_button, buttons=[0]):
        #     break

        ## FOR KEYBOARD END: ##
        events = keys.getKeys()
        if len(events) != 0:
            break

        # adjust countdown value, to be displayed with the next flip
        if timeout_counter >= (
            (wait_time - warning_time) * 60) and timeout_counter % 60 == 0:
            count_label.setText(((wait_time * 60) - timeout_counter) / 60)

    # turn off microphone and saves the audio file automatically
    ser.write("Finish")
    microphone.switchOff()
    finish_time = clock.getTime()

    # once the round is finished, use previous counters to calculate total time spent and individual click times
    total_stimuli_time = finish_time - speech_beg_time
    print "\n%f" % (finish_time)
    print "%f TOTAL TIME TO FINISH ROUND" % (total_stimuli_time)

    # save data in the experiment file
    exp.addData("stimulus_begin_time", speech_beg_time)
    exp.addData("in_between_time", in_between_time)
    exp.addData("total_stimuli_time", total_stimuli_time)
    exp.addData("time1", start_time)
    exp.addData("time2", finish_time)

    # return status code based on correctness of sequence
    if timeout_counter == wait_time * 60:
        return 2
    if timeout_counter < wait_time * 60:  # assume finished normally by clicking button
        return 0
    return -1
Exemple #8
0
def trial(self, clock, window, shapes, text_color, centered, wait_time,
          warning_time, exp, count, ser):
    """
    Main eye tracking type function
    :param clock: clock used for standardized timing; initialized in the main experimental loop
    :param window: display window
    :param shapes: array of shape objects to be used (not already randomized)
    :param text_color: color for text
    :param centered: true if blocks are to be centered, false otherwise
    :param wait_time: max seconds for trial to wait before continuing if trial is not completed
    :param warning_time: num of seconds left to begin countdown
    :param exp: experiment object for adding trial data
    :param count: number of eye tracking trials during this experiment for file naming
    :param ser: serial port that links to XBee for syncing
    :return: status of trial where 0 = completed but incorrect; 1 = completed and correct; 2 = incomplete
    """

    # Default Value Set Up for Timing #
    global stimulus_beg_time
    stimulus_beg_time = -1
    global in_between_time
    in_between_time = -1
    global total_stimuli_time
    total_stimuli_time = -1

    # Position Tracking File Set Up #
    text_file = open("eye_exp_%d.txt" % count, "w")
    text_file.write("Time\tX\tY\tRandom\n")

    # Eye tracker set up
    tracker = self.hub.devices.tracker
    tracker.runSetupProcedure()
    tracker.setConnectionState(True)
    tracker.setRecordingState(True)

    # Check if eye tracker is returning any data over a short range of time.
    # Quits the trial if the eye tracker if it is not connected or cannot detect eyes.
    connection_counter = 0
    for i in range(100):
        gpos = tracker.getLastGazePosition()
        if not isinstance(gpos, (tuple, list)):
            connection_counter += 1
        time.sleep(0.01)
    if connection_counter > 97:
        print "no connection"
        return

    # Text Values #
    gaze_dot = visual.GratingStim(window,
                                  tex=None,
                                  mask="gauss",
                                  pos=(0, 0),
                                  size=(0.1, 0.1),
                                  color='green',
                                  units='norm')

    instructions_text_stim = visual.TextStim(window,
                                             units='norm',
                                             text=u'Look at blocks',
                                             pos=[0, 0.2],
                                             height=0.1,
                                             color=text_color,
                                             colorSpace='rgb',
                                             alignHoriz='center',
                                             alignVert='center')

    count_label = visual.TextStim(window,
                                  units='norm',
                                  text=u'',
                                  pos=[-0.5, -0.5],
                                  height=0.2,
                                  color=text_color,
                                  colorSpace='rgb255',
                                  alignHoriz='center',
                                  alignVert='center')

    next_label = visual.TextStim(window,
                                 units='norm',
                                 text=u'Eye Round',
                                 pos=[0, 0],
                                 height=0.1,
                                 color=text_color,
                                 colorSpace='rgb',
                                 alignHoriz='center',
                                 alignVert='center')

    # Display round name
    helper.displayNewRound(window, next_label)

    # Set up default values #
    self.hub.clearEvents('all')
    init_time_array = [-1, -1, -1]
    if len(shapes) == 3:
        init_time_array[0] = 0
        init_time_array[1] = 0
        init_time_array[2] = 0
    elif len(shapes) == 2:
        init_time_array[0] = 0
        init_time_array[1] = 0
    elif len(shapes) == 1:
        init_time_array[0] = 0

    time_diff_array = [-1, -1, -1]
    length = len(shapes)

    # block sequence display #
    print "%f BEGIN BLOCK SEQUENCE" % (clock.getTime())
    ser.write("Begin Sequence")
    global in_between_time
    in_between_time = helper.drawSequence(window, shapes, clock)
    ser.write("End Sequence")
    print "%f END BLOCK SEQUENCE" % (clock.getTime())

    # instructions are displayed #
    self.hub.clearEvents('all')
    for nFrames in range(200):
        instructions_text_stim.draw()
        window.flip()

    # for block interaction #
    beg_time = clock.getTime()
    curr_time = clock.getTime()
    self.hub.clearEvents()

    # changes location of shapes if centered, so that they don't overlap #
    if centered and length > 1:
        helper.adjustShapeLoc(shapes)

    # store time right when clicking stimuli is presented for reference
    window.callOnFlip(track_time, clock)

    # draw the interactive stimuli
    [s.draw() for s in shapes]
    window.flip()

    # initialize the block vertices
    shapes_verts = []
    for num in range(len(shapes)):
        shapes_verts.append(
            helper.pix_conv(window.size[0], window.size[1], shapes[num].width,
                            shapes[num].height, shapes[num].pos[0],
                            shapes[num].pos[1]))
    print shapes_verts

    # loop until trial finished or timed out
    while curr_time - beg_time < wait_time:
        [s.draw() for s in shapes]
        count_label.draw()

        # Get the latest gaze position
        gpos = tracker.getLastGazePosition()

        if not isinstance(gpos, (tuple, list)):
            window.flip()
            continue

        # Check if eye position is within each block.
        # If so, then the time is recorded and the opacity is changed accordingly.
        for num in range(length):
            s = shapes[num]
            if s.opacity == 0.0:
                continue
            if isinstance(gpos, (tuple, list)):
                if shapes_verts[num][0] < gpos[0] < shapes_verts[num][
                        1] and shapes_verts[num][3] < gpos[1] < shapes_verts[
                            num][2]:
                    init_time_array[num] += 1
                    time_diff_array[num] = clock.getTime()
                    if init_time_array[num] == REQUIRED_FRAMES / 2:
                        s.setOpacity(0.5)
                    if init_time_array[num] > REQUIRED_FRAMES:
                        s.setOpacity(0.0)
                        init_time_array[num] = clock.getTime()
                    break  # if position is within one block, it could not be in any of the other blocks

                # reset the opacity of the block if the eye looks away for a specified amount time
                # implemented to prevent registering blocks when the eye is just passing over the screen
                elif clock.getTime() - time_diff_array[num] > THRES_TIME_AWAY:
                    init_time_array[num] = 0
                    time_diff_array[num] = -1
                    s.setOpacity(1.0)

        ## EYE TRACKING DISPLAY DOT; NOT NECESSARY FOR ACTUAL IMPLEMENTATION ##
        # if isinstance(gpos,(tuple,list)):
        #     # Adjusting eye tracking values to match norm units to display on the screen
        #     gpos0_adj = (gpos[0]/window.size[1])*2
        #     gpos1_adj = (gpos[1]/window.size[0])*2
        #     gaze_dot.setPos([gpos0_adj, gpos1_adj])
        #     gaze_dot.draw()

        # once the round is finished, use previous counters to calculate total time spent and individual position times
        if helper.checkOpacity(shapes):
            finish_time = clock.getTime()
            total_stimuli_time = finish_time - stimulus_beg_time
            print "\n%f\t%f\t%f" % (init_time_array[0], init_time_array[1],
                                    init_time_array[2])
            print "%f TOTAL TIME TO FINISH ROUND" % (total_stimuli_time)
            break

        num = random.randint(0, 10)
        ser.write(num)  # write random number to Zigbee for syncing
        # gets and saves the eye position and time
        eye_position_time(clock, gpos, text_file)

        # adjust count_down, to be displayed with the next flip
        curr_time = clock.getTime()
        if (curr_time - beg_time) >= (wait_time - warning_time - 0.1):
            count_label.setText(int(round(wait_time - (curr_time - beg_time))),
                                0)

        window.flip()

    # turn off eye tracker
    self.hub.clearEvents('all')
    tracker.setRecordingState(False)
    tracker.setConnectionState(False)

    # save data in the experiment file
    exp.addData("stimulus_begin_time", stimulus_beg_time)
    exp.addData("in_between_time", in_between_time)
    exp.addData("total_stimuli_time", total_stimuli_time)
    exp.addData("time1", init_time_array[0])
    exp.addData("time2", init_time_array[1])
    exp.addData("time3", init_time_array[2])

    # closes the position tracking file at the end A
    text_file.close()

    # return status code based on correctness of sequence
    if (curr_time - beg_time) > wait_time:
        return 2
    if length == 1:
        return 1
    elif length == 2:
        if init_time_array[1] > init_time_array[0]:
            return 1  # correct
        else:
            return 0  # not correct
    elif length == 3:
        if init_time_array[0] < init_time_array[1] < init_time_array[2]:
            return 1  # correct
        else:
            return 0  # not correct
Exemple #9
0
def trial(self, clock, window, shapes, keys, text_color, centered, wait_time,
          warning_time, exp, count, ser):
    """
    Main motor type function
    :param clock: clock used for standardized timing; initialized in the main experimental loop
    :param window: display window
    :param shapes: array of shape objects to be used (not already randomized)
    :param keys: keyboard device
    :param text_color: color for text
    :param centered: true if blocks are to be centered, false otherwise
    :param wait_time: max seconds for trial to wait before continuing if trial is not completed
    :param warning_time: num of seconds left to begin countdown
    :param exp: experiment object for adding trial data
    :param count: number of motor trials during this experiment for file naming
    :param ser: serial port that links to XBee for syncing
    :return: status of trial where 0 = completed but incorrect; 1 = completed and correct; 2 = incomplete
    """

    # Default Value Set Up for Timing #
    global stimulus_beg_time
    stimulus_beg_time = -1
    global in_between_time
    in_between_time = -1
    global total_stimuli_time
    total_stimuli_time = -1

    # Position Tracking File Set Up #
    text_file = open("keys_exp_%d.txt" % count, "w")
    text_file.write("Time\tKey Event\tKey Type\n")

    # Text Values #
    count_label = visual.TextStim(window,
                                  units='norm',
                                  text=u'',
                                  pos=[-0.5, -0.5],
                                  height=0.2,
                                  color=text_color,
                                  colorSpace='rgb255',
                                  alignHoriz='center',
                                  alignVert='center')

    second_label = visual.TextStim(window,
                                   units='norm',
                                   text=u'Press on keyboard.',
                                   pos=[0, 0],
                                   height=0.1,
                                   color=text_color,
                                   colorSpace='rgb255',
                                   alignHoriz='center',
                                   alignVert='center')

    next_label = visual.TextStim(window,
                                 units='norm',
                                 text=u'Motor Round',
                                 pos=[0, 0],
                                 height=0.1,
                                 color=text_color,
                                 colorSpace='rgb',
                                 alignHoriz='center',
                                 alignVert='center')

    # Display round name
    helper.displayNewRound(window, next_label)

    # Set up default values for tracking mouse click timing
    key_times = [-1, -1, -1]
    key_counter = [0, 0, 0]
    length = len(shapes)
    event.clearEvents()

    # block sequence display #
    print "%f BEGIN BLOCK SEQUENCE" % (clock.getTime())
    global in_between_time
    in_between_time = helper.drawSequence(window, shapes, clock)
    print "%f END BLOCK SEQUENCE" % (clock.getTime())

    # instructions are displayed #
    self.hub.clearEvents('all')
    for nFrames in range(200):
        second_label.draw()
        window.flip()

    # for block interaction #
    beg_time = clock.getTime()
    curr_time = clock.getTime()
    self.hub.clearEvents()

    # changes location of shapes if centered, so that they don't overlap
    if centered and length > 1:
        helper.adjustShapeLoc(shapes)

    # Map the blocks in each corner to the respective keyboard events
    keyMap = mapKeys(shapes)

    # store time right when interactive stimuli is presented for reference
    window.callOnFlip(track_time, clock)

    # draw the interactive stimuli
    [s.draw() for s in shapes]
    window.flip()

    temp_time = -1
    key_char = ''
    no_release = False

    # loop until trial finished or timed out
    while curr_time - beg_time < wait_time:
        # redraw the stimuli every window flip
        [s.draw() for s in shapes]
        count_label.draw()
        window.flip()

        # If the shape is pressed long enough to set it to 0 opacity, then the timing of that setting is recorded.
        events = keys.getKeys()  # iohub device keyboard info
        events2 = event.getKeys(
            timeStamped=clock
        )  # event keyboard with event timing based on clock input
        for kbe in events2:  # get accurate timing
            key_char = kbe[0]
            temp_time = kbe[1]
            print kbe
        for kbe in events:  # use for recording keystrokes and durations
            text_file.write(str(clock.getTime()))
            text_file.write("\t")
            text_file.write(kbe.type)
            text_file.write("\t")
            text_file.write(kbe.char)
            text_file.write("\n")
            if kbe.type == 'KEYBOARD_RELEASE':
                no_release = False
            elif kbe.type == 'KEYBOARD_PRESS':
                no_release = True
        if no_release is True:
            if key_char == keyMap[0]:
                key_counter[0] += 1
                if 0 < key_counter[0] < CHNG_INTERVAL:
                    shapes[0].setOpacity(shapes[0].opacity - ADJ_INTERVAL)
                elif key_counter[0] == CHNG_INTERVAL:
                    shapes[0].setOpacity(OPACITY_THRES)
                elif key_counter[0] == REQUIRED_FRAMES:
                    shapes[0].setOpacity(0.0)
                    key_times[0] = temp_time
            elif key_char == keyMap[1]:
                key_counter[1] += 1
                if 0 < key_counter[1] < CHNG_INTERVAL:
                    shapes[1].setOpacity(shapes[1].opacity - ADJ_INTERVAL)
                elif key_counter[1] == CHNG_INTERVAL:
                    shapes[1].setOpacity(OPACITY_THRES)
                elif key_counter[1] == REQUIRED_FRAMES:
                    shapes[1].setOpacity(0.0)
                    key_times[1] = temp_time
            elif key_char == keyMap[2]:
                key_counter[2] += 1
                if 0 < key_counter[2] < CHNG_INTERVAL:
                    shapes[2].setOpacity(shapes[2].opacity - ADJ_INTERVAL)
                elif key_counter[2] == CHNG_INTERVAL:
                    shapes[2].setOpacity(OPACITY_THRES)
                elif key_counter[2] == REQUIRED_FRAMES:
                    shapes[2].setOpacity(0.0)
                    key_times[2] = temp_time

        # once the round is finished, use previous counters to calculate total time spent and individual click times
        if helper.checkOpacity(shapes):
            finish_time = clock.getTime()
            total_stimuli_time = finish_time - stimulus_beg_time
            print "\n%f\t%f\t%f" % (key_times[0], key_times[1], key_times[2])
            print "%f TOTAL TIME TO FINISH ROUND" % (total_stimuli_time)
            break

        # adjust countdown value, to be displayed with the next flip
        curr_time = clock.getTime()
        if (curr_time - beg_time) >= (wait_time - warning_time - 0.1):
            count_label.setText(int(round(wait_time - (curr_time - beg_time))),
                                0)

    event.clearEvents()

    # save data in the experiment file
    global stimulus_beg_time
    exp.addData("stimulus_begin_time", stimulus_beg_time)
    exp.addData("in_between_time", in_between_time)
    exp.addData("total_stimuli_time", total_stimuli_time)
    exp.addData("time1", key_times[0])
    exp.addData("time2", key_times[1])
    exp.addData("time3", key_times[2])

    # return status code based on correctness of sequence
    if (curr_time - beg_time) > wait_time:
        return 2
    if length == 1:
        return 1
    elif length == 2:
        if key_times[1] > key_times[0]:
            return 1  # correct
        else:
            return 0  # not correct
    elif length == 3:
        if key_times[0] < key_times[1] < key_times[2]:
            return 1  # correct
        else:
            return 0  # not correct
    return -1