Ejemplo n.º 1
0
def test_return_filtered():
    """Test return filtered option."""
    # Check return_filtered
    # Simulated more noise data and with broader freqquency than the desired
    X, _, _ = simulate_data(SNR=0.9, freqs_sig=[4, 13])
    sf = 250
    n_channels = X.shape[0]
    info = create_info(ch_names=n_channels, sfreq=sf, ch_types='eeg')

    filt_params_signal = dict(l_freq=freqs_sig[0], h_freq=freqs_sig[1],
                              l_trans_bandwidth=1, h_trans_bandwidth=1)
    filt_params_noise = dict(l_freq=freqs_noise[0], h_freq=freqs_noise[1],
                             l_trans_bandwidth=1, h_trans_bandwidth=1)

    # return filtered to true
    ssd = SSD(info, filt_params_signal, filt_params_noise,
              sort_by_spectral_ratio=False, return_filtered=True)
    ssd.fit(X)

    out = ssd.transform(X)
    psd_out, freqs = psd_array_welch(out[0], sfreq=250, n_fft=250)
    freqs_up = int(freqs[psd_out > 0.5][0]), int(freqs[psd_out > 0.5][-1])
    assert (freqs_up == freqs_sig)

    # return filtered to false
    ssd = SSD(info, filt_params_signal, filt_params_noise,
              sort_by_spectral_ratio=False, return_filtered=False)
    ssd.fit(X)

    out = ssd.transform(X)
    psd_out, freqs = psd_array_welch(out[0], sfreq=250, n_fft=250)
    freqs_up = int(freqs[psd_out > 0.5][0]), int(freqs[psd_out > 0.5][-1])
    assert (freqs_up != freqs_sig)
Ejemplo n.º 2
0
def test_psd_nan():
    """Test handling of NaN in psd_array_welch."""
    n_samples, n_fft, n_overlap = 2048, 1024, 512
    x = np.random.RandomState(0).randn(1, n_samples)
    psds, freqs = psd_array_welch(x[:, :n_fft + n_overlap],
                                  float(n_fft),
                                  n_fft=n_fft,
                                  n_overlap=n_overlap)
    x[:, n_fft + n_overlap:] = np.nan  # what Raw.get_data() will give us
    psds_2, freqs_2 = psd_array_welch(x,
                                      float(n_fft),
                                      n_fft=n_fft,
                                      n_overlap=n_overlap)
    assert_allclose(freqs, freqs_2)
    assert_allclose(psds, psds_2)
    # 1-d
    psds_2, freqs_2 = psd_array_welch(x[0],
                                      float(n_fft),
                                      n_fft=n_fft,
                                      n_overlap=n_overlap)
    assert_allclose(freqs, freqs_2)
    assert_allclose(psds[0], psds_2)
    # defaults
    with catch_logging() as log:
        psd_array_welch(x, float(n_fft), verbose='debug')
    log = log.getvalue()
    assert 'using 256-point FFT on 256 samples with 0 overlap' in log
    assert 'hamming window' in log
Ejemplo n.º 3
0
def test_psd_nan():
    """Test handling of NaN in psd_array_welch."""
    n_samples, n_fft, n_overlap = 2048,  1024, 512
    x = np.random.RandomState(0).randn(1, n_samples)
    psds, freqs = psd_array_welch(
        x[:n_fft + n_overlap], float(n_fft), n_fft=n_fft, n_overlap=n_overlap)
    x[n_fft + n_overlap:] = np.nan  # what Raw.get_data() will give us
    psds_2, freqs_2 = psd_array_welch(
        x, float(n_fft), n_fft=n_fft, n_overlap=n_overlap)
    assert_allclose(freqs, freqs_2)
    assert_allclose(psds, psds_2)
Ejemplo n.º 4
0
def get_avg_band_power_single_channel(signal, fs):
    # PSD
    # calculate PSD using Welch's method. Although better approach is to use multitaper algorithm,
    # but firstly, it is much slower than Welch's method. Secondly, our data is already
    # cleaned and preprocessed, so both methods probably will give similar results

    psds, freqs = psd_array_welch(signal, sfreq=fs, n_per_seg=7, n_fft=np.shape(signal)[0])

    plt.plot(freqs[1:np.shape(freqs)[0] - 1], psds[1:np.shape(psds)[0] - 1])
    plt.show()

    # 1. find average band powers (for alpha, beta, gamma and theta bands)
    freq_bands = {  # upper and lower limits of all the needed bands
        'alpha': [8, 13],
        'beta': [13, 30],
        'gamma': [30, 40],
        'theta': [4, 8]
    }

    freq_res = freqs[1] - freqs[0]  # frequency resolution
    avg_power = []  # we have to store the avg band power somewhere...

    # calculate avg band power (absolute, not relative - we don't need percents) in each of the bands
    # The absolute delta power is equal to the area under the plot of already calculated PSD.
    # And as we know, this can be obtained by integrating. As we don't have any formula, which we can
    # integrate to obtain this area, we need to approximate it. As suggested in
    # https://raphaelvallat.com/bandpower.html, let's choose Simpson's method, which is relying on
    # decomposition of the area into several parabola and then summing up the area of these parabola.
    for band in ['alpha', 'beta', 'gamma', 'theta']:  # maybe strange, but definitely readable xD
        # find indices, which satisfy the limits of the specific band
        idx = np.logical_and(freqs >= freq_bands[band][0], freqs <= freq_bands[band][1])
        avg = simps(psds[idx], dx=freq_res)  # integrals, sweet integrals <3
        avg_power.append(avg)  # success, save the computed value!

    return avg_power
