Exemplo n.º 1
0
 def test_ibl_sync_maps(self):
     s = ephys_fpga.get_ibl_sync_map({'ap': 'toto', 'path': self.workdir}, '3A')
     self.assertEqual(s, ephys_fpga.CHMAPS['3A']['ap'])
     s = ephys_fpga.get_ibl_sync_map({'nidq': 'toto', 'path': self.workdir}, '3B')
     self.assertEqual(s, ephys_fpga.CHMAPS['3B']['nidq'])
     s = ephys_fpga.get_ibl_sync_map({'ap': 'toto', 'path': self.workdir}, '3B')
     self.assertEqual(s, ephys_fpga.CHMAPS['3B']['ap'])
Exemplo n.º 2
0
def version3B(ses_path, display=True, type=None, tol=2.5):
    """
    From a session path with _spikeglx_sync arrays extraccted, locate ephys files for 3A and
     outputs one sync.timestamps.probeN.npy file per acquired probe. By convention the reference
     probe is the one with the most synchronisation pulses.
     Assumes the _spikeglx_sync datasets are already extracted from binary data
    :param ses_path:
    :param type: linear, exact or smooth
    :return: None
    """
    DEFAULT_TYPE = 'smooth'
    ephys_files = spikeglx.glob_ephys_files(ses_path, bin_exists=False)
    for ef in ephys_files:
        ef['sync'] = alf.io.load_object(ef.path,
                                        'sync',
                                        namespace='spikeglx',
                                        short_keys=True)
        ef['sync_map'] = get_ibl_sync_map(ef, '3B')
    nidq_file = [ef for ef in ephys_files if ef.get('nidq')]
    ephys_files = [ef for ef in ephys_files if not ef.get('nidq')]
    # should have at least 2 probes and only one nidq
    assert (len(nidq_file) == 1)
    nidq_file = nidq_file[0]
    sync_nidq = _get_sync_fronts(nidq_file.sync,
                                 nidq_file.sync_map['imec_sync'])

    qc_all = True
    out_files = []
    for ef in ephys_files:
        sync_probe = _get_sync_fronts(ef.sync, ef.sync_map['imec_sync'])
        sr = _get_sr(ef)
        try:
            assert (sync_nidq.times.size == sync_probe.times.size)
        except AssertionError:
            raise Neuropixel3BSyncFrontsNonMatching(f"{ses_path}")
        # if the qc of the diff finds anomalies, do not attempt to smooth the interp function
        qcdiff = _check_diff_3b(sync_probe)
        if not qcdiff:
            qc_all = False
            type_probe = type or 'exact'
        else:
            type_probe = type or DEFAULT_TYPE
        timestamps, qc = sync_probe_front_times(sync_probe.times,
                                                sync_nidq.times,
                                                sr,
                                                display=display,
                                                type=type_probe,
                                                tol=tol)
        qc_all &= qc
        out_files.extend(_save_timestamps_npy(ef, timestamps, sr))
    return qc_all, out_files
