def demo_copy_phrase_wrapper(): # We need to train a dummy model num_x_p = 100 num_x_n = 900 x_p = mean_pos + var_pos * np.random.randn(num_ch, num_x_p, dim_x) x_n = mean_neg + var_neg * np.random.randn(num_ch, num_x_n, dim_x) y_p = [1] * num_x_p y_n = [0] * num_x_n train_x = np.concatenate((x_p, x_n), 1) train_y = np.concatenate((y_p, y_n), 0) permutation = np.random.permutation(train_x.shape[1]) train_x = train_x[:, permutation, :] train_y = train_y[permutation] train_x = train_x[list(np.where(np.asarray(channel_map) == 1)[0]), :, :] k_folds = 10 model, _ = train_pca_rda_kde_model(train_x, train_y, k_folds=k_folds) # Define task and operate task_list = [('I_LOVE_COOKIES', 'I_LOVE_'), ('THIS_IS_A_DEMO', 'THIS_IS_A_')] task = CopyPhraseWrapper(min_num_inq=1, max_num_inq=25, signal_model=model, fs=dim_x * 2, k=1, alp=alphabet(), task_list=task_list) print(task)
def __init__(self, window, clock, experiment_clock, task_color='white', task_font='Times', task_pos=(-.75, .75), task_height=0.1, grid_rows=6, grid_columns=6, time_flash=.25, task_text='1/100', stim_font='Times', stim_pos=(0, .0), stim_height=0.25, is_txt_stim=True, alp=None): self.win = window self.logger = log = logging.getLogger(__name__) # TASK TEXT self.task_font_text = task_font self.task_height = task_height self.task_pos = task_pos self.task_text = task_text self.task_color = task_color # STIM / GRID self.is_txt_stim = is_txt_stim self.stimuli = [] self.rows = grid_rows self.stimuli_font = stim_font self.columns = grid_columns self.stim_height = stim_height self.stim_number = grid_rows + grid_columns self.max_height_grid = -1 + stim_height self.max_width_grid = 1 - stim_height self.uniform_grid_values_row = sorted( np.linspace( start=self.max_height_grid, stop=self.max_width_grid, num=self.rows)) self.uniform_grid_values_col = sorted( np.linspace( start=self.max_height_grid, stop=self.max_width_grid - .25, num=self.columns), reverse=True) if not alp: self.alp = alphabet() else: self.alp = alp self.flash = time_flash # Clocks self.trialClock = clock self.expClock = experiment_clock # Length of the stimuli (number of stimuli on screen) self.stim_length = len(self.stimuli)
def test_alphabet_text(self): parameters_used = 'bcipy/parameters/parameters.json' parameters = load_json_parameters(parameters_used, value_cast=True) parameters['is_txt_stim'] = True alp = alphabet(parameters) self.assertEqual(alp, [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '<', '_' ])
def test_alphabet_images(self): parameters_used = 'bcipy/parameters/parameters.json' parameters = load_json_parameters(parameters_used, value_cast=True) parameters['is_txt_stim'] = False parameters['path_to_presentation_images'] = ('bcipy/static/images/' 'rsvp_images/') alp = alphabet(parameters) self.assertNotEqual(alp, [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'V', 'Y', 'Z', '<', '_' ])
def session_data(data_dir: str, alp=None): """Returns a dict of session data transformed to map the alphabet letter to the likelihood when presenting the evidence. Also removes attributes not useful for debugging.""" # TODO: Better error handling for missing parameters. # Get the alphabet based on the provided parameters (txt or icon). parameters = load_json_parameters(os.path.join(data_dir, "parameters.json"), value_cast=True) if parameters.get('is_txt_sti', False): parameters['is_txt_stim'] = parameters['is_txt_sti'] if not alp: alp = alphabet(parameters=parameters) session_path = os.path.join(data_dir, "session.json") with open(session_path, 'r') as json_file: data = json.load(json_file) data['copy_phrase'] = parameters['task_text'] for epoch in data['epochs'].keys(): for trial in data['epochs'][epoch].keys(): likelihood = dict( zip(alp, data['epochs'][epoch][trial]['likelihood'])) # Remove unused properties unused = [ 'eeg_len', 'timing_sti', 'triggers', 'target_info', 'copy_phrase' ] remove_props(data['epochs'][epoch][trial], unused) data['epochs'][epoch][trial]['stimuli'] = data['epochs'][ epoch][trial]['stimuli'][0] # Associate letters to values data['epochs'][epoch][trial]['lm_evidence'] = dict( zip(alp, data['epochs'][epoch][trial]['lm_evidence'])) data['epochs'][epoch][trial]['eeg_evidence'] = dict( zip(alp, data['epochs'][epoch][trial]['eeg_evidence'])) data['epochs'][epoch][trial]['likelihood'] = likelihood # Display the 5 most likely values. data['epochs'][epoch][trial]['most_likely'] = dict( Counter(likelihood).most_common(5)) return data
def __init__(self, win, daq, parameters, file_save): super(RSVPCalibrationTask, self).__init__() self.window = win self.frame_rate = self.window.getActualFrameRate() self.parameters = parameters self.daq = daq self.static_clock = core.StaticPeriod(screenHz=self.frame_rate) self.experiment_clock = core.Clock() self.buffer_val = parameters['task_buffer_len'] self.alp = alphabet(parameters) self.rsvp = init_calibration_display_task(self.parameters, self.window, self.daq, self.static_clock, self.experiment_clock) self.file_save = file_save trigger_save_location = f"{self.file_save}/{parameters['trigger_file_name']}" self.trigger_file = open(trigger_save_location, 'w', encoding='utf-8') self.wait_screen_message = parameters['wait_screen_message'] self.wait_screen_message_color = parameters[ 'wait_screen_message_color'] self.stim_number = parameters['stim_number'] self.stim_length = parameters['stim_length'] self.timing = [ parameters['time_target'], parameters['time_cross'], parameters['time_flash'] ] self.color = [ parameters['target_letter_color'], parameters['fixation_color'], parameters['stim_color'] ] self.task_info_color = parameters['task_color'] self.stimuli_height = parameters['stim_height'] self.is_txt_stim = parameters['is_txt_stim'] self.eeg_buffer = parameters['eeg_buffer_len'] self.enable_breaks = parameters['enable_breaks']
def __init__(self, path2eeg): self.abc = alphabet() self.samples = eegs(path2eeg)
def test_valid_letters(self): alp = alphabet() cp = CopyPhraseWrapper(min_num_seq=1, max_num_seq=50, signal_model=None, fs=25, k=2, alp=alp, task_list=[('HELLO_WORLD', 'HE')], is_txt_sti=True, device_name='LSL', evidence_names=['LM', 'ERP'], device_channels=[ 'ch1', 'ch2', 'ch3', 'ch4', 'ch5', 'ch6', 'ch7', 'ch8', 'ch9', 'ch10', 'ch11', 'ch12', 'ch13', 'ch14', 'ch15', 'ch16', 'TRG' ], stimuli_timing=[0.5, 0.25]) triggers = [('+', 0.0), ('H', 0.5670222830376588), ('D', 0.8171830819919705), ('J', 1.0843321380089037), ('B', 1.3329724550130777), ('C', 1.5825864360085689), ('A', 1.833380013005808), ('F', 2.083211077027954), ('G', 2.333359022042714), ('I', 2.583265081048012), ('E', 2.833274284028448)] target_info = [ 'nontarget', 'nontarget', 'nontarget', 'nontarget', 'nontarget', 'nontarget', 'nontarget', 'nontarget', 'nontarget', 'nontarget', 'nontarget' ] letters, timings, labels = cp.letter_info(triggers, target_info) expected_letters = ['H', 'D', 'J', 'B', 'C', 'A', 'F', 'G', 'I', 'E'] expected_time = [ 0.5670222830376588, 0.8171830819919705, 1.0843321380089037, 1.3329724550130777, 1.5825864360085689, 1.833380013005808, 2.083211077027954, 2.333359022042714, 2.583265081048012, 2.833274284028448 ] self.assertEqual(expected_letters, letters) self.assertEqual(expected_time, timings) self.assertEqual(len(letters), len(labels)) triggers = [('calibration_trigger', 0.0), ('+', 0.1), ('H', 0.5670222830376588), ('D', 0.8171830819919705), ('J', 1.0843321380089037), ('B', 1.3329724550130777), ('C', 1.5825864360085689), ('A', 1.833380013005808), ('F', 2.083211077027954), ('G', 2.333359022042714), ('I', 2.583265081048012), ('E', 2.833274284028448)] target_info = [ 'calib', 'fixation', 'nontarget', 'nontarget', 'nontarget', 'nontarget', 'nontarget', 'nontarget', 'nontarget', 'nontarget', 'nontarget', 'nontarget' ] letters, timings, labels = cp.letter_info(triggers, target_info) self.assertEqual(expected_letters, letters) self.assertEqual(expected_time, timings) self.assertEqual(['nontarget'] * (len(letters)), labels) # Test it throws an exception when letter is outside alphabet with self.assertRaises(Exception): cp.letter_info([('A', 0.0), ('*', 1.0)], ['nontarget', 'nontarget'])
def __init__(self, win, daq, parameters, file_save, signal_model, language_model, fake, is_word, auc_filename): super(RSVPIconToIconTask, self).__init__() self.window = win self.frame_rate = self.window.getActualFrameRate() self.parameters = parameters self.daq = daq self.static_clock = core.StaticPeriod(screenHz=self.frame_rate) self.experiment_clock = core.Clock() self.buffer_val = parameters['task_buffer_len'] self.image_path = parameters['path_to_presentation_images'] # Alphabet is comprised of the image base names self.alp = alphabet(parameters, include_path=False) self.rsvp = _init_icon_to_icon_display_task( self.parameters, self.window, self.daq, self.static_clock, self.experiment_clock, is_word) self.file_save = file_save self.is_word = is_word trigger_save_location = f'{self.file_save}/{parameters["trigger_file_name"]}' self.trigger_file = open(trigger_save_location, 'w+') self.session_save_location = f'{self.file_save}/{parameters["session_file_name"]}' self.wait_screen_message = parameters['wait_screen_message'] self.wait_screen_message_color = parameters[ 'wait_screen_message_color'] self.stim_number = parameters['stim_number'] self.stim_length = parameters['stim_length'] self.timing = [ parameters['time_target'], parameters['time_cross'], parameters['time_flash'] ] self.color = [ parameters['target_letter_color'], parameters['fixation_color'], parameters['stim_color'] ] self.task_info_color = parameters['task_color'] self.stimuli_height = parameters['stim_height'] self.eeg_buffer = parameters['eeg_buffer_len'] self.max_seconds = parameters['max_minutes'] * 60 # convert to seconds self.max_seq_length = parameters['max_seq_len'] self.max_seq_per_trial = parameters['max_seq_per_trial'] self.fake = fake self.language_model = language_model self.signal_model = signal_model self.auc_filename = auc_filename self.task_height = parameters['task_height'] self.is_txt_stim = False self.min_num_seq = parameters['min_seq_len'] self.word_matching_text_size = parameters['word_matching_text_size'] self.collection_window_len = parameters[ 'collection_window_after_trial_length'] self.data_save_path = parameters['data_save_loc'] match_type = 'Word' if self.is_word else 'Icon' self.session_description = f'Icon to {match_type} Matching'
import logging import sys from typing import List from collections import defaultdict from bcipy.helpers.task import alphabet, SPACE_CHAR from bcipy.language_model import lm_server from bcipy.language_model.errors import (EvidenceDataStructError, NBestError, NBestHighValue) from bcipy.language_model.lm_server import LmServerConfig log = logging.getLogger(__name__) sys.path.append('.') ALPHABET = alphabet() LM_SPACE = '#' class LangModel: DEFAULT_CONFIG = LmServerConfig(image="oclmimage:version2.0", port=6000, docker_port=5000) def __init__(self, server_config: LmServerConfig = DEFAULT_CONFIG, logfile: str = "log"): """ Initiate the langModel class and starts the corresponding docker server for the given type. Input: lmtype - language model type
def session_db(data_dir: str, db_name='session.db', alp=None): """Writes a relational database (sqlite3) of session data that can be used for exploratory analysis. Parameters: ----------- data_dir - directory with the session.json data (and parameters.json) db_name - name of database to write; defaults to session.db alp - optional alphabet to use; may be required if using icons that do not exist on the current machine. Returns: -------- Creates a sqlite3 database and returns a pandas dataframe of the evidence table for use within a repl. Schema: ------ trial: - id: int - target: str evidence: - trial integer (0-based) - sequence integer (0-based) - letter text (letter or icon) - lm real (language model probability for the trial; same for every sequence and only considered in the cumulative value during the first sequence) - eeg real (likelihood for the given sequence; a value of 1.0 indicates that the letter was not presented) - cumulative real (cumulative likelihood for the trial thus far) - seq_position integer (sequence position; null if not presented) - is_target integer (boolean; true(1) if this letter is the target) - presented integer (boolean; true if the letter was presented in this sequence) - above_threshold (boolean; true if cumulative likelihood was above the configured threshold) """ # TODO: Better error handling for missing parameters. # Get the alphabet based on the provided parameters (txt or icon). parameters = load_json_parameters(os.path.join(data_dir, "parameters.json"), value_cast=True) if parameters.get('is_txt_sti', False): parameters['is_txt_stim'] = parameters['is_txt_sti'] if not alp: alp = alphabet(parameters=parameters) session_path = os.path.join(data_dir, "session.json") with open(session_path, 'r') as json_file: data = json.load(json_file) # Create database conn = sqlite3.connect(db_name) cursor = conn.cursor() cursor.execute('CREATE TABLE trial (id integer, target text)') cursor.execute( 'CREATE TABLE evidence (series integer, sequence integer, ' 'stim text, lm real, eeg real, cumulative real, seq_position ' 'integer, is_target integer, presented integer, above_threshold)') conn.commit() for series in data['epochs'].keys(): for i, seq_index in enumerate(data['epochs'][series].keys()): sequence = data['epochs'][series][seq_index] session_type = data['session_type'] target_letter = get_target( session_type, sequence, max(sequence['likelihood']) > parameters['decision_threshold']) stimuli = get_stimuli(session_type, sequence) if i == 0: # create record for the trial conn.executemany('INSERT INTO trial VALUES (?,?)', [(int(series), target_letter)]) lm_ev = dict(zip(alp, sequence['lm_evidence'])) cumulative_likelihoods = dict(zip(alp, sequence['likelihood'])) ev_rows = [] for letter, prob in zip(alp, sequence['eeg_evidence']): seq_position = None if letter in stimuli: seq_position = stimuli.index(letter) if target_letter: is_target = 1 if target_letter == letter else 0 else: is_target = None cumulative = cumulative_likelihoods[letter] above_threshold = cumulative >= parameters[ 'decision_threshold'] ev_row = (int(series), int(seq_index), letter, lm_ev[letter], prob, cumulative, seq_position, is_target, seq_position is not None, above_threshold) ev_rows.append(ev_row) conn.executemany( 'INSERT INTO evidence VALUES (?,?,?,?,?,?,?,?,?,?)', ev_rows) conn.commit() dataframe = pd.read_sql_query("SELECT * FROM evidence", conn) conn.close() return dataframe
def __init__(self, win, daq, parameters, file_save, signal_model, language_model, fake): super(RSVPCopyPhraseTask, self).__init__() self.window = win self.frame_rate = self.window.getActualFrameRate() self.parameters = parameters self.daq = daq self.static_clock = core.StaticPeriod(screenHz=self.frame_rate) self.experiment_clock = core.Clock() self.buffer_val = parameters['task_buffer_len'] self.alp = alphabet(parameters) self.rsvp = _init_copy_phrase_display(self.parameters, self.window, self.daq, self.static_clock, self.experiment_clock) self.file_save = file_save trigger_save_location = f"{self.file_save}/{parameters['trigger_file_name']}" self.trigger_file = open(trigger_save_location, 'w') self.session_save_location = f"{self.file_save}/{parameters['session_file_name']}" self.wait_screen_message = parameters['wait_screen_message'] self.wait_screen_message_color = parameters[ 'wait_screen_message_color'] self.stim_number = parameters['stim_number'] self.stim_length = parameters['stim_length'] self.time_cross = parameters['time_cross'] self.time_target = parameters['time_target'] self.time_flash = parameters['time_flash'] self.timing = [self.time_target, self.time_cross, self.time_flash] self.color = [ parameters['target_color'], parameters['fixation_color'], parameters['stim_color'] ] self.task_info_color = parameters['task_color'] self.stimuli_height = parameters['stim_height'] self.is_txt_stim = parameters['is_txt_stim'] self.eeg_buffer = parameters['eeg_buffer_len'] self.copy_phrase = parameters['task_text'] self.spelled_letters_count = int(parameters['spelled_letters_count']) if self.spelled_letters_count > len(self.copy_phrase): self.logger.debug('Already spelled letters exceeds phrase length.') self.spelled_letters_count = 0 self.max_inq_length = parameters['max_inq_len'] self.max_seconds = parameters['max_minutes'] * 60 # convert to seconds self.max_inq_per_trial = parameters['max_inq_per_trial'] self.fake = fake self.language_model = language_model self.signal_model = signal_model self.down_sample_rate = parameters['down_sampling_rate'] self.filter_low = self.parameters['filter_low'] self.filter_high = self.parameters['filter_high'] self.fitler_order = self.parameters['filter_order'] self.notch_filter_frequency = self.parameters['notch_filter_frequency'] self.min_num_inq = parameters['min_inq_len'] self.collection_window_len = parameters['trial_length'] self.static_offset = parameters['static_trigger_offset'] self.show_feedback = parameters['show_feedback'] self.feedback_color = parameters['feedback_message_color'] if self.show_feedback: self.feedback = VisualFeedback(self.window, self.parameters, self.experiment_clock)