Exemple #1
0
def extract_frequency_features(X):
    from mne.time_frequency import psd_array_multitaper
    from pywt import wavedec

    psds, freqs = psd_array_multitaper(X, SAMPLE_RATE, fmax=110)
    bands = [(name, 0) for (name, _) in FREQ_BANDS]
    num_bands = len(bands)

    total = psds.sum(axis=-1)
    total_no_zeros = np.where(total > 0, total, 1)
    for i in range(num_bands):
        fmin = FREQ_BANDS[i][1]
        fmax = (freqs[-1] + 1) if i == (num_bands - 1) else FREQ_BANDS[i +
                                                                       1][1]
        bands[i][1] = (psds[:, :, (freqs >= fmin) & (freqs < fmax)].sum() /
                       total_no_zeros)
    bands.append(["energy", total])

    dwt_level = 7
    wavelet = "db4"
    coeff_approx, coeff_detail = wavedec(X, wavelet, level=dwt_level)[:2]
    X_enriched = np.concatenate(
        [band for (_, band) in bands] + [
            coeff_approx.swapaxes(2, 1).reshape(X.shape[0], -1),
            coeff_detail.swapaxes(2, 1).reshape(X.shape[0], -1),
        ],
        axis=-1,
    )

    features = [band for (band, _) in bands]
    features += [f"cA{dwt_level}_{i}" for i in range(coeff_approx.shape[-1])]
    features += [f"cD{dwt_level}_{i}" for i in range(coeff_detail.shape[-1])]

    extractor = {"wavedec": {"wavelet": wavelet, "level": dwt_level}}
    return X_enriched, extractor, features
def hfb_to_psd(hfb,
               start=500,
               stop=None,
               duration=20,
               tmin=-0.1,
               tmax=20,
               preload=True,
               baseline=None,
               fmin=0.1,
               fmax=20,
               adaptive=True,
               bandwidth=0.5,
               sfreq=500):
    events = mne.make_fixed_length_events(hfb,
                                          start=start,
                                          stop=stop,
                                          duration=duration)
    epochs = mne.Epochs(hfb,
                        events,
                        tmin=tmin,
                        tmax=tmax,
                        baseline=None,
                        preload=True)
    X = epochs.copy().get_data()
    (n_trials, n_chans, n_times) = X.shape
    psd, freqs = psd_array_multitaper(X,
                                      sfreq,
                                      fmin=fmin,
                                      fmax=fmax,
                                      bandwidth=bandwidth,
                                      adaptive=adaptive)
    psd = np.mean(psd, axis=0)  # average over channels
    return psd, freqs
Exemple #3
0
def bandpower(data, sf, band, method='welch', window_sec=None, relative=False):
    """Compute the average power of the signal x in a specific frequency band.

    Requires MNE-Python >= 0.14.

    Parameters
    ----------
    data : 1d-array
      Input signal in the time-domain.
    sf : float
      Sampling frequency of the data.
    band : list
      Lower and upper frequencies of the band of interest.
    method : string
      Periodogram method: 'welch' or 'multitaper'
    window_sec : float
      Length of each window in seconds. Useful only if method == 'welch'.
      If None, window_sec = (1 / min(band)) * 2.
    relative : boolean
      If True, return the relative power (= divided by the total power of the signal).
      If False (default), return the absolute power.

    Return
    ------
    bp : float
      Absolute or relative band power.
    """
    from scipy.signal import welch
    from scipy.integrate import simps
    from mne.time_frequency import psd_array_multitaper
    import numpy as np

    band = np.asarray(band)
    low, high = band

    # Compute the modified periodogram (Welch)
    if method == 'welch':
        if window_sec is not None:
            nperseg = window_sec * sf
        else:
            nperseg = (2 / low) * sf

        freqs, psd = welch(data, sf, nperseg=nperseg)

    elif method == 'multitaper':
        psd, freqs = psd_array_multitaper(data, sf, adaptive=True,
                                          normalization='full', verbose=0)

    # Frequency resolution
    freq_res = freqs[1] - freqs[0]

    # Find index of band in frequency vector
    idx_band = np.logical_and(freqs >= low, freqs <= high)

    # Integral approximation of the spectrum using parabola (Simpson's rule)
    bp = simps(psd[idx_band], dx=freq_res)

    if relative:
        bp /= simps(psd, dx=freq_res)
    return bp
Exemple #4
0
def get_psd(data, rate, win_size):

    ### Demo cells: 583 (strong periodicity) and 48 (low periodicity)
    pcf = pipe.load_pcf(r'W:\Neurophysiology-Storage1\Wahl\Hendrik\PhD\Data\Batch3\M41\20200625')

    neurons = [583, 49]
    rate = 1/5  # samples per centimeter

    fig, ax = plt.subplots(len(neurons), 3, sharex='col')
    for i, neuron in enumerate(neurons):
        data = pcf.bin_avg_activity[neuron]
        psd, freqs = psd_array_multitaper(data, rate, adaptive=True, normalization='full')

        # Plot activity
        ax[i, 0].plot(np.arange(0, 400, 5), data)
        ax[i, 0].set_ylabel(f'mean dF/F')

        # Plot frequencies
        ax[i, 1].plot(freqs, psd)
        ax[i, 1].set_ylabel(f'PSD')

        # Plot periods
        ax[i, 2].plot(1/freqs, psd)
        ax[i, 2].set_ylabel(f'PSD')


    ax[0, 0].set_title(f'Spatial activity map')
    ax[0, 1].set_title(f'Frequency power density')
    ax[0, 2].set_title(f'Period power density')
    ax[1, 0].set_xlabel(f'VR position [cm]')
    ax[1, 1].set_xlabel(f'Frequency [1/cm]')
    ax[1, 2].set_xlabel(f'Period [cm]')
    plt.tight_layout()