Exemplo n.º 3
0
def version3A(ses_path, display=True, linear=False, tol=1.5):
    """
    From a session path with _spikeglx_sync arrays extracted, locate ephys files for 3A and
     outputs one sync.timestamps.probeN.npy file per acquired probe. By convention the reference
     probe is the one with the most synchronisation pulses.
     Assumes the _spikeglx_sync datasets are already extracted from binary data
    :param ses_path:
    :return: bool True on a a successful sync
    """
    ephys_files = spikeglx.glob_ephys_files(ses_path)
    nprobes = len(ephys_files)
    if nprobes <= 1:
        _logger.warning(f"Skipping single probe session: {ses_path}")
        return True
    d = Bunch({'times': [], 'nsync': np.zeros(nprobes, )})
    for ind, ephys_file in enumerate(ephys_files):
        sync = alf.io.load_object(ephys_file.ap.parent,
                                  '_spikeglx_sync',
                                  short_keys=True)
        sync_map = get_ibl_sync_map(ephys_file, '3A')
        isync = np.in1d(sync['channels'], np.array([sync_map['right_camera']]))
        d.nsync[ind] = len(sync.channels)
        d['times'].append(sync['times'][isync])
    # chop off to the lowest number of sync points
    nsyncs = [t.size for t in d['times']]
    if len(set(nsyncs)) > 1:
        _logger.warning(
            "Probes don't have the same number of synchronizations pulses")
    d['times'] = np.r_[[t[:min(nsyncs)] for t in d['times']]].transpose()

    # the reference probe is the one with the most sync pulses detected
    iref = np.argmax(d.nsync)
    # islave = np.setdiff1d(np.arange(nprobes), iref)
    # get the sampling rate from the reference probe using metadata file
    sr = _get_sr(ephys_files[iref])
    qc_all = True
    # output timestamps files as per ALF convention
    for ind, ephys_file in enumerate(ephys_files):
        if ind == iref:
            timestamps = np.array([[0, 0], [1, 1]])
        else:
            timestamps, qc = sync_probe_front_times(d.times[:, iref],
                                                    d.times[:, ind],
                                                    sr,
                                                    display=display,
                                                    linear=linear,
                                                    tol=tol)
            qc_all &= qc
        _save_timestamps_npy(ephys_file, timestamps)
    return qc_all
Exemplo n.º 4
0
 def get_sync_fronts(auxiliary_name):
     d = Bunch({'times': [], 'nsync': np.zeros(nprobes, )})
     # auxiliary_name: frame2ttl or right_camera
     for ind, ephys_file in enumerate(ephys_files):
         sync = alf.io.load_object(ephys_file.ap.parent, '_spikeglx_sync', short_keys=True)
         sync_map = get_ibl_sync_map(ephys_file, '3A')
         # exits if sync label not found for current probe
         if auxiliary_name not in sync_map:
             return
         isync = np.in1d(sync['channels'], np.array([sync_map[auxiliary_name]]))
         # only returns syncs if we get fronts for all probes
         if np.all(~isync):
             return
         d.nsync[ind] = len(sync.channels)
         d['times'].append(sync['times'][isync])
     return d
Exemplo n.º 5
0
def version3B(ses_path, display=True, linear=False, tol=2.5):
    """
    From a session path with _spikeglx_sync arrays extraccted, locate ephys files for 3A and
     outputs one sync.timestamps.probeN.npy file per acquired probe. By convention the reference
     probe is the one with the most synchronisation pulses.
     Assumes the _spikeglx_sync datasets are already extracted from binary data
    :param ses_path:
    :return: None
    """
    ephys_files = spikeglx.glob_ephys_files(ses_path)
    for ef in ephys_files:
        ef['sync'] = alf.io.load_object(ef.path,
                                        '_spikeglx_sync',
                                        short_keys=True)
        ef['sync_map'] = get_ibl_sync_map(ef, '3B')
    nidq_file = [ef for ef in ephys_files if ef.get('nidq')]
    ephys_files = [ef for ef in ephys_files if not ef.get('nidq')]
    nprobes = len(ephys_files)
    # should have at least 2 probes and only one nidq
    if nprobes <= 1:
        return True
    assert (len(nidq_file) == 1)
    nidq_file = nidq_file[0]
    sync_nidq = _get_sync_fronts(nidq_file.sync,
                                 nidq_file.sync_map['imec_sync'])

    qc_all = True
    for ef in ephys_files:
        sync_probe = _get_sync_fronts(ef.sync, ef.sync_map['imec_sync'])
        sr = _get_sr(ef)
        assert (sync_nidq.times.size == sync_probe.times.size)
        timestamps, qc = sync_probe_front_times(sync_probe.times,
                                                sync_nidq.times,
                                                sr,
                                                display=display,
                                                linear=linear,
                                                tol=tol)
        qc_all &= qc
        _save_timestamps_npy(ef, timestamps)
    return qc_all