def _handle_picks(epochs): """Aux function to handle picks.""" if any('ICA' in k for k in epochs.ch_names): picks = pick_types(epochs.info, misc=True, ref_meg=False, exclude=[]) else: picks = pick_types(epochs.info, meg=True, eeg=True, eog=True, ecg=True, seeg=True, ecog=True, ref_meg=False, exclude=[]) return picks
def _interpolate_bads_meg(inst, mode='accurate', origin=None, verbose=None): """Interpolate bad channels from data in good channels. Parameters ---------- inst : mne.io.Raw, mne.Epochs or mne.Evoked The data to interpolate. Must be preloaded. mode : str Either `'accurate'` or `'fast'`, determines the quality of the Legendre polynomial expansion used for interpolation. `'fast'` should be sufficient for most applications. origin : None | list If None, origin is set to sensor center of mass, otherwise use the coordinates provided as origin. The old standard value is (0., 0., 0.04) verbose : bool, str, int, or None If not None, override default verbose level (see :func:`mne.verbose` and :ref:`Logging documentation <tut_logging>` for more). """ from mne.channels.interpolation import _do_interp_dots picks_meg = pick_types(inst.info, meg=True, eeg=False, exclude=[]) picks_good = pick_types(inst.info, meg=True, eeg=False, exclude='bads') meg_ch_names = [inst.info['ch_names'][p] for p in picks_meg] bads_meg = [ch for ch in inst.info['bads'] if ch in meg_ch_names] # select the bad meg channel to be interpolated if len(bads_meg) == 0: picks_bad = [] else: picks_bad = pick_channels(inst.info['ch_names'], bads_meg, exclude=[]) # return without doing anything if there are no meg channels if len(picks_meg) == 0 or len(picks_bad) == 0: return info_from = pick_info(inst.info, picks_good) info_to = pick_info(inst.info, picks_bad) if check_version('mne', min_version='0.21'): from mne.forward import _map_meg_or_eeg_channels mapping = _map_meg_or_eeg_channels(info_from, info_to, mode=mode, origin=origin) else: from mne.forward import _map_meg_channels mapping = _map_meg_channels(info_from, info_to, mode=mode, origin=origin) _do_interp_dots(inst, mapping, picks_good, picks_bad)
def _infer_eeg_placement_scheme(raw): """Based on the channel names, try to infer an EEG placement scheme. Parameters ---------- raw : instance of Raw The data as MNE-Python Raw object. Returns ------- placement_scheme : str Description of the EEG placement scheme. Will be "n/a" for unsuccessful extraction. """ placement_scheme = 'n/a' # Check if the raw data contains eeg data at all if 'eeg' not in raw: return placement_scheme # How many of the channels in raw are based on the extended 10/20 system raw.load_data() sel = pick_types(raw.info, meg=False, eeg=True) ch_names = [raw.ch_names[i] for i in sel] channel_names = [ch.lower() for ch in ch_names] montage1005 = make_standard_montage('standard_1005') montage1005_names = [ch.lower() for ch in montage1005.ch_names] if set(channel_names).issubset(set(montage1005_names)): placement_scheme = 'based on the extended 10/20 system' return placement_scheme
def find_bad_channels(epochs, picks=None, method='faster', method_params=None, return_by_metric=False, verbose=None): """Implements the first step of the FASTER algorithm. This function attempts to automatically mark bad EEG channels by performing outlier detection. It operated on epoched data, to make sure only relevant data is analyzed. Parameters ---------- epochs : Instance of Epochs The epochs for which bad channels need to be marked picks : list of int | None Channels to operate on. Defaults to EEG channels. method : {'faster'} The detection algorithm. method_params : dict | None The method parameters in a dict. If ``method`` equals 'faster', and ``method_params``is None, defaults to the following parameters. Partial updates are supported. use_metrics : list of str List of metrics to use. Can be any combination of: 'variance', 'correlation', 'hurst', 'kurtosis', 'line_noise' Defaults to all of them. thresh : float The threshold value, in standard deviations, to apply. A channel crossing this threshold value is marked as bad. Defaults to 3. max_iter : int The maximum number of iterations performed during outlier detection (defaults to 1, as in the original FASTER paper). return_by_metric : bool Whether to return the bad channels as a flat list (False, default) or as a dictionary with the names of the used metrics as keys and the bad channels found by this metric as values. Is ignored if not supported by method. verbose : bool, str, int, or None If not None, override default verbose level (see mne.verbose). Defaults to self.verbose. Returns ------- bads : list of str The names of the bad EEG channels. """ if picks is None: picks = pick_types(epochs.info, meg=True, eeg=True, exclude=[]) _method_params = _handle_default('bads' + '_' + method, method_params) if method == 'faster': bads = _find_bad_channels(epochs, picks, **_method_params) else: raise NotImplementedError( 'Come back later, for now there is only "FASTER"') if return_by_metric: return bads else: return _combine_indices(bads)
def make_interpolators(interp_cache, keys, bads, epochs): make = [k for k in keys if (bads, k) not in interp_cache] logger = logging.getLogger(__name__) logger.debug("Making %i of %i interpolators" % (len(make), len(keys))) for key in make: picks_good = pick_types(epochs.info, ref_meg=False, exclude=key) picks_bad = pick_channels(epochs.ch_names, key) interpolation = map_meg_channels(epochs, picks_good, picks_bad, 'accurate') interp_cache[bads, key] = picks_good, picks_bad, interpolation
def make_interpolators(interp_cache, keys, bads, epochs): make = [k for k in keys if (bads, k) not in interp_cache] logger = logging.getLogger(__name__) logger.debug("Making %i of %i interpolators" % (len(make), len(keys))) for key in make: picks_good = pick_types(epochs.info, ref_meg=False, exclude=key) picks_bad = pick_channels(epochs.ch_names, key) interpolation = map_meg_channels(epochs, picks_good, picks_bad, 'accurate') interp_cache[bads, key] = picks_good, picks_bad, interpolation
def get_power(raw, picks=None): """Helper to compute power of magnetometer channels in raw object""" # Grab only magnetometers for calculation (though both mags and grads # affect shielding factor calculation) if picks is None: picks = pick_types(raw.info, meg='mag') # Return norm along channel axis return norm(raw[picks, :][0], axis=0)
def pre_whiten(data, info, picks, pre_whitener=None): """Aux function based on ica._pre_whiten from mne v0.15 pre_whitener[this_picks] = np.std(data[this_picks], axis=1)[:, None] """ if pre_whitener is None: # use standardization as whitener # Scale (z-score) the data by channel type info = pick_info(info, picks) pre_whitener = np.empty([len(data), 1]) for ch_type in _DATA_CH_TYPES_SPLIT + ['eog']: if _contains_ch_type(info, ch_type): if ch_type == 'seeg': this_picks = pick_types(info, meg=False, seeg=True) elif ch_type == 'ecog': this_picks = pick_types(info, meg=False, ecog=True) elif ch_type == 'eeg': this_picks = pick_types(info, meg=False, eeg=True) elif ch_type in ('mag', 'grad'): this_picks = pick_types(info, meg=ch_type) elif ch_type == 'eog': this_picks = pick_types(info, meg=False, eog=True) elif ch_type in ('hbo', 'hbr'): this_picks = pick_types(info, meg=False, fnirs=ch_type) else: raise RuntimeError('Should not be reached.' 'Unsupported channel {0}' .format(ch_type)) pre_whitener[this_picks] = np.std(data[this_picks], axis=1)[:, None] data /= pre_whitener return data, pre_whitener
def _fit_evoked(self, raw, picks, start, stop, decim, reject, flat, tstep, verbose): """Aux method """ if self.current_fit != 'unfitted': self._reset() if picks is None: # just use good data channels picks = pick_types(raw.info, meg=True, eeg=True, eog=False, ecg=False, misc=False, stim=False, ref_meg=False, exclude='bads') logger.info('Fitting ICA to data using %i channels. \n' 'Please be patient, this may take some time' % len(picks)) if self.max_pca_components is None: self.max_pca_components = len(picks) logger.info('Inferring max_pca_components from picks.') self.info = pick_info(raw.info, picks) if self.info['comps']: self.info['comps'] = [] self.ch_names = self.info['ch_names'] start, stop = _check_start_stop(raw, start, stop) data = raw.data[picks, start:stop] print data.shape if decim is not None: data = data[:, ::decim].copy() if (reject is not None) or (flat is not None): data, self.drop_inds_ = _reject_data_segments( data, reject, flat, decim, self.info, tstep) self.n_samples_ = data.shape[1] data, self._pre_whitener = self._pre_whiten(data, raw.info, picks) self._fit(data, self.max_pca_components, 'evoked') #'raw') return self
def _prep_eeg_channels(info, exclude=(), verbose=None): """Prepare EEG electrode definitions for forward calculation. Parameters ---------- info : instance of Info The measurement information dictionary exclude : list of str | str List of channels to exclude. If 'bads', exclude channels in info['bads'] verbose : bool, str, int, or None If not None, override default verbose level (see :func:`mne.verbose` and :ref:`Logging documentation <tut_logging>` for more). Returns ------- eegels : list of dict Information for each prepped EEG electrode eegnames : list of str Name of each prepped EEG electrode """ eegnames, eegels = [], [] info_extra = 'info' # Find EEG electrodes picks = pick_types(info, meg=False, eeg=True, ref_meg=False, exclude=exclude) # Make sure EEG electrodes exist neeg = len(picks) if neeg <= 0: raise RuntimeError('Could not find any EEG channels') # Get channel info and names for EEG channels eegchs = pick_info(info, picks)['chs'] eegnames = [info['ch_names'][p] for p in picks] logger.info('Read %3d EEG channels from %s' % (len(picks), info_extra)) # Create EEG electrode descriptions eegels = _create_eeg_els(eegchs) logger.info('Head coordinate coil definitions created.') return eegels, eegnames
def get_channel_positions(self, picks=None): """Gets channel locations from info Parameters ---------- picks : array-like of int | None Indices of channels to include. If None (default), all meg and eeg channels that are available are returned (bad channels excluded). """ if picks is None: picks = pick_types(self.info, meg=True, eeg=True) chs = self.info['chs'] pos = np.array([chs[k]['loc'][:3] for k in picks]) n_zero = np.sum(np.sum(np.abs(pos), axis=1) == 0) if n_zero > 1: # XXX some systems have origin (0, 0, 0) raise ValueError('Could not extract channel positions for ' '{} channels'.format(n_zero)) return pos
def get_channel_positions(self, picks=None): """Gets channel locations from info Parameters ---------- picks : array-like of int | None Indices of channels to include. If None (default), all meg and eeg channels that are available are returned (bad channels excluded). """ if picks is None: picks = pick_types(self.info, meg=True, eeg=True) chs = self.info['chs'] pos = np.array([chs[k]['loc'][:3] for k in picks]) n_zero = np.sum(np.sum(np.abs(pos), axis=1) == 0) if n_zero > 1: # XXX some systems have origin (0, 0, 0) raise ValueError('Could not extract channel positions for ' '{} channels'.format(n_zero)) return pos
def _pre_whiten(self, data, info, picks): """Aux function.""" has_pre_whitener = hasattr(self, 'pre_whitener_') if not has_pre_whitener and self.noise_cov is None: # use standardization as whitener # Scale (z-score) the data by channel info = pick_info(info, picks) pre_whitener = np.empty([len(data), 1]) for ch_type in _DATA_CH_TYPES_SPLIT + ('eog', "ref_meg"): if _contains_ch_type(info, ch_type): if ch_type == 'seeg': this_picks = pick_types(info, meg=False, seeg=True) elif ch_type == 'ecog': this_picks = pick_types(info, meg=False, ecog=True) elif ch_type == 'eeg': this_picks = pick_types(info, meg=False, eeg=True) elif ch_type in ('mag', 'grad'): this_picks = pick_types(info, meg=ch_type) elif ch_type == 'eog': this_picks = pick_types(info, meg=False, eog=True) elif ch_type in ('hbo', 'hbr'): this_picks = pick_types(info, meg=False, fnirs=ch_type) elif ch_type == 'ref_meg': this_picks = pick_types(info, meg=False, ref_meg=True) else: raise RuntimeError( 'Should not be reached.' 'Unsupported channel {}'.format(ch_type)) pre_whitener[this_picks] = np.std(data[this_picks], axis=1)[:, None] data /= pre_whitener elif not has_pre_whitener and self.noise_cov is not None: from mne.cov import compute_whitener pre_whitener, _ = compute_whitener(self.noise_cov, info, picks) assert data.shape[0] == pre_whitener.shape[1] data = np.dot(pre_whitener, data) elif has_pre_whitener and self.noise_cov is None: data /= self.pre_whitener_ pre_whitener = self.pre_whitener_ else: data = np.dot(self.pre_whitener_, data) pre_whitener = self.pre_whitener_ return data, pre_whitener
def _make_interpolator(inst, bad_channels): """Find indexes and interpolation matrix to interpolate bad channels Parameters ---------- inst : mne.io.Raw, mne.Epochs or mne.Evoked The data to interpolate. Must be preloaded. """ bads_idx = np.zeros(len(inst.ch_names), dtype=np.bool) goods_idx = np.zeros(len(inst.ch_names), dtype=np.bool) picks = pick_types(inst.info, meg=False, eeg=True, exclude=[]) bads_idx[picks] = [inst.ch_names[ch] in bad_channels for ch in picks] goods_idx[picks] = True goods_idx[bads_idx] = False if bads_idx.sum() != len(bad_channels): logger.warning('Channel interpolation is currently only implemented ' 'for EEG. The MEG channels marked as bad will remain ' 'untouched.') pos = get_channel_positions(inst, picks) # Make sure only EEG are used bads_idx_pos = bads_idx[picks] goods_idx_pos = goods_idx[picks] pos_good = pos[goods_idx_pos] pos_bad = pos[bads_idx_pos] # test spherical fit radius, center = _fit_sphere(pos_good) distance = np.sqrt(np.sum((pos_good - center)**2, 1)) distance = np.mean(distance / radius) if np.abs(1. - distance) > 0.1: logger.warning('Your spherical fit is poor, interpolation results are ' 'likely to be inaccurate.') logger.info('Computing interpolation matrix from {0} sensor ' 'positions'.format(len(pos_good))) interpolation = _make_interpolation_matrix(pos_good, pos_bad) return goods_idx, bads_idx, interpolation
def _make_interpolator(inst, bad_channels): """Find indexes and interpolation matrix to interpolate bad channels Parameters ---------- inst : mne.io.Raw, mne.Epochs or mne.Evoked The data to interpolate. Must be preloaded. """ bads_idx = np.zeros(len(inst.ch_names), dtype=np.bool) goods_idx = np.zeros(len(inst.ch_names), dtype=np.bool) picks = pick_types(inst.info, meg=False, eeg=True, exclude=[]) bads_idx[picks] = [inst.ch_names[ch] in bad_channels for ch in picks] goods_idx[picks] = True goods_idx[bads_idx] = False if bads_idx.sum() != len(bad_channels): logger.warning('Channel interpolation is currently only implemented ' 'for EEG. The MEG channels marked as bad will remain ' 'untouched.') pos = get_channel_positions(inst, picks) # Make sure only EEG are used bads_idx_pos = bads_idx[picks] goods_idx_pos = goods_idx[picks] pos_good = pos[goods_idx_pos] pos_bad = pos[bads_idx_pos] # test spherical fit radius, center = _fit_sphere(pos_good) distance = np.sqrt(np.sum((pos_good - center) ** 2, 1)) distance = np.mean(distance / radius) if np.abs(1. - distance) > 0.1: logger.warning('Your spherical fit is poor, interpolation results are ' 'likely to be inaccurate.') logger.info('Computing interpolation matrix from {0} sensor ' 'positions'.format(len(pos_good))) interpolation = _make_interpolation_matrix(pos_good, pos_bad) return goods_idx, bads_idx, interpolation
def _prepare_data(self, picks, target): this_picks = {k: None for k in ['times', 'channels', 'epochs']} if picks is not None: if any([x not in this_picks.keys() for x in picks.keys()]): raise ValueError('Picking is not compatible for {}'.format( self._get_title())) if picks is None: picks = {} this_picks.update(picks) to_preserve = self._get_preserve_axis(target) if len(to_preserve) > 0: for axis in to_preserve: this_picks[axis] = None # Pick Times based on original times time_picks = this_picks['times'] time_mask = _time_mask(self.epochs_.times, self.tmin, self.tmax) if time_picks is not None: picks_mask = np.zeros(len(time_mask), dtype=np.bool) picks_mask[time_picks] = True time_mask = np.logical_and(time_mask, picks_mask) # Pick epochs based on original indices epochs_picks = this_picks['epochs'] this_epochs = self.epochs_ if epochs_picks is not None: this_epochs = this_epochs[epochs_picks] # Pick channels based on original indices ch_picks = this_picks['channels'] if ch_picks is None: ch_picks = pick_types(this_epochs.info, eeg=True, meg=True) if (self.subset and self.missing_nan and not epochs_has_event(this_epochs, self.subset)): data = np.array([[[np.nan]]]) else: if self.subset: this_epochs = this_epochs[self.subset] data = this_epochs.get_data()[:, ch_picks][..., time_mask] return data
def _fit_evoked(self, raw, picks, start, stop, decim, reject, flat, tstep, verbose): """Aux method """ if self.current_fit != 'unfitted': self._reset() if picks is None: # just use good data channels picks = pick_types(raw.info, meg=True, eeg=True, eog=False, ecg=False, misc=False, stim=False, ref_meg=False, exclude='bads') logger.info('Fitting ICA to data using %i channels. \n' 'Please be patient, this may take some time' % len(picks)) if self.max_pca_components is None: self.max_pca_components = len(picks) logger.info('Inferring max_pca_components from picks.') self.info = pick_info(raw.info, picks) if self.info['comps']: self.info['comps'] = [] self.ch_names = self.info['ch_names'] start, stop = _check_start_stop(raw, start, stop) data = raw.data[picks, start:stop] print data.shape if decim is not None: data = data[:, ::decim].copy() if (reject is not None) or (flat is not None): data, self.drop_inds_ = _reject_data_segments(data, reject, flat, decim, self.info, tstep) self.n_samples_ = data.shape[1] data, self._pre_whitener = self._pre_whiten(data, raw.info, picks) self._fit(data, self.max_pca_components, 'evoked') #'raw') return self
def _interpolate_bads_meg(epochs, bad_channels_by_epoch, mode='fast'): """Interpolate bad MEG channels per epoch Parameters ---------- inst : mne.io.Raw, mne.Epochs or mne.Evoked The data to interpolate. Must be preloaded. bad_channels_by_epoch : list of list of str Bad channel names specified for each epoch. For example, for an Epochs instance containing 3 epochs: ``[['F1'], [], ['F3', 'FZ']]`` Notes ----- Based on mne 0.9.0 MEG channel interpolation. """ if len(bad_channels_by_epoch) != len(epochs): raise ValueError("Unequal length of epochs (%i) and " "bad_channels_by_epoch (%i)" % (len(epochs), len(bad_channels_by_epoch))) interp_cache = {} for i, bad_channels in enumerate(bad_channels_by_epoch): if not bad_channels: continue # find interpolation matrix key = tuple(sorted(bad_channels)) if key in interp_cache: picks_good, picks_bad, interpolation = interp_cache[key] else: picks_good = pick_types(epochs.info, ref_meg=False, exclude=key) picks_bad = pick_channels(epochs.ch_names, key) interpolation = _map_meg_channels(epochs, picks_good, picks_bad, mode) interp_cache[key] = picks_good, picks_bad, interpolation # apply interpolation logger.info('Interpolating sensors %s on epoch %s', picks_bad, i) epochs._data[i, picks_bad, :] = interpolation.dot(epochs._data[i, picks_good, :])
def get_sensor_pos_from_fwd(inst, info=None, picks=None, trans=None): from mne import SourceSpaces, Forward from mne.io.constants import FIFF from six import string_types from mne.transforms import read_trans, _ensure_trans, invert_transform, Transform, apply_trans from mne.io.pick import channel_type, pick_types if isinstance(inst, Forward): info = inst['info'] src = inst['src'] elif isinstance(inst, SourceSpaces): src = inst if info is None: raise ValueError('You need to specify an Info object with ' 'information about the channels.') # Load the head<->MRI transform if necessary if src[0]['coord_frame'] == FIFF.FIFFV_COORD_MRI: if trans is None: raise ValueError('Source space is in MRI coordinates, but no ' 'head<->MRI transform was given. Please specify ' 'the full path to the appropriate *-trans.fif ' 'file as the "trans" parameter.') if isinstance(trans, string_types): trans = read_trans(trans, return_all=True) for trans in trans: # we got at least 1 try: trans = _ensure_trans(trans, 'head', 'mri') except Exception as exp: pass else: break else: raise exp src_trans = invert_transform(_ensure_trans(trans, 'head', 'mri')) print('Transform!') else: src_trans = Transform('head', 'head') # Identity transform dev_to_head = _ensure_trans(info['dev_head_t'], 'meg', 'head') if picks is None: picks = pick_types(info, meg=True) if len(picks) > 0: print('Using MEG channels') else: print('Using EEG channels') picks = pick_types(info, eeg=True) sensor_pos = [] for ch in picks: # MEG channels are in device coordinates, translate them to head if channel_type(info, ch) in ['mag', 'grad']: sensor_pos.append( apply_trans(dev_to_head, info['chs'][ch]['loc'][:3])) else: sensor_pos.append(info['chs'][ch]['loc'][:3]) sensor_pos = np.array(sensor_pos) return sensor_pos
def _estimate_line_freq(raw, verbose=False): """Estimate power line noise from a given BaseRaw. Uses 5 channels of either meg, eeg, ecog, or seeg to estimate the line frequency. Parameters ---------- raw : mne.io.BaseRaw Returns ------- line_freq : int | None Either 50, or 60 Hz depending if European, or USA data recording. """ sfreq = raw.info['sfreq'] # if sampling is not high enough, line_freq does not matter if sfreq < 100: return None # setup picks of the data to get at least 5 channels pick_dict = {"meg": True} picks = list(pick_types(raw.info, exclude='bads', **pick_dict)) if len(picks) < 5: pick_dict = {"eeg": True} picks = pick_types(raw.info, exclude='bads', **pick_dict) if len(picks) < 5: pick_dict = {"ecog": True} picks = pick_types(raw.info, exclude='bads', **pick_dict) if len(picks) < 5: pick_dict = {"seeg": True} picks = pick_types(raw.info, exclude='bads', **pick_dict) if len(picks) < 5: warn("Estimation of line frequency only " "supports 'meg', 'eeg', 'ecog', or 'seeg'.") return None # only sample first 10 seconds, or whole time series tmin = 0 tmax = int(min(len(raw.times), 10 * sfreq)) # get just five channels of data to estimate on data = raw.get_data(start=tmin, stop=tmax, picks=picks, return_times=False)[0:5, :] # run a multi-taper FFT between Power Line Frequencies of interest psds, freqs = psd_array_welch(data, fmin=49, fmax=61, sfreq=sfreq, average="mean") usa_ind = np.where(freqs == min(freqs, key=lambda x: abs(x - 60)))[0] eu_ind = np.where(freqs == min(freqs, key=lambda x: abs(x - 50)))[0] # get the average power within those frequency bands usa_psd = np.mean((psds[..., usa_ind])) eu_psd = np.mean((psds[..., eu_ind])) if verbose is True: print("EU (i.e. 50 Hz) PSD is {} and " "USA (i.e. 60 Hz) PSD is {}".format(eu_psd, usa_psd)) if usa_psd > eu_psd: line_freq = 60 else: line_freq = 50 return line_freq
def test_fix_stim_artifact(): """Test fix stim artifact.""" events = read_events(event_fname) raw = read_raw_fif(raw_fname) pytest.raises(RuntimeError, fix_stim_artifact, raw) raw = read_raw_fif(raw_fname, preload=True) # use window before stimulus in epochs tmin, tmax, event_id = -0.2, 0.5, 1 picks = pick_types(raw.info, meg=True, eeg=True, eog=True, stim=False, exclude='bads') epochs = Epochs(raw, events, event_id, tmin, tmax, picks=picks, preload=True, reject=None) e_start = int(np.ceil(epochs.info['sfreq'] * epochs.tmin)) tmin, tmax = -0.045, -0.015 tmin_samp = int(-0.035 * epochs.info['sfreq']) - e_start tmax_samp = int(-0.015 * epochs.info['sfreq']) - e_start epochs = fix_stim_artifact(epochs, tmin=tmin, tmax=tmax, mode='linear') data = epochs.get_data()[:, :, tmin_samp:tmax_samp] diff_data0 = np.diff(data[0][0]) diff_data0 -= np.mean(diff_data0) assert_array_almost_equal(diff_data0, np.zeros(len(diff_data0))) epochs = fix_stim_artifact(epochs, tmin=tmin, tmax=tmax, mode='window') data_from_epochs_fix = epochs.get_data()[:, :, tmin_samp:tmax_samp] # XXX This is a very weird check... assert np.all(data_from_epochs_fix) == 0. # use window before stimulus in raw event_idx = np.where(events[:, 2] == 1)[0][0] tmin, tmax = -0.045, -0.015 tmin_samp = int(-0.035 * raw.info['sfreq']) tmax_samp = int(-0.015 * raw.info['sfreq']) tidx = int(events[event_idx, 0] - raw.first_samp) pytest.raises(ValueError, fix_stim_artifact, raw, events=np.array([])) raw = fix_stim_artifact(raw, events=None, event_id=1, tmin=tmin, tmax=tmax, mode='linear', stim_channel='STI 014') data, times = raw[:, (tidx + tmin_samp):(tidx + tmax_samp)] diff_data0 = np.diff(data[0]) diff_data0 -= np.mean(diff_data0) assert_array_almost_equal(diff_data0, np.zeros(len(diff_data0))) raw = fix_stim_artifact(raw, events, event_id=1, tmin=tmin, tmax=tmax, mode='window') data, times = raw[:, (tidx + tmin_samp):(tidx + tmax_samp)] assert np.all(data) == 0. # get epochs from raw with fixed data tmin, tmax, event_id = -0.2, 0.5, 1 epochs = Epochs(raw, events, event_id, tmin, tmax, picks=picks, preload=True, reject=None, baseline=None) e_start = int(np.ceil(epochs.info['sfreq'] * epochs.tmin)) tmin_samp = int(-0.035 * epochs.info['sfreq']) - e_start tmax_samp = int(-0.015 * epochs.info['sfreq']) - e_start data_from_raw_fix = epochs.get_data()[:, :, tmin_samp:tmax_samp] assert np.all(data_from_raw_fix) == 0. # use window after stimulus evoked = epochs.average() tmin, tmax = 0.005, 0.045 tmin_samp = int(0.015 * evoked.info['sfreq']) - evoked.first tmax_samp = int(0.035 * evoked.info['sfreq']) - evoked.first evoked = fix_stim_artifact(evoked, tmin=tmin, tmax=tmax, mode='linear') data = evoked.data[:, tmin_samp:tmax_samp] diff_data0 = np.diff(data[0]) diff_data0 -= np.mean(diff_data0) assert_array_almost_equal(diff_data0, np.zeros(len(diff_data0))) evoked = fix_stim_artifact(evoked, tmin=tmin, tmax=tmax, mode='window') data = evoked.data[:, tmin_samp:tmax_samp] assert np.all(data) == 0.
def find_bad_channels_in_epochs(epochs, picks=None, method='faster', method_params=None, return_by_metric=False): """Implements the fourth step of the FASTER algorithm. This function attempts to automatically mark bad channels in each epochs by performing outlier detection. Parameters ---------- epochs : Instance of Epochs The epochs to analyze. picks : list of int | None Channels to operate on. Defaults to EEG channels. method : {'faster'} The detection algorithm. method_params : dict | None The method parameters in a dict. If ``method`` equals 'faster', and ``method_params``is None, defaults to the following parameters. Partial updates are supported. use_metrics : list of str List of metrics to use. Can be any combination of: 'amplitude', 'variance', 'deviation', 'median_gradient' Defaults to all of them. thresh : float The threshold value, in standard deviations, to apply. A channel crossing this threshold value is marked as bad. Defaults to 3. max_iter : int The maximum number of iterations performed during outlier detection (defaults to 1, as in the original FASTER paper). return_by_metric : bool Whether to return the bad channels as a flat list (False, default) or as a dictionary with the names of the used metrics as keys and the bad channels found by this metric as values. Is ignored if not supported by method. Returns ------- bads : list of lists of int For each epoch, the indices of the bad channels. """ if picks is None: picks = pick_types(epochs.info, meg=True, eeg=True, exclude=[]) _method_params = _handle_default('bads' + '_' + method, method_params) if method == 'faster': bads = _find_bad_channels_in_epochs(epochs, picks, **_method_params) else: raise NotImplementedError( 'Come back later, for now there is only "FASTER"') info = pick_info(epochs.info, picks, copy=True) if return_by_metric: bads = dict((m, _bad_mask_to_names(info, v)) for m, v in bads.items()) else: bads = np.sum(bads.values(), axis=0).astype(bool) bads = _bad_mask_to_names(info, bads) return bads
def _prep_meg_channels(info, perts, accurate=True, exclude=(), ignore_ref=False, elekta_defs=False, head_frame=True, do_es=False, do_picking=True, verbose=None): """Prepare MEG coil definitions for forward calculation. Parameters ---------- info : instance of Info The measurement information dictionary perts : dict A dictionary containing perturbation parameters for gradiometer imbalance, sensor miscalibration, and misalignment accurate : bool If true (default) then use `accurate` coil definitions (more integration points) exclude : list of str | str List of channels to exclude. If 'bads', exclude channels in info['bads'] ignore_ref : bool If true, ignore compensation coils elekta_defs : bool If True, use Elekta's coil definitions, which use different integration point geometry. False by default. head_frame : bool If True (default), use head frame coords. Otherwise, use device frame. do_es : bool If True, compute and store ex, ey, ez, and r0_exey. do_picking : bool If True, pick info and return it. verbose : bool, str, int, or None If not None, override default verbose level (see :func:`mne.verbose` and :ref:`Logging documentation <tut_logging>` for more). Returns ------- megcoils : list of dict Information for each prepped MEG coil compcoils : list of dict Information for each prepped MEG coil megnames : list of str Name of each prepped MEG coil meginfo : instance of Info Information subselected for just the set of MEG coils """ accuracy = 'accurate' if accurate else 'normal' info_extra = 'info' megnames, megcoils, compcoils = [], [], [] # Find MEG channels picks = pick_types(info, meg=True, eeg=False, ref_meg=False, exclude=exclude) # Make sure MEG coils exist nmeg = len(picks) if nmeg <= 0: raise RuntimeError('Could not find any MEG channels') # Get channel info and names for MEG channels megchs = [info['chs'][pick] for pick in picks] megnames = [info['ch_names'][p] for p in picks] logger.info('Read %3d MEG channels from %s' % (len(picks), info_extra)) # Get MEG compensation channels if not ignore_ref: picks = pick_types(info, meg=False, ref_meg=True, exclude=exclude) ncomp = len(picks) if (ncomp > 0): compchs = pick_info(info, picks)['chs'] logger.info('Read %3d MEG compensation channels from %s' % (ncomp, info_extra)) # We need to check to make sure these are NOT KIT refs if _has_kit_refs(info, picks): raise NotImplementedError( 'Cannot create forward solution with KIT reference ' 'channels. Consider using "ignore_ref=True" in ' 'calculation') else: ncomp = 0 # Make info structure to allow making compensator later ncomp_data = len(info['comps']) ref_meg = True if not ignore_ref else False picks = pick_types(info, meg=True, ref_meg=ref_meg, exclude=exclude) # Create coil descriptions with transformation to head or device frame templates = _read_coil_defs(perts, elekta_defs=elekta_defs) if head_frame: _print_coord_trans(info['dev_head_t']) transform = info['dev_head_t'] else: transform = None megcoils = _create_meg_coils(megchs, accuracy, transform, templates, do_es=do_es) if ncomp > 0: logger.info('%d compensation data sets in %s' % (ncomp_data, info_extra)) compcoils = _create_meg_coils(compchs, 'normal', transform, templates, do_es=do_es) # Check that coordinate frame is correct and log it if head_frame: assert megcoils[0]['coord_frame'] == FIFF.FIFFV_COORD_HEAD logger.info('MEG coil definitions created in head coordinates.') else: assert megcoils[0]['coord_frame'] == FIFF.FIFFV_COORD_DEVICE logger.info('MEG coil definitions created in device coordinate.') out = (megcoils, compcoils, megnames) if do_picking: out = out + (pick_info(info, picks) if nmeg > 0 else None, ) return out
def _prepare_mne_browse_epochs(params, projs, n_channels, n_epochs, scalings, title, picks, order=None): """Helper for setting up the mne_browse_epochs window.""" import matplotlib.pyplot as plt import matplotlib as mpl from matplotlib.collections import LineCollection from matplotlib.colors import colorConverter epochs = params['epochs'] if picks is None: picks = _handle_picks(epochs) if len(picks) < 1: raise RuntimeError('No appropriate channels found. Please' ' check your picks') picks = sorted(picks) # Reorganize channels inds = list() types = list() for t in ['grad', 'mag']: idxs = pick_types(params['info'], meg=t, ref_meg=False, exclude=[]) if len(idxs) < 1: continue mask = np.in1d(idxs, picks, assume_unique=True) inds.append(idxs[mask]) types += [t] * len(inds[-1]) pick_kwargs = dict(meg=False, ref_meg=False, exclude=[]) if order is None: order = ['eeg', 'seeg', 'ecog', 'eog', 'ecg', 'emg', 'ref_meg', 'stim', 'resp', 'misc', 'chpi', 'syst', 'ias', 'exci'] for ch_type in order: pick_kwargs[ch_type] = True idxs = pick_types(params['info'], **pick_kwargs) if len(idxs) < 1: continue mask = np.in1d(idxs, picks, assume_unique=True) inds.append(idxs[mask]) types += [ch_type] * len(inds[-1]) pick_kwargs[ch_type] = False inds = np.concatenate(inds).astype(int) if not len(inds) == len(picks): raise RuntimeError('Some channels not classified. Please' ' check your picks') ch_names = [params['info']['ch_names'][x] for x in inds] # set up plotting size = get_config('MNE_BROWSE_RAW_SIZE') n_epochs = min(n_epochs, len(epochs.events)) duration = len(epochs.times) * n_epochs n_channels = min(n_channels, len(picks)) if size is not None: size = size.split(',') size = tuple(float(s) for s in size) if title is None: title = epochs.name if epochs.name is None or len(title) == 0: title = '' fig = figure_nobar(facecolor='w', figsize=size, dpi=80) fig.canvas.set_window_title('mne_browse_epochs') ax = plt.subplot2grid((10, 15), (0, 1), colspan=13, rowspan=9) ax.annotate(title, xy=(0.5, 1), xytext=(0, ax.get_ylim()[1] + 15), ha='center', va='bottom', size=12, xycoords='axes fraction', textcoords='offset points') color = _handle_default('color', None) ax.axis([0, duration, 0, 200]) ax2 = ax.twiny() ax2.set_zorder(-1) ax2.axis([0, duration, 0, 200]) ax_hscroll = plt.subplot2grid((10, 15), (9, 1), colspan=13) ax_hscroll.get_yaxis().set_visible(False) ax_hscroll.set_xlabel('Epochs') ax_vscroll = plt.subplot2grid((10, 15), (0, 14), rowspan=9) ax_vscroll.set_axis_off() ax_vscroll.add_patch(mpl.patches.Rectangle((0, 0), 1, len(picks), facecolor='w', zorder=3)) ax_help_button = plt.subplot2grid((10, 15), (9, 0), colspan=1) help_button = mpl.widgets.Button(ax_help_button, 'Help') help_button.on_clicked(partial(_onclick_help, params=params)) # populate vertical and horizontal scrollbars for ci in range(len(picks)): if ch_names[ci] in params['info']['bads']: this_color = params['bad_color'] else: this_color = color[types[ci]] ax_vscroll.add_patch(mpl.patches.Rectangle((0, ci), 1, 1, facecolor=this_color, edgecolor=this_color, zorder=4)) vsel_patch = mpl.patches.Rectangle((0, 0), 1, n_channels, alpha=0.5, edgecolor='w', facecolor='w', zorder=5) ax_vscroll.add_patch(vsel_patch) ax_vscroll.set_ylim(len(types), 0) ax_vscroll.set_title('Ch.') # populate colors list type_colors = [colorConverter.to_rgba(color[c]) for c in types] colors = list() for color_idx in range(len(type_colors)): colors.append([type_colors[color_idx]] * len(epochs.events)) lines = list() n_times = len(epochs.times) for ch_idx in range(n_channels): if len(colors) - 1 < ch_idx: break lc = LineCollection(list(), antialiased=False, linewidths=0.5, zorder=3, picker=3.) ax.add_collection(lc) lines.append(lc) times = epochs.times data = np.zeros((params['info']['nchan'], len(times) * n_epochs)) ylim = (25., 0.) # Hardcoded 25 because butterfly has max 5 rows (5*5=25). # make shells for plotting traces offset = ylim[0] / n_channels offsets = np.arange(n_channels) * offset + (offset / 2.) times = np.arange(len(times) * len(epochs.events)) epoch_times = np.arange(0, len(times), n_times) ax.set_yticks(offsets) ax.set_ylim(ylim) ticks = epoch_times + 0.5 * n_times ax.set_xticks(ticks) ax2.set_xticks(ticks[:n_epochs]) labels = list(range(1, len(ticks) + 1)) # epoch numbers ax.set_xticklabels(labels) ax2.set_xticklabels(labels) xlim = epoch_times[-1] + len(epochs.times) ax_hscroll.set_xlim(0, xlim) vertline_t = ax_hscroll.text(0, 1, '', color='y', va='bottom', ha='right') # fit horizontal scroll bar ticks hscroll_ticks = np.arange(0, xlim, xlim / 7.0) hscroll_ticks = np.append(hscroll_ticks, epoch_times[-1]) hticks = list() for tick in hscroll_ticks: hticks.append(epoch_times.flat[np.abs(epoch_times - tick).argmin()]) hlabels = [x / n_times + 1 for x in hticks] ax_hscroll.set_xticks(hticks) ax_hscroll.set_xticklabels(hlabels) for epoch_idx in range(len(epoch_times)): ax_hscroll.add_patch(mpl.patches.Rectangle((epoch_idx * n_times, 0), n_times, 1, facecolor=(0.8, 0.8, 0.8), edgecolor=(0.8, 0.8, 0.8), alpha=0.5)) hsel_patch = mpl.patches.Rectangle((0, 0), duration, 1, edgecolor='k', facecolor=(0.5, 0.5, 0.5), alpha=0.25, linewidth=1, clip_on=False) ax_hscroll.add_patch(hsel_patch) text = ax.text(0, 0, 'blank', zorder=3, verticalalignment='baseline', ha='left', fontweight='bold') text.set_visible(False) params.update({'fig': fig, 'ax': ax, 'ax2': ax2, 'ax_hscroll': ax_hscroll, 'ax_vscroll': ax_vscroll, 'vsel_patch': vsel_patch, 'hsel_patch': hsel_patch, 'lines': lines, 'projs': projs, 'ch_names': ch_names, 'n_channels': n_channels, 'n_epochs': n_epochs, 'scalings': scalings, 'duration': duration, 'ch_start': 0, 'colors': colors, 'def_colors': type_colors, # don't change at runtime 'picks': picks, 'data': data, 'times': times, 'epoch_times': epoch_times, 'offsets': offsets, 'labels': labels, 'scale_factor': 1.0, 'butterfly_scale': 1.0, 'fig_proj': None, 'types': np.array(types), 'inds': inds, 'vert_lines': list(), 'vertline_t': vertline_t, 'butterfly': False, 'text': text, 'ax_help_button': ax_help_button, # needed for positioning 'help_button': help_button, # reference needed for clicks 'fig_options': None, 'settings': [True, True, True, True], 'image_plot': None}) params['plot_fun'] = partial(_plot_traces, params=params) # callbacks callback_scroll = partial(_plot_onscroll, params=params) fig.canvas.mpl_connect('scroll_event', callback_scroll) callback_click = partial(_mouse_click, params=params) fig.canvas.mpl_connect('button_press_event', callback_click) callback_key = partial(_plot_onkey, params=params) fig.canvas.mpl_connect('key_press_event', callback_key) callback_resize = partial(_resize_event, params=params) fig.canvas.mpl_connect('resize_event', callback_resize) fig.canvas.mpl_connect('pick_event', partial(_onpick, params=params)) params['callback_key'] = callback_key # Draw event lines for the first time. _plot_vert_lines(params) # Plot bad epochs for epoch_idx in params['bads']: params['ax_hscroll'].patches[epoch_idx].set_color((1., 0., 0., 1.)) params['ax_hscroll'].patches[epoch_idx].set_zorder(3) params['ax_hscroll'].patches[epoch_idx].set_edgecolor('w') for ch_idx in range(len(params['ch_names'])): params['colors'][ch_idx][epoch_idx] = (1., 0., 0., 1.) assert params['fix_log'].shape == (len(epochs.events), len(params['ch_names'])) # Plot bad segments if params['fix_log'] is not None: for ch_idx in range(len(params['ch_names'])): for epoch_idx in range(len(epochs.events)): this_log = params['fix_log'][epoch_idx, ch_idx] if epoch_idx in params['bads']: pass else: if this_log == 1: params['colors'][ch_idx][epoch_idx] = (1., 0., 0., 1.) elif this_log == 2: params['colors'][ch_idx][epoch_idx] = (0., 0., 1., 1.) params['plot_fun']()
def test_fix_stim_artifact(): """Test fix stim artifact.""" events = read_events(event_fname) raw = read_raw_fif(raw_fname) assert_raises(RuntimeError, fix_stim_artifact, raw) raw = read_raw_fif(raw_fname, preload=True) # use window before stimulus in epochs tmin, tmax, event_id = -0.2, 0.5, 1 picks = pick_types(raw.info, meg=True, eeg=True, eog=True, stim=False, exclude='bads') epochs = Epochs(raw, events, event_id, tmin, tmax, picks=picks, preload=True, reject=None) e_start = int(np.ceil(epochs.info['sfreq'] * epochs.tmin)) tmin, tmax = -0.045, -0.015 tmin_samp = int(-0.035 * epochs.info['sfreq']) - e_start tmax_samp = int(-0.015 * epochs.info['sfreq']) - e_start epochs = fix_stim_artifact(epochs, tmin=tmin, tmax=tmax, mode='linear') data = epochs.get_data()[:, :, tmin_samp:tmax_samp] diff_data0 = np.diff(data[0][0]) diff_data0 -= np.mean(diff_data0) assert_array_almost_equal(diff_data0, np.zeros(len(diff_data0))) epochs = fix_stim_artifact(epochs, tmin=tmin, tmax=tmax, mode='window') data_from_epochs_fix = epochs.get_data()[:, :, tmin_samp:tmax_samp] assert_true(np.all(data_from_epochs_fix) == 0.) # use window before stimulus in raw event_idx = np.where(events[:, 2] == 1)[0][0] tmin, tmax = -0.045, -0.015 tmin_samp = int(-0.035 * raw.info['sfreq']) tmax_samp = int(-0.015 * raw.info['sfreq']) tidx = int(events[event_idx, 0] - raw.first_samp) assert_raises(ValueError, fix_stim_artifact, raw, events=np.array([])) raw = fix_stim_artifact(raw, events=None, event_id=1, tmin=tmin, tmax=tmax, mode='linear', stim_channel='STI 014') data, times = raw[:, (tidx + tmin_samp):(tidx + tmax_samp)] diff_data0 = np.diff(data[0]) diff_data0 -= np.mean(diff_data0) assert_array_almost_equal(diff_data0, np.zeros(len(diff_data0))) raw = fix_stim_artifact(raw, events, event_id=1, tmin=tmin, tmax=tmax, mode='window') data, times = raw[:, (tidx + tmin_samp):(tidx + tmax_samp)] assert_true(np.all(data) == 0.) # get epochs from raw with fixed data tmin, tmax, event_id = -0.2, 0.5, 1 epochs = Epochs(raw, events, event_id, tmin, tmax, picks=picks, preload=True, reject=None, baseline=None) e_start = int(np.ceil(epochs.info['sfreq'] * epochs.tmin)) tmin_samp = int(-0.035 * epochs.info['sfreq']) - e_start tmax_samp = int(-0.015 * epochs.info['sfreq']) - e_start data_from_raw_fix = epochs.get_data()[:, :, tmin_samp:tmax_samp] assert_true(np.all(data_from_raw_fix) == 0.) # use window after stimulus evoked = epochs.average() tmin, tmax = 0.005, 0.045 tmin_samp = int(0.015 * evoked.info['sfreq']) - evoked.first tmax_samp = int(0.035 * evoked.info['sfreq']) - evoked.first evoked = fix_stim_artifact(evoked, tmin=tmin, tmax=tmax, mode='linear') data = evoked.data[:, tmin_samp:tmax_samp] diff_data0 = np.diff(data[0]) diff_data0 -= np.mean(diff_data0) assert_array_almost_equal(diff_data0, np.zeros(len(diff_data0))) evoked = fix_stim_artifact(evoked, tmin=tmin, tmax=tmax, mode='window') data = evoked.data[:, tmin_samp:tmax_samp] assert_true(np.all(data) == 0.)
def _interpolate_bads_meg(inst, mode='accurate', origin=None, verbose=None): """Interpolate bad channels from data in good channels. Parameters ---------- inst : mne.io.Raw, mne.Epochs or mne.Evoked The data to interpolate. Must be preloaded. mode : str Either `'accurate'` or `'fast'`, determines the quality of the Legendre polynomial expansion used for interpolation. `'fast'` should be sufficient for most applications. origin : None | list If None, origin is set to sensor center of mass, otherwise use the coordinates provided as origin. The old standard value is (0., 0., 0.04) verbose : bool, str, int, or None If not None, override default verbose level (see :func:`mne.verbose` and :ref:`Logging documentation <tut_logging>` for more). """ picks_meg = pick_types(inst.info, meg=True, eeg=False, exclude=[]) picks_good = pick_types(inst.info, meg=True, eeg=False, exclude='bads') meg_ch_names = [inst.info['ch_names'][p] for p in picks_meg] bads_meg = [ch for ch in inst.info['bads'] if ch in meg_ch_names] # select the bad meg channel to be interpolated if len(bads_meg) == 0: picks_bad = [] else: picks_bad = pick_channels(inst.info['ch_names'], bads_meg, exclude=[]) # return without doing anything if there are no meg channels if len(picks_meg) == 0 or len(picks_bad) == 0: return info_from = pick_info(inst.info, picks_good) info_to = pick_info(inst.info, picks_bad) if origin is None: posvec = np.array([inst.info['chs'][p]['loc'][0:3] for p in picks_meg]) norvec = np.array( [inst.info['chs'][p]['loc'][9:12] for p in picks_meg]) cogpos = np.mean(posvec, axis=0) norsum = np.mean(norvec, axis=0) anorm = np.sqrt(np.dot(norsum, norsum.T)) ndir = norsum / anorm # push the position slightly (4cm) away from the helmet: altpos = cogpos - 0.04 * ndir print(">_interpolate_bads_meg\\DBG> cog(sens) = [%8.5f %8.5f %8.5f]" % \ (cogpos[0], cogpos[1], cogpos[2])) print(">_interpolate_bads_meg\\DBG> alt(sens) = [%8.5f %8.5f %8.5f]" % \ (altpos[0], altpos[1], altpos[2])) cogposhd = apply_trans(inst.info['dev_head_t']['trans'], cogpos, move=True) altposhd = apply_trans(inst.info['dev_head_t']['trans'], altpos, move=True) print(">_interpolate_bads_meg\\DBG> cog(hdcs) = [%8.5f %8.5f %8.5f]" % \ (cogposhd[0], cogposhd[1], cogposhd[2])) print(">_interpolate_bads_meg\\DBG> alt(hdcs) = [%8.5f %8.5f %8.5f]" % \ (altposhd[0], altposhd[1], altposhd[2])) print(">_interpolate_bads_meg\\DBG> calling _map_meg_channels(..., origin=(%8.5f %8.5f %8.5f))" % \ (altposhd[0], altposhd[1], altposhd[2])) origin = (altposhd[0], altposhd[1], altposhd[2]) else: origin = origin mapping = _map_meg_channels(info_from, info_to, mode=mode, origin=origin) _do_interp_dots(inst, mapping, picks_good, picks_bad)
def find_bad_epochs(epochs, picks=None, return_by_metric=False, method='faster', method_params=None, verbose=None): """Implements the second step of the FASTER algorithm. This function attempts to automatically mark bad epochs by performing outlier detection. Parameters ---------- epochs : Instance of Epochs The epochs to analyze. picks : list of int | None Channels to operate on. Defaults to EEG channels. method : {'faster'} The detection algorithm. method_params : dict | None The method parameters in a dict. If ``method`` equals 'faster', and ``method_params``is None, defaults to the following parameters. Partial updates are supported. use_metrics : list of str List of metrics to use. Can be any combination of: 'amplitude', 'variance', 'deviation'. Defaults to all of them. thresh : float The threshold value, in standard deviations, to apply. A channel crossing this threshold value is marked as bad. Defaults to 3. max_iter : int The maximum number of iterations performed during outlier detection (defaults to 1, as in the original FASTER paper). return_by_metric : bool Whether to return the bad channels as a flat list (False, default) or as a dictionary with the names of the used metrics as keys and the bad channels found by this metric as values. Is ignored if not supported by method. verbose : bool, str, int, or None If not None, override default verbose level (see mne.verbose). Defaults to self.verbose. Returns ------- bads : list of int The indices of the bad epochs. """ if picks is None: picks = pick_types(epochs.info, meg=True, eeg=True, exclude='bads') _method_params = _handle_default('bads' + '_' + method, method_params) if method == 'faster': bads = _find_bad_epochs(epochs, picks, **_method_params) else: raise NotImplementedError( 'Come back later, for now there is only "FASTER"') if return_by_metric: return bads else: return _combine_indices(bads)
def interpolate_bads(inst, reset_bads=True, mode='accurate', origin=None, verbose=None): """ Interpolate bad MEG and EEG channels. We added this method since the original interpolation routine resulted in some interpolated channels having amplitudes being magnitudes smaller than the channels they are being interpolated from. _interpolate_bads_meg(inst, origin=None) now calculates the center of mass of the sensors and uses that as origin (written by Eberhard). Operates in place. Parameters ---------- inst : mne.io.Raw, mne.Epochs or mne.Evoked The data to interpolate. Must be preloaded. reset_bads : bool If True, remove the bads from info. mode : str Either ``'accurate'`` or ``'fast'``, determines the quality of the Legendre polynomial expansion used for interpolation of MEG channels. origin : None | list If None, origin is set to sensor center of mass, otherwise use the coordinates provided as origin. The old standard value is (0., 0., 0.04) verbose : bool, str, int, or None If not None, override default verbose level (see :func:`mne.verbose` and :ref:`Logging documentation <tut_logging>` for more). Returns ------- inst : instance of Raw, Epochs, or Evoked The modified instance. """ from mne.channels.interpolation import _interpolate_bads_eeg if getattr(inst, 'preload', None) is False: raise ValueError('Data must be preloaded.') picks_meg = pick_types(inst.info, meg=True, eeg=False, exclude=[]) if len(picks_meg) != 0: if origin is None: origin = _estimate_origin(inst.info, picks_meg) else: origin = origin if check_version('mne', '0.20'): _interpolate_bads_eeg(inst, origin=origin) else: # workaround for compatibility with 0.19, should be removed soon import warnings warnings.warn( 'EEG channels may be interpolated with an incorrect origin,' 'leading to inaccurate interpolation. Please update mne' 'to the latest version for best results.', Warning) _interpolate_bads_eeg(inst) _interpolate_bads_meg(inst, origin=origin, mode=mode) if reset_bads is True: inst.info['bads'] = [] return inst
std_freq_i = coil_freqs.index(std_freq) cal_dims = [1, 3] # dimension of calibration files to test (1 and/or 3) ########################### # Load raw for channel info ########################### # Construct fname date = '160302' file_beg = date + '_empty_room_rotating_coil_' file_end = '_hz_raw.fif' fname_raw = op.join(file_head_dir, 'coil_data', '160302', file_beg + str(std_freq) + '_hz_raw.fif') # Load file and get mag inds raw = mne.io.Raw(fname_raw) mag_picks = pick_types(raw.info, meg='mag') loc_arr = np.zeros((len(coil_freqs), len(mag_picks), 3)) ########################################### # Loop over all combinations of frequencies ########################################### # Fill array with normal vectors for both sets of frequencies for ci, freq in enumerate(coil_freqs): freq_fname = op.join(data_dir, 'sss_' + str(freq) + 'Hz_1D_cal.dat') loc_arr[ci, :, :] = extract_znorm(freq_fname, mag_picks) ######################################################## # Compare all vector normals ######################################################## diff = {}
def select_vertices_in_sensor_range(inst, dist, info=None, picks=None, trans=None, indices=False, verbose=None): """Find vertices within given distance to a sensor. Parameters ---------- inst : instance of Forward | instance of SourceSpaces The object to select vertices from. dist : float The minimum distance between a vertex and the nearest sensor. All vertices for which the distance to the nearest sensor exceeds this limit are discarded. info : instance of Info | None The info structure that contains information about the channels. Only needs to be specified if the object to select vertices from does is an instance of SourceSpaces. picks : array-like of int | None Indices of sensors to include in the search for the nearest sensor. If ``None``, the default, only MEG channels are used. trans : str | instance of Transform | None Either the full path to the head<->MRI transform ``*-trans.fif`` file produced during coregistration, or the Transformation itself. If trans is None, an identity matrix is assumed. Only needed when ``inst`` is a source space in MRI coordinates. indices: False | True If ``True``, return vertex indices instead of vertex numbers. Defaults to ``False``. verbose : bool | str | int | None If not None, override default verbose level (see :func:`mne.verbose` and :ref:`Logging documentation <tut_logging>` for more). Returns ------- vertices : pair of lists | list of int Either a list of vertex numbers for the left and right hemisphere (if ``indices==False``) or a single list with vertex indices. See Also -------- restrict_forward_to_vertices : restrict Forward to the given vertices restrict_src_to_vertices : restrict SourceSpaces to the given vertices """ if isinstance(inst, Forward): info = inst['info'] src = inst['src'] elif isinstance(inst, SourceSpaces): src = inst if info is None: raise ValueError('You need to specify an Info object with ' 'information about the channels.') # Load the head<->MRI transform if necessary if src[0]['coord_frame'] == FIFF.FIFFV_COORD_MRI: if trans is None: raise ValueError('Source space is in MRI coordinates, but no ' 'head<->MRI transform was given. Please specify ' 'the full path to the appropriate *-trans.fif ' 'file as the "trans" parameter.') if isinstance(trans, string_types): trans = read_trans(trans, return_all=True) for trans in trans: # we got at least 1 try: trans = _ensure_trans(trans, 'head', 'mri') except Exception as exp: pass else: break else: raise exp src_trans = invert_transform(_ensure_trans(trans, 'head', 'mri')) print('Transform!') else: src_trans = Transform('head', 'head') # Identity transform dev_to_head = _ensure_trans(info['dev_head_t'], 'meg', 'head') if picks is None: picks = pick_types(info, meg=True) if len(picks) > 0: logger.info('Using MEG channels') else: logger.info('Using EEG channels') picks = pick_types(info, eeg=True) src_pos = np.vstack([ apply_trans(src_trans, s['rr'][s['inuse'].astype(np.bool)]) for s in src ]) sensor_pos = [] for ch in picks: # MEG channels are in device coordinates, translate them to head if channel_type(info, ch) in ['mag', 'grad']: sensor_pos.append( apply_trans(dev_to_head, info['chs'][ch]['loc'][:3])) else: sensor_pos.append(info['chs'][ch]['loc'][:3]) sensor_pos = np.array(sensor_pos) # Find vertices that are within range of a sensor. We use a KD-tree for # speed. logger.info('Finding vertices within sensor range...') tree = cKDTree(sensor_pos) distances, _ = tree.query(src_pos, distance_upper_bound=dist) # Vertices out of range are flagged as np.inf src_sel = np.isfinite(distances) logger.info('[done]') if indices: return np.flatnonzero(src_sel) else: n_lh_verts = src[0]['nuse'] lh_sel, rh_sel = src_sel[:n_lh_verts], src_sel[n_lh_verts:] vert_lh = src[0]['vertno'][lh_sel] vert_rh = src[1]['vertno'][rh_sel] return [vert_lh, vert_rh]
def _prepare_for_forward(src, mri_head_t, info, bem, mindist, n_jobs, perts, bem_extra='', trans='', info_extra='', meg=True, eeg=True, ignore_ref=False, verbose=None): """Prepare for forward computation.""" # Read the source locations logger.info('') # let's make a copy in case we modify something src = _ensure_src(src).copy() nsource = sum(s['nuse'] for s in src) if nsource == 0: raise RuntimeError('No sources are active in these source spaces. ' '"do_all" option should be used.') logger.info('Read %d source spaces a total of %d active source locations' % (len(src), nsource)) # Delete some keys to clean up the source space: for key in ['working_dir', 'command_line']: if key in src.info: del src.info[key] # Read the MRI -> head coordinate transformation logger.info('') _print_coord_trans(mri_head_t) # make a new dict with the relevant information arg_list = [ info_extra, trans, src, bem_extra, meg, eeg, mindist, n_jobs, verbose ] cmd = 'make_forward_solution(%s)' % (', '.join([str(a) for a in arg_list])) mri_id = dict(machid=np.zeros(2, np.int32), version=0, secs=0, usecs=0) info = Info(chs=info['chs'], comps=info['comps'], dev_head_t=info['dev_head_t'], mri_file=trans, mri_id=mri_id, meas_file=info_extra, meas_id=None, working_dir=os.getcwd(), command_line=cmd, bads=info['bads'], mri_head_t=mri_head_t) info._update_redundant() info._check_consistency() logger.info('') megcoils, compcoils, megnames, meg_info = [], [], [], [] eegels, eegnames = [], [] if meg and len(pick_types(info, ref_meg=False, exclude=[])) > 0: megcoils, compcoils, megnames, meg_info = \ _prep_meg_channels(info, perts, ignore_ref=ignore_ref) if eeg and len( pick_types(info, meg=False, eeg=True, ref_meg=False, exclude=[])) > 0: eegels, eegnames = _prep_eeg_channels(info) # Check that some channels were found if len(megcoils + eegels) == 0: raise RuntimeError('No MEG or EEG channels found.') # pick out final info info = pick_info( info, pick_types(info, meg=meg, eeg=eeg, ref_meg=False, exclude=[])) # Transform the source spaces into the appropriate coordinates # (will either be HEAD or MRI) for s in src: transform_surface_to(s, 'head', mri_head_t) logger.info('Source spaces are now in %s coordinates.' % _coord_frame_name(s['coord_frame'])) # Prepare the BEM model bem = _setup_bem(bem, bem_extra, len(eegnames), mri_head_t) # Circumvent numerical problems by excluding points too close to the skull if not bem['is_sphere']: inner_skull = _bem_find_surface(bem, 'inner_skull') _filter_source_spaces(inner_skull, mindist, mri_head_t, src, n_jobs) logger.info('') rr = np.concatenate([s['rr'][s['vertno']] for s in src]) if len(rr) < 1: raise RuntimeError('No points left in source space after excluding ' 'points close to inner skull.') # deal with free orientations: source_nn = np.tile(np.eye(3), (len(rr), 1)) update_kwargs = dict(nchan=len(info['ch_names']), nsource=len(rr), info=info, src=src, source_nn=source_nn, source_rr=rr, surf_ori=False, mri_head_t=mri_head_t) return megcoils, meg_info, compcoils, megnames, eegels, eegnames, rr, \ info, update_kwargs, bem
def find_bad_channels_in_epochs(epochs, picks=None, method='faster', method_params=None, return_by_metric=False): """Implements the fourth step of the FASTER algorithm. This function attempts to automatically mark bad channels in each epochs by performing outlier detection. Parameters ---------- epochs : Instance of Epochs The epochs to analyze. picks : list of int | None Channels to operate on. Defaults to EEG channels. method : {'faster'} The detection algorithm. method_params : dict | None The method parameters in a dict. If ``method`` equals 'faster', and ``method_params``is None, defaults to the following parameters. Partial updates are supported. use_metrics : list of str List of metrics to use. Can be any combination of: 'amplitude', 'variance', 'deviation', 'median_gradient' Defaults to all of them. thresh : float The threshold value, in standard deviations, to apply. A channel crossing this threshold value is marked as bad. Defaults to 3. max_iter : int The maximum number of iterations performed during outlier detection (defaults to 1, as in the original FASTER paper). return_by_metric : bool Whether to return the bad channels as a flat list (False, default) or as a dictionary with the names of the used metrics as keys and the bad channels found by this metric as values. Is ignored if not supported by method. Returns ------- bads : list of lists of int For each epoch, the indices of the bad channels. """ if picks is None: picks = pick_types(epochs.info, meg=True, eeg=True, exclude=[]) _method_params = _handle_default('bads' + '_' + method, method_params) if method == 'faster': bads = _find_bad_channels_in_epochs(epochs, picks, **_method_params) else: raise NotImplementedError( 'Come back later, for now there is only "FASTER"') info = pick_info(epochs.info, picks, copy=True) if return_by_metric: bads = dict((m, _bad_mask_to_names(info, v)) for m, v in bads.items()) else: bads = np.sum(bads.values(), axis=0).astype(bool) bads = _bad_mask_to_names(info, bads) return bads