Beispiel #1
0
def assess_bads(raw_fname, is_eroom=False):
    '''Code sampled from MNE python website
    https://mne.tools/dev/auto_tutorials/preprocessing/\
        plot_60_maxwell_filtering_sss.html'''
    from mne.preprocessing import find_bad_channels_maxwell
    raw = mne.io.read_raw_fif(raw_fname)
    if raw.times[-1] > 60.0:
        raw.crop(tmax=60)
    raw.info['bads'] = []
    raw_check = raw.copy()
    if is_eroom == False:
        auto_noisy_chs, auto_flat_chs, auto_scores = find_bad_channels_maxwell(
            raw_check,
            cross_talk=None,
            calibration=None,
            return_scores=True,
            verbose=True)
    else:
        auto_noisy_chs, auto_flat_chs, auto_scores = find_bad_channels_maxwell(
            raw_check,
            cross_talk=None,
            calibration=None,
            return_scores=True,
            verbose=True,
            coord_frame="meg")

    return {'noisy': auto_noisy_chs, 'flat': auto_flat_chs}
Beispiel #2
0
def find_bad_channels_maxwell_util(raw_):
    """ Inplace update of bad channels.
    Find noisy and flat channels according to the Maxwell filter.
    """
    raw_.info['bads'] = []
    raw_check = raw_.copy()
    auto_noisy_chs, auto_flat_chs, auto_scores = find_bad_channels_maxwell(
        raw_check,
        # cross_talk=crosstalk_file,
        calibration=fine_cal_file,
        return_scores=True,
        verbose=True,
        coord_frame="meg")

    print("auto_noisy_chs", auto_noisy_chs)
    print("auto_flat_chs", auto_flat_chs)
    bads = raw_.info['bads'] + auto_noisy_chs + auto_flat_chs
    raw_.info['bads'] = bads
    raw_.auto_scores = auto_scores
Beispiel #3
0
def find_bad_channels(raw, subject, session, task, run):
    if (config.find_flat_channels_meg and not config.find_noisy_channels_meg):
        msg = 'Finding flat channels.'
    elif (config.find_noisy_channels_meg
          and not config.find_flat_channels_meg):
        msg = 'Finding noisy channels using Maxwell filtering.'
    else:
        msg = ('Finding flat channels, and noisy channels using '
               'Maxwell filtering.')

    logger.info(
        gen_log_message(message=msg, step=1, subject=subject, session=session))

    bids_path = BIDSPath(subject=subject,
                         session=session,
                         task=task,
                         run=run,
                         acquisition=config.acq,
                         processing=config.proc,
                         recording=config.rec,
                         space=config.space,
                         suffix=config.get_datatype(),
                         datatype=config.get_datatype(),
                         root=config.deriv_root)

    auto_noisy_chs, auto_flat_chs, auto_scores = find_bad_channels_maxwell(
        raw=raw,
        calibration=get_mf_cal_fname(subject, session),
        cross_talk=get_mf_ctc_fname(subject, session),
        return_scores=True)

    preexisting_bads = raw.info['bads'].copy()
    bads = preexisting_bads.copy()

    if config.find_flat_channels_meg:
        msg = f'Found {len(auto_flat_chs)} flat channels.'
        logger.info(
            gen_log_message(message=msg,
                            step=1,
                            subject=subject,
                            session=session))
        bads.extend(auto_flat_chs)
    if config.find_noisy_channels_meg:
        msg = f'Found {len(auto_noisy_chs)} noisy channels.'
        logger.info(
            gen_log_message(message=msg,
                            step=1,
                            subject=subject,
                            session=session))
        bads.extend(auto_noisy_chs)

    bads = sorted(set(bads))
    raw.info['bads'] = bads
    msg = f'Marked {len(raw.info["bads"])} channels as bad.'
    logger.info(
        gen_log_message(message=msg, step=1, subject=subject, session=session))

    if config.find_noisy_channels_meg:
        auto_scores_fname = bids_path.copy().update(suffix='scores',
                                                    extension='.json',
                                                    check=False)
        with open(auto_scores_fname, 'w') as f:
            json_tricks.dump(auto_scores,
                             fp=f,
                             allow_nan=True,
                             sort_keys=False)

        if config.interactive:
            import matplotlib.pyplot as plt
            config.plot_auto_scores(auto_scores)
            plt.show()

    # Write the bad channels to disk.
    bads_tsv_fname = bids_path.copy().update(suffix='bads',
                                             extension='.tsv',
                                             check=False)
    bads_for_tsv = []
    reasons = []

    if config.find_flat_channels_meg:
        bads_for_tsv.extend(auto_flat_chs)
        reasons.extend(['auto-flat'] * len(auto_flat_chs))
        preexisting_bads = set(preexisting_bads) - set(auto_flat_chs)

    if config.find_noisy_channels_meg:
        bads_for_tsv.extend(auto_noisy_chs)
        reasons.extend(['auto-noisy'] * len(auto_noisy_chs))
        preexisting_bads = set(preexisting_bads) - set(auto_noisy_chs)

    preexisting_bads = list(preexisting_bads)
    if preexisting_bads:
        bads_for_tsv.extend(preexisting_bads)
        reasons.extend(['pre-existing (before mne-study-template was run)'] *
                       len(preexisting_bads))

    tsv_data = pd.DataFrame(dict(name=bads_for_tsv, reason=reasons))
    tsv_data = tsv_data.sort_values(by='name')
    tsv_data.to_csv(bads_tsv_fname, sep='\t', index=False)
