コード例 #1
0
ファイル: plots.py プロジェクト: wmvanvliet/psychic
def plot_erp_psd(d, freq_range=(2, 60), fig=None, **kwargs):
    '''
    Plot the power spectral density (PSD), calculated using Welch' method, of
    all channels, averaged over all trials. This means for each trial, the PSD
    is computed and the resulting PSDs are averaged.

    In addition to the keyword arguments accepted by this function, any
    keyword arguments to the matplotlib.mlab.psd function can also be specified
    and will be passed along. 

    Parameters
    ----------
    d : :class:`psychic.DataSet`
        The dataset to plot the PSD of
    freq_range : pair of floats (default: (2, 60))
        The minimum and maximum frequency to plot in Hz
    fig : handle to matplotlib figure (default: None)
        If specified, the plot will be drawn in this figure.

    Returns
    -------
    fig : handle to matplotlib figure
        The resulting figure

    See also
    --------
    :func:`psychic.plot_psd`
    :func:`matplotlib.mlab.psd`
    '''
    assert d.data.ndim == 3, 'Expecting EEG data cut in trials'

    if fig is None:
        fig = plt.figure(figsize=(8,5))

    Fs = psychic.get_samplerate(d)
    NFFT = d.data.shape[1]

    # Ensure even NFFT
    if NFFT % 2 != 0:
        NFFT += 1

    for channel in range(d.data.shape[0]):
        all_psd = []
        for trial in d:
            psd, freqs = mlab.psd(trial.data[channel,:,0], NFFT=NFFT, Fs=Fs, *kwargs)
            all_psd.append(psd)
        plt.plot(freqs, np.mean(np.array(all_psd), axis=0))

    plt.xlim(freq_range[0], freq_range[1])
    plt.xlabel('Frequency (Hz)')
    plt.ylabel('Power (Db)')
    plt.legend(d.feat_lab[0])
    plt.title('Power spectral density, averaged over trials')

    return fig
コード例 #2
0
ファイル: plots.py プロジェクト: wmvanvliet/psychic
def plot_psd(d, freq_range=(2, 60), fig=None, **kwargs):
    '''
    Plot the power spectral density (PSD), calculated using Welch' method, of
    all channels.

    In addition to the keyword arguments accepted by this function, any
    keyword arguments to the matplotlib.mlab.psd function can also be specified
    and will be passed along. 

    Parameters
    ----------
    d : :class:`psychic.DataSet`
        The dataset to plot the PSD of
    freq_range : pair of floats (default: (2, 60))
        The minimum and maximum frequency to plot in Hz
    fig : handle to matplotlib figure (default: None)
        If specified, the plot will be drawn in this figure.

    Returns
    -------
    fig : handle to matplotlib figure
        The resulting figure

    See also
    --------
    :func:`psychic.plot_erp_psd`
    :func:`matplotlib.mlab.psd`
    
    '''
    assert d.data.ndim == 2, 'Expecting continuous EEG data'

    if fig is None:
        fig = plt.figure(figsize=(8,5))

    Fs = psychic.get_samplerate(d)
    NFFT = d.ninstances

    # Ensure even NFFT
    if NFFT % 2 != 0:
        NFFT += 1

    for channel in range(d.nfeatures):
        psd, freqs = mlab.psd(d.data[channel,:], NFFT=NFFT, Fs=Fs, *kwargs)
        plt.plot(freqs, psd)

    plt.xlim(freq_range[0], freq_range[1])
    plt.xlabel('Frequency (Hz)')
    plt.ylabel('Power (Db)')
    plt.legend(d.feat_lab[0])
    plt.title('Power spectral density')

    return fig
コード例 #3
0
ファイル: plots.py プロジェクト: wmvanvliet/psychic
def plot_specgrams(
        data,
        samplerate=None,
        NFFT=256,
        freq_range=[0.1, 50],
        fig=None):
    ''' For each channel, plot a spectogram. '''

    if fig is None:
        fig = plot.figure()

    if samplerate is None:
        samplerate = psychic.get_samplerate(data)

    num_channels = data.nfeatures
    num_cols = max(1, num_channels/8)
    num_rows = min(num_channels, 8)

    fig.subplots_adjust(hspace=0)
    for channel in range(num_channels):
        col = channel / num_rows
        row = channel % num_rows

        ax = plot.subplot(num_rows, num_cols, num_cols*row+col+1)
        s,freqs,_,_ = plot.specgram(data.data[channel,:], NFFT, samplerate, noverlap=NFFT/2, xextent=(np.min(data.ids), np.max(data.ids)))
        selection = np.logical_and(freqs >= freq_range[0], freqs <= freq_range[1])

        s = s[selection,:]
        freqs = freqs[selection]
        plot.ylim(freq_range[0], freq_range[1])
        plot.clim(np.min(np.log(s)), np.max(np.log(s)))

        ax.xaxis.grid(True, which='major', color='w')
        ax.yaxis.grid(False)

        if data.feat_lab is not None:
            plot.ylabel(data.feat_lab[channel])
        else:
            plot.ylabel('CH%02d' % (channel+1))

        if row == num_rows-1 or channel == num_channels-1:
            plot.xlabel('Time (s)')
        else:
            [label.set_visible(False) for label in ax.get_xticklabels()]
            [tick.set_visible(False) for tick in ax.get_xticklines()]


    return fig
コード例 #4
0
ファイル: template.py プロジェクト: wmvanvliet/psychic
    def train_(self, d):
        if self.time_range is None:
            self.time_range = (0, d.feat_lab[1][-1])
            self.time_idx = (0, d.data.shape[1]+1)
        else:
            sample_rate = psychic.get_samplerate(d)
            offset = d.feat_lab[1][0] * sample_rate
            self.time_idx = [int(x * sample_rate - offset) for x in self.time_range]
            self.time_idx[1] += 1

        erp = psychic.erp(d)

        if type(self.classes) == int:
            template = erp.data[:,:,self.classes]
        else:
            template = erp.data[:,:,self.classes[0]] - erp.data[:,:,self.classes[1]]
        self.template = DataSet(
            data = template,
            ids = [erp.feat_lab[1]],
            feat_lab=[erp.feat_lab[0]],
        )

        if self.peak_ch is None:
            peak = (self.time_idx[0] + np.argmax(np.abs(np.sum(
                self.template.data[:, self.time_idx[0]:self.time_idx[1]],
                axis=0))))
        else:
            if type(self.peak_ch) == str:
                self.peak_ch = self.template.feat_lab[0].index(self.peak_ch)
            peak = (self.time_idx[0] +
                np.argmax(np.abs(self.template.data[self.peak_ch,
                    self.time_idx[0]:self.time_idx[1]])))
        self.spatial_template = self.template.data[:, [peak]]

        sigma_x = psychic.nodes.spatialfilter.plain_cov0(self.template)
        sigma_x += self.reg * np.eye(sigma_x.shape[0])
        sigma_x_i = np.linalg.inv(sigma_x)
        W_spatial = sigma_x_i.dot(self.spatial_template)

        self.temp_template = psychic.nodes.spatialfilter.sfilter_plain(self.template, W_spatial)
        data = self.temp_template.data.copy()
        data[:,:self.time_idx[0]] = 0
        data[:,self.time_idx[1]:] = 0
        feat_lab=['temp']
        self.temp_template = DataSet(data=data, feat_lab=feat_lab, default=self.temp_template)
コード例 #5
0
ファイル: bdf.py プロジェクト: wmvanvliet/psychic
    def __init__(self, file, sample_rate=0, num_channels=0, header={}, dataset=None):
        try:
            self.f = open(file, 'wb') if isinstance(file, str) else file
        except:
            raise

        if dataset is not None:
            # Figure out some values from the datafile
            header = header.copy()
            header['n_channels'] = dataset.nfeatures

            if dataset.feat_lab is not None:
                header['label'] = list(dataset.feat_lab[0])

            sample_rate = psychic.get_samplerate(dataset)
            
            record_length = header['record_length'] if 'record_length' in header else 1
            header['n_samples_per_record'] = [int(sample_rate*record_length) for x in range(header['n_channels'])]

        # Use supplied header or defaults
        self.id_code = '\xffBIOSEMI'
        self.local_subject_id = header['local_subject_id'] if 'local_subject_id' in header else ''
        self.local_recording_id = header['local_recording_id'] if 'local_recording_id' in header else ''

        start_date_time = header['date_time'] if 'date_time' in header else datetime.datetime.now()
        self.start_date = header['start_date'] if 'start_date' in header else start_date_time.strftime('%d.%m.%y')
        self.start_time = header['start_time'] if 'start_time' in header else start_date_time.strftime('%H.%M.%S')

        self.format = header['format'] if 'format' in header else '24BIT'
        self.n_records = header['n_records'] if 'n_records' in header else -1
        self.record_length = header['record_length'] if 'record_length' in header else 1

        n_channels = header['n_channels'] if 'n_channels' in header else num_channels
        assert n_channels > 0, 'Please supply the number of channels.'
        self.n_channels = n_channels

        self.label = header['label'] if 'label' in header else [('channel %d' % (x+1)) for x in range(n_channels)]
        self.transducer_type = header['transducer_type'] if 'transducer_type' in header else ['unknown' for x in range(n_channels)]
        self.units = header['units'] if 'units' in header else ['uV' for x in range(n_channels)]
        self.physical_min = header['physical_min'] if 'physical_min' in header else [-1 for x in range(n_channels)]
        self.physical_max = header['physical_max'] if 'physical_max' in header else [1 for x in range(n_channels)]
        self.digital_min = header['digital_min'] if 'digital_min' in header else [-1000 for x in range(n_channels)]
        self.digital_max = header['digital_max'] if 'digital_max' in header else [1000 for x in range(n_channels)]
        self.prefiltering = header['prefiltering'] if 'prefiltering' in header else ['' for x in range(n_channels)]
        self.n_samples_per_record = header['n_samples_per_record'] if 'n_samples_per_record' in header else [sample_rate for x in range(n_channels)]
        assert len(np.unique(self.n_samples_per_record)) == 1, 'Sample rates differ for different channels'
        assert self.n_samples_per_record[0] > 0, 'Number of samples per record cannot be determined. Please specify a sample rate.'
        self.reserved = header['reserved'] if 'reserved' in header else ['Reserved' for x in range(n_channels)]

        self.records_written = 0
        self.samples_left_in_record = None

        # Append status channel if necessary
        if not 'Status' in self.label:
            self.append_status_channel()

        self.gain = np.array(self.physical_max) - np.array(self.physical_min)
        self.gain = self.gain.astype(np.float)
        self.gain /= np.array(self.digital_max) - np.array(self.digital_min)
        self.inv_gain = 1 / self.gain
        self.offset = np.array(self.physical_min) - self.gain * np.array(self.digital_min)
        self.header_written = False