From 94e1aa8389350186fa0c3255a9cb322248d4061b Mon Sep 17 00:00:00 2001 From: Miles Wells Date: Wed, 11 Dec 2024 13:54:40 +0200 Subject: [PATCH] Exclude spacers from dud protocols --- ibllib/io/extractors/ephys_fpga.py | 21 +++++++++++++++++---- ibllib/pipes/behavior_tasks.py | 2 +- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/ibllib/io/extractors/ephys_fpga.py b/ibllib/io/extractors/ephys_fpga.py index 2980eb7bf..4da3d6bd8 100644 --- a/ibllib/io/extractors/ephys_fpga.py +++ b/ibllib/io/extractors/ephys_fpga.py @@ -69,7 +69,7 @@ """int: The number of encoder pulses per channel for one complete rotation.""" BPOD_FPGA_DRIFT_THRESHOLD_PPM = 150 -"""int: Throws an error if Bpod to FPGA clock drift is higher than this value.""" +"""int: Logs a warning if Bpod to FPGA clock drift is higher than this value.""" CHMAPS = {'3A': {'ap': @@ -545,17 +545,23 @@ def get_main_probe_sync(session_path, bin_exists=False): return sync, sync_chmap -def get_protocol_period(session_path, protocol_number, bpod_sync): +def get_protocol_period(session_path, protocol_number, bpod_sync, exclude_empty_periods=True): """ + Return the start and end time of the protocol number. + + Note that the start time is the start of the spacer pulses and the end time is either None + if the protocol is the final one, or the start of the next spacer. Parameters ---------- session_path : str, pathlib.Path The absolute session path, i.e. '/path/to/subject/yyyy-mm-dd/nnn'. protocol_number : int - The order that the protocol was run in. + The order that the protocol was run in, counted from 0. bpod_sync : dict The sync times and polarities for Bpod BNC1. + exclude_empty_periods : bool + When true, spacers are ignored if no bpod pulses are detected between periods. Returns ------- @@ -565,7 +571,14 @@ def get_protocol_period(session_path, protocol_number, bpod_sync): The time of the next detected spacer or None if this is the last protocol run. """ # The spacers are TTLs generated by Bpod at the start of each protocol - spacer_times = Spacer().find_spacers_from_fronts(bpod_sync) + sp = Spacer() + spacer_times = sp.find_spacers_from_fronts(bpod_sync) + if exclude_empty_periods: + # Drop dud protocol spacers (those without any bpod pulses after the spacer) + spacer_length = len(sp.generate_template(fs=1000)) / 1000 + periods = np.c_[spacer_times + spacer_length, np.r_[spacer_times[1:], np.inf]] + valid = [np.any((bpod_sync['times'] > pp[0]) & (bpod_sync['times'] < pp[1])) for pp in periods] + spacer_times = spacer_times[valid] # Ensure that the number of detected spacers matched the number of expected tasks if acquisition_description := session_params.read_params(session_path): n_tasks = len(acquisition_description.get('tasks', [])) diff --git a/ibllib/pipes/behavior_tasks.py b/ibllib/pipes/behavior_tasks.py index 3f519a10c..be75cf0d6 100644 --- a/ibllib/pipes/behavior_tasks.py +++ b/ibllib/pipes/behavior_tasks.py @@ -20,7 +20,7 @@ from ibllib.pipes import training_status from ibllib.plots.figures import BehaviourPlots -_logger = logging.getLogger('ibllib') +_logger = logging.getLogger(__name__) class HabituationRegisterRaw(base_tasks.RegisterRawDataTask, base_tasks.BehaviourTask):