Skip to content

Commit

Permalink
Simulator fix and orchestrator saving updates (#358)
Browse files Browse the repository at this point in the history
  • Loading branch information
tab-cmd authored Oct 30, 2024
1 parent 437e720 commit be07e59
Show file tree
Hide file tree
Showing 23 changed files with 235 additions and 168 deletions.
51 changes: 41 additions & 10 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,68 @@ Our final release candidate before the official 2.0 release!
- Multimodal Acquisition and Querying
- Support for multiple devices in online querying #286
- Support for trigger handling relative to a given device #293
- Session Orchestrator
- New task protocol for orchestrating tasks in a session. This refactors several Task and Cli functionality #339
- Support multiple device static offests #331
- Support for Device Status (passive or active) #310
- Session Orchestrator #339
- New task protocol for orchestrating tasks in a session. This refactors several Task and Cli functionality #339, #343
- Parameter guardrails #340
- Allow multiple phrases in a single protocol to be defined in a phrase.json and randomized #352
- BciPy Client Additions #346
- Other commands added for offline analysis, visualization and simulation.
- Artifact Module #336
- Simulator #350
- Task
- Calibration Task Refactor: pulls out common elements from RSVP and Matrix calibration tasks #330
- Registry Refactor #332
- Inquiry Preview
- Surface button error probability #347
- Add to Matrix #353
- Bugfixes/Refactor #348
- Add more stoppage criteria #351 (max_incorrect)
- Matrix
- Layout Support #349
- Grid always on #313
- Output stimuli position, screen capture and monitor information after Matrix tasks #303
- Row/Column spacing support #298
- VEP Calibration #304/#296
- session data to VEP calibration #322
- Model
- Offline analysis to support multimodal fusion. Initial release of GazeModel, GazeReshaper, and Gaze Visualization #294
- Language Model
- Add Oracle model #316
- Random Uniform model #311
- Stimuli
- Updates to ensure stimuli are presented at the same frequency #287 Output stimuli position, screen capture and monitor information after Matrix tasks #303
- Updates to ensure stimuli are presented at the same frequency #287
- Dynamic Selection Window
- Updated trial_length to trial_window to allow for greater control of window used after stimulus presentations #291
- Report
- Functionality to generate a report in the form of a PDF #325
- Add a BciPy Calbiraiton Report Action #357
- Offset Support
- Add support for determining offsets between timing verification Tasks (Ex. RSVPTimingVerificationCalibration) and RawData with a photodiode trigger column. This is useful for setting up new systems and preventing errors before an experiment begins. #TODO
- Add support for determining offsets between timing verification Tasks (Ex. RSVPTimingVerificationCalibration) and RawData with a photodiode trigger column. This is useful for setting up new systems and preventing errors before an experiment begins. #327
- Parameters
- Add a Range type parameter #285 Add editable fields #340 Update parameters.json to seperate relevant parameters by task
- Housekeeping
- Add mypy typing to the codebase #301
- Change default log level to INFO to prevent too many messages in the experiment logs #288
- Upgrade requirements for m1/2 chips #299/#300
- Fix GitHub actions build issues with macOS
- Fix occasionally failing test in `test_stimuli` #326
- GUI Refactor
- Fix GitHub actions build issues with macOS #324
- Tests Improvements
- Fix occasionally failing test in `test_stimuli` #326
- Reshaper tests #302
- Fix parameter save as #323
- Pause error #321
- Fix data buffer issue #308
- GUI Refactor #337
- Create new `BCIUI` class for simpler more straightforward UI creation.
- Create dedicated external stylesheet for global styling
- Rewrite Experiment Registry to use new GUI code
- Create intertask action UI
- Task Return Object
- Task Return Object #334
- Create `TaskData` dataclass to be returned from tasks
- updates task `execute` methods to return an instance of `TaskData`
- Allows for optional storage of a save path and task dictionary in `TaskData`
-Experiment Refactor
-Experiment Refactor #333 #329
- Refactors the Experiment Field Collection GUI to be an action
- Allows task protocol to be defined in the orchestrator

Expand Down Expand Up @@ -77,7 +109,6 @@ Our final release candidate before the official 2.0 release!
- added KenLM model `kenlm.py` #268
- added mixture model `mixture.py` and script to tune weights `mixture_tuning.py` #268
- added script to evaluate language model performance `lm_eval.py` #268
- added Oracle model #316
- Signal Model
- added `RdaKdeModel` and restructured to pull out common elements from the PcaRdaKdeModel #279
- Bug Fixes
Expand Down
4 changes: 2 additions & 2 deletions bcipy/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
DEFAULT_USER_ID = 'test_user'
TASK_SEPERATOR = '->'

DEFAULT_PARAMETER_FILENAME = 'parameters.json'
DEFAULT_PARAMETERS_FILENAME = 'parameters.json'
DEFAULT_DEVICES_PATH = f"{BCIPY_ROOT}/parameters"
DEFAULT_PARAMETERS_PATH = f'{BCIPY_ROOT}/parameters/{DEFAULT_PARAMETER_FILENAME}'
DEFAULT_PARAMETERS_PATH = f'{BCIPY_ROOT}/parameters/{DEFAULT_PARAMETERS_FILENAME}'
DEFAULT_DEVICE_SPEC_FILENAME = 'devices.json'
DEVICE_SPEC_PATH = f'{BCIPY_ROOT}/parameters/{DEFAULT_DEVICE_SPEC_FILENAME}'
DEFAULT_LM_PARAMETERS_FILENAME = 'lm_params.json'
Expand Down
2 changes: 0 additions & 2 deletions bcipy/display/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
Display,
InformationProperties,
init_display_window,
PreviewInquiryProperties,
StimuliProperties,
VEPStimuliProperties
)
Expand All @@ -20,5 +19,4 @@
'StimuliProperties',
'VEPStimuliProperties',
'InformationProperties',
'PreviewInquiryProperties'
]
31 changes: 0 additions & 31 deletions bcipy/display/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,37 +251,6 @@ class ButtonPressMode(Enum):
REJECT = 2