Exemple #5
0
def psd_multitaper(arr, **mne_kwargs):

    if not mne_kwargs:
        mne_kwargs = DEFAULT_PSD_KWARGS

    psd, freqs = psd_array_multitaper(arr.T, **mne_kwargs)
    psd = np.expand_dims(psd.T, axis=0)

    return psd, freqs
    def multitaper_diagram(self, data, channel, plot=False):

        psd, freq = psd_array_multitaper(data,
                                         self.sf,
                                         adaptive=True,
                                         normalization='full',
                                         verbose=0)
        if plot:
            if channel is "CH1":
                self.ch1_d_line.set_data(freq, psd)
                self.ch1_d_fig.set_xlim(left=min(freq), right=max(freq))
                self.ch1_d_fig.set_ylim(min(psd), max(psd))
                pyplot.draw()
                pyplot.pause(0.0001)
            if channel is "CH2":
                self.ch2_d_line.set_data(freq, psd)
                self.ch2_d_fig.set_xlim(left=min(freq), right=max(freq))
                self.ch2_d_fig.set_ylim(min(psd), max(psd))
                pyplot.draw()
                pyplot.pause(0.0001)
        return freq, psd
Exemple #7
0
    def calc_psd_mt(self, bandwidth):
        """ Calculate multitaper power spectrum 

            Params
            ------
            bandwidth: float
                frequency resolution (NW)

            Returns
            -------
            psd_mt: dict
                'freqs': ndarray
                'psd': ndarray. power spectral density in (V^2/Hz). 10log10 to convert to dB.

        """
        self.metadata['analysis_info']['psd_method'] = 'multitaper'
        self.metadata['analysis_info']['psd_bandwidth'] = bandwidth
        sf_interp = self.metadata['analysis_info']['s_freq_interp']

        pwr, freqs = psd_array_multitaper(self.ii_interp, sf_interp, adaptive=True, 
                                            bandwidth=bandwidth, normalization='full', verbose=0)
        self.psd_mt = {'freqs': freqs, 'pwr': pwr}
        self.metadata['analysis_info']['psd_method'] = 'multitaper'
def _pca15_fft(flip, data):
    U, s, V = linalg.svd(data, full_matrices=False)

    maxeig = 15

    # use average power in label for scaling
    epoch_spectra, freq_bins = psd_array_multitaper(
        V[0:maxeig],
        300,  #!!!!################ HardCodede
        fmin=1,
        fmax=45,
        bandwidth=2,
        n_jobs=1,
        adaptive=True,
        low_bias=True,
        normalization='full')

    eigval_weighted_spectra = s[0:maxeig, np.newaxis] * epoch_spectra

    # Reject top and bottom 10% using trimmed mean
    output_spectra = trim_mean(eigval_weighted_spectra, 0.1, axis=0)
    # Normalize by number of samples
    normalized_spectra = output_spectra / np.sqrt(len(data))
    return output_spectra
    print('epoch_event_DONE')

   
    #baseline_chunk_around_event = ch_downsampled[baseline_idx-offset : baseline_idx+offset]
    for b, base in enumerate(baseline_idx):
         
        baseline_chunk_around_event[b,:] = ch_downsampled[base-offset : base+offset]
        #print(b)    
    print('epoch_baseline_DONE')
        
        
    ch_downsampled = None
    
    chunk_lenght = offset*2
        
    p_ch, f_ch = time_frequency.psd_array_multitaper(chunk_around_event, sfreq= 1000, fmin = 1, fmax = 60, bandwidth = 2.5, n_jobs = 8)

    p_base, f_base = time_frequency.psd_array_multitaper(baseline_chunk_around_event, sfreq= 1000, fmin = 1, fmax = 60, bandwidth = 2.5, n_jobs = 8)
#        
#                
#                test = np.sum(p_base)
#                
#                
#                for t in arange(len(downsampled_event_idx)):
#                    
#                    if t < 5:
#                        figure_name= str(t)+'.png'
#                        plt.plot(f_base, p_base[t], color = 'k',alpha=1, label = 'touch', linewidth= 1)
#                        plt.title('base')
#                    else:
#                        plt.plot(f_base, p_base[t], color = '#228B22',alpha=0.3, label = 'touch', linewidth= 1)
Exemple #10
0
raw = mne.concatenate_raws(raws)
bem_fname = op.join(bem_dir, subject + '-20480-bem-sol.fif')
bem = mne.read_bem_solution(bem_fname)
src = mne.setup_source_space(subject, spacing='ico5',
                             add_dist=False, subjects_dir=subjects_mri_dir)