Ejemplo n.º 5
0
    def spectral_ratio_ssd(self, ssd_sources):
        """Spectral ratio measure for best n_components selection
        See Nikulin 2011, Eq. (24)
        
        Parameters
        ----------
        ssd_sources : data projected on the SSD space. 
        output of transform
       
        """

        psd, freqs = psd_array_welch(ssd_sources,
                                     sfreq=self.sampling_freq,
                                     n_fft=self.n_fft)
        sig_idx = _time_mask(freqs, *self.freqs_signal)
        noise_idx = _time_mask(freqs, *self.freqs_noise)
        if psd.ndim == 3:
            spec_ratio = psd[:, :, sig_idx].mean(axis=2).mean(
                axis=0) / psd[:, :, noise_idx].mean(axis=2).mean(axis=0)

        else:

            spec_ratio = psd[:, sig_idx].mean(axis=1) / psd[:, noise_idx].mean(
                axis=1)
        sorter_spec = spec_ratio.argsort()[::-1]
        return spec_ratio, sorter_spec
Ejemplo n.º 6
0
def welch_p(X, sfreq, fmin, fmax, n_fft, n_overlap, n_per_seg):
    '''
    Use welch method to estimate signal power spectral density
    Basic function is mne.psd_array_welch
    :param X: input data array (n_events, n_epochs, n_times)
    :param sfreq: the sampling frequency
    :param fmin, fmax: the lower(upper) frequency of interest
    :param n_fft: the length of FFT used, must be >= n_per_seg
    :param n_overlap: the number of points of overlap between segments
    :param n_per_seg: length of each welch segment, usually = n_fft
    :param psds: power spectral density array (n_events, n_epochs, n_freqs)
    :param freqs: frequencies used in psd analysis
    '''
    num_freqs = int(math.floor((fmax - fmin) / (sfreq / n_fft)) + 1)
    psds = np.zeros((X.shape[0], X.shape[1], num_freqs))
    freqs = np.zeros((X.shape[0], X.shape[1], num_freqs))

    for i in range(X.shape[0]):
        for j in range(X.shape[1]):
            psds[i, j, :], freqs[i,
                                 j, :] = psd_array_welch(X[i, j, :],
                                                         sfreq=sfreq,
                                                         fmin=fmin,
                                                         fmax=fmax,
                                                         n_fft=n_fft,
                                                         n_overlap=n_overlap,
                                                         n_per_seg=n_per_seg)

    return psds, freqs
Ejemplo n.º 7
0
def eeg_power_band(epochs):
    """EEG relative power band feature extraction.

    This function takes an ``mne.Epochs`` object and creates EEG features based
    on relative power in specific frequency bands that are compatible with
    scikit-learn.

    Parameters
    ----------
    epochs : Epochs
        The data.

    Returns
    -------
    X : numpy array of shape [n_samples, 5]
        Transformed data.
    """
    # specific frequency bands
    FREQ_BANDS = {
        "delta": [0.5, 4.5],
        "theta": [4.5, 8.5],
        "alpha": [8.5, 11.5],
        "sigma": [11.5, 15.5],
        "beta": [15.5, 30]
    }

    EEG_CHANNELS = ["EEG Fpz-Cz", "EEG Pz-Oz"]

    sfreq = epochs.info['sfreq']
    data = epochs.load_data().pick_channels(EEG_CHANNELS).get_data()
    psds, freqs = psd_array_welch(data,
                                  sfreq,
                                  fmin=0.5,
                                  fmax=30.,
                                  n_fft=512,
                                  n_overlap=256)
    # Normalize the PSDs
    psds /= np.sum(psds, axis=-1, keepdims=True)

    X = []
    for _, (fmin, fmax) in FREQ_BANDS.items():
        psds_band = psds[:, :, (freqs >= fmin) & (freqs < fmax)].mean(axis=-1)
        X.append(psds_band.reshape(len(psds), -1))

    return np.concatenate(X, axis=1)