class PreviewInquiryProperties:
""""Preview Inquiry Properties.
An encapsulation of properties relevant to preview_inquiry() operation.
"""

def __init__(
self,
preview_on: bool,
preview_only: bool,
preview_inquiry_length: float,
preview_inquiry_progress_method: int,
preview_inquiry_key_input: str,
preview_inquiry_isi: float):
"""Initialize Inquiry Preview Parameters.
preview_on(bool): If True, display an inquiry preview before the main inquiry.
preview_only(bool): If True, only preview the inquiry and do not probe for response
preview_inquiry_length(float): Length of time in seconds to present the inquiry preview
preview_inquiry_progress_method(int): Method of progression for inquiry preview.
0 == preview only; 1 == press to accept inquiry; 2 == press to skip inquiry.
preview_inquiry_key_input(str): Defines which key should be listened to for progressing
preview_inquiry_isi(float): Length of time after displaying the inquiry preview to display a blank screen
"""
self.preview_on = preview_on
self.preview_inquiry_length = preview_inquiry_length
self.preview_inquiry_key_input = preview_inquiry_key_input
self.press_to_accept = True if preview_inquiry_progress_method == 1 else False
self.preview_only = preview_only
self.preview_inquiry_isi = preview_inquiry_isi


class PreviewParams(NamedTuple):
"""Parameters relevant for the Inquiry Preview functionality.
Expand Down
4 changes: 4 additions & 0 deletions bcipy/display/tests/components/test_button_press_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,7 @@ def test_press_to_reject_with_keypress(self, get_key_press_mock):
self.assertTrue(handler.has_response())
self.assertEqual('bcipy_key_press_space', handler.response_label)
self.assertEqual(1.5, handler.response_timestamp)


if __name__ == '__main__':
unittest.main()
4 changes: 2 additions & 2 deletions bcipy/helpers/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from tqdm import tqdm

from bcipy.acquisition.devices import preconfigured_device
from bcipy.config import (DEFAULT_PARAMETER_FILENAME, RAW_DATA_FILENAME,
from bcipy.config import (DEFAULT_PARAMETERS_FILENAME, RAW_DATA_FILENAME,
TRIGGER_FILENAME, SESSION_LOG_FILENAME)
from bcipy.helpers.load import load_json_parameters, load_raw_data
from bcipy.helpers.raw_data import RawData
Expand Down Expand Up @@ -174,7 +174,7 @@ def pyedf_convert(data_dir: str,
otherwise a string of the filter parameters used to filter the data
"""

params = load_json_parameters(str(Path(data_dir, DEFAULT_PARAMETER_FILENAME)),
params = load_json_parameters(str(Path(data_dir, DEFAULT_PARAMETERS_FILENAME)),
value_cast=True)
data = load_raw_data(str(Path(data_dir, f'{RAW_DATA_FILENAME}.csv')))
fs = data.sample_rate
Expand Down
4 changes: 2 additions & 2 deletions bcipy/helpers/demo/demo_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from bcipy.helpers.triggers import trigger_decoder, TriggerType
from bcipy.config import (
BCIPY_ROOT,
DEFAULT_PARAMETER_FILENAME,
DEFAULT_PARAMETERS_FILENAME,
RAW_DATA_FILENAME,
TRIGGER_FILENAME,
DEFAULT_DEVICE_SPEC_FILENAME)
Expand Down Expand Up @@ -44,7 +44,7 @@
if prompt != 'skip':
# load the parameters from the data directory
parameters = load_json_parameters(
f'{session}/{DEFAULT_PARAMETER_FILENAME}', value_cast=True)
f'{session}/{DEFAULT_PARAMETERS_FILENAME}', value_cast=True)

