Пример #1
0
    def test_frame2ttl_flickers(self):
        """
        Frame2ttl can flicker abnormally. One way to detect this is to remove consecutive polarity
        switches under a given threshold
        """
        DISPLAY = False  # for debug purposes
        diff = ephys_fpga.F2TTL_THRESH * np.array([0.5, 10])

        # flicker ends with a polarity switch - downgoing pulse is removed
        t = np.r_[0, np.cumsum(diff[np.array([1, 1, 0, 0, 1])])] + 1
        frame2ttl = {
            'times': t,
            'polarities': np.mod(np.arange(t.size) + 1, 2) * 2 - 1
        }
        expected = {
            'times': np.array([1., 1.1, 1.2, 1.31]),
            'polarities': np.array([1, -1, 1, -1])
        }
        frame2ttl_ = ephys_fpga._clean_frame2ttl(frame2ttl, display=DISPLAY)
        assert all([np.all(frame2ttl_[k] == expected[k]) for k in frame2ttl_])

        # stand-alone flicker
        t = np.r_[0, np.cumsum(diff[np.array([1, 1, 0, 0, 0, 1])])] + 1
        frame2ttl = {
            'times': t,
            'polarities': np.mod(np.arange(t.size) + 1, 2) * 2 - 1
        }
        expected = {
            'times': np.array([1., 1.1, 1.2, 1.215, 1.315]),
            'polarities': np.array([1, -1, 1, -1, 1])
        }
        frame2ttl_ = ephys_fpga._clean_frame2ttl(frame2ttl, display=DISPLAY)
        assert all([np.all(frame2ttl_[k] == expected[k]) for k in frame2ttl_])
Пример #2
0
def extract_task_replay(
    session_path: str, sync: dict = None, sync_map: dict = None, treplay: np.array = None
) -> Tuple[pd.DataFrame, pd.DataFrame]:
    if sync is None or sync_map is None:
        sync, sync_map = ephys_fpga.get_main_probe_sync(session_path, bin_exists=False)

    if treplay is None:
        passivePeriods_df = extract_passive_periods(session_path, sync=sync, sync_map=sync_map)
        treplay = passivePeriods_df.taskReplay.values

    fttl = ephys_fpga.get_sync_fronts(sync, sync_map["frame2ttl"], tmin=treplay[0])
    fttl = ephys_fpga._clean_frame2ttl(fttl)
    passiveGabor_df = _extract_passiveGabor_df(fttl, session_path)

    bpod = ephys_fpga.get_sync_fronts(sync, sync_map["bpod"], tmin=treplay[0])
    passiveValve_intervals = _extract_passiveValve_intervals(bpod)

    task_version = _load_task_protocol(session_path)
    audio = ephys_fpga.get_sync_fronts(sync, sync_map["audio"], tmin=treplay[0])
    passiveTone_intervals, passiveNoise_intervals = _extract_passiveAudio_intervals(audio,
                                                                                    task_version)

    passiveStims_df = np.concatenate(
        [passiveValve_intervals, passiveTone_intervals, passiveNoise_intervals], axis=1
    )
    columns = ["valveOn", "valveOff", "toneOn", "toneOff", "noiseOn", "noiseOff"]
    passiveStims_df = pd.DataFrame(passiveStims_df, columns=columns)
    return (
        passiveGabor_df,
        passiveStims_df,
    )  # _ibl_passiveGabor.table.csv, _ibl_passiveStims.times_table.csv
Пример #3
0
def extract_rfmapping(
    session_path: str, sync: dict = None, sync_map: dict = None, trfm: np.array = None
) -> Tuple[np.array, np.array]:
    meta = _load_passive_stim_meta()
    mkey = (
        "VISUAL_STIM_"
        + {v: k for k, v in meta["VISUAL_STIMULI"].items()}["receptive_field_mapping"]
    )
    if sync is None or sync_map is None:
        sync, sync_map = ephys_fpga.get_main_probe_sync(session_path, bin_exists=False)
    if trfm is None:
        passivePeriods_df = extract_passive_periods(session_path, sync=sync, sync_map=sync_map)
        trfm = passivePeriods_df.RFM.values

    fttl = ephys_fpga.get_sync_fronts(sync, sync_map["frame2ttl"], tmin=trfm[0], tmax=trfm[1])
    fttl = ephys_fpga._clean_frame2ttl(fttl)
    RF_file = Path().joinpath(session_path, "raw_passive_data", "_iblrig_RFMapStim.raw.bin")
    passiveRFM_frames, RF_ttl_trace = _reshape_RF(RF_file=RF_file, meta_stim=meta[mkey])
    rf_id_up, rf_id_dw, RF_n_ttl_expected = _get_id_raisefall_from_analogttl(RF_ttl_trace)
    meta[mkey]["ttl_num"] = RF_n_ttl_expected
    rf_times_on_idx = np.where(np.diff(fttl["times"]) < 1)[0]
    rf_times_off_idx = rf_times_on_idx + 1
    RF_times = fttl["times"][np.sort(np.concatenate([rf_times_on_idx, rf_times_off_idx]))]
    RF_times_1 = RF_times[0::2]
    # Interpolate times for RF before outputting dataset
    passiveRFM_times = _interpolate_rf_mapping_stimulus(
        idxs_up=rf_id_up,
        idxs_dn=rf_id_dw,
        times=RF_times_1,
        Xq=np.arange(passiveRFM_frames.shape[0]),
        t_bin=1 / FRAME_FS,
    )

    return passiveRFM_times  # _ibl_passiveRFM.times.npy
