|
| 1 | +"""Demo VEP display""" |
1 | 2 | import logging
|
2 | 3 | import sys
|
3 |
| - |
4 |
| -from psychopy import core |
| 4 | +from typing import Any, List |
5 | 5 |
|
6 | 6 | from bcipy.display import (InformationProperties, VEPStimuliProperties,
|
7 | 7 | init_display_window)
|
8 | 8 | from bcipy.display.components.layout import centered
|
9 | 9 | from bcipy.display.components.task_bar import CalibrationTaskBar
|
| 10 | +from bcipy.display.paradigm.vep.codes import DEFAULT_FLICKER_RATES |
10 | 11 | from bcipy.display.paradigm.vep.display import VEPDisplay
|
11 | 12 | from bcipy.display.paradigm.vep.layout import BoxConfiguration
|
12 | 13 | from bcipy.helpers.clock import Clock
|
| 14 | +from bcipy.helpers.system_utils import get_screen_info |
13 | 15 |
|
14 | 16 | root = logging.getLogger()
|
15 | 17 | root.setLevel(logging.DEBUG)
|
|
26 | 28 | info_text=['VEP Display Demo'],
|
27 | 29 | )
|
28 | 30 |
|
29 |
| -task_text = ['1/4', '2/4', '3/4', '4/4'] |
30 |
| -num_boxes = 6 |
31 |
| - |
| 31 | +task_text = ['1/3', '2/3', '3/3'] |
| 32 | +stim_screen = 0 |
32 | 33 | window_parameters = {
|
33 | 34 | 'full_screen': False,
|
34 | 35 | 'window_height': 700,
|
35 | 36 | 'window_width': 700,
|
36 |
| - 'stim_screen': 1, |
| 37 | + 'stim_screen': stim_screen, |
37 | 38 | 'background_color': 'black'
|
38 | 39 | }
|
39 | 40 | win = init_display_window(window_parameters)
|
40 | 41 | win.recordFrameIntervals = True
|
41 |
| -frameRate = win.getActualFrameRate() |
| 42 | +frame_rate = win.getActualFrameRate() |
| 43 | +if not frame_rate: |
| 44 | + # Allow the demo to work using the configured rate. |
| 45 | + frame_rate = get_screen_info(stim_screen).rate |
42 | 46 |
|
43 |
| -print(f'Monitor refresh rate: {frameRate} Hz') |
| 47 | +print(f'Monitor refresh rate: {frame_rate} Hz') |
44 | 48 |
|
45 |
| -box_colors = ['#00FF80', '#FFFFB3', '#CB99FF', '#FB8072', '#80B1D3', '#FF8232'] |
46 |
| -stim_color = [[color] for i, color in enumerate(box_colors) if i < num_boxes] |
| 49 | +stim_color = [ |
| 50 | + 'green', 'red', '#00FF80', '#FFFFB3', '#CB99FF', '#FB8072', '#80B1D3', |
| 51 | + '#FF8232' |
| 52 | +] |
47 | 53 |
|
48 | 54 | layout = centered(width_pct=0.95, height_pct=0.80)
|
49 |
| -box_config = BoxConfiguration(layout, num_boxes=num_boxes) |
| 55 | +box_config = BoxConfiguration(layout, height_pct=0.30) |
50 | 56 |
|
51 | 57 | experiment_clock = Clock()
|
52 | 58 | len_stimuli = 10
|
53 |
| -stimuli = VEPStimuliProperties( |
54 |
| - stim_color=stim_color, |
| 59 | +stim_props = VEPStimuliProperties( |
| 60 | + stim_font=font, |
55 | 61 | stim_pos=box_config.positions,
|
56 | 62 | stim_height=0.1,
|
57 |
| - stim_font=font, |
58 |
| - timing=(1, 0.5, 2, 4), # prompt, fixation, animation, stimuli |
| 63 | + timing=[4, 0.5, 4], # target, fixation, stimuli |
| 64 | + stim_color=stim_color, |
| 65 | + inquiry=[], |
59 | 66 | stim_length=1, # how many times to stimuli
|
60 |
| -) |
61 |
| -task_bar = CalibrationTaskBar(win, |
62 |
| - inquiry_count=4, |
63 |
| - current_index=0, |
64 |
| - font=font) |
65 |
| -vep = VEPDisplay(win, experiment_clock, stimuli, task_bar, info, box_config=box_config) |
66 |
| -timing = [] |
| 67 | + animation_seconds=2.0) |
| 68 | +task_bar = CalibrationTaskBar(win, inquiry_count=3, current_index=0, font=font) |
| 69 | +vep = VEPDisplay(win, |
| 70 | + experiment_clock, |
| 71 | + stim_props, |
| 72 | + task_bar, |
| 73 | + info, |
| 74 | + box_config=box_config, |
| 75 | + flicker_rates=DEFAULT_FLICKER_RATES, |
| 76 | + should_prompt_target=True, |
| 77 | + frame_rate=frame_rate) |
67 | 78 | wait_seconds = 2
|
68 | 79 |
|
| 80 | +inquiries: List[List[Any]] = [[ |
| 81 | + 'U', '+', ['C', 'M', 'S'], ['D', 'P', 'X', '_'], ['L', 'U', 'Y'], |
| 82 | + ['E', 'K', 'O'], ['<', 'A', 'F', 'H', 'I', 'J', 'N', 'Q', 'R', 'V', 'Z'], |
| 83 | + ['B', 'G', 'T', 'W'] |
| 84 | +], |
| 85 | + [ |
| 86 | + 'D', '+', ['O', 'X'], ['D'], ['P', 'U'], |
| 87 | + ['<', 'B', 'E', 'G', 'H', 'J', 'K', 'L', 'R', 'T'], |
| 88 | + ['A', 'C', 'F', 'I', 'M', 'N', 'Q', 'V', 'Y', '_'], |
| 89 | + ['S', 'W', 'Z'] |
| 90 | +], |
| 91 | + [ |
| 92 | + 'S', '+', ['A', 'J', 'K', 'T', 'V', 'W'], ['S'], ['_'], |
| 93 | + ['E', 'G', 'M', 'R'], |
| 94 | + [ |
| 95 | + '<', 'B', 'C', 'D', 'H', 'I', 'L', 'N', 'O', 'P', 'Q', |
| 96 | + 'U', 'X', 'Z' |
| 97 | + ], ['F', 'Y'] |
| 98 | +]] |
| 99 | + |
| 100 | +timing = [] |
69 | 101 | # loop over the text and colors, present the stimuli and record the timing
|
70 |
| -for txt in task_text: |
| 102 | +for i, txt in enumerate(task_text): |
71 | 103 | vep.update_task_bar(txt)
|
72 |
| - if num_boxes == 4: |
73 |
| - stim = [['A', 'B'], ['Z'], ['P'], ['R', 'W']] |
74 |
| - if num_boxes == 6: |
75 |
| - stim = [['A'], ['B'], ['Z', 'X'], ['P', 'I'], ['R'], ['W', 'C']] |
76 |
| - vep.schedule_to(stimuli=stim) |
| 104 | + inq = inquiries[i] |
| 105 | + vep.schedule_to(stimuli=inq) |
77 | 106 | timing += vep.do_inquiry()
|
78 | 107 |
|
79 |
| - # show the wait screen, this will only happen once |
80 |
| - while wait_seconds > 0: |
81 |
| - wait_seconds -= 1 |
82 |
| - vep.wait_screen(f"Waiting for {wait_seconds}s", color='white') |
83 |
| - core.wait(1) |
84 |
| - |
85 | 108 | print(timing)
|
86 | 109 | win.close()
|
0 commit comments