fwd = mne.make_forward_solution(raw.info, trans=trans_file, src=src, bem=bem, meg=True, eeg=False, n_jobs=2)
inv = mne.minimum_norm.make_inverse_operator(raw.info, fwd, cov, loose=0.2, depth=0.8)

labels = mne.read_labels_from_annot(subject, 'aparc', subjects_dir=subjects_mri_dir)
labels_name = np.array([label.name for label in labels])
stcs = mne.minimum_norm.apply_inverse_epochs(epochs, inv, lambda2=1. / 9., pick_ori='normal', return_generator=True)

label_ts = np.array(mne.extract_label_time_course(stcs, labels, inv['src'], return_generator=False))

psds, freqs = psd_array_multitaper(label_ts, epochs.info['sfreq'], fmin=2, fmax=55)

tfr_alpha = tfr_array_multitaper(label_ts, epochs.info['sfreq'], freqs=np.arange(8, 13), output='avg_power', n_jobs=4)
tfr_beta = tfr_array_multitaper(label_ts, epochs.info['sfreq'], freqs=np.arange(16, 30), output='avg_power', n_jobs=4)
tfr_lgamma = tfr_array_multitaper(label_ts, epochs.info['sfreq'], freqs=np.arange(30, 55), output='avg_power', n_jobs=4)
tfr_hgamma = tfr_array_multitaper(label_ts, epochs.info['sfreq'], freqs=np.arange(65, 100), output='avg_power', n_jobs=4)


for ix, inds in enumerate(np.split(np.arange(68), 4)):
    plt.figure(figsize=(15, 20))
    plt.rc('xtick', labelsize=25)
    plt.rc('ytick', labelsize=25)
    lineObjects = plt.plot(freqs, 20 * np.log10(psds.mean(0).T)[:, inds], linewidth=4)
    plt.xlabel('Frequency (Hz)', fontsize=30)
    plt.ylabel('Power (20*log10)', fontsize=30)
    plt.xlim(2, 55)
