def from_path(session_path, force=False, save=True): """ Extract a session from full ALF path (ex: '/scratch/witten/ibl_witten_01/2018-12-18/001') :param force: (False) overwrite existing files :param save: (True) boolean or list of ALF file names to extract :return: None """ extractor_type = get_session_extractor_type(session_path) logger_.info(f"Extracting {session_path} as {extractor_type}") if is_extracted(session_path) and not force: logger_.info(f"Session {session_path} already extracted.") return if extractor_type == 'training': settings, data = raw.load_bpod(session_path) logger_.info('training session on ' + settings['PYBPOD_BOARD']) training_trials.extract_all(session_path, data=data, save=save) training_wheel.extract_all(session_path, bp_data=data, save=save) logger_.info('session extracted \n') # timing info in log if extractor_type == 'biased': settings, data = raw.load_bpod(session_path) logger_.info('biased session on ' + settings['PYBPOD_BOARD']) biased_trials.extract_all(session_path, data=data, save=save) biased_wheel.extract_all(session_path, bp_data=data, save=save) logger_.info('session extracted \n') # timing info in log if extractor_type == 'ephys': data = raw.load_data(session_path) logger_.info('extract BPOD for ephys session') ephys_trials.extract_all(session_path, data=data, save=save) logger_.info('extract FPGA information for ephys session') ephys_fpga.extract_all(session_path, save=save) if extractor_type == 'sync_ephys': ephys_fpga.extract_sync(session_path, save=save)
def sync_gen(self, fn, ns, nc, sync_depth): # nidq has 1 analog and 1 digital sync channels with tempfile.TemporaryDirectory() as tdir: ses_path = Path(tdir).joinpath('raw_ephys_data') ses_path.mkdir(parents=True, exist_ok=True) bin_file = ses_path.joinpath(fn).with_suffix('.bin') nidq = spikeglx._mock_spikeglx_file(bin_file, self.workdir / fn, ns=ns, nc=nc, sync_depth=sync_depth) syncs, files = ephys_fpga.extract_sync(tdir) self.assertTrue(np.all(syncs[0].channels[slice(1, None, 2)] == np.arange(0, nidq['sync_depth']))) with self.assertLogs(level='INFO') as log: ephys_fpga.extract_sync(tdir) self.assertEqual(1, len(log.output)) self.assertIn('SGLX sync found', log.output[0])
def extract_pulses(session_path, overwrite=False): # outputs numpy syncs, out_files = ephys_fpga.extract_sync(session_path, overwrite=overwrite) for out_file in out_files: _logger.info(f"extracted pulses for {out_file}") status, sync_files = sync_probes.sync(session_path) return out_files + sync_files
def validate_ttl_test(ses_path, display=False): """ For a mock session on the Ephys Choice world task, check the sync channels for all device properly connected and perform a synchronization if dual probes to check that all channels are recorded properly :param ses_path: session path :param display: show the probe synchronization plot if several probes :return: True if tests pass, errors otherwise """ def _single_test(assertion, str_ok, str_ko): if assertion: _logger.info(str_ok) return True else: _logger.error(str_ko) return False EXPECTED_RATES_HZ = {'left_camera': 60, 'right_camera': 150, 'body_camera': 30} SYNC_RATE_HZ = 1 MIN_TRIALS_NB = 6 ok = True ses_path = Path(ses_path) if not ses_path.exists(): return False # get the synchronization fronts (from the raw binary if necessary) ephys_fpga.extract_sync(session_path=ses_path, overwrite=False) rawsync, sync_map = ephys_fpga.get_main_probe_sync(ses_path) last_time = rawsync['times'][-1] # get upgoing fronts for each sync = Bunch({}) for k in sync_map: fronts = ephys_fpga._get_sync_fronts(rawsync, sync_map[k]) sync[k] = fronts['times'][fronts['polarities'] == 1] wheel = ephys_fpga.extract_wheel_sync(rawsync, chmap=sync_map) frame_rates = {'right_camera': np.round(1 / np.median(np.diff(sync.right_camera))), 'left_camera': np.round(1 / np.median(np.diff(sync.left_camera))), 'body_camera': np.round(1 / np.median(np.diff(sync.body_camera)))} # check the camera frame rates for lab in frame_rates: expect = EXPECTED_RATES_HZ[lab] ok &= _single_test(assertion=abs((1 - frame_rates[lab] / expect)) < 0.1, str_ok=f'PASS: {lab} frame rate: {frame_rates[lab]} = {expect} Hz', str_ko=f'FAILED: {lab} frame rate: {frame_rates[lab]} != {expect} Hz') # check that the wheel has a minimum rate of activity on both channels re_test = abs(1 - sync.rotary_encoder_1.size / sync.rotary_encoder_0.size) < 0.1 re_test &= len(wheel[1]) / last_time > 5 ok &= _single_test(assertion=re_test, str_ok="PASS: Rotary encoder", str_ko="FAILED: Rotary encoder") # check that the frame 2 ttls has a minimum rate of activity ok &= _single_test(assertion=len(sync.frame2ttl) / last_time > 0.2, str_ok="PASS: Frame2TTL", str_ko="FAILED: Frame2TTL") # the audio has to have at least one event per trial ok &= _single_test(assertion=len(sync.bpod) > len(sync.audio) > MIN_TRIALS_NB, str_ok="PASS: audio", str_ko="FAILED: audio") # the bpod has to have at least twice the amount of min trial pulses ok &= _single_test(assertion=len(sync.bpod) > MIN_TRIALS_NB * 2, str_ok="PASS: Bpod", str_ko="FAILED: Bpod") try: # note: tried to depend as little as possible on the extraction code but for the valve... behaviour = ephys_fpga.extract_behaviour_sync(rawsync, chmap=sync_map) res = behaviour.valveOpen_times.size > 1 except AssertionError: res = False # check that the reward valve is actionned at least once ok &= _single_test(assertion=res, str_ok="PASS: Valve open", str_ko="FAILED: Valve open not detected") _logger.info('ALL CHECKS PASSED !') # the imec sync is for 3B Probes only if sync.get('imec_sync') is not None: ok &= _single_test(assertion=np.all(1 - SYNC_RATE_HZ * np.diff(sync.imec_sync) < 0.1), str_ok="PASS: imec sync", str_ko="FAILED: imec sync") # second step is to test that we can make the sync. Assertions are whithin the synch code if sync.get('imec_sync') is not None: sync_result, _ = sync_probes.version3B(ses_path, display=display) else: sync_result, _ = sync_probes.version3A(ses_path, display=display) ok &= _single_test(assertion=sync_result, str_ok="PASS: synchronisation", str_ko="FAILED: probe synchronizations threshold exceeded") if not ok: raise ValueError('FAILED TTL test') return ok
def _run(self, overwrite=False): syncs, out_files = ephys_fpga.extract_sync(self.session_path, overwrite=overwrite) for out_file in out_files: _logger.info(f"extracted pulses for {out_file}") return out_files
def _run(self, overwrite=False): syncs, out_files = ephys_fpga.extract_sync(self.session_path, overwrite=overwrite) return out_files