def build_output_arrays(self, wavelet_pow_array, wavelet_phase_array, time_axis): wavelet_pow_array_xray = None wavelet_phase_array_xray = None if isinstance(self.time_series, xr.DataArray): dims = list(self.time_series.dims[:-1] + ( 'frequency', 'time', )) transposed_dims = [] # NOTE all computaitons up till this point assume that frequency position is -2 whereas # the default setting for this filter sets frequency axis index to 0. To avoid unnecessary transpositions # we need to adjust position of the frequency axis in the internal computations # getting frequency dim position as positive integer self.frequency_dim_pos = (len(dims) + self.frequency_dim_pos) % len(dims) orig_frequency_idx = dims.index('frequency') if self.frequency_dim_pos != orig_frequency_idx: transposed_dims = dims[:orig_frequency_idx] + dims[ orig_frequency_idx + 1:] transposed_dims.insert(self.frequency_dim_pos, 'frequency') coords = { dim_name: self.time_series.coords[dim_name] for dim_name in self.time_series.dims[:-1] } coords['frequency'] = self.freqs coords['time'] = time_axis if 'samplerate' not in coords: coords['samplerate'] = self.time_series.coords['samplerate'] if 'offsets' in list(self.time_series.coords.keys()): coords['offsets'] = ('time', self.time_series['offsets']) if wavelet_pow_array is not None: wavelet_pow_array_xray = TimeSeriesX(wavelet_pow_array, coords=coords, dims=dims) if len(transposed_dims): wavelet_pow_array_xray = wavelet_pow_array_xray.transpose( *transposed_dims) wavelet_pow_array_xray.attrs = self.time_series.attrs.copy() if wavelet_phase_array is not None: wavelet_phase_array_xray = TimeSeriesX(wavelet_phase_array, coords=coords, dims=dims) if len(transposed_dims): wavelet_phase_array_xray = wavelet_phase_array_xray.transpose( *transposed_dims) wavelet_phase_array_xray.attrs = self.time_series.attrs.copy() return wavelet_pow_array_xray, wavelet_phase_array_xray
def filter(self): ''' Applies Butterwoth filter to input time series and returns filtered TimeSeriesX object :return: TimeSeriesX object ''' from ptsa.filt import buttfilt time_axis_index = get_axis_index(self.time_series, axis_name='time') filtered_array = buttfilt(self.time_series, self.freq_range, float(self.time_series['samplerate']), self.filt_type, self.order, axis=time_axis_index) coords_dict = {coord_name: DataArray(coord.copy()) for coord_name, coord in self.time_series.coords.items()} coords_dict['samplerate'] = self.time_series['samplerate'] dims = [dim_name for dim_name in self.time_series.dims] filtered_time_series = TimeSeriesX( filtered_array, dims=dims, coords=coords_dict ) # filtered_time_series.attrs['samplerate'] = self.time_series.attrs['samplerate'] # filtered_time_series.attrs['samplerate'] = self.time_series['samplerate'] filtered_time_series = TimeSeriesX(filtered_time_series) return filtered_time_series
def build_output_arrays(self, wavelet_pow_array, wavelet_phase_array, time_axis): wavelet_pow_array_xray = None wavelet_phase_array_xray = None if isinstance(self.time_series, xr.DataArray): dims = list(self.time_series.dims[:-1] + ( 'frequency', 'time', )) transposed_dims = [] # getting frequency dim position as positive integer self.frequency_dim_pos = (len(dims) + self.frequency_dim_pos) % len(dims) orig_frequency_idx = dims.index('frequency') if self.frequency_dim_pos != orig_frequency_idx: transposed_dims = dims[:orig_frequency_idx] + dims[ orig_frequency_idx + 1:] transposed_dims.insert(self.frequency_dim_pos, 'frequency') coords = { dim_name: self.time_series.coords[dim_name] for dim_name in self.time_series.dims[:-1] } coords['frequency'] = self.freqs coords['time'] = time_axis if wavelet_pow_array is not None: wavelet_pow_array_xray = self.construct_output_array( wavelet_pow_array, dims=dims, coords=coords) if wavelet_phase_array is not None: wavelet_phase_array_xray = self.construct_output_array( wavelet_phase_array, dims=dims, coords=coords) if wavelet_pow_array_xray is not None: wavelet_pow_array_xray = TimeSeriesX(wavelet_pow_array_xray) if len(transposed_dims): wavelet_pow_array_xray = wavelet_pow_array_xray.transpose( *transposed_dims) wavelet_pow_array_xray.attrs = self.time_series.attrs.copy() if wavelet_phase_array_xray is not None: wavelet_phase_array_xray = TimeSeriesX( wavelet_phase_array_xray) if len(transposed_dims): wavelet_phase_array_xray = wavelet_phase_array_xray.transpose( *transposed_dims) wavelet_phase_array_xray.attrs = self.time_series.attrs.copy() return wavelet_pow_array_xray, wavelet_phase_array_xray
def read_session_data(self): """ Reads entire session worth of data :return: TimeSeriesX object (channels x events x time) with data for entire session the events dimension has length 1 """ brr = self.READER_FILETYPE_DICT[self.session_dataroot]( dataroot=self.session_dataroot, channels=self.channels) session_array, read_ok_mask = brr.read() self.channel_name = brr.channel_name offsets_axis = session_array['offsets'] number_of_time_points = offsets_axis.shape[0] samplerate = float(session_array['samplerate']) physical_time_array = np.arange(number_of_time_points) * (1.0 / samplerate) # session_array = session_array.rename({'start_offsets': 'events'}) session_time_series = TimeSeriesX( session_array.values, dims=[self.channel_name, 'start_offsets', 'time'], coords={ self.channel_name: session_array[self.channel_name], 'start_offsets': session_array['start_offsets'], 'time': physical_time_array, 'offsets': ('time', session_array['offsets']), 'samplerate': session_array['samplerate'] }) session_time_series.attrs = session_array.attrs.copy() session_time_series.attrs['dataroot'] = self.session_dataroot return session_time_series
def filter(self): """ Chops session into chunks orresponding to events :return: timeSeriesX object with chopped session """ chop_on_start_offsets_flag = bool(len(self.start_offsets)) if chop_on_start_offsets_flag: start_offsets = self.start_offsets chopping_axis_name = 'start_offsets' chopping_axis_data = start_offsets else: evs = self.events[self.events.eegfile == self.session_data.attrs['dataroot']] start_offsets = evs.eegoffset chopping_axis_name = 'events' chopping_axis_data = evs # samplerate = self.session_data.attrs['samplerate'] samplerate = float(self.session_data['samplerate']) offset_time_array = self.session_data['offsets'] event_chunk_size, start_point_shift = self.get_event_chunk_size_and_start_point_shift( eegoffset=start_offsets[0], samplerate=samplerate, offset_time_array=offset_time_array) event_time_axis = np.arange(event_chunk_size)*(1.0/samplerate)+(self.start_time-self.buffer_time) data_list = [] for i, eegoffset in enumerate(start_offsets): start_chop_pos = np.where(offset_time_array >= eegoffset)[0][0] start_chop_pos += start_point_shift selector_array = np.arange(start=start_chop_pos, stop=start_chop_pos + event_chunk_size) chopped_data_array = self.session_data.isel(time=selector_array) chopped_data_array['time'] = event_time_axis chopped_data_array['start_offsets'] = [i] data_list.append(chopped_data_array) ev_concat_data = xr.concat(data_list, dim='start_offsets') ev_concat_data = ev_concat_data.rename({'start_offsets':chopping_axis_name}) ev_concat_data[chopping_axis_name] = chopping_axis_data # ev_concat_data.attrs['samplerate'] = samplerate ev_concat_data['samplerate'] = samplerate ev_concat_data.attrs['start_time'] = self.start_time ev_concat_data.attrs['end_time'] = self.end_time ev_concat_data.attrs['buffer_time'] = self.buffer_time return TimeSeriesX(ev_concat_data)
def filter(self): event_data_dict = OrderedDict() for eegfile_name, data in self.data_dict.items(): evs = self.events[self.events.eegfile == eegfile_name] samplerate = data.attrs['samplerate'] # used in constructing time_axis offset_time_array = data['time'].values['eegoffset'] event_chunk_size, start_point_shift = self.get_event_chunk_size_and_start_point_shift(ev=evs[0], samplerate=samplerate, offset_time_array=offset_time_array) event_time_axis = np.linspace(-self.buffer + self.time_shift, self.event_duration + self.buffer + self.time_shift, event_chunk_size) data_list = [] shape = None for i, ev in enumerate(evs): # print ev.eegoffset start_chop_pos = np.where(offset_time_array >= ev.eegoffset)[0][0] start_chop_pos += start_point_shift selector_array = np.arange(start=start_chop_pos, stop=start_chop_pos + event_chunk_size) # ev_array = eeg_session_data[:,:,selector_array] # ORIG CODE chopped_data_array = data.isel(time=selector_array) chopped_data_array['time'] = event_time_axis chopped_data_array['events'] = [i] data_list.append(chopped_data_array) # print i ev_concat_data = xray.concat(data_list, dim='events') # replacing simple events axis (consecutive integers) with recarray of events ev_concat_data['events'] = evs ev_concat_data.attrs['samplerate'] = samplerate ev_concat_data.attrs['time_shift'] = self.time_shift ev_concat_data.attrs['event_duration'] = self.event_duration ev_concat_data.attrs['buffer'] = self.buffer event_data_dict[eegfile_name] = TimeSeriesX(ev_concat_data) break # REMOVE THIS return event_data_dict
class ButterworthFilter(PropertiedObject, BaseFilter): """Applies Butterworth filter to a time series. Keyword Arguments ----------------- time_series TimeSeriesX object order Butterworth filter order freq_range: list-like Array [min_freq, max_freq] describing the filter range """ _descriptors = [ TypeValTuple('time_series', TimeSeriesX, TimeSeriesX([0.0], dict(samplerate=1.), dims=['time'])), TypeValTuple('order', int, 4), TypeValTuple('freq_range', list, [58, 62]), TypeValTuple('filt_type', str, 'stop'), ] def __init__(self, **kwds): self.init_attrs(kwds) def filter(self): """ Applies Butterwoth filter to input time series and returns filtered TimeSeriesX object Returns ------- filtered: TimeSeriesX The filtered time series """ time_axis_index = get_axis_index(self.time_series, axis_name='time') filtered_array = buttfilt(self.time_series, self.freq_range, float(self.time_series['samplerate']), self.filt_type, self.order, axis=time_axis_index) coords_dict = { coord_name: DataArray(coord.copy()) for coord_name, coord in list(self.time_series.coords.items()) } coords_dict['samplerate'] = self.time_series['samplerate'] dims = [dim_name for dim_name in self.time_series.dims] filtered_time_series = TimeSeriesX(filtered_array, dims=dims, coords=coords_dict) # filtered_time_series = TimeSeriesX(filtered_time_series) filtered_time_series.attrs = self.time_series.attrs.copy() return filtered_time_series
def test_init(): """Test that everything is initialized properly.""" data = np.random.random((10, 10, 10)) rate = 1000 with pytest.raises(AssertionError): TimeSeriesX(data, {}) with pytest.raises(AssertionError): TimeSeriesX.create(data, None, coords={}) assert TimeSeriesX.create(data, None, coords={ 'samplerate': 1 }).samplerate == 1 ts = TimeSeriesX(data, dict(samplerate=rate)) assert isinstance(ts, xr.DataArray) assert ts.shape == (10, 10, 10) assert ts['samplerate'] == rate
def create_time_seriesX_from_superEEG(data, samplerate=500.0): times = {'time': np.arange(data.data.shape[0]) * 1000.0 / samplerate} samplerate = {'samplerate': samplerate} mni_coords = data.locs.to_dict('series') channels = {'channels': np.arange(data.data.shape[1])} coords = {**times, **channels, **samplerate} data = TimeSeriesX(data.data, coords=coords, dims=['time', 'channels']) data.attrs['x'] = mni_coords['x'] data.attrs['y'] = mni_coords['y'] data.attrs['z'] = mni_coords['z'] return data
def filter(self): """ Turns time series for monopolar electrodes into time series where where 'channels' axis is replaced by 'bipolar_pairs' axis and the time series data is a difference between time series corresponding to different electrodes as specified by bipolar pairs :return: TimeSeriesX object """ # a = np.arange(20)*2 # # template = [2,4,6,6,8,2,4] # # sorter = np.argsort(a) # idx = sorter[np.searchsorted(a, template, sorter=sorter)] # idx = np.where(a == 6) # # print ch0 # # print ch1 channel_axis = self.time_series['channels'] ch0 = self.bipolar_pairs['ch0'] ch1 = self.bipolar_pairs['ch1'] sel0 = channel_axis.loc[ch0] sel1 = channel_axis.loc[ch1] ts0 = self.time_series.loc[dict(channels=sel0)] ts1 = self.time_series.loc[dict(channels=sel1)] dims_bp = list(self.time_series.dims) channels_idx = dims_bp.index('channels') dims_bp[channels_idx] = 'bipolar_pairs' # coords_bp = [self.time_series[dim_name].copy() for dim_name in self.time_series.dims] # coords_bp[channels_idx] = self.bipolar_pairs coords_bp = { coord_name: coord for coord_name, coord in self.time_series.coords.items() } del coords_bp['channels'] coords_bp['bipolar_pairs'] = self.bipolar_pairs ts = TimeSeriesX(data=ts0.values - ts1.values, dims=dims_bp, coords=coords_bp) ts['samplerate'] = self.time_series['samplerate'] ts.attrs = self.time_series.attrs.copy() return ts
class ButterworthFilter(PropertiedObject,BaseFilter): ''' Applies Butterworth filter to a time series ''' _descriptors = [ TypeValTuple('time_series', TimeSeriesX, TimeSeriesX([0.0], dims=['time'])), TypeValTuple('order', int, 4), TypeValTuple('freq_range', list, [58, 62]), TypeValTuple('filt_type', str, 'stop'), ] def __init__(self, **kwds): ''' Constructor :param kwds:allowed values are: ------------------------------------- :param time_series - TimeSeriesX object :param order - Butterworth filter order :param freq_range - array of frequencies [min_freq, max_freq] to filter out :return: None ''' self.init_attrs(kwds) def filter(self): ''' Applies Butterwoth filter to input time series and returns filtered TimeSeriesX object :return: TimeSeriesX object ''' from ptsa.filt import buttfilt time_axis_index = get_axis_index(self.time_series, axis_name='time') filtered_array = buttfilt(self.time_series, self.freq_range, float(self.time_series['samplerate']), self.filt_type, self.order, axis=time_axis_index) coords_dict = {coord_name: DataArray(coord.copy()) for coord_name, coord in self.time_series.coords.items()} coords_dict['samplerate'] = self.time_series['samplerate'] dims = [dim_name for dim_name in self.time_series.dims] filtered_time_series = TimeSeriesX( filtered_array, dims=dims, coords=coords_dict ) # filtered_time_series.attrs['samplerate'] = self.time_series.attrs['samplerate'] # filtered_time_series.attrs['samplerate'] = self.time_series['samplerate'] filtered_time_series = TimeSeriesX(filtered_time_series) return filtered_time_series
def concat_time_seriesX(data_vec): n_events = len(data_vec) times = {'time': data_vec[0]['time'].values} channels = {'channels': data_vec[0]['channels'].values} samplerate = {'samplerate': data_vec[0]['samplerate']} events = {'event': np.arange(n_events)} coords = {**times, **channels, **samplerate, **events} data_vec_values = [x.values for x in data_vec] data_array = np.stack(data_vec_values) data = TimeSeriesX(data_array, coords=coords, dims=['event', 'time', 'channels']) data.attrs['x'] = data_vec[0].attrs['x'] data.attrs['y'] = data_vec[0].attrs['y'] data.attrs['z'] = data_vec[0].attrs['z'] return data
def test_wavelets_synthetic_data(self): samplerate = 1000. frequency = 180.0 modulation_frequency = 80.0 duration = 1.0 n_points = int(np.round(duration * samplerate)) x = np.arange(n_points, dtype=np.float) y = np.sin(x * (2 * np.pi * frequency / n_points)) y_mod = np.sin(x * (2 * np.pi * frequency / n_points)) * np.sin( x * (2 * np.pi * modulation_frequency / n_points)) ts = TimeSeriesX(y, dims=['time'], coords=[x]) ts['samplerate'] = samplerate ts.attrs['samplerate'] = samplerate frequencies = [10.0, 30.0, 50.0, 80., 120., 180., 250.0, 300.0, 500.] for frequency in frequencies: wf = MorletWaveletFilter(time_series=ts, freqs=np.array([frequency]), output='both', frequency_dim_pos=0, verbose=True) pow_wavelet, phase_wavelet = wf.filter() from ptsa.wavelet import phase_pow_multi pow_wavelet_ptsa_orig = phase_pow_multi(freqs=[frequency], samplerates=samplerate, dat=ts.data, to_return='power') assert_array_almost_equal( (pow_wavelet_ptsa_orig - pow_wavelet) / pow_wavelet_ptsa_orig, np.zeros_like(pow_wavelet), decimal=6)
def read_session(self, eegfile_name): samplesize = 1.0 / self.samplerate bin_reader = self.bin_readers_dict[eegfile_name] print 'reading ', eegfile_name start_offset = self.offset end_offset = -1 if self.event_data_only: #reading continuous data containig events and small buffer start_offset, end_offset = self.determine_read_offset_range(eegfile_name) eegdata = bin_reader._load_all_data(channels=self.channels, start_offset=start_offset, end_offset=end_offset) # constructing time exis as record array [(session_time_in_sec,offset)] number_of_time_points = eegdata.shape[2] start_time = start_offset * samplesize end_time = start_time + number_of_time_points * samplesize time_range = np.linspace(start_time, end_time, number_of_time_points) eegoffset = np.arange(start_offset, start_offset+ number_of_time_points) time_axis = np.rec.fromarrays([time_range, eegoffset], names='time,eegoffset') # constructing xray Data Array with session eeg data - note we are adding event dimension to simplify # chopping of the data sample into events - single events will be concatenated allong events axis eegdata_xray = xray.DataArray(eegdata, coords=[self.channels, np.arange(1), time_axis], dims=['channels', 'events', 'time']) eegdata_xray.attrs['samplerate'] = self.samplerate print 'last_time_stamp=',eegdata_xray['time'][-1] return TimeSeriesX(eegdata_xray)
class DataChopper(PropertiedObject,BaseFilter): """ EventDataChopper converts continuous time series of entire session into chunks based on the events specification In other words you may read entire eeg session first and then using EventDataChopper divide it into chunks corresponding to events of your choice """ _descriptors = [ TypeValTuple('start_time', float, 0.0), TypeValTuple('end_time', float, 0.0), TypeValTuple('buffer_time', float, 0.0), TypeValTuple('events', np.recarray, np.recarray((1,), dtype=[('x', int)])), TypeValTuple('start_offsets', np.ndarray, np.array([], dtype=int)), TypeValTuple('session_data', TimeSeriesX, TimeSeriesX([0.0], dims=['time'])), ] def __init__(self, **kwds): """ Constructor: :param kwds:allowed values are: ------------------------------------- :param start_time {float} - read start offset in seconds w.r.t to the eegeffset specified in the events recarray :param end_time {float} - read end offset in seconds w.r.t to the eegeffset specified in the events recarray :param end_time {float} - extra buffer in seconds (subtracted from start read and added to end read) :param events {np.recarray} - numpy recarray representing events :param startoffsets {np.ndarray} - numpy array with offsets at which chopping should take place :param session_datar {str} - TimeSeriesX object with eeg session data :return: None """ self.init_attrs(kwds) def get_event_chunk_size_and_start_point_shift(self, eegoffset, samplerate, offset_time_array): """ Computes number of time points for each event and read offset w.r.t. event's eegoffset :param ev: record representing single event :param samplerate: samplerate fo the time series :param offset_time_array: "offsets" axis of the DataArray returned by EEGReader. This is the axis that represents time axis but instead of beind dimensioned to seconds it simply represents position of a given data point in a series The time axis is constructed by dividint offsets axis by the samplerate :return: event's read chunk size {int}, read offset w.r.t. to event's eegoffset {} """ # figuring out read size chunk and shift w.r.t to eegoffset. We need this fcn in case we pass resampled session data original_samplerate = float((offset_time_array[-1] - offset_time_array[0])) / offset_time_array.shape[ 0] * samplerate start_point = eegoffset - int(np.ceil((self.buffer_time - self.start_time) * original_samplerate)) end_point = eegoffset + int( np.ceil((self.end_time + self.buffer_time) * original_samplerate)) selector_array = np.where((offset_time_array >= start_point) & (offset_time_array < end_point))[0] start_point_shift = selector_array[0] - np.where((offset_time_array >= eegoffset))[0][0] return len(selector_array), start_point_shift def filter(self): """ Chops session into chunks orresponding to events :return: timeSeriesX object with chopped session """ chop_on_start_offsets_flag = bool(len(self.start_offsets)) if chop_on_start_offsets_flag: start_offsets = self.start_offsets chopping_axis_name = 'start_offsets' chopping_axis_data = start_offsets else: evs = self.events[self.events.eegfile == self.session_data.attrs['dataroot']] start_offsets = evs.eegoffset chopping_axis_name = 'events' chopping_axis_data = evs # samplerate = self.session_data.attrs['samplerate'] samplerate = float(self.session_data['samplerate']) offset_time_array = self.session_data['offsets'] event_chunk_size, start_point_shift = self.get_event_chunk_size_and_start_point_shift( eegoffset=start_offsets[0], samplerate=samplerate, offset_time_array=offset_time_array) event_time_axis = np.arange(event_chunk_size)*(1.0/samplerate)+(self.start_time-self.buffer_time) data_list = [] for i, eegoffset in enumerate(start_offsets): start_chop_pos = np.where(offset_time_array >= eegoffset)[0][0] start_chop_pos += start_point_shift selector_array = np.arange(start=start_chop_pos, stop=start_chop_pos + event_chunk_size) chopped_data_array = self.session_data.isel(time=selector_array) chopped_data_array['time'] = event_time_axis chopped_data_array['start_offsets'] = [i] data_list.append(chopped_data_array) ev_concat_data = xr.concat(data_list, dim='start_offsets') ev_concat_data = ev_concat_data.rename({'start_offsets':chopping_axis_name}) ev_concat_data[chopping_axis_name] = chopping_axis_data # ev_concat_data.attrs['samplerate'] = samplerate ev_concat_data['samplerate'] = samplerate ev_concat_data.attrs['start_time'] = self.start_time ev_concat_data.attrs['end_time'] = self.end_time ev_concat_data.attrs['buffer_time'] = self.buffer_time return TimeSeriesX(ev_concat_data)
def compute_ps_powers(self, events, sessions, monopolar_channels, bipolar_pairs, experiment): n_freqs = len(self.params.freqs) n_bps = len(bipolar_pairs) pow_mat_pre = pow_mat_post = None pow_ev = None samplerate = winsize = bufsize = None monopolar_channels_list = list(monopolar_channels) for sess in sessions: sess_events = events[events.session == sess] # print type(sess_events) n_events = len(sess_events) print 'Loading EEG for', n_events, 'events of session', sess pre_start_time = self.params.ps_start_time - self.params.ps_offset pre_end_time = self.params.ps_end_time - self.params.ps_offset # eegs_pre = Events(sess_events).get_data(channels=channels, start_time=pre_start_time, end_time=pre_end_time, # buffer_time=self.params.ps_buf, eoffset='eegoffset', keep_buffer=True, eoffset_in_time=False) eeg_pre_reader = EEGReader( events=sess_events, channels=np.array(monopolar_channels_list), start_time=pre_start_time, end_time=pre_end_time, buffer_time=self.params.ps_buf) eegs_pre = eeg_pre_reader.read() if samplerate is None: # samplerate = round(eegs_pre.samplerate) # samplerate = eegs_pre.attrs['samplerate'] samplerate = float(eegs_pre['samplerate']) winsize = int( round(samplerate * (pre_end_time - pre_start_time + 2 * self.params.ps_buf))) bufsize = int(round(samplerate * self.params.ps_buf)) print 'samplerate =', samplerate, 'winsize =', winsize, 'bufsize =', bufsize pow_ev = np.empty(shape=n_freqs * winsize, dtype=float) self.wavelet_transform.init(self.params.width, self.params.freqs[0], self.params.freqs[-1], n_freqs, samplerate, winsize) # mirroring nb_ = int(round(samplerate * (self.params.ps_buf))) eegs_pre[..., -nb_:] = eegs_pre[..., -nb_ - 2:-2 * nb_ - 2:-1] dim3_pre = eegs_pre.shape[ 2] # because post-stim time inreval does not align for all stim events (stims have different duration) # we have to take care of aligning eegs_post ourselves time dim to dim3 # eegs_post = np.zeros_like(eegs_pre) from ptsa.data.TimeSeriesX import TimeSeriesX eegs_post = TimeSeriesX(np.zeros_like(eegs_pre), dims=eegs_pre.dims, coords=eegs_pre.coords) post_start_time = self.params.ps_offset post_end_time = self.params.ps_offset + (self.params.ps_end_time - self.params.ps_start_time) for i_ev in xrange(n_events): ev_offset = sess_events[i_ev].pulse_duration if ev_offset > 0: if experiment == 'PS3' and sess_events[i_ev].nBursts > 0: ev_offset *= sess_events[i_ev].nBursts + 1 ev_offset *= 0.001 else: ev_offset = 0.0 # eeg_post = Events(sess_events[i_ev:i_ev+1]).get_data(channels=channels, start_time=post_start_time+ev_offset, # end_time=post_end_time+ev_offset, buffer_time=self.params.ps_buf, # eoffset='eegoffset', keep_buffer=True, eoffset_in_time=False) eeg_post_reader = EEGReader( events=sess_events[i_ev:i_ev + 1], channels=np.array(monopolar_channels_list), start_time=post_start_time + ev_offset, end_time=post_end_time + ev_offset, buffer_time=self.params.ps_buf) eeg_post = eeg_post_reader.read() dim3_post = eeg_post.shape[2] # here we take care of possible mismatch of time dim length if dim3_pre == dim3_post: eegs_post[:, i_ev:i_ev + 1, :] = eeg_post elif dim3_pre < dim3_post: eegs_post[:, i_ev:i_ev + 1, :] = eeg_post[:, :, :-1] else: eegs_post[:, i_ev:i_ev + 1, :-1] = eeg_post # mirroring eegs_post[..., :nb_] = eegs_post[..., 2 * nb_:nb_:-1] print 'Computing', experiment, 'powers' sess_pow_mat_pre = np.empty(shape=(n_events, n_bps, n_freqs), dtype=np.float) sess_pow_mat_post = np.empty_like(sess_pow_mat_pre) for i, ti in enumerate(bipolar_pairs): bp = ti['channel_str'] print 'Computing powers for bipolar pair', bp elec1 = np.where(monopolar_channels == bp[0])[0][0] elec2 = np.where(monopolar_channels == bp[1])[0][0] # # for i,ti in enumerate(tal_info): # bp = ti['channel_str'] # print 'Computing powers for bipolar pair', bp # elec1 = np.where(channels == bp[0])[0][0] # elec2 = np.where(channels == bp[1])[0][0] bp_data_pre = eegs_pre[elec1] - eegs_pre[elec2] # bp_data_pre.attrs['samplerate'] = samplerate bp_data_pre = bp_data_pre.filtered( [58, 62], filt_type='stop', order=self.params.filt_order) for ev in xrange(n_events): #pow_pre_ev = phase_pow_multi(self.params.freqs, bp_data_pre[ev], to_return='power') self.wavelet_transform.multiphasevec( bp_data_pre[ev][0:winsize], pow_ev) #sess_pow_mat_pre[ev,i,:] = np.mean(pow_pre_ev[:,nb_:-nb_], axis=1) pow_ev_stripped = np.reshape( pow_ev, (n_freqs, winsize))[:, bufsize:winsize - bufsize] if self.params.log_powers: np.log10(pow_ev_stripped, out=pow_ev_stripped) sess_pow_mat_pre[ev, i, :] = np.nanmean(pow_ev_stripped, axis=1) bp_data_post = eegs_post[elec1] - eegs_post[elec2] # bp_data_post.attrs['samplerate'] = samplerate bp_data_post = bp_data_post.filtered( [58, 62], filt_type='stop', order=self.params.filt_order) for ev in xrange(n_events): #pow_post_ev = phase_pow_multi(self.params.freqs, bp_data_post[ev], to_return='power') self.wavelet_transform.multiphasevec( bp_data_post[ev][0:winsize], pow_ev) #sess_pow_mat_post[ev,i,:] = np.mean(pow_post_ev[:,nb_:-nb_], axis=1) pow_ev_stripped = np.reshape( pow_ev, (n_freqs, winsize))[:, bufsize:winsize - bufsize] if self.params.log_powers: np.log10(pow_ev_stripped, out=pow_ev_stripped) sess_pow_mat_post[ev, i, :] = np.nanmean(pow_ev_stripped, axis=1) sess_pow_mat_pre = sess_pow_mat_pre.reshape( (n_events, n_bps * n_freqs)) #sess_pow_mat_pre = zscore(sess_pow_mat_pre, axis=0, ddof=1) sess_pow_mat_post = sess_pow_mat_post.reshape( (n_events, n_bps * n_freqs)) #sess_pow_mat_post = zscore(sess_pow_mat_post, axis=0, ddof=1) sess_pow_mat_joint = zscore(np.vstack( (sess_pow_mat_pre, sess_pow_mat_post)), axis=0, ddof=1) sess_pow_mat_pre = sess_pow_mat_joint[:n_events, ...] sess_pow_mat_post = sess_pow_mat_joint[n_events:, ...] pow_mat_pre = np.vstack( (pow_mat_pre, sess_pow_mat_pre )) if pow_mat_pre is not None else sess_pow_mat_pre pow_mat_post = np.vstack( (pow_mat_post, sess_pow_mat_post )) if pow_mat_post is not None else sess_pow_mat_post return pow_mat_pre, pow_mat_post
def read_events_data(self): """ Reads eeg data for individual event :return: TimeSeriesX object (channels x events x time) with data for individual events """ self.event_ok_mask_sorted = None # reset self.event_ok_mask_sorted evs = self.events raw_readers, original_dataroots = self.__create_base_raw_readers() # used for restoring original order of the events ordered_indices = np.arange(len(evs)) event_indices_list = [] events = [] ts_array_list = [] event_ok_mask_list = [] for s, (raw_reader, dataroot) in enumerate(zip(raw_readers, original_dataroots)): ts_array, read_ok_mask = raw_reader.read() event_ok_mask_list.append(np.all(read_ok_mask, axis=0)) ind = np.atleast_1d(evs.eegfile == dataroot) event_indices_list.append(ordered_indices[ind]) events.append(evs[ind]) ts_array_list.append(ts_array) if not all([ r.channel_name == raw_readers[0].channel_name for r in raw_readers ]): raise IncompatibleDataError( 'cannot read monopolar and bipolar data together') self.channel_name = raw_readers[0].channel_name # print('raw_reader_channel_names: \n%s'%[x.channel_name for x in raw_readers]) # print('self.channel_name: %s'%self.channel_name) event_indices_array = np.hstack(event_indices_list) event_indices_restore_sort_order_array = event_indices_array.argsort() start_extend_time = time.time() # new code eventdata = xr.concat(ts_array_list, dim='start_offsets') # tdim = np.linspace(self.start_time-self.buffer_time,self.end_time+self.buffer_time,num=eventdata['offsets'].shape[0]) # samplerate=eventdata.attrs['samplerate'].data samplerate = float(eventdata['samplerate']) tdim = np.arange(eventdata.shape[-1]) * (1.0 / samplerate) + ( self.start_time - self.buffer_time) cdim = eventdata[self.channel_name] edim = np.concatenate(events).view(np.recarray).copy() attrs = eventdata.attrs.copy() # constructing TimeSeries Object # eventdata = TimeSeriesX(eventdata.data,dims=['channels','events','time'],coords=[cdim,edim,tdim]) eventdata = TimeSeriesX(eventdata.data, dims=[self.channel_name, 'events', 'time'], coords={ self.channel_name: cdim, 'events': edim, 'time': tdim, 'samplerate': samplerate }) eventdata.attrs = attrs # restoring original order of the events eventdata = eventdata[:, event_indices_restore_sort_order_array, :] event_ok_mask = np.hstack(event_ok_mask_list) event_ok_mask_sorted = event_ok_mask[ event_indices_restore_sort_order_array] #removing bad events if np.any(~event_ok_mask_sorted): self.removed_corrupt_events = True self.event_ok_mask_sorted = event_ok_mask_sorted eventdata = eventdata[:, event_ok_mask_sorted, :] return eventdata
class MonopolarToBipolarMapper(PropertiedObject, BaseFilter): """ Object that takes as an input time series for monopolar electrodes and an array of bipolar pairs and outputs Time series where 'channels' axis is replaced by 'bipolar_pairs' axis and the time series data is a difference between time series corresponding to different electrodes as specified by bipolar pairs """ _descriptors = [ TypeValTuple('time_series', TimeSeriesX, TimeSeriesX([0.0], dims=['time'])), TypeValTuple( 'bipolar_pairs', np.recarray, np.recarray((0, ), dtype=[('ch0', '|S3'), ('ch1', '|S3')])), ] def __init__(self, **kwds): """ Constructor: :param kwds:allowed values are: ------------------------------------- :param time_series - TimeSeriesX object with eeg session data and 'channels as one of the axes' :param bipolar_pairs {np.recarray} - an array of bipolar electrode pairs :return: None """ self.init_attrs(kwds) def filter(self): """ Turns time series for monopolar electrodes into time series where where 'channels' axis is replaced by 'bipolar_pairs' axis and the time series data is a difference between time series corresponding to different electrodes as specified by bipolar pairs :return: TimeSeriesX object """ # a = np.arange(20)*2 # # template = [2,4,6,6,8,2,4] # # sorter = np.argsort(a) # idx = sorter[np.searchsorted(a, template, sorter=sorter)] # idx = np.where(a == 6) # # print ch0 # # print ch1 channel_axis = self.time_series['channels'] ch0 = self.bipolar_pairs['ch0'] ch1 = self.bipolar_pairs['ch1'] sel0 = channel_axis.loc[ch0] sel1 = channel_axis.loc[ch1] ts0 = self.time_series.loc[dict(channels=sel0)] ts1 = self.time_series.loc[dict(channels=sel1)] dims_bp = list(self.time_series.dims) channels_idx = dims_bp.index('channels') dims_bp[channels_idx] = 'bipolar_pairs' # coords_bp = [self.time_series[dim_name].copy() for dim_name in self.time_series.dims] # coords_bp[channels_idx] = self.bipolar_pairs coords_bp = { coord_name: coord for coord_name, coord in self.time_series.coords.items() } del coords_bp['channels'] coords_bp['bipolar_pairs'] = self.bipolar_pairs ts = TimeSeriesX(data=ts0.values - ts1.values, dims=dims_bp, coords=coords_bp) ts['samplerate'] = self.time_series['samplerate'] ts.attrs = self.time_series.attrs.copy() return ts
def read(self, channels): evs = self.events raw_bin_wrappers, original_eeg_files = self.__create_bin_readers() # we need to create rawbinwrappers first to figure out sample rate before calling __compute_time_series_length() time_series_length = self.__compute_time_series_length() time_series_data = np.empty( (len(channels), len(evs), time_series_length), dtype=np.float) * np.nan ordered_indices = np.arange(len(evs)) event_indices_list = [] events = [] newdat_list = [] eventdata = None for s, (src, eegfile) in enumerate(zip(raw_bin_wrappers, original_eeg_files)): ind = np.atleast_1d(evs.eegfile == eegfile) event_indices_list.append(ordered_indices[ind]) if len(ind) == 1: event_offsets = evs['eegoffset'] events.append(evs) else: event_offsets = evs[ind]['eegoffset'] events.append(evs[ind]) # get the timeseries for those events newdat = src.get_event_data_xray(channels, event_offsets, self.start_time, self.end_time, self.buffer_time, resampled_rate=None, filt_freq=None, filt_type=None, filt_order=None, keep_buffer=self.keep_buffer, loop_axis=None, num_mp_procs=0, eoffset='eegoffset', eoffset_in_time=False) newdat_list.append(newdat) event_indices_array = np.hstack(event_indices_list) event_indices_restore_sort_order_array = event_indices_array.argsort() start_extend_time = time.time() #new code eventdata = xr.concat(newdat_list, dim='events') end_extend_time = time.time() # concatenate (must eventually check that dims match) # ORIGINAL CODE tdim = eventdata['time'] cdim = eventdata['channels'] # srate = eventdata.samplerate srate = eventdata.attrs['samplerate'] events = np.concatenate(events).view(Events) eventdata_xray = xr.DataArray(eventdata.values, coords=[cdim, events, tdim], dims=['channels', 'events', 'time']) eventdata_xray.attrs['samplerate'] = eventdata.attrs['samplerate'] eventdata_xray = eventdata_xray[:, event_indices_restore_sort_order_array, :] #### RESTORE THIS if not self.keep_buffer: # trimming buffer data samples number_of_buffer_samples = self.get_number_of_samples_for_interval( self.buffer_time) if number_of_buffer_samples > 0: eventdata_xray = eventdata_xray[:, :, number_of_buffer_samples: -number_of_buffer_samples] return TimeSeriesX(eventdata_xray)
class ResampleFilter(PropertiedObject, BaseFilter): """Upsample or downsample a time series to a new sample rate. Keyword Arguments ----------------- time_series TimeSeriesX object resamplerate: float new sampling frequency time_axis_index: int index of the time axis round_to_original_timepoints: bool Flag indicating if timepoints from original time axis should be reused after proper rounding. Defaults to False """ _descriptors = [ TypeValTuple('time_series', TimeSeriesX, TimeSeriesX([0.0], dict(samplerate=1), dims=['time'])), TypeValTuple('resamplerate', float, -1.0), TypeValTuple('time_axis_index', int, -1), TypeValTuple('round_to_original_timepoints', bool, False), ] def ___syntax_helper(self): self.time_series = None self.resamplerate = None self.time_axis_index = None self.round_to_original_timepoints = None def __init__(self, **kwds): self.window = None # self.time_series = None self.init_attrs(kwds) def filter(self): """resamples time series Returns ------- resampled: TimeSeriesX resampled time series with sampling frequency set to resamplerate """ samplerate = float(self.time_series['samplerate']) time_axis_length = np.squeeze(self.time_series.coords['time'].shape) new_length = int( np.round(time_axis_length * self.resamplerate / samplerate)) print(new_length) if self.time_axis_index < 0: self.time_axis_index = self.time_series.get_axis_num('time') time_axis = self.time_series.coords[self.time_series.dims[ self.time_axis_index]] try: time_axis_data = time_axis.data[ 'time'] # time axis can be recarray with one of the arrays being time except (KeyError, IndexError) as excp: # if we get here then most likely time axis is ndarray of floats time_axis_data = time_axis.data time_idx_array = np.arange(len(time_axis)) if self.round_to_original_timepoints: filtered_array, new_time_idx_array = resample( self.time_series.data, new_length, t=time_idx_array, axis=self.time_axis_index, window=self.window) # print new_time_axis new_time_idx_array = np.rint(new_time_idx_array).astype(np.int) new_time_axis = time_axis[new_time_idx_array] else: filtered_array, new_time_axis = resample(self.time_series.data, new_length, t=time_axis_data, axis=self.time_axis_index, window=self.window) coords = {} for i, dim_name in enumerate(self.time_series.dims): if i != self.time_axis_index: coords[dim_name] = self.time_series.coords[dim_name].copy() else: coords[dim_name] = new_time_axis coords['samplerate'] = self.resamplerate filtered_time_series = TimeSeriesX(filtered_array, coords=coords, dims=self.time_series.dims) return filtered_time_series
def filter(self): """resamples time series Returns ------- resampled: TimeSeriesX resampled time series with sampling frequency set to resamplerate """ samplerate = float(self.time_series['samplerate']) time_axis_length = np.squeeze(self.time_series.coords['time'].shape) new_length = int( np.round(time_axis_length * self.resamplerate / samplerate)) print(new_length) if self.time_axis_index < 0: self.time_axis_index = self.time_series.get_axis_num('time') time_axis = self.time_series.coords[self.time_series.dims[ self.time_axis_index]] try: time_axis_data = time_axis.data[ 'time'] # time axis can be recarray with one of the arrays being time except (KeyError, IndexError) as excp: # if we get here then most likely time axis is ndarray of floats time_axis_data = time_axis.data time_idx_array = np.arange(len(time_axis)) if self.round_to_original_timepoints: filtered_array, new_time_idx_array = resample( self.time_series.data, new_length, t=time_idx_array, axis=self.time_axis_index, window=self.window) # print new_time_axis new_time_idx_array = np.rint(new_time_idx_array).astype(np.int) new_time_axis = time_axis[new_time_idx_array] else: filtered_array, new_time_axis = resample(self.time_series.data, new_length, t=time_axis_data, axis=self.time_axis_index, window=self.window) coords = {} for i, dim_name in enumerate(self.time_series.dims): if i != self.time_axis_index: coords[dim_name] = self.time_series.coords[dim_name].copy() else: coords[dim_name] = new_time_axis coords['samplerate'] = self.resamplerate filtered_time_series = TimeSeriesX(filtered_array, coords=coords, dims=self.time_series.dims) return filtered_time_series
def filter(self): time_axis = self.time_series['time'] time_axis_size = time_axis.shape[0] samplerate = float(self.time_series['samplerate']) wavelet_dims = self.time_series.shape[:-1] + (self.freqs.shape[0], ) print(wavelet_dims) powers_reshaped = np.array([[]], dtype=np.float) phases_reshaped = np.array([[]], dtype=np.float) wavelets_complex_reshaped = np.array([[]], dtype=np.complex) if self.output == 'power': powers_reshaped = np.empty(shape=(np.prod(wavelet_dims), self.time_series.shape[-1]), dtype=np.float) if self.output == 'phase': phases_reshaped = np.empty(shape=(np.prod(wavelet_dims), self.time_series.shape[-1]), dtype=np.float) if self.output == 'both': powers_reshaped = np.empty(shape=(np.prod(wavelet_dims), self.time_series.shape[-1]), dtype=np.float) phases_reshaped = np.empty(shape=(np.prod(wavelet_dims), self.time_series.shape[-1]), dtype=np.float) if self.output == 'complex': wavelets_complex_reshaped = np.empty( shape=(np.prod(wavelet_dims), self.time_series.shape[-1]), dtype=np.complex) # mt = morlet.MorletWaveletTransformMP(self.cpus) # mt = MorletWaveletTransformMP(self.cpus) mt = MorletWaveletTransformMP(self.cpus) time_series_reshaped = np.ascontiguousarray( self.time_series.data.reshape(np.prod(self.time_series.shape[:-1]), self.time_series.shape[-1]), self.time_series.data.dtype) if self.output == 'power': mt.set_output_type(morlet.POWER) if self.output == 'phase': mt.set_output_type(morlet.PHASE) if self.output == 'both': mt.set_output_type(morlet.BOTH) if self.output == 'complex': mt.set_output_type(morlet.COMPLEX) mt.set_signal_array(time_series_reshaped) mt.set_wavelet_pow_array(powers_reshaped) mt.set_wavelet_phase_array(phases_reshaped) mt.set_wavelet_complex_array(wavelets_complex_reshaped) # mt.initialize_arrays(time_series_reshaped, wavelets_reshaped) mt.initialize_signal_props(float(self.time_series['samplerate'])) mt.initialize_wavelet_props(self.width, self.freqs) mt.prepare_run() s = time.time() mt.compute_wavelets_threads() powers_final = None phases_final = None wavelet_complex_final = None if self.output == 'power': powers_final = powers_reshaped.reshape( wavelet_dims + (self.time_series.shape[-1], )) if self.output == 'phase': phases_final = phases_reshaped.reshape( wavelet_dims + (self.time_series.shape[-1], )) if self.output == 'both': powers_final = powers_reshaped.reshape( wavelet_dims + (self.time_series.shape[-1], )) phases_final = phases_reshaped.reshape( wavelet_dims + (self.time_series.shape[-1], )) if self.output == 'complex': wavelet_complex_final = wavelets_complex_reshaped.reshape( wavelet_dims + (self.time_series.shape[-1], )) # wavelets_final = powers_reshaped.reshape( wavelet_dims+(self.time_series.shape[-1],) ) coords = {k: v for k, v in list(self.time_series.coords.items())} coords['frequency'] = self.freqs powers_ts = None phases_ts = None wavelet_complex_ts = None if powers_final is not None: powers_ts = TimeSeriesX(powers_final, dims=self.time_series.dims[:-1] + ( 'frequency', self.time_series.dims[-1], ), coords=coords) final_dims = (powers_ts.dims[-2], ) + powers_ts.dims[:-2] + ( powers_ts.dims[-1], ) powers_ts = powers_ts.transpose(*final_dims) if phases_final is not None: phases_ts = TimeSeriesX(phases_final, dims=self.time_series.dims[:-1] + ( 'frequency', self.time_series.dims[-1], ), coords=coords) final_dims = (phases_ts.dims[-2], ) + phases_ts.dims[:-2] + ( phases_ts.dims[-1], ) phases_ts = phases_ts.transpose(*final_dims) if wavelet_complex_final is not None: wavelet_complex_ts = TimeSeriesX(wavelet_complex_final, dims=self.time_series.dims[:-1] + ( 'frequency', self.time_series.dims[-1], ), coords=coords) final_dims = (wavelet_complex_ts.dims[-2], ) + wavelet_complex_ts.dims[:-2] + ( wavelet_complex_ts.dims[-1], ) wavelet_complex_ts = wavelet_complex_ts.transpose(*final_dims) if self.verbose: print('CPP total time wavelet loop: ', time.time() - s) if wavelet_complex_ts is not None: return wavelet_complex_ts, None else: return powers_ts, phases_ts
class ResampleFilter(PropertiedObject, BaseFilter): ''' Resample Filter ''' _descriptors = [ # TypeValTuple('time_series', np.ndarray, np.array([0.0])), TypeValTuple('time_series', TimeSeriesX, TimeSeriesX([0.0], dims=['time'])), # TypeValTuple('time_series', np.ndarray, np.array([0.0])), TypeValTuple('resamplerate', float, -1.0), TypeValTuple('time_axis_index', int, -1), TypeValTuple('round_to_original_timepoints', bool, False), ] # def __aaa(self): # self.resamplerate = None # self.time_axis_index = None # self.round_to_original_timepoints = None # # self.round_to_original_timepoints = None # # setattr(self,'round_to_original_timepoints',None) def ___syntax_helper(self): self.time_series = None self.resamplerate = None self.time_axis_index = None self.round_to_original_timepoints = None def __init__(self, **kwds): ''' :param kwds: allowed values are: ------------------------------------- :param resamplerate - new sampling frequency :param time_series - TimeSeriesX object :param time_axis_index - index of the time axis :param round_to_original_timepoints - boolean flag indicating if timepoints from original time axis should be reused after proper rounding. Default setting is False ------------------------------------- :return: ''' self.window = None # self.time_series = None self.init_attrs(kwds) def filter(self): ''' resamples time series :return:resampled time series with sampling frequency set to resamplerate ''' # samplerate = self.time_series.attrs['samplerate'] samplerate = float(self.time_series['samplerate']) time_axis_length = np.squeeze(self.time_series.coords['time'].shape) new_length = int( np.round(time_axis_length * self.resamplerate / samplerate)) print new_length if self.time_axis_index < 0: self.time_axis_index = self.time_series.get_axis_num('time') time_axis = self.time_series.coords[self.time_series.dims[ self.time_axis_index]] try: time_axis_data = time_axis.data[ 'time'] # time axis can be recarray with one of the arrays being time except (KeyError, IndexError) as excp: # if we get here then most likely time axis is ndarray of floats time_axis_data = time_axis.data time_idx_array = np.arange(len(time_axis)) if self.round_to_original_timepoints: filtered_array, new_time_idx_array = resample( self.time_series.data, new_length, t=time_idx_array, axis=self.time_axis_index, window=self.window) # print new_time_axis new_time_idx_array = np.rint(new_time_idx_array).astype(np.int) new_time_axis = time_axis[new_time_idx_array] else: filtered_array, new_time_axis = resample(self.time_series.data, new_length, t=time_axis_data, axis=self.time_axis_index, window=self.window) coords = [] for i, dim_name in enumerate(self.time_series.dims): if i != self.time_axis_index: coords.append(self.time_series.coords[dim_name].copy()) else: coords.append((dim_name, new_time_axis)) filtered_time_series = xray.DataArray(filtered_array, coords=coords) # filtered_time_series.attrs['samplerate'] = self.resamplerate filtered_time_series['samplerate'] = self.resamplerate return TimeSeriesX(filtered_time_series)