def main():
    count = 600
    sn = socket.socket()
    hostn = 'localhost'
    portn = 14564
    sn.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sn.bind((hostn, portn))
    print('Server Started')
    sn.listen(5)
    cn, addrn = sn.accept()
    print('Got connection from', addrn)

    mapping = {0: 'Wake', 1: 'N1', 2: 'N2', 3: 'N3', 4: 'REM'}
    # hyp = {0: 4, 1: 2, 2: 1, 3: 0, 4: 3}
    channels = {
        0: 'EEG-FPZ-CZ',
        1: 'EEG-PZ-OZ',
        2: 'EOG',
        3: 'Resp-Oro-Nasal',
        4: 'EMG',
        5: 'Temp'
    }

    npz_file = 'SleepEDF_NPZ/SC4001E0.npz'
    with np.load(npz_file) as f:
        data = f["x"]
        labels = f["y"]

    save_path = 'data/epoch_custom.npz'

    save_dict = {"x": data[count, :, :], "y": labels[count]}

    np.savez(save_path, **save_dict)

    rt = RepeatedTimer(30, func, qu)  # it auto-starts, no need of rt.start()
    while True:
        print("Epoch Number: ", count)
        save_dict = {'x': data[count, :, :], 'y': labels[count]}
        np.savez(save_path, **save_dict)
        dict_temp = qu.get()

        grads = dict_temp["grads"]
        sleepstage = dict_temp["Y_pred"]
        print(sleepstage)

        json_data = data[count, :, :]

        from datetime import datetime
        now = datetime.now()
        print("now =", now)

        root_time = strftime("%b-%d-%Y %H:%M")

        just_time = strftime("%H:%M:%S")

        json_data_eeg_fpzcz = np.transpose(np.transpose(json_data)[0][:][:])
        json_data_eeg_pzoz = np.transpose(np.transpose(json_data)[1][:][:])

        json_data_eeg_fpzcz = json_data_eeg_fpzcz.reshape(3000, )
        json_data_eeg_pzoz = json_data_eeg_pzoz.reshape(3000, )

        plt.specgram(json_data_eeg_fpzcz, Fs=100, cmap='viridis')
        plt.ylabel('Frequency [Hz]')
        plt.xlabel('Time [sec]')
        plt.savefig('../frontend/views/eeg_fpzcz_specgram.png',
                    bbox_inches='tight')

        sf = 100
        # Define window length (4 seconds)
        win = 4 * sf

        # Apply the detection using yasa.spindles_detect
        sp = yasa.spindles_detect(json_data_eeg_fpzcz, sf)

        sw = sw_detect(json_data_eeg_fpzcz,
                       sf,
                       include=(2, 3),
                       freq_sw=(0.3, 2),
                       dur_neg=(0.3, 1.5),
                       dur_pos=(0.1, 1),
                       amp_neg=(40, 300),
                       amp_pos=(10, 150),
                       amp_ptp=(75, 400),
                       remove_outliers=False,
                       coupling=False,
                       freq_sp=(12, 16))

        if sp is None:
            mask_spindles = np.zeros(len(json_data_eeg_fpzcz))
        else:
            mask_spindles = sp.get_mask()

        spindles_highlight = json_data_eeg_fpzcz * mask_spindles
        spindles_highlight[spindles_highlight == 0] = np.nan

        if sw is None:
            mask_sw = np.zeros(len(json_data_eeg_fpzcz))
        else:
            mask_sw = sw.get_mask()

        sw_highlight = json_data_eeg_fpzcz * mask_sw
        sw_highlight[sw_highlight == 0] = np.nan

        all_rows = []
        for i in range(len(json_data_eeg_fpzcz)):
            current_time = root_time + ':{}:{}0'.format(
                str(math.floor(i / 100)).zfill(2),
                str(math.floor(i % 100)).zfill(2))
            current_time = "{}".format(current_time).replace('\'', '')
            row = {}
            row["date"] = current_time
            row["EEG_FPZ_CZ"] = json_data_eeg_fpzcz[i]
            if (np.isnan(spindles_highlight[i])):
                row["EEG_FPZ_CZ_Spindle"] = None
            else:
                row["EEG_FPZ_CZ_Spindle"] = json_data_eeg_fpzcz[i]

            if (np.isnan(sw_highlight[i])):
                row["EEG_FPZ_CZ_Slow Waves"] = None
            else:
                row["EEG_FPZ_CZ_Slow Waves"] = json_data_eeg_fpzcz[i]
            all_rows.append(row)

        with open('../frontend/data/EEG-FPZ-CZ.json', 'w') as f:
            f.write(str(all_rows).replace('\'', '"').replace('None', 'null'))

        # Apply the detection using yasa.spindles_detect
        sp = yasa.spindles_detect(json_data_eeg_pzoz, sf)

        sw = sw_detect(json_data_eeg_pzoz,
                       sf,
                       include=(2, 3),
                       freq_sw=(0.3, 2),
                       dur_neg=(0.3, 1.5),
                       dur_pos=(0.1, 1),
                       amp_neg=(40, 300),
                       amp_pos=(10, 150),
                       amp_ptp=(75, 400),
                       remove_outliers=False,
                       coupling=False,
                       freq_sp=(12, 16))

        if sp is None:
            mask_spindles = np.zeros(len(json_data_eeg_pzoz))
        else:
            mask_spindles = sp.get_mask()

        spindles_highlight = json_data_eeg_pzoz * mask_spindles
        spindles_highlight[spindles_highlight == 0] = np.nan

        if sw is None:
            mask_sw = np.zeros(len(json_data_eeg_pzoz))
        else:
            mask_sw = sw.get_mask()

        sw_highlight = json_data_eeg_pzoz * mask_sw
        sw_highlight[sw_highlight == 0] = np.nan

        all_rows = []
        for i in range(len(json_data_eeg_pzoz)):
            current_time = root_time + ':{}:{}0'.format(
                str(math.floor(i / 100)).zfill(2),
                str(math.floor(i % 100)).zfill(2))
            current_time = "{}".format(current_time).replace('\'', '')
            row = {}
            row["date"] = current_time
            row["EEG_PZ_OZ"] = json_data_eeg_pzoz[i]
            if (np.isnan(spindles_highlight[i])):
                row["EEG_PZ_OZ_Spindle"] = None
            else:
                row["EEG_PZ_OZ_Spindle"] = json_data_eeg_pzoz[i]

            if (np.isnan(sw_highlight[i])):
                row["EEG_PZ_OZ_Slow Waves"] = None
            else:
                row["EEG_PZ_OZ_Slow Waves"] = json_data_eeg_pzoz[i]
            all_rows.append(row)

        with open('../frontend/data/EEG-PZ-OZ.json', 'w') as f:
            f.write(str(all_rows).replace('\'', '"').replace('None', 'null'))

        # EEG-FPZ-CZ-Grad
        all_rows = []
        for i in range(len(json_data_eeg_fpzcz)):
            current_time = root_time + ':{}:{}0'.format(
                str(math.floor(i / 100)).zfill(2),
                str(math.floor(i % 100)).zfill(2))
            current_time = "{}".format(current_time).replace('\'', '')
            row = {}
            row["date"] = current_time
            row["EEG-FPZ-CZ"] = json_data_eeg_fpzcz[i]
            if (grads[0, i] < 0.15):
                row["EEG-FPZ-CZ-Grad"] = None
            else:
                row["EEG-FPZ-CZ-Grad"] = json_data_eeg_fpzcz[i]

            all_rows.append(row)

        with open('../frontend/data/EEG-FPZ-CZ-Grad.json', 'w') as f:
            f.write(str(all_rows).replace('\'', '"').replace('None', 'null'))

        # EEG-PZ-OZ-Grad
        all_rows = []
        for i in range(len(json_data_eeg_pzoz)):
            current_time = root_time + ':{}:{}0'.format(
                str(math.floor(i / 100)).zfill(2),
                str(math.floor(i % 100)).zfill(2))
            current_time = "{}".format(current_time).replace('\'', '')
            row = {}
            row["date"] = current_time
            row["EEG-PZ-OZ"] = json_data_eeg_pzoz[i]
            if (grads[0, i] < 0.15):
                row["EEG-PZ-OZ-Grad"] = None
            else:
                row["EEG-PZ-OZ-Grad"] = json_data_eeg_pzoz[i]

            all_rows.append(row)

        with open('../frontend/data/EEG-PZ-OZ-Grad.json', 'w') as f:
            f.write(str(all_rows).replace('\'', '"').replace('None', 'null'))

        #Other channel grads
        for index in range(2, 6):
            json_data_tmp = np.transpose(np.transpose(json_data)[index][:][:])
            json_data_tmp = json_data_tmp.reshape(3000, )

            all_rows = []
            for i in range(len(json_data_tmp)):
                current_time = root_time + ':{}:{}0'.format(
                    str(math.floor(i / 100)).zfill(2),
                    str(math.floor(i % 100)).zfill(2))
                current_time = "{}".format(current_time).replace('\'', '')
                row = {}
                row["date"] = current_time
                row[channels[index]] = json_data_tmp[i]
                if (grads[0, i] < 0.15):
                    row[channels[index] + "-Grad"] = None
                else:
                    row[channels[index] + "-Grad"] = json_data_tmp[i]
                all_rows.append(row)

            with open('../frontend/data/' + channels[index] + '-Grad.json',
                      'w') as f:
                f.write(
                    str(all_rows).replace('\'', '"').replace('None', 'null'))

        #Normal non-EEG channels
        for index in range(2, 6):
            json_data_tmp = np.transpose(np.transpose(json_data)[index][:][:])
            json_data_tmp = json_data_tmp.reshape(3000, )

            all_rows = []
            for i in range(len(json_data_tmp)):
                current_time = root_time + ':{}:{}0'.format(
                    str(math.floor(i / 100)).zfill(2),
                    str(math.floor(i % 100)).zfill(2))
                current_time = "{}".format(current_time).replace('\'', '')
                row = {}
                row["date"] = current_time
                row[channels[index]] = json_data_tmp[i]
                all_rows.append(row)

            with open('../frontend/data/' + channels[index] + '.json',
                      'w') as f:
                f.write(
                    str(all_rows).replace('\'', '"').replace('None', 'null'))

        psd, freqs = psd_array_multitaper(json_data_eeg_fpzcz,
                                          sf,
                                          normalization='full',
                                          verbose=0)

        all_rows = []
        for i in range(len(freqs[:1801])):  #Upto 60Hz (Elaborate)
            row = {}
            row["Frequencies"] = freqs[i]
            row["PSD"] = psd[i]
            all_rows.append(row)

        with open('../frontend/data/PSD-FPZCZ.json', 'w') as f:
            f.write(str(all_rows).replace('\'', '"'))

        psd, freqs = psd_array_multitaper(json_data_eeg_pzoz,
                                          sf,
                                          normalization='full',
                                          verbose=0)

        all_rows = []
        for i in range(len(freqs[:1801])):
            row = {}
            row["Frequencies"] = freqs[i]
            row["PSD"] = psd[i]
            all_rows.append(row)

        with open('../frontend/data/PSD-PZOZ.json', 'w') as f:
            f.write(str(all_rows).replace('\'', '"'))

        from scipy.fftpack import rfft, rfftfreq
        SAMPLE_RATE = 100
        DURATION = 30

        # Number of samples in normalized_tone
        N = SAMPLE_RATE * DURATION

        yf = rfft(json_data_eeg_fpzcz)
        xf = rfftfreq(N, 1 / SAMPLE_RATE)

        all_rows = []
        for i in range(len(xf)):
            row = {}
            row["x"] = xf[i]
            row["y"] = np.abs(yf[i])
            all_rows.append(row)

        with open('../frontend/data/FFT-FPZCZ.json', 'w') as f:
            f.write(str(all_rows).replace('\'', '"'))

        count_json = {}
        count_json["data"] = count

        with open('../frontend/data/count.json', 'w') as f:
            f.write(str(count_json).replace('\'', '"'))

        print("Sleepstage: ", mapping[sleepstage])

        row = {}
        row["time"] = just_time
        row["stage"] = sleepstage + 1
        print(row)
        with open('../frontend/data/sleepstage.json', 'w') as f:
            f.write(str(row).replace('\'', '"'))

        # nodeserv(hyp[int(sleepstage)], cn)
        nodeserv(int(sleepstage), cn)
        count += 1
        qu.task_done()

    try:
        sleep(150)  # your long-running job goes here
    finally:
        rt.stop(
        )  # better in a try/finally block to make sure the program ends
                     
 #                 #baseline_chunk_around_event = ch_downsampled[baseline_idx-offset : baseline_idx+offset]
 #                for b, base in enumerate(baseline_idx):
 #                     
 #                    baseline_chunk_around_event[b,:] = ch_downsampled[base-offset : base+offset]
 #                    #print(b)    
 #                print('epoch_baseline_DONE')
 #                print('epoch_event_DONE')
 #        
 #           
 
                 #half size chunk double  bandwidth   
                 ch_downsampled = None
                 
                     
                 p_before, f_before = time_frequency.psd_array_multitaper(chunk_before, sfreq= 1000, fmin = 1, fmax = 300, bandwidth = 10, n_jobs = 8)
         
                 p_after, f_after= time_frequency.psd_array_multitaper(chunk_after, sfreq= 1000, fmin = 1, fmax = 300, bandwidth = 10, n_jobs = 8)
         
                 #p_base, f_base = time_frequency.psd_array_multitaper(baseline_chunk_around_event, sfreq= 1000, fmin = 1, fmax = 100, bandwidth = 2.5, n_jobs = 8)
         
                 #p_base_avg = np.mean(p_base, axis =0) #[:len(downsampled_event_idx)]
                 #p_base_sem = stats.sem(p_base, axis = 0)
                 
                 # tot baseline excluding noise and sum 
                 
 #                baseline_tot = [i for i,v in enumerate(f_base) if  v <45 or v>55 ]
 #                baseline_sel = p_base_avg[baseline_tot]
 #                baseline_sum_tot = np.sum(baseline_sel)
 #                tot_base_sum.append(baseline_sum_tot)    
 #                