Пример #4
0
def _get_passive_spacers(session_path, sync=None, sync_map=None):
    """
    load and get spacer information, do corr to find spacer timestamps
    returns t_passive_starts, t_starts, t_ends
    """
    if sync is None or sync_map is None:
        sync, sync_map = ephys_fpga.get_main_probe_sync(session_path, bin_exists=False)
    meta = _load_passive_stim_meta()
    # t_end_ephys = passive.ephysCW_end(session_path=session_path)
    fttl = ephys_fpga.get_sync_fronts(sync, sync_map["frame2ttl"], tmin=None)
    fttl = ephys_fpga._clean_frame2ttl(fttl, display=False)
    spacer_template = (
        np.array(meta["VISUAL_STIM_0"]["ttl_frame_nums"], dtype=np.float32) / FRAME_FS
    )
    jitter = 3 / FRAME_FS  # allow for 3 screen refresh as jitter
    t_quiet = meta["VISUAL_STIM_0"]["delay_around"]
    spacer_times, _ = _get_spacer_times(
        spacer_template=spacer_template, jitter=jitter, ttl_signal=fttl["times"], t_quiet=t_quiet
    )

    # Check correct number of spacers found
    n_exp_spacer = np.sum(np.array(meta["STIM_ORDER"]) == 0)  # Hardcoded 0 for spacer
    if n_exp_spacer != np.size(spacer_times) / 2:
        raise ValueError(
            f"The number of expected spacer ({n_exp_spacer}) "
            f"is different than the one found on the raw "
            f"trace ({np.size(spacer_times)/2})"
        )

    spacer_times = np.r_[spacer_times.flatten(), sync["times"][-1]]
    return spacer_times[0], spacer_times[1::2], spacer_times[2::2]
Пример #5
0
def check_stimulus_move_before_goCue(data, photodiode=None, **_):
    """ Check that there are no visual stimulus change(s) between the start of the trial and the
    go cue sound onset - 20 ms.

    Metric: M = number of visual stimulus change events between trial start and goCue_times - 20ms
    Criterion: M == 0
    Units: -none-, integer

    :param data: dict of trial data with keys ('goCue_times', 'intervals', 'choice')
    :param photodiode: the fronts from Bpod's BNC1 input or FPGA frame2ttl channel
    """
    if photodiode is None:
        _log.warning("No photodiode TTL input in function call, returning None")
        return None
    photodiode_clean = ephys_fpga._clean_frame2ttl(photodiode)
    s = photodiode_clean["times"]
    s = s[~np.isnan(s)]  # Remove NaNs
    metric = np.array([])
    for i, c in zip(data["intervals"][:, 0], data["goCue_times"]):
        metric = np.append(metric, np.count_nonzero(s[s > i] < (c - 0.02)))

    passed = (metric == 0).astype(float)
    # Remove no go trials
    passed[data["choice"] == 0] = np.nan
    assert data["intervals"].shape[0] == len(metric) == len(passed)
    return metric, passed
Пример #6
0
    def load_raw_data(self):
        """
        Loads the TTLs, raw task data and task settings
        :return:
        """
        self.log.info(f"Loading raw data from {self.session_path}")
        self.type = self.type or get_session_extractor_type(self.session_path)
        self.settings, self.raw_data = raw.load_bpod(self.session_path)
        # Fetch the TTLs for the photodiode and audio
        if self.type != 'ephys' or self.bpod_only is True:  # Extract from Bpod
            self.frame_ttls, self.audio_ttls = raw.load_bpod_fronts(
                self.session_path, data=self.raw_data)
        else:  # Extract from FPGA
            sync, chmap = ephys_fpga.get_main_probe_sync(self.session_path)

            def channel_events(name):
                """Fetches the polarities and times for a given channel"""
                keys = ('polarities', 'times')
                mask = sync['channels'] == chmap[name]
                return dict(zip(keys, (sync[k][mask] for k in keys)))

            ttls = [ephys_fpga._clean_frame2ttl(channel_events('frame2ttl')),
                    ephys_fpga._clean_audio(channel_events('audio')),
                    channel_events('bpod')]
            self.frame_ttls, self.audio_ttls, self.bpod_ttls = ttls