Ejemplo n.º 8
0
def prepare_psd(times, t_win, ch_group, meta, X, freq_band, info, psd_params):
    """
    df.data is average PSD across ch_group and times between t_lo and t_hi
    psd is non-averaged PSD returned for plotting/inspection

    """
    df, X = _drop_by_confidence(meta, X, 0, 30, 70, 100)
    df = add_condition(df, 30, 70)

    time_mask, ch_inds = _get_masks(times, t_win[0], t_win[1], ch_group, info)
    psd, freqs = psd_array_welch(X[:, ch_inds, time_mask],
                                 sfreq=info["sfreq"],
                                 **psd_params)

    freq_mask = np.logical_and(freqs > freq_band[0], freqs < freq_band[1])
    df["data"] = psd[:, :, freq_mask].mean(axis=(1, 2))

    return df, psd, freqs
Ejemplo n.º 9
0
def prepare_band_power(times, t_win, meta, X, freq_band, info, psd_params):
    """
    df.data is average PSD across ch_group and times between t_lo and t_hi
    psd is non-averaged PSD returned for plotting/inspection

    """
    df, X = _drop_by_confidence(meta, X, 0, 30, 70, 100)
    df = add_condition(df, 30, 70)

    time_mask, _ = _get_masks(times, t_win[0], t_win[1], "parietal", info)
    psd, freqs = psd_array_welch(X[:, :, time_mask.squeeze()],
                                 sfreq=info["sfreq"],
                                 **psd_params)
    # freq_mask = np.logical_and(freqs > freq_band[0], freqs < freq_band[1])
    # power = (
    #     psd[:, :, freq_mask].mean(axis=2, keepdims=True).transpose((0, 2, 1))
    # )
    power = psd.transpose((0, 2, 1))

    return df, power, freqs
Ejemplo n.º 10
0
def eeg_power_band(epochs):
    """EEG relative power band feature extraction.

    This function takes an ``mne.Epochs`` object and creates EEG features based
    on relative power in specific frequency bands that are compatible with
    scikit-learn.

    Parameters
    ----------
    epochs : Epochs
        The data.

    Returns
    -------
    X : numpy array of shape [n_samples, 5]
        Transformed data.
    """
    # specific frequency bands
    FREQ_BANDS = {"delta": [0.5, 4.5],
                  "theta": [4.5, 8.5],
                  "alpha": [8.5, 11.5],
                  "sigma": [11.5, 15.5],
                  "beta": [15.5, 30]}

    EEG_CHANNELS = ["EEG Fpz-Cz", "EEG Pz-Oz"]

    sfreq = epochs.info['sfreq']
    data = epochs.load_data().pick_channels(EEG_CHANNELS).get_data()
    psds, freqs = psd_array_welch(data, sfreq, fmin=0.5, fmax=30.,
                                  n_fft=512, n_overlap=256)
    # Normalize the PSDs
    psds /= np.sum(psds, axis=-1, keepdims=True)

    X = []
    for _, (fmin, fmax) in FREQ_BANDS.items():
        psds_band = psds[:, :, (freqs >= fmin) & (freqs < fmax)].mean(axis=-1)
        X.append(psds_band.reshape(len(psds), -1))

    return np.concatenate(X, axis=1)