cross_population_hfb, populations = hf.ts_to_population_hfb(
    cross_ts, df_all_visual_chans, parcellation='group')

(npop, m, N, ncat) = cross_population_hfb.shape
new_shape = (npop, ncat, N, m)
cross_population_hfb = np.transpose(cross_population_hfb, (0, 3, 2, 1))
#%% Compute psd

fmin = 0.1
fmax = 100
adaptive = True
bandwidth = 2

psd, freqs = psd_array_multitaper(cross_population_hfb,
                                  args.sfreq,
                                  fmin=fmin,
                                  fmax=fmax,
                                  bandwidth=bandwidth,
                                  adaptive=adaptive)
average_psd = np.mean(psd, axis=2)
max_psd = np.max(psd)
#%% Plot psd in each conditions for each populations

sns.set(font_scale=1.6)
f, ax = plt.subplots(3, 1)
cat = ['Rest', 'Face', 'Place']
bands = [4, 8, 16, 31]
bands_name = [r'$\delta$', r'$\theta$', r'$\alpha$', r'$\beta$', r'$\gamma$']
xbands = [2, 6, 12, 18, 50]
ybands = [12] * 5
for i in range(ncat):
    for j in range(npop):
Exemple #14
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)
        kws.update(verbose='debug')
        if func is psd_welch:
            kws.update(window='hann')
        with catch_logging() as log:
            psds, freqs = func(raw, proj=False, **kws)
        log = log.getvalue()
        if func is psd_welch:
            assert f'{n_fft}-point FFT on {n_fft} samples with 0 overl' in log
            assert 'hann window' in log
        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)

    # -- psd_array_multitaper --
    psd_complex, freq, weights = psd_array_multitaper(raw._data[:4, :500],
                                                      raw.info['sfreq'],
                                                      output='complex')
    psd, freq = psd_array_multitaper(raw._data[:4, :500],
                                     raw.info['sfreq'],
                                     output='power')
    assert psd_complex.ndim == 3  # channels x tapers x freqs
    psd_from_complex = _psd_from_mt(psd_complex, weights)
    assert_allclose(psd_from_complex, psd)

    # -- 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)))