# load the raw data from the data directory
raw_data = load_raw_data(Path(session, f'{RAW_DATA_FILENAME}.csv'))
Expand Down
4 changes: 2 additions & 2 deletions bcipy/helpers/demo/demo_visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"""
import bcipy.acquisition.devices as devices
from bcipy.config import (DEFAULT_DEVICE_SPEC_FILENAME,
DEFAULT_PARAMETER_FILENAME, RAW_DATA_FILENAME,
DEFAULT_PARAMETERS_FILENAME, RAW_DATA_FILENAME,
TRIGGER_FILENAME)
from bcipy.helpers.acquisition import analysis_channels
from bcipy.helpers.load import (load_experimental_data, load_json_parameters,
Expand Down Expand Up @@ -44,7 +44,7 @@
if not path:
path = load_experimental_data()

parameters = load_json_parameters(f'{path}/{DEFAULT_PARAMETER_FILENAME}',
parameters = load_json_parameters(f'{path}/{DEFAULT_PARAMETERS_FILENAME}',
value_cast=True)

# extract all relevant parameters
Expand Down
4 changes: 2 additions & 2 deletions bcipy/helpers/offset.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
DIODE_TRIGGER,
RAW_DATA_FILENAME,
DEFAULT_TRIGGER_CHANNEL_NAME,
DEFAULT_PARAMETER_FILENAME
DEFAULT_PARAMETERS_FILENAME
)


Expand Down Expand Up @@ -343,7 +343,7 @@ def extract_data_latency_calculation(
data_path = ask_directory()

# grab the stim length from the data directory parameters
stim_length = load_json_parameters(f'{data_path}/{DEFAULT_PARAMETER_FILENAME}', value_cast=True)['stim_length']
stim_length = load_json_parameters(f'{data_path}/{DEFAULT_PARAMETERS_FILENAME}', value_cast=True)['stim_length']

raw_data, triggers, static_offset = extract_data_latency_calculation(
data_path,
Expand Down
4 changes: 2 additions & 2 deletions bcipy/helpers/save.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
DEFAULT_EXPERIMENT_ID,
DEFAULT_LM_PARAMETERS_FILENAME,
DEFAULT_LM_PARAMETERS_PATH,
DEFAULT_PARAMETER_FILENAME,
DEFAULT_PARAMETERS_FILENAME,
SIGNAL_MODEL_FILE_SUFFIX,
STIMULI_POSITIONS_FILENAME)
from bcipy.signal.model.base_model import SignalModel
Expand Down Expand Up @@ -95,7 +95,7 @@ def init_save_data_structure(data_save_path: str,
os.makedirs(save_directory)
os.makedirs(os.path.join(save_directory, 'logs'), exist_ok=True)

copyfile(parameters, Path(save_directory, DEFAULT_PARAMETER_FILENAME))
copyfile(parameters, Path(save_directory, DEFAULT_PARAMETERS_FILENAME))

copyfile(DEFAULT_LM_PARAMETERS_PATH, Path(save_directory, DEFAULT_LM_PARAMETERS_FILENAME))

Expand Down
4 changes: 2 additions & 2 deletions bcipy/helpers/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
WHITE = COLOR_INDEX[1]
YELLOW = COLOR_INDEX[5]
from bcipy.config import (BCIPY_ROOT, DEFAULT_ENCODING,
DEFAULT_PARAMETER_FILENAME, EXPERIMENT_DATA_FILENAME,
DEFAULT_PARAMETERS_FILENAME, EXPERIMENT_DATA_FILENAME,
SESSION_DATA_FILENAME, SESSION_SUMMARY_FILENAME)
from bcipy.helpers.load import (load_experiment_fields, load_experiments,
load_json_parameters)
Expand All @@ -37,7 +37,7 @@ def session_data(data_dir: str) -> Dict:
not useful for debugging."""

parameters = load_json_parameters(os.path.join(data_dir,
DEFAULT_PARAMETER_FILENAME),
DEFAULT_PARAMETERS_FILENAME),
value_cast=True)
session = read_session(os.path.join(data_dir, SESSION_DATA_FILENAME))
data = session.as_dict(evidence_only=True)
Expand Down
4 changes: 2 additions & 2 deletions bcipy/helpers/tests/test_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from mockito import mock, unstub, verify, verifyNoMoreInteractions, when