Ejemplo n.º 11
0
def plot_extended(S,
                  sfreq,
                  f_scale,
                  powers,
                  ica_mne,
                  sort=True,
                  plot_env=True,
                  number=False,
                  h_freq_filt=2.,
                  save=None,
                  t_min=1,
                  y_lim=None,
                  t_max=10,
                  pdf_from_sources=True,
                  extension='pdf'):
    n_plots = 10
    n_s = S.shape[0]
    if sort is True:
        order = np.argsort(kurtosis(S, axis=1))[::-1]
    elif type(sort) is list:
        order = sort
        n_s = len(order)
    else:
        order = np.arange(n_s)
    if plot_env:
        n_col = 3
        width_ratios = [1.5, 1, .7]
        figsize = (3, 8)
    else:
        n_col = 2
        width_ratios = [1, .3]
        figsize = (3, 8)
    n_f = max(n_s // n_plots, 1)
    for i in range(n_f):
        f, ax = plt.subplots(n_plots,
                             n_col,
                             figsize=figsize,
                             gridspec_kw=dict(width_ratios=width_ratios,
                                              top=0.95,
                                              bottom=0.11,
                                              left=0.11,
                                              right=0.9,
                                              hspace=0.18,
                                              wspace=0.04))
        for j in range(n_plots):
            if i * n_plots + j >= n_s:
                break
            idx = order[i * n_plots + j]
            ax_idx = 0
            axe = ax[j]
            if plot_env:
                s = S[idx]
                s *= np.sign(np.mean(s**3))
                # amp = np.abs(hilbert(s))
                #
                # to_plot = amp[100:-100]
                # to_plot = filter_data(to_plot, sfreq=sfreq, l_freq=None,
                #                       h_freq=h_freq_filt)
                n_s = 3000
                idx_min = int(sfreq * t_min)
                idx_max = int(sfreq * t_max)
                slice_len = int((idx_max - idx_min) / n_s) + 1
                to_plot = s[idx_min:idx_max:slice_len]
                # loc = np.argmax(to_plot)
                # n_points = 3000
                # idx_loc = np.arange(max(0, loc - n_points),
                #                     min(len(to_plot), loc + n_points))
                # to_plot = to_plot[idx_loc]
                n_s = len(to_plot)
                t = np.linspace(t_min, t_max, n_s)
                axe[0].plot(t, to_plot, linewidth=0.4, color='k')
                # axe[0].set_xlim([t_min, t_max])
                axe[0].set_yticklabels([])
                if j == n_plots - 1:
                    times = np.arange(t_min, t_max + 1, dtype=int)
                    axe[0].set_xticks(times)
                    axe[0].set_xticklabels(['%d' % time for time in times])
                    axe[0].set_xlabel('time (sec.)')
                else:
                    axe[0].set_xticklabels([])
                axe[0].set_yticks([])
                for axis in ['top', 'left', 'right']:
                    axe[0].spines[axis].set_visible(False)
                ax_idx = 1
            # axe[0].set_xlim([0, n_s])
            freqs = np.arange(0, max(f_scale), 20, dtype=int)
            axe[ax_idx].set_xticks(freqs)
            if j == n_plots - 1:
                axe[ax_idx].set_xlabel('f (Hz)')

                axe[ax_idx].set_xticklabels(['%d' % freq for freq in freqs])
            else:
                axe[ax_idx].set_xticklabels([])
            if pdf_from_sources:
                s_ = s / np.sqrt(np.mean(s**2))
                fmin = min(f_scale)
                fmax = max(f_scale)
                pows, f_ = psd_array_welch(s_, sfreq, fmin, fmax)
                print(min(pows), max(pows))
            else:
                pows = powers[:, idx]
                f_ = f_scale
            axe[ax_idx].semilogy(f_, pows, color='k', linewidth=1)
            if y_lim is None:
                y_lim = np.min(powers), np.max(powers)
            axe[ax_idx].set_ylim(*y_lim)
            axe[ax_idx].grid()
            axe[ax_idx].set_yticklabels([])
            axe[ax_idx].minorticks_off()
            ica_mne._ica_names[idx] = ''
            _plot_ica_topomap(ica_mne,
                              idx=idx,
                              axes=axe[ax_idx + 1],
                              title='',
                              sensors=False)
            if number is not False:
                if type(number) is np.ndarray:
                    string = '%d, %.2f' % (i * n_plots + j,
                                           number[i * n_plots + j])
                else:
                    string = '%d' % (i * n_plots + j + 1)
                axe[0].set_ylabel(string, rotation=0)
            if j == 0:
                if plot_env:
                    axe[0].set_title('Source')
                axe[ax_idx].set_title('Spectrum')
                axe[ax_idx + 1].set_title('Topo')
        if save is not None:
            plt.savefig('%s_%d.%s' % (save, i, extension))

    plt.show()
Ejemplo n.º 12
0
def test_ssd():
    """Test Common Spatial Patterns algorithm on raw data."""
    X, A, S = simulate_data()
    sf = 250
    n_channels = X.shape[0]
    info = create_info(ch_names=n_channels, sfreq=sf, ch_types='eeg')
    n_components_true = 5

    # Init
    filt_params_signal = dict(l_freq=freqs_sig[0],
                              h_freq=freqs_sig[1],
                              l_trans_bandwidth=1,
                              h_trans_bandwidth=1)
    filt_params_noise = dict(l_freq=freqs_noise[0],
                             h_freq=freqs_noise[1],
                             l_trans_bandwidth=1,
                             h_trans_bandwidth=1)
    ssd = SSD(info, filt_params_signal, filt_params_noise)
    # freq no int
    freq = 'foo'
    filt_params_signal = dict(l_freq=freq,
                              h_freq=freqs_sig[1],
                              l_trans_bandwidth=1,
                              h_trans_bandwidth=1)
    filt_params_noise = dict(l_freq=freqs_noise[0],
                             h_freq=freqs_noise[1],
                             l_trans_bandwidth=1,
                             h_trans_bandwidth=1)
    with pytest.raises(TypeError, match='must be an instance '):
        ssd = SSD(info, filt_params_signal, filt_params_noise)

    # Wrongly specified noise band
    freq = 2
    filt_params_signal = dict(l_freq=freq,
                              h_freq=freqs_sig[1],
                              l_trans_bandwidth=1,
                              h_trans_bandwidth=1)
    filt_params_noise = dict(l_freq=freqs_noise[0],
                             h_freq=freqs_noise[1],
                             l_trans_bandwidth=1,
                             h_trans_bandwidth=1)
    with pytest.raises(ValueError, match='Wrongly specified '):
        ssd = SSD(info, filt_params_signal, filt_params_noise)

    # filt param no dict
    filt_params_signal = freqs_sig
    filt_params_noise = freqs_noise
    with pytest.raises(ValueError, match='must be defined'):
        ssd = SSD(info, filt_params_signal, filt_params_noise)

    # Data type
    filt_params_signal = dict(l_freq=freqs_sig[0],
                              h_freq=freqs_sig[1],
                              l_trans_bandwidth=1,
                              h_trans_bandwidth=1)
    filt_params_noise = dict(l_freq=freqs_noise[0],
                             h_freq=freqs_noise[1],
                             l_trans_bandwidth=1,
                             h_trans_bandwidth=1)
    ssd = SSD(info, filt_params_signal, filt_params_noise)
    raw = io.RawArray(X, info)

    pytest.raises(TypeError, ssd.fit, raw)

    # More than 1 channel type
    ch_types = np.reshape([['mag'] * 10, ['eeg'] * 10], n_channels)
    info_2 = create_info(ch_names=n_channels, sfreq=sf, ch_types=ch_types)

    with pytest.raises(ValueError, match='At this point SSD'):
        ssd = SSD(info_2, filt_params_signal, filt_params_noise)

    # Number of channels
    info_3 = create_info(ch_names=n_channels + 1, sfreq=sf, ch_types='eeg')
    ssd = SSD(info_3, filt_params_signal, filt_params_noise)
    pytest.raises(ValueError, ssd.fit, X)

    # Fit
    n_components = 10
    ssd = SSD(info,
              filt_params_signal,
              filt_params_noise,
              n_components=n_components)

    # Call transform before fit
    pytest.raises(AttributeError, ssd.transform, X)

    # Check outputs
    ssd.fit(X)

    assert (ssd.filters_.shape == (n_channels, n_channels))
    assert (ssd.patterns_.shape == (n_channels, n_channels))

    # Transform
    X_ssd = ssd.fit_transform(X)
    assert (X_ssd.shape[0] == n_components)
    # back and forward
    ssd = SSD(info,
              filt_params_signal,
              filt_params_noise,
              n_components=None,
              sort_by_spectral_ratio=False)
    ssd.fit(X)
    X_denoised = ssd.inverse_transform(X)
    assert_array_almost_equal(X_denoised, X)

    # Power ratio ordering
    spec_ratio, _ = ssd.get_spectral_ratio(ssd.transform(X))
    # since we now that the number of true components is 5, the relative
    # difference should be low for the first 5 components and then increases
    index_diff = np.argmax(-np.diff(spec_ratio))
    assert index_diff == n_components_true - 1

    # Check detected peaks
    # fit ssd
    n_components = n_components_true
    filt_params_signal = dict(l_freq=freqs_sig[0],
                              h_freq=freqs_sig[1],
                              l_trans_bandwidth=1,
                              h_trans_bandwidth=1)
    filt_params_noise = dict(l_freq=freqs_noise[0],
                             h_freq=freqs_noise[1],
                             l_trans_bandwidth=1,
                             h_trans_bandwidth=1)
    ssd = SSD(info,
              filt_params_signal,
              filt_params_noise,
              n_components=n_components,
              sort_by_spectral_ratio=False)
    ssd.fit(X)

    out = ssd.transform(X)
    psd_out, _ = psd_array_welch(out[0], sfreq=250, n_fft=250)
    psd_S, _ = psd_array_welch(S[0], sfreq=250, n_fft=250)
    corr = np.abs(np.corrcoef((psd_out, psd_S))[0, 1])
    assert np.abs(corr) > 0.95

    # Check pattern estimation
    # Since there is no exact ordering of the recovered patterns
    # a pair-wise greedy search will be done
    error = list()
    for ii in range(n_channels):
        corr = np.abs(np.corrcoef(ssd.patterns_[ii, :].T, A[:, 0])[0, 1])
        error.append(1 - corr)
        min_err = np.min(error)
    assert min_err < 0.3  # threshold taken from SSD original paper
Ejemplo n.º 13
0
def power_spectrum(sfreq,
                   data,
                   fmin=0.,
                   fmax=256.,
                   psd_method='welch',
                   welch_n_fft=256,
                   welch_n_per_seg=None,
                   welch_n_overlap=0,
                   verbose=False):
    """Power Spectral Density (PSD).

    Utility function to compute the (one-sided) Power Spectral Density which
    acts as a wrapper for :func:`mne.time_frequency.psd_array_welch` (if
    ``method='welch'``) or :func:`mne.time_frequency.psd_array_multitaper`
    (if ``method='multitaper'``). The multitaper method, although more
    computationally intensive than Welch's method or FFT, should be prefered
    for 'short' windows. Welch's method is more suitable for 'long' windows.

    Parameters
    ----------
    sfreq : float
        Sampling rate of the data.

    data : ndarray, shape (..., n_times).

    fmin : float (default: 0.)
        Lower bound of the frequency range to consider.

    fmax : float (default: 256.)
        Upper bound of the frequency range to consider.

    psd_method : str (default: 'welch')
        Method used to estimate the PSD from the data. The valid values for
        the parameter ``method`` are: ``'welch'``, ``'fft'`` or
        ``'multitaper'``.

    welch_n_fft : int (default: 256)
        The length of the FFT used. The segments will be zero-padded if
        `welch_n_fft > welch_n_per_seg`. This parameter will be ignored if
        `method = 'fft'` or `method = 'multitaper'`.

    welch_n_per_seg : int or None (default: None)
        Length of each Welch segment (windowed with a Hamming window). If
        None, `welch_n_per_seg` is equal to `welch_n_fft`. This parameter
        will be ignored if `method = 'fft'` or `method = 'multitaper'`.

    welch_n_overlap : int (default: 0)
        The number of points of overlap between segments. Should be
        `<= welch_n_per_seg`. This parameter will be ignored if
        `method = 'fft'` or `method = 'multitaper'`.

    verbose : bool (default: False)
        Verbosity parameter. If True, info and warnings related to
        :func:`mne.time_frequency.psd_array_welch` or
        :func:`mne.time_frequency.psd_array_multitaper` are printed.

    Returns
    -------
    psd : ndarray, shape (..., n_freqs)
        Estimated PSD.

    freqs : ndarray, shape (n_freqs,)
        Array of frequency bins.
    """
    _verbose = 40 * (1 - int(verbose))
    _fmin, _fmax = max(0, fmin), min(fmax, sfreq / 2)
    if psd_method == 'welch':
        _n_fft = min(data.shape[-1], welch_n_fft)
        return psd_array_welch(data,
                               sfreq,
                               fmin=_fmin,
                               fmax=_fmax,
                               n_fft=_n_fft,
                               verbose=_verbose,
                               n_per_seg=welch_n_per_seg,
                               n_overlap=welch_n_overlap)
    elif psd_method == 'multitaper':
        return psd_array_multitaper(data,
                                    sfreq,
                                    fmin=_fmin,
                                    fmax=_fmax,
                                    verbose=_verbose)
    elif psd_method == 'fft':
        n_times = data.shape[-1]
        m = np.mean(data, axis=-1)
        _data = data - m[..., None]
        spect = np.fft.rfft(_data, n_times)
        mag = np.abs(spect)
        freqs = np.fft.rfftfreq(n_times, 1. / sfreq)
        psd = np.power(mag, 2) / (n_times**2)
        psd *= 2.
        psd[..., 0] /= 2.
        if n_times % 2 == 0:
            psd[..., -1] /= 2.
        mask = np.logical_and(freqs >= _fmin, freqs <= _fmax)
        return psd[..., mask], freqs[mask]
    else:
        raise ValueError('The given method (%s) is not implemented. Valid '
                         'methods for the computation of the PSD are: '
                         '`welch`, `fft` or `multitaper`.' % str(psd_method))
Ejemplo n.º 14
0
def generate_welch(data, fmin=1, fmax=70, fs=250, n_jobs=1):

    psds, freqs = psd_array_welch(data, fs, fmin, fmax, n_per_seg=int(fs/2),
                          n_overlap=int(fs/4), n_jobs=n_jobs)

    return np.expand_dims(psds, 1)
Ejemplo n.º 15
0
def test_psd():
    """Tests the welch and multitaper PSD."""
    raw = read_raw_fif(raw_fname)
    picks_psd = [0, 1]

    # Populate raw with sinusoids
    rng = np.random.RandomState(40)
    data = 0.1 * rng.randn(len(raw.ch_names), raw.n_times)
    freqs_sig = [8., 50.]
    for ix, freq in zip(picks_psd, freqs_sig):
        data[ix, :] += 2 * np.sin(np.pi * 2. * freq * raw.times)
    first_samp = raw._first_samps[0]
    raw = RawArray(data, raw.info)

    tmin, tmax = 0, 20  # use a few seconds of data
    fmin, fmax = 2, 70  # look at frequencies between 2 and 70Hz
    n_fft = 128

    # -- Raw --
    kws_psd = dict(tmin=tmin, tmax=tmax, fmin=fmin, fmax=fmax,
                   picks=picks_psd)  # Common to all
    kws_welch = dict(n_fft=n_fft)
    kws_mt = dict(low_bias=True)
    funcs = [(psd_welch, kws_welch),
             (psd_multitaper, kws_mt)]

    for func, kws in funcs:
        kws = kws.copy()
        kws.update(kws_psd)
        psds, freqs = func(raw, proj=False, **kws)
        psds_proj, freqs_proj = func(raw, proj=True, **kws)

        assert psds.shape == (len(kws['picks']), len(freqs))
        assert np.sum(freqs < 0) == 0
        assert np.sum(psds < 0) == 0

        # Is power found where it should be
        ixs_max = np.argmax(psds, axis=1)
        for ixmax, ifreq in zip(ixs_max, freqs_sig):
            # Find nearest frequency to the "true" freq
            ixtrue = np.argmin(np.abs(ifreq - freqs))
            assert (np.abs(ixmax - ixtrue) < 2)

        # Make sure the projection doesn't change channels it shouldn't
        assert_array_almost_equal(psds, psds_proj)
        # Array input shouldn't work
        pytest.raises(ValueError, func, raw[:3, :20][0])

    # test n_per_seg in psd_welch (and padding)
    psds1, freqs1 = psd_welch(raw, proj=False, n_fft=128, n_per_seg=128,
                              **kws_psd)
    psds2, freqs2 = psd_welch(raw, proj=False, n_fft=256, n_per_seg=128,
                              **kws_psd)
    assert (len(freqs1) == np.floor(len(freqs2) / 2.))
    assert (psds1.shape[-1] == np.floor(psds2.shape[-1] / 2.))

    kws_psd.update(dict(n_fft=tmax * 1.1 * raw.info['sfreq']))
    with pytest.raises(ValueError, match='n_fft is not allowed to be > n_tim'):
        psd_welch(raw, proj=False, n_per_seg=None,
                  **kws_psd)
    kws_psd.update(dict(n_fft=128, n_per_seg=64, n_overlap=90))
    with pytest.raises(ValueError, match='n_overlap cannot be greater'):
        psd_welch(raw, proj=False, **kws_psd)
    with pytest.raises(ValueError, match='No frequencies found'):
        psd_array_welch(np.zeros((1, 1000)), 1000., fmin=10, fmax=1)

    # -- Epochs/Evoked --
    events = read_events(event_fname)
    events[:, 0] -= first_samp
    tmin, tmax, event_id = -0.5, 0.5, 1
    epochs = Epochs(raw, events[:10], event_id, tmin, tmax, picks=picks_psd,
                    proj=False, preload=True, baseline=None)
    evoked = epochs.average()

    tmin_full, tmax_full = -1, 1
    epochs_full = Epochs(raw, events[:10], event_id, tmin_full, tmax_full,
                         picks=picks_psd, proj=False, preload=True,
                         baseline=None)
    kws_psd = dict(tmin=tmin, tmax=tmax, fmin=fmin, fmax=fmax,
                   picks=picks_psd)  # Common to all
    funcs = [(psd_welch, kws_welch),
             (psd_multitaper, kws_mt)]

    for func, kws in funcs:
        kws = kws.copy()
        kws.update(kws_psd)

        psds, freqs = func(
            epochs[:1], proj=False, **kws)
        psds_proj, freqs_proj = func(
            epochs[:1], proj=True, **kws)
        psds_f, freqs_f = func(
            epochs_full[:1], proj=False, **kws)

        # this one will fail if you add for example 0.1 to tmin
        assert_array_almost_equal(psds, psds_f, 27)
        # Make sure the projection doesn't change channels it shouldn't
        assert_array_almost_equal(psds, psds_proj, 27)

        # Is power found where it should be
        ixs_max = np.argmax(psds.mean(0), axis=1)
        for ixmax, ifreq in zip(ixs_max, freqs_sig):
            # Find nearest frequency to the "true" freq
            ixtrue = np.argmin(np.abs(ifreq - freqs))
            assert (np.abs(ixmax - ixtrue) < 2)
        assert (psds.shape == (1, len(kws['picks']), len(freqs)))
        assert (np.sum(freqs < 0) == 0)
        assert (np.sum(psds < 0) == 0)

        # Array input shouldn't work
        pytest.raises(ValueError, func, epochs.get_data())

        # Testing evoked (doesn't work w/ compute_epochs_psd)
        psds_ev, freqs_ev = func(
            evoked, proj=False, **kws)
        psds_ev_proj, freqs_ev_proj = func(
            evoked, proj=True, **kws)

        # Is power found where it should be
        ixs_max = np.argmax(psds_ev, axis=1)
        for ixmax, ifreq in zip(ixs_max, freqs_sig):
            # Find nearest frequency to the "true" freq
            ixtrue = np.argmin(np.abs(ifreq - freqs_ev))
            assert (np.abs(ixmax - ixtrue) < 2)

        # Make sure the projection doesn't change channels it shouldn't
        assert_array_almost_equal(psds_ev, psds_ev_proj, 27)
        assert (psds_ev.shape == (len(kws['picks']), len(freqs)))
Ejemplo n.º 16
0
time_window = (0.4, 0.8)
ch_group = "parietal"
ch_type = "grad"
freq_band = (4, 8)
baseline = (-0.2, 0)

X, meta, times, info = assemble_epochs_new(ch_type=ch_type, baseline=baseline)

df, data = prepare_erp(times, time_window, ch_group, meta, X, info)

psd_params = dict(fmin=0, fmax=30, n_fft=128)

time_mask = np.logical_and(times >= time_window[0], times < time_window[1])
psd, freqs = psd_array_welch(data[:, :, time_mask],
                             sfreq=info["sfreq"],
                             **psd_params)
freq_mask = np.logical_and(freqs >= freq_band[0], freqs < freq_band[1])
df.data = psd[:, :, freq_mask].mean(axis=(1, 2)) * 1e13**2

md = smf.mixedlm("data ~ cond", data=df, groups="subj")
mdf = md.fit()
print(mdf.summary())

legend = []
for cond in np.unique(df.cond):
    plt.plot(freqs, psd[df.cond == cond, :, :].mean(axis=(0, 1)))
    legend.append(cond)
plt.legend(legend)
plt.show()
Ejemplo n.º 17
0
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
Ejemplo n.º 18
0
    def plot_mean_spectrum(self,
                           channel_desc,
                           fmin=2,
                           fmax=90,
                           plot_hits=1,
                           plot_cr=1,
                           plot_omissions=0,
                           plot_fa=0):
        channel_desc = np.array(channel_desc)
        if channel_desc.dtype.char == 'U':
            channel_num = np.atleast_1d(
                self.channel_info.get_channel_pos(channel_desc))
        else:
            channel_num = np.atleast_1d(channel_desc)

        def plot_mean_spectrum_subplot(freqs, psds, color, ax, plot_ci=1):
            psd_mean, psd_std = (10 * np.log10(psds)).mean(0), (
                10 * np.log10(psds)).std(0)
            ci95_up_pre = psd_mean - 2 * psd_std / psds.shape[0]
            ci95_down_pre = psd_mean + 2 * psd_std / psds.shape[0]
            ax.plot(freqs, psd_mean, c=color)
            if plot_ci:
                ax.fill_between(freqs,
                                ci95_up_pre,
                                ci95_down_pre,
                                color=color,
                                alpha=0.4)

        for chan_num_i in channel_num:
            data_i = self.data[chan_num_i, :, :]
            nfft = min(self.n_pnts, 2048)
            f = plt.figure()
            ax = f.add_subplot(111)
            legend_str = []
            if plot_hits:
                psds_i, freqs = psd_array_welch(data_i[:, self.hits].T,
                                                self.srate,
                                                fmin=fmin,
                                                fmax=fmax,
                                                n_fft=nfft)
                plot_mean_spectrum_subplot(freqs, psds_i,
                                           self.colors_dict['hits'], ax)
                legend_str.append('Hits')
            if plot_cr:
                psds_i, freqs = psd_array_welch(data_i[:,
                                                       self.correct_rejects].T,
                                                self.srate,
                                                fmin=fmin,
                                                fmax=fmax,
                                                n_fft=nfft)
                plot_mean_spectrum_subplot(freqs, psds_i,
                                           self.colors_dict['cr'], ax)
                legend_str.append('Correct Rejects')
            if plot_omissions:
                psds_i, freqs = psd_array_welch(data_i[:, self.omissions].T,
                                                self.srate,
                                                fmin=fmin,
                                                fmax=fmax,
                                                n_fft=nfft)
                plot_mean_spectrum_subplot(freqs, psds_i,
                                           self.colors_dict['omissions'], ax)
                legend_str.append('Omissions')
            if plot_fa:
                psds_i, freqs = psd_array_welch(data_i[:, self.false_alarms].T,
                                                self.srate,
                                                fmin=fmin,
                                                fmax=fmax,
                                                n_fft=nfft)
                plot_mean_spectrum_subplot(freqs, psds_i,
                                           self.colors_dict['fa'], ax)
                legend_str.append('False Alarms')
            chan_name_i = self.channel_info.get_channel_name(chan_num_i)
            ax.legend(legend_str)
            ax.autoscale(axis='both', tight=True)
            ax.set(
                xlabel='Frequency (Hz)',
                ylabel='Gain (dB)',
                title='Mean Power Spectral Density - {}'.format(chan_name_i))