Beispiel #4
0
    raw_LD.info['bads'] = []

    # For closer equivalence with MaxFilter, it's recommended to low-pass
    # filter your data prior to running this function
    raw_check_f = raw_fruit.copy().pick_types(exclude=()).load_data().filter(
        None, 48)
    raw_check_o = raw_odour.copy().pick_types(exclude=()).load_data().filter(
        None, 48)
    raw_check_m = raw_milk.copy().pick_types(exclude=()).load_data().filter(
        None, 48)
    raw_check_l = raw_LD.copy().pick_types(exclude=()).load_data().filter(
        None, 48)
    # Find MEG bad channels using Maxwell filtering
    auto_noisy_chs_f, auto_flat_chs_f = find_bad_channels_maxwell(
        raw_check_f,
        cross_talk=cross_talk,
        calibration=calibration,
        verbose=True)
    auto_noisy_chs_o, auto_flat_chs_o = find_bad_channels_maxwell(
        raw_check_o,
        cross_talk=cross_talk,
        calibration=calibration,
        verbose=True)
    auto_noisy_chs_m, auto_flat_chs_m = find_bad_channels_maxwell(
        raw_check_m,
        cross_talk=cross_talk,
        calibration=calibration,
        verbose=True)
    auto_noisy_chs_l, auto_flat_chs_l = find_bad_channels_maxwell(
        raw_check_l,
        cross_talk=cross_talk,
def find_bad_channels(raw, subject, session, task, run):
    if (config.find_flat_channels_meg and not config.find_noisy_channels_meg):
        msg = 'Finding flat channels.'
    elif (config.find_noisy_channels_meg
          and not config.find_flat_channels_meg):
        msg = 'Finding noisy channels using Maxwell filtering.'
    else:
        msg = ('Finding flat channels, and noisy channels using '
               'Maxwell filtering.')

    logger.info(
        gen_log_message(message=msg, step=1, subject=subject, session=session))
    raw_lp_filtered_for_maxwell = (raw.copy().filter(l_freq=None, h_freq=40))
    auto_noisy_chs, auto_flat_chs = find_bad_channels_maxwell(
        raw=raw_lp_filtered_for_maxwell,
        calibration=config.mf_cal_fname,
        cross_talk=config.mf_ctc_fname)
    del raw_lp_filtered_for_maxwell

    preexisting_bads = raw.info['bads'].copy()
    bads = preexisting_bads.copy()
    if config.find_flat_channels_meg:
        msg = f'Found {len(auto_flat_chs)} flat channels.'
        logger.info(
            gen_log_message(message=msg,
                            step=1,
                            subject=subject,
                            session=session))
        bads.extend(auto_flat_chs)
    if config.find_noisy_channels_meg:
        msg = f'Found {len(auto_noisy_chs)} noisy channels.'
        logger.info(
            gen_log_message(message=msg,
                            step=1,
                            subject=subject,
                            session=session))
        bads.extend(auto_noisy_chs)

    bads = sorted(set(bads))
    raw.info['bads'] = bads
    msg = f'Marked {len(raw.info["bads"])} channels as bad.'
    logger.info(
        gen_log_message(message=msg, step=1, subject=subject, session=session))

    # Write the bad channels to disk.
    deriv_path = config.get_subject_deriv_path(subject=subject,
                                               session=session,
                                               kind=config.get_kind())

    bids_basename = make_bids_basename(subject=subject,
                                       session=session,
                                       task=config.get_task(),
                                       acquisition=config.acq,
                                       run=run,
                                       processing=config.proc,
                                       recording=config.rec,
                                       space=config.space)

    bads_tsv_fname = op.join(deriv_path, f'{bids_basename}_bad_channels.tsv')
    bads_for_tsv = []
    reasons = []

    if config.find_flat_channels_meg:
        bads_for_tsv.extend(auto_flat_chs)
        reasons.extend(['auto-flat'] * len(auto_flat_chs))
        preexisting_bads = set(preexisting_bads) - set(auto_flat_chs)

    if config.find_noisy_channels_meg:
        bads_for_tsv.extend(auto_noisy_chs)
        reasons.extend(['auto-noisy'] * len(auto_noisy_chs))
        preexisting_bads = set(preexisting_bads) - set(auto_noisy_chs)

    preexisting_bads = list(preexisting_bads)
    if preexisting_bads:
        bads_for_tsv.extend(preexisting_bads)
        reasons.extend(['pre-existing (before mne-study-template was run)'] *
                       len(preexisting_bads))

    tsv_data = pd.DataFrame(dict(name=bads_for_tsv, reason=reasons))
    tsv_data = tsv_data.sort_values(by='name')
    tsv_data.to_csv(bads_tsv_fname, sep='\t', index=False)
# Before we perform SSS we'll look for bad channels — ``MEG 2443`` is quite
# noisy.
#
# .. warning::
#
#     It is critical to mark bad channels in ``raw.info['bads']`` *before*
#     calling :func:`~mne.preprocessing.maxwell_filter` in order to prevent
#     bad channel noise from spreading.
#
# Let's see if we can automatically detect it.

raw.info['bads'] = []
raw_check = raw.copy()
auto_noisy_chs, auto_flat_chs, auto_scores = find_bad_channels_maxwell(
    raw_check,
    cross_talk=crosstalk_file,
    calibration=fine_cal_file,
    return_scores=True,
    verbose=True)
print(auto_noisy_chs)  # we should find them!
print(auto_flat_chs)  # none for this dataset

###############################################################################
#
# .. note:: `~mne.preprocessing.find_bad_channels_maxwell` needs to operate on
#           a signal without line noise or cHPI signals. By default, it simply
#           applies a low-pass filter with a cutoff frequency of 40 Hz to the
#           data, which should remove these artifacts. You may also specify a
#           different cutoff by passing the ``h_freq`` keyword argument. If you
#           set ``h_freq=None``, no filtering will be applied. This can be
#           useful if your data has already been preconditioned, for example
#           using :func:`mne.chpi.filter_chpi`,
Beispiel #7
0
def maxwellfilter(
    raw,
    crosstalk_file,
    fine_cal_file,
    subject,
    headpos_file=None,
    compute_motion_params=True,
    figdir="/tmp/",
    outdir="/tmp/",
    filtering=False,
    filter_args=None,
):
    """

    :param raw: Raw data to apply SSS on
    :param crosstalk_file: crosstalk compensation file from the Elekta system to
     reduce interference between gradiometers and magnetometers
    :param fine_cal_file: site-specific sensor orientation and calibration
    :param subject: str, subject identifier, takes the form '001'
    :param headpos_file: str, path; If existing, read in head positions from a file
    :param compute_motion_params: Boolean, whether to perform motion correction
    :param figdir: str, path to directory to save figures in
    :param outdir: str, path to save bids compliant sss-corrected data in
    (derivatives directory)
    :param filtering: if True, a filter function is ran on the data after SSS.
    By default, it is a 40Hz low-pass filter.
    :param filter_args: dict; if filtering is True, initializes a filter with the
    arguments provided

    :return:
    """
    from mne.preprocessing import find_bad_channels_maxwell

    if not compute_motion_params:
        if not headpos_file or not os.path.exists(headpos_file):
            logging.info(
                f"Could not find or read head position files under the supplied"
                f"path: {headpos_file}. Recalculating from scratch.")
            head_pos = motion_estimation(subject, raw, figdir)
        else:
            logging.info(
                f"Reading in head positions for subject sub-{subject} "
                f"from {headpos_file}.")
            head_pos = mne.chpi.read_head_pos(headpos_file)

    else:
        logging.info(f"Starting motion estimation for subject sub-{subject}.")
        head_pos = motion_estimation(subject, raw, figdir)

    raw.info["bads"] = []
    raw_check = raw.copy()

    preconditioned = False  # TODO handle this here atm. Needs to become global.
    if preconditioned:
        # preconditioned is a global variable that is set to True if some form
        # of filtering (CHPI and line noise removal or general filtering) has
        # been applied.
        # the data has been filtered, and we can pass h_freq=None
        logging.info("Performing bad channel detection without filtering")
        auto_noisy_chs, auto_flat_chs, auto_scores = find_bad_channels_maxwell(
            raw_check,
            cross_talk=crosstalk_file,
            calibration=fine_cal_file,
            return_scores=True,
            verbose=True,
            h_freq=None,
        )
    else:
        # the data still contains line noise (50Hz) and CHPI coils. It will
        # filter the data before extracting bad channels
        auto_noisy_chs, auto_flat_chs, auto_scores = find_bad_channels_maxwell(
            raw_check,
            cross_talk=crosstalk_file,
            calibration=fine_cal_file,
            return_scores=True,
            verbose=True,
        )
    logging.info(f"Found the following noisy channels: {auto_noisy_chs} \n "
                 f"and the following flat channels: {auto_flat_chs} \n"
                 f"for subject sub-{subject}")
    bads = raw.info["bads"] + auto_noisy_chs + auto_flat_chs
    raw.info["bads"] = bads
    # free up space
    del raw_check
    # plot as a sanity check
    for ch_type in ["grad", "mag"]:
        plot_noisy_channel_detection(auto_scores,
                                     ch_type=ch_type,
                                     subject=subject,
                                     outpath=figdir)
    logging.info(f"Signal Space Separation with movement compensation "
                 f"starting for subject sub-{subject}")
    raw_sss = mne.preprocessing.maxwell_filter(
        raw,
        cross_talk=crosstalk_file,
        calibration=fine_cal_file,
        head_pos=head_pos,
        verbose=True,
    )

    if filtering:
        logging.info(
            f"Filtering raw SSS data for subject {subject}. The following "
            f"additional parameters were passed: {filter_args}")
        raw_sss_filtered = raw_sss.copy()
        raw_sss_filtered = _filter_data(raw_sss_filtered, **filter_args)
        # TODO: Downsample
        plot_psd(raw_sss_filtered, subject, figdir, filtering)
        # TODO: save file
        return raw_sss_filtered

    plot_psd(raw_sss, subject, figdir, filtering)
    return raw_sss