import bcipy.acquisition.devices as devices
from bcipy.config import (DEFAULT_ENCODING, DEFAULT_PARAMETER_FILENAME,
from bcipy.config import (DEFAULT_ENCODING, DEFAULT_PARAMETERS_FILENAME,
RAW_DATA_FILENAME, TRIGGER_FILENAME)
from bcipy.helpers import convert
from bcipy.helpers.convert import (archive_list, compress, convert_to_bdf,
Expand Down Expand Up @@ -64,7 +64,7 @@ def create_bcipy_session_artifacts(
filter_high=filter_settings['filter_high'],
filter_low=filter_settings['filter_low'],
filter_order=filter_settings['filter_order'])
params.save(write_dir, DEFAULT_PARAMETER_FILENAME)
params.save(write_dir, DEFAULT_PARAMETERS_FILENAME)
return trg_data, data, params


Expand Down
4 changes: 2 additions & 2 deletions bcipy/helpers/tests/test_save.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from bcipy.config import (
DEFAULT_PARAMETERS_PATH,
DEFAULT_PARAMETER_FILENAME,
DEFAULT_PARAMETERS_FILENAME,
DEFAULT_EXPERIMENT_ID,
STIMULI_POSITIONS_FILENAME)
from bcipy.helpers import save
Expand Down Expand Up @@ -50,7 +50,7 @@ def test_init_save_data_structure_creates_correct_save_folder(self):
def test_parameter_file_copies(self):

# construct the path of the parameters
param_path = self.save_folder_name + f'/{DEFAULT_PARAMETER_FILENAME}'
param_path = self.save_folder_name + f'/{DEFAULT_PARAMETERS_FILENAME}'

# assert that the params file was created in the correct location
self.assertTrue(os.path.isfile(param_path))
Expand Down
4 changes: 2 additions & 2 deletions bcipy/signal/evaluate/artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import logging

from bcipy.config import (
DEFAULT_PARAMETER_FILENAME,
DEFAULT_PARAMETERS_FILENAME,
RAW_DATA_FILENAME,
TRIGGER_FILENAME,
DEFAULT_DEVICE_SPEC_FILENAME,
Expand Down Expand Up @@ -577,7 +577,7 @@ def write_mne_annotations(
if prompt != 'skip':
# load the parameters from the data directory
parameters = load_json_parameters(
f'{session}/{DEFAULT_PARAMETER_FILENAME}', value_cast=True)
f'{session}/{DEFAULT_PARAMETERS_FILENAME}', value_cast=True)

# load the raw data from the data directory
raw_data = load_raw_data(str(Path(session, f'{RAW_DATA_FILENAME}.csv')))
Expand Down
4 changes: 2 additions & 2 deletions bcipy/signal/tests/model/test_offline_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import random
import gzip

from bcipy.config import RAW_DATA_FILENAME, DEFAULT_PARAMETER_FILENAME, TRIGGER_FILENAME, DEFAULT_DEVICE_SPEC_FILENAME
from bcipy.config import RAW_DATA_FILENAME, DEFAULT_PARAMETERS_FILENAME, TRIGGER_FILENAME, DEFAULT_DEVICE_SPEC_FILENAME
from bcipy.helpers.load import load_json_parameters
from bcipy.signal.model.offline_analysis import offline_analysis

Expand Down Expand Up @@ -48,7 +48,7 @@ def setUpClass(cls):
shutil.copyfile(input_folder / TRIGGER_FILENAME, cls.tmp_dir / TRIGGER_FILENAME)
shutil.copyfile(input_folder / DEFAULT_DEVICE_SPEC_FILENAME, cls.tmp_dir / DEFAULT_DEVICE_SPEC_FILENAME)

params_path = pwd.parent.parent.parent / "parameters" / DEFAULT_PARAMETER_FILENAME
params_path = pwd.parent.parent.parent / "parameters" / DEFAULT_PARAMETERS_FILENAME
cls.parameters = load_json_parameters(params_path, value_cast=True)
models = offline_analysis(
str(cls.tmp_dir),
Expand Down
4 changes: 2 additions & 2 deletions bcipy/simulator/data/data_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from bcipy.acquisition.devices import DeviceSpec
from bcipy.acquisition.multimodal import ContentType
from bcipy.config import (DEFAULT_DEVICE_SPEC_FILENAME,
DEFAULT_PARAMETER_FILENAME, TRIGGER_FILENAME)
DEFAULT_PARAMETERS_FILENAME, TRIGGER_FILENAME)
from bcipy.helpers.acquisition import analysis_channels, raw_data_filename
from bcipy.helpers.list import grouper
from bcipy.helpers.load import load_json_parameters, load_raw_data
Expand Down Expand Up @@ -270,7 +270,7 @@ def process(self, data_folder: str,
raw_data, device_spec = load_device_data(data_folder,
self.content_type.name)
data_parameters = load_json_parameters(
f"{data_folder}/{DEFAULT_PARAMETER_FILENAME}", value_cast=True)
f"{data_folder}/{DEFAULT_PARAMETERS_FILENAME}", value_cast=True)

timing_params = parameters.instantiate(TimingParams)

Expand Down
Loading

0 comments on commit be07e59

Please sign in to comment.