Exemple #15
0
def power_spectral_density(data: np.ndarray,
                           band: Tuple[float, float],
                           sampling_rate: float = 100.0,
                           window_length: float = 4.0,
                           plot: bool = False,
                           method: PSD_TYPE = PSD_TYPE.WELCH,
                           relative=False):
    """Power spectral density:

    Many thanks to: https://raphaelvallat.github.io/bandpower.html

    Parameters
    ----------
        data: Numpy Array.
            Time series data in the form of a numpy ndarray used to estimate the
                power spectral density.
        band: tuple.
            frequency band psd to export. Note this must be within the Nyquist frequency
            for your data. Approximated as sampling rate / 2.
        sampling_rate: float
            Sampling rate of the data in # of samples per second.
        window_length: float
            Length in seconds of data window.
        plot: boolean.
            Whether of not to plot the PSD estimated. Helpful for debugging and exploration.
        method: PSD_TYPE
            Type of PSD estimation method to use during calculation.
        relative: boolean
            Whether or not to express the power in a frequency band as a percentage of the
            total power of the signal.

    """
    band = np.asarray(band)
    low, high = band

    # Compute the modified periodogram (Welch)
    if method == PSD_TYPE.WELCH:
        nperseg = window_length * sampling_rate
        freqs, psd = welch(data, sampling_rate, nperseg=nperseg)

    # Compute the modified periodogram (MultiTaper)
    elif method == PSD_TYPE.MULTITAPER:
        psd, freqs = psd_array_multitaper(data,
                                          sampling_rate,
                                          adaptive=True,
                                          normalization='full',
                                          verbose=False)

    # Find index of band in frequency vector
    idx_band = np.logical_and(freqs >= low, freqs <= high)

    # Frequency resolution
    freq_res = freqs[1] - freqs[0]

    # Integral approximation of the spectrum using parabola (Simpson's rule)
    bp = simps(psd[idx_band], dx=freq_res)

    # Plot the power spectrum
    if plot:
        sns.set(font_scale=1.2, style='white')
        plt.figure(figsize=(8, 4))
        plt.plot(freqs, psd, color='k', lw=2)
        plt.xlabel('Frequency (Hz)')
        plt.ylabel('Power spectral density (V^2 / Hz)')
        plt.ylim([0, psd.max() * 1.1])
        plt.title(f'{method.value}')
        plt.xlim([0, sampling_rate / 2])
        sns.despine()
        plt.show()

    # Whether or not to return PSD as a percentage of total power
    if relative:
        bp /= simps(psd, dx=freq_res)

    return bp
def extract_power_band_metrics(data_segment, **params):
    """
    From a given EEG data segment, extract EEG features
    :param data_segment: DataFrame, table of electrode timeseries segment data
    :param eeg_metric: str, 'coherence' or 'power', for spectral coherence, or power band calculations
    :param channels: list, channel names to use in the feature calculations
    :param s_rate: float, data sampling rate
    :param bands: dict, dictionary of tuple of start and stop frequencies for desired power bands
    :return: (ndarray, list), calculated user features and corresponding names; or None if window was too small
    """
    eeg_metric = params['eeg_metric']
    _avail_metrics = ['power', 'asymmetry', 'coherence']
    assert eeg_metric in _avail_metrics, f"Supported EEG metrics: {', '.join(_avail_metrics)}"

    channels = params['channels']
    srate = params['s_rate']
    data = data_segment.loc[:, channels].values
    bands = params['bands']
    band_names = list(bands.keys())
    band_names.sort()
    feature_names = []
    metrics = []

    freq = None
    pwr = None

    freq_mins = [band[0] for band in bands.values()]
    freq_maxs = [band[1] for band in bands.values()]

    # Enforce minimum of 1 seconds for data
    if len(data) / srate < 1.0:
        log = logging.getLogger(__name__)
        log.warning(
            "Extract Power Metrics: At least 1 second of data required")
        return None, None

    # Multitaper power band calculation
    if eeg_metric == 'power':
        for freq_min, freq_max in zip(freq_mins, freq_maxs):
            pwr, freq = psd_array_multitaper(data.T,
                                             srate,
                                             adaptive=True,
                                             normalization='full',
                                             verbose=False,
                                             fmin=freq_min,
                                             fmax=freq_max)
            metrics.append(np.log10(pwr.sum(axis=1)))
        for band in band_names:
            for chan in channels:
                feature_names.append("{:s}_{:s}".format(chan, band))

    elif eeg_metric == 'asymmetry':
        n_chan = data.shape[1] // 2
        data_left = data[:, :n_chan]
        data_right = data[:, n_chan:]
        for freq_min, freq_max in zip(freq_mins, freq_maxs):
            pwr_left, freq = psd_array_multitaper(data_left.T,
                                                  srate,
                                                  adaptive=True,
                                                  normalization='full',
                                                  verbose=False,
                                                  fmin=freq_min,
                                                  fmax=freq_max)
            pwr_right, freq = psd_array_multitaper(data_right.T,
                                                   srate,
                                                   adaptive=True,
                                                   normalization='full',
                                                   verbose=False,
                                                   fmin=freq_min,
                                                   fmax=freq_max)
            metrics.append(
                np.log10(pwr_right.sum(axis=1)) -
                np.log10(pwr_left.sum(axis=1)))
        for band in band_names:
            for chan_left, chan_right in zip(channels[:n_chan],
                                             channels[n_chan:]):
                feature_names.append("{:s}_{:s}_{:s}".format(
                    chan_left, chan_right, band))

    # Multitaper coherence calculations
    elif eeg_metric == 'coherence':
        c_idxs = np.stack(
            [c_pair for c_pair in combinations(range(len(channels)), 2)])
        coh = spectral_connectivity([data.T],
                                    sfreq=srate,
                                    fmin=freq_mins,
                                    fmax=freq_maxs,
                                    faverage=True,
                                    method='coh',
                                    mode='multitaper',
                                    verbose=False)
        pwr, freq = coh[:2]
        for band in band_names:
            for c_pair in c_idxs:
                c0, c1 = c_pair
                feature_names.append("{:s}_{:s}_{:s}".format(
                    channels[c0], channels[c1], band))

        for _, band in enumerate(band_names):
            # Flatten coherence output container
            metrics = pwr.T[pwr.T > 0].reshape(-1)
            #coh_band = pwr[:, :, idx].T
            #metrics.append(coh_band[coh_band != 0].reshape(-1))

    return np.hstack(metrics), feature_names
Exemple #17
0
def extract(filepaths, ica=None, fit_ica=True):
    if ica is None:
        ica = get_ica_transformers("infomax")

    epochs, labels = list(), list()
    for filepath in filepaths:
        print("loading", filepath)
        try:
            gdf = read_raw_gdf(
                filepath,
                eog=["EOG-left", "EOG-central", "EOG-right"],
                exclude=["EOG-left", "EOG-central", "EOG-right"])
            events = events_from_annotations(gdf,
                                             event_id={
                                                 "769": 0,
                                                 "770": 1,
                                                 "771": 2,
                                                 "772": 3
                                             })
            epoch = Epochs(gdf,
                           events[0],
                           event_repeated="drop",
                           reject_by_annotation=True,
                           tmin=-.3,
                           tmax=.7,
                           reject=dict(eeg=1e-4))
            epoch.drop_bad()
        except ValueError:
            print("Error in", filepath)
            continue
        epochs.append(epoch)
        labels.append(epoch.events[:, 2])

    labels = np.concatenate(labels)
    n_epochs, n_channels, n_times = epochs[0].get_data().shape
    ica_vec = [
        epoch.get_data().transpose(1, 0, 2).reshape(n_channels, -1).T
        for epoch in epochs
    ]
    ica_vec = np.concatenate(ica_vec, axis=0)

    if fit_ica:
        ica.fit(ica_vec)

    transformed = ica.transform(ica_vec)
    transformed = ica_vec

    transformed = transformed.T.reshape(n_channels, -1,
                                        n_times).transpose(1, 0, 2)

    features, freqs = psd_array_multitaper(transformed,
                                           250.,
                                           fmin=0,
                                           fmax=20,
                                           bandwidth=2)

    n_epochs, _, _ = features.shape
    #    features = features.reshape(n_epochs, -1)
    features = features.mean(axis=2)
    labels_placeholder = np.zeros((len(labels), 4))

    for i, l in enumerate(labels):
        labels_placeholder[i, l] = 1

    labels = labels_placeholder
    return features, labels, ica
Exemple #18
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))
Exemple #19
0
            chunk_around_event[e,:] = ch_downsampled[event-offset : event+offset]
            print(e)



        for b, base in enumerate(baseline_idx):
   
            baseline_chunk_around_event[b,:] = ch_downsampled[base-offset : base+offset]
            print(b)
            
            
        ch_downsampled = None
        
        chunk_lenght = offset*2
            
        p_ch, f_ch = time_frequency.psd_array_multitaper(chunk_around_event, sfreq= 1000, fmin = 1, fmax = 100, bandwidth = 2.5, n_jobs = 8)

        p_base, f_base = time_frequency.psd_array_multitaper(baseline_chunk_around_event, sfreq= 1000, fmin = 1, fmax = 100, bandwidth = 2.5, n_jobs = 8)


        p_ch_avg = np.mean(p_ch, axis =0)
        p_ch_sem = stats.sem(p_ch, axis = 0)

        p_base_avg = np.mean(p_base, axis =0)
        p_base_sem = stats.sem(p_base)

        sns.set()
        fig = plt.figure()
        

        plt.plot(f_ch, p_ch_avg, color = '#1E90FF',alpha=0.3, label = 'touch', linewidth= 1)    
Exemple #20
0
def plot_spectrum_methods(data, sf, window_sec, band=None, dB=False):
    """Plot the periodogram, Welch's and multitaper PSD.

    Requires MNE-Python >= 0.14.

    Parameters
    ----------
    data : 1d-array
        Input signal in the time-domain.
    sf : float
        Sampling frequency of the data.
    band : list
        Lower and upper frequencies of the band of interest.
    window_sec : float
        Length of each window in seconds for Welch's PSD
    dB : boolean
        If True, convert the power to dB.
    """
    from mne.time_frequency import psd_array_multitaper
    from scipy.signal import welch, periodogram
    sns.set(style="white", font_scale=1.2)
    # Compute the PSD
    freqs, psd = periodogram(data, sf)
    freqs_welch, psd_welch = welch(data, sf, nperseg=window_sec * sf)
    psd_mt, freqs_mt = psd_array_multitaper(data,
                                            sf,
                                            adaptive=True,
                                            normalization='full',
                                            verbose=0)
    sharey = False

    # Optional: convert power to decibels (dB = 10 * log10(power))
    if dB:
        psd = 10 * np.log10(psd)
        psd_welch = 10 * np.log10(psd_welch)
        psd_mt = 10 * np.log10(psd_mt)
        sharey = True

    # Start plot
    fig, (ax1, ax2, ax3) = plt.subplots(1,
                                        3,
                                        figsize=(12, 4),
                                        sharex=True,
                                        sharey=sharey)
    # Stem
    sc = 'slategrey'
    ax1.stem(freqs, psd, linefmt=sc, basefmt=" ", markerfmt=" ")
    ax2.stem(freqs_welch, psd_welch, linefmt=sc, basefmt=" ", markerfmt=" ")
    ax3.stem(freqs_mt, psd_mt, linefmt=sc, basefmt=" ", markerfmt=" ")
    # Line
    lc, lw = 'k', 2
    ax1.plot(freqs, psd, lw=lw, color=lc)
    ax2.plot(freqs_welch, psd_welch, lw=lw, color=lc)
    ax3.plot(freqs_mt, psd_mt, lw=lw, color=lc)
    # Labels and axes
    ax1.set_xlabel('Frequency (Hz)')
    if not dB:
        ax1.set_ylabel('Power spectral density (V^2/Hz)')
    else:
        ax1.set_ylabel('Decibels (dB / Hz)')
    ax1.set_title('Periodogram')
    ax2.set_title('Welch')
    ax3.set_title('Multitaper')
    if band is not None:
        ax1.set_xlim(band)
    ax1.set_ylim(ymin=0)
    ax2.set_ylim(ymin=0)
    ax3.set_ylim(ymin=0)
    sns.despine()