1
2
3
4
5
6
7
8
9 """Dataset handling data structured in channels."""
10
11 __docformat__ = 'restructuredtext'
12
13
14 import numpy as N
15
16 from mvpa.datasets.mapped import MappedDataset
17 from mvpa.mappers.mask import MaskMapper
18 from mvpa.base.dochelpers import enhancedDocString
19
20 import mvpa.support.copy as copy
21
22 from mvpa.base import externals
23
24 if externals.exists('scipy'):
25 from scipy import signal
26
27
29 """Dataset handling data structured into channels.
30
31 Channels are assumes to contain several timepoints, thus this Dataset
32 stores some additional properties (reference time `t0`, temporal
33 distance of two timepoints `dt` and `channelids` (names)).
34 """
35 - def __init__(self, samples=None, dsattr=None,
36 t0=None, dt=None, channelids=None, **kwargs):
37 """Initialize ChannelDataset.
38
39 :Parameters:
40 samples: ndarray
41 Three-dimensional array: (samples x channels x timepoints).
42 t0: float
43 Reference time of the first timepoint. Can be used to preserve
44 information about the onset of some stimulation. Preferably in
45 seconds.
46 dt: float
47 Temporal distance between two timepoints. Has to be given in
48 seconds. Otherwise `samplingrate` property will not return
49 `Hz`.
50 channelids: list
51 List of channel names.
52 """
53
54 if dsattr is None:
55 dsattr = {}
56
57
58 if not samples is None and len(samples.shape) != 3:
59 raise ValueError, \
60 "ChannelDataset takes 3D array as samples."
61
62
63
64 if (not dt is None) or not dsattr.has_key('ch_dt'):
65 dsattr['ch_dt'] = dt
66 if (not channelids is None) or not dsattr.has_key('ch_ids'):
67 dsattr['ch_ids'] = channelids
68 if (not t0 is None) or not dsattr.has_key('ch_t0'):
69 dsattr['ch_t0'] = t0
70
71
72 if not samples is None:
73 mapper = MaskMapper(N.ones(samples.shape[1:], dtype='bool'))
74 else:
75
76 mapper = dsattr.get('mapper', None)
77
78
79 MappedDataset.__init__(self,
80 samples=samples,
81 mapper=mapper,
82 dsattr=dsattr,
83 **(kwargs))
84
85
86 __doc__ = enhancedDocString('ChannelDataset', locals(), MappedDataset)
87
88
90 """Substract mean baseline signal from the each timepoint.
91
92 The baseline is determined by computing the mean over all timepoints
93 specified by `t`.
94
95 The samples of the dataset are modified in-place and nothing is
96 returned.
97
98 :Parameter:
99 t: int | float | None
100 If an integer, `t` denotes the number of timepoints in the from the
101 start of each sample to be used to compute the baseline signal.
102 If a floating point value, `t` is the duration of the baseline
103 window from the start of each sample in whatever unit
104 corresponding to the datasets `samplingrate`. Finally, if `None`
105 the `t0` property of the dataset is used to determine `t` as it
106 would have been specified as duration.
107 """
108
109 if t is None:
110 t = N.abs(self.t0)
111
112
113 if isinstance(t, float):
114 t = N.round(t * self.samplingrate)
115
116
117 data = self.O
118
119
120
121 baseline = N.mean(data[:, :, :t], axis=2)
122
123 data -= baseline[..., N.newaxis]
124
125
126 self.samples[:] = self.mapForward(data)
127
128
129 if externals.exists('scipy'):
130 - def resample(self, nt=None, sr=None, dt=None, window='ham',
131 inplace=True, **kwargs):
132 """Convenience method to resample data sample channel-wise.
133
134 Resampling target can be specified by number of timepoint
135 or temporal distance or sampling rate.
136
137 Please note that this method only operates on
138 `ChannelDataset` and always returns such.
139
140 :Parameters:
141 nt: int
142 Number of timepoints to resample to.
143 dt: float
144 Temporal distance of samples after resampling.
145 sr: float
146 Target sampling rate.
147 inplace : bool
148 If inplace=False, it would create and return a new dataset
149 with new samples
150 **kwargs:
151 All additional arguments are passed to resample() from
152 scipy.signal
153
154 :Return:
155 ChannelDataset
156 """
157 if nt is None and sr is None and dt is None:
158 raise ValueError, \
159 "Required argument missing. Either needs ntimepoints, sr or dt."
160
161
162 orig_data = self.O
163
164 if len(orig_data.shape) != 3:
165 raise ValueError, "resample() only works with data from ChannelDataset."
166
167 orig_nt = orig_data.shape[2]
168 orig_length = self.dt * orig_nt
169
170 if nt is None:
171
172 if not dt is None:
173 nt = orig_nt * float(self.dt) / dt
174 elif not sr is None:
175 nt = orig_nt * float(sr) / self.samplingrate
176 else:
177 raise RuntimeError, 'This should not happen!'
178 else:
179 raise RuntimeError, 'This should not happen!'
180
181
182 nt = N.round(nt)
183
184
185 data = signal.resample(orig_data, nt, axis=2, window=window, **kwargs)
186 new_dt = float(orig_length) / nt
187
188 dsattr = self._dsattr
189
190
191 if inplace:
192 dsattr['ch_dt'] = new_dt
193
194
195
196
197
198 mapper = MaskMapper(N.ones(data.shape[1:], dtype='bool'))
199
200 dsattr['mapper'] = mapper
201 self.samples = mapper.forward(data)
202 return self
203 else:
204
205
206
207 dsattr = copy.deepcopy(dsattr)
208 return ChannelDataset(data=self._data,
209 dsattr=dsattr,
210 samples=data,
211 t0=self.t0,
212 dt=new_dt,
213 channelids=self.channelids,
214 copy_data=True,
215 copy_dsattr=False)
216
217 channelids = property(fget=lambda self: self._dsattr['ch_ids'],
218 doc='List of channel IDs')
219 t0 = property(fget=lambda self: self._dsattr['ch_t0'],
220 doc='Temporal position of first sample in the ' \
221 'timeseries (in seconds) -- possibly relative ' \
222 'to stimulus onset.')
223 dt = property(fget=lambda self: self._dsattr['ch_dt'],
224 doc='Time difference between two samples ' \
225 '(in seconds).')
226 samplingrate = property(fget=lambda self: 1.0 / self._dsattr['ch_dt'],
227 doc='Yeah, sampling rate.')
228