braindecode 0.4.7__tar.gz → 0.4.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. {Braindecode-0.4.7 → Braindecode-0.4.8}/Braindecode.egg-info/PKG-INFO +1 -1
  2. {Braindecode-0.4.7 → Braindecode-0.4.8}/Braindecode.egg-info/SOURCES.txt +2 -0
  3. {Braindecode-0.4.7 → Braindecode-0.4.8}/PKG-INFO +1 -1
  4. Braindecode-0.4.8/braindecode/__init__.py +1 -0
  5. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/datasets/__init__.py +1 -1
  6. Braindecode-0.4.8/braindecode/datasets/bbci.py +595 -0
  7. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/datasets/bcic_iv_2a.py +20 -24
  8. Braindecode-0.4.8/braindecode/datasets/lazy_dataset.py +48 -0
  9. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/datasets/multiple.py +14 -9
  10. Braindecode-0.4.8/braindecode/datasets/sensor_positions.py +225 -0
  11. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/datautil/__init__.py +1 -1
  12. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/datautil/iterators.py +73 -55
  13. Braindecode-0.4.8/braindecode/datautil/lazy_iterators.py +148 -0
  14. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/datautil/signal_target.py +2 -1
  15. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/datautil/signalproc.py +28 -28
  16. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/datautil/splitters.py +16 -22
  17. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/datautil/trial_segment.py +214 -127
  18. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/datautil/util.py +0 -1
  19. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/experiments/experiment.py +150 -66
  20. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/experiments/loggers.py +3 -0
  21. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/experiments/monitors.py +67 -56
  22. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/experiments/stopcriteria.py +7 -2
  23. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/mne_ext/signalproc.py +31 -15
  24. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/models/base.py +167 -78
  25. Braindecode-0.4.8/braindecode/models/deep4.py +231 -0
  26. Braindecode-0.4.8/braindecode/models/eegnet.py +305 -0
  27. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/models/hybrid.py +43 -33
  28. Braindecode-0.4.8/braindecode/models/shallow_fbcsp.py +149 -0
  29. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/models/util.py +6 -5
  30. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/torch_ext/constraints.py +6 -4
  31. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/torch_ext/functions.py +1 -0
  32. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/torch_ext/init.py +3 -3
  33. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/torch_ext/losses.py +3 -4
  34. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/torch_ext/modules.py +29 -24
  35. Braindecode-0.4.8/braindecode/torch_ext/optimizers.py +81 -0
  36. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/torch_ext/schedulers.py +24 -22
  37. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/torch_ext/util.py +4 -4
  38. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/util.py +41 -32
  39. Braindecode-0.4.8/braindecode/version.py +1 -0
  40. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/visualization/input_windows.py +83 -41
  41. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/visualization/perturbation.py +96 -60
  42. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/visualization/plot.py +60 -29
  43. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/visualization/sinfit.py +25 -20
  44. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/Makefile +1 -1
  45. Braindecode-0.4.8/docs/notebooks/Cropped_Decoding.ipynb +1139 -0
  46. Braindecode-0.4.8/docs/notebooks/Trialwise_Decoding.ipynb +1100 -0
  47. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/notebooks/visualization/Perturbation.ipynb +1 -1
  48. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/source/braindecode.datasets.rst +8 -0
  49. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/source/braindecode.datautil.rst +8 -0
  50. Braindecode-0.4.7/braindecode/__init__.py +0 -1
  51. Braindecode-0.4.7/braindecode/datasets/bbci.py +0 -399
  52. Braindecode-0.4.7/braindecode/datasets/sensor_positions.py +0 -223
  53. Braindecode-0.4.7/braindecode/models/deep4.py +0 -194
  54. Braindecode-0.4.7/braindecode/models/eegnet.py +0 -236
  55. Braindecode-0.4.7/braindecode/models/shallow_fbcsp.py +0 -119
  56. Braindecode-0.4.7/braindecode/torch_ext/optimizers.py +0 -77
  57. Braindecode-0.4.7/braindecode/version.py +0 -1
  58. Braindecode-0.4.7/docs/notebooks/Cropped_Decoding.ipynb +0 -982
  59. Braindecode-0.4.7/docs/notebooks/Trialwise_Decoding.ipynb +0 -1034
  60. {Braindecode-0.4.7 → Braindecode-0.4.8}/Braindecode.egg-info/dependency_links.txt +0 -0
  61. {Braindecode-0.4.7 → Braindecode-0.4.8}/Braindecode.egg-info/not-zip-safe +0 -0
  62. {Braindecode-0.4.7 → Braindecode-0.4.8}/Braindecode.egg-info/requires.txt +0 -0
  63. {Braindecode-0.4.7 → Braindecode-0.4.8}/Braindecode.egg-info/top_level.txt +0 -0
  64. {Braindecode-0.4.7 → Braindecode-0.4.8}/LICENSE.txt +0 -0
  65. {Braindecode-0.4.7 → Braindecode-0.4.8}/MANIFEST.in +0 -0
  66. {Braindecode-0.4.7 → Braindecode-0.4.8}/README.rst +0 -0
  67. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/experiments/__init__.py +0 -0
  68. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/mne_ext/__init__.py +0 -0
  69. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/models/__init__.py +0 -0
  70. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/torch_ext/__init__.py +0 -0
  71. {Braindecode-0.4.7 → Braindecode-0.4.8}/braindecode/visualization/__init__.py +0 -0
  72. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/conf.py +0 -0
  73. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/index.rst +0 -0
  74. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/notebooks/BBCI_Data.ipynb +0 -0
  75. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/notebooks/BBCI_Data_Start_Stop.ipynb +0 -0
  76. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/notebooks/BBCI_Data_Trialwise.ipynb +0 -0
  77. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/notebooks/Cropped_Manual_Training_Loop.ipynb +0 -0
  78. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/notebooks/Cropped_Trialwise_Explanation_Figures.ipynb +0 -0
  79. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/notebooks/Trialwise_Manual_Training_Loop.ipynb +0 -0
  80. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/source/braindecode.experiments.rst +0 -0
  81. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/source/braindecode.mne_ext.rst +0 -0
  82. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/source/braindecode.models.rst +0 -0
  83. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/source/braindecode.rst +0 -0
  84. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/source/braindecode.torch_ext.rst +0 -0
  85. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/source/braindecode.visualization.rst +0 -0
  86. {Braindecode-0.4.7 → Braindecode-0.4.8}/docs/source/modules.rst +0 -0
  87. {Braindecode-0.4.7 → Braindecode-0.4.8}/setup.cfg +0 -0
  88. {Braindecode-0.4.7 → Braindecode-0.4.8}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: Braindecode
3
- Version: 0.4.7
3
+ Version: 0.4.8
4
4
  Summary: A deep learning toolbox to decode raw time-domain EEG.
5
5
  Home-page: https://github.com/robintibor/braindecode
6
6
  Author: Robin Tibor Schirrmeister
@@ -14,10 +14,12 @@ braindecode/version.py
14
14
  braindecode/datasets/__init__.py
15
15
  braindecode/datasets/bbci.py
16
16
  braindecode/datasets/bcic_iv_2a.py
17
+ braindecode/datasets/lazy_dataset.py
17
18
  braindecode/datasets/multiple.py
18
19
  braindecode/datasets/sensor_positions.py
19
20
  braindecode/datautil/__init__.py
20
21
  braindecode/datautil/iterators.py
22
+ braindecode/datautil/lazy_iterators.py
21
23
  braindecode/datautil/signal_target.py
22
24
  braindecode/datautil/signalproc.py
23
25
  braindecode/datautil/splitters.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: Braindecode
3
- Version: 0.4.7
3
+ Version: 0.4.8
4
4
  Summary: A deep learning toolbox to decode raw time-domain EEG.
5
5
  Home-page: https://github.com/robintibor/braindecode
6
6
  Author: Robin Tibor Schirrmeister
@@ -0,0 +1 @@
1
+ from braindecode.version import __version__
@@ -1,3 +1,3 @@
1
1
  """
2
2
  Loader code for some datasets.
3
- """
3
+ """
@@ -0,0 +1,595 @@
1
+ import logging
2
+ import re
3
+ from glob import glob
4
+ import os.path
5
+
6
+ import numpy as np
7
+ import h5py
8
+ import mne
9
+
10
+ log = logging.getLogger(__name__)
11
+
12
+
13
+ class BBCIDataset(object):
14
+ """
15
+ Loader class for files created by saving BBCI files in matlab (make
16
+ sure to save with '-v7.3' in matlab, see
17
+ https://de.mathworks.com/help/matlab/import_export/mat-file-versions.html#buk6i87
18
+ )
19
+
20
+ Parameters
21
+ ----------
22
+ filename: str
23
+ load_sensor_names: list of str, optional
24
+ Also speeds up loading if you only load some sensors.
25
+ None means load all sensors.
26
+ check_class_names: bool, optional
27
+ check if the class names are part of some known class names at
28
+ Translational NeuroTechnology Lab, AG Ball, Freiburg, Germany.
29
+ """
30
+
31
+ def __init__(self, filename, load_sensor_names=None, check_class_names=False):
32
+ self.__dict__.update(locals())
33
+ del self.self
34
+
35
+ def load(self):
36
+ cnt = self._load_continuous_signal()
37
+ cnt = self._add_markers(cnt)
38
+ return cnt
39
+
40
+ def _load_continuous_signal(self):
41
+ wanted_chan_inds, wanted_sensor_names = self._determine_sensors()
42
+ fs = self._determine_samplingrate()
43
+ with h5py.File(self.filename, "r") as h5file:
44
+ samples = int(h5file["nfo"]["T"][0, 0])
45
+ cnt_signal_shape = (samples, len(wanted_chan_inds))
46
+ continuous_signal = np.ones(cnt_signal_shape, dtype=np.float32) * np.nan
47
+ for chan_ind_arr, chan_ind_set in enumerate(wanted_chan_inds):
48
+ # + 1 because matlab/this hdf5-naming logic
49
+ # has 1-based indexing
50
+ # i.e ch1,ch2,....
51
+ chan_set_name = "ch" + str(chan_ind_set + 1)
52
+ # first 0 to unpack into vector, before it is 1xN matrix
53
+ chan_signal = h5file[chan_set_name][
54
+ :
55
+ ].squeeze() # already load into memory
56
+ continuous_signal[:, chan_ind_arr] = chan_signal
57
+ assert not np.any(np.isnan(continuous_signal)), "No NaNs expected in signal"
58
+
59
+ if self.load_sensor_names is None:
60
+ ch_types = ["EEG"] * len(wanted_chan_inds)
61
+ else:
62
+ # Assume we cant know channel type here automatically
63
+ ch_types = ["misc"] * len(wanted_chan_inds)
64
+ info = mne.create_info(
65
+ ch_names=wanted_sensor_names, sfreq=fs, ch_types=ch_types
66
+ )
67
+
68
+ cnt = mne.io.RawArray(continuous_signal.T, info)
69
+ return cnt
70
+
71
+ def _determine_sensors(self):
72
+ all_sensor_names = self.get_all_sensors(self.filename, pattern=None)
73
+ if self.load_sensor_names is None:
74
+
75
+ # if no sensor names given, take all EEG-chans
76
+ eeg_sensor_names = all_sensor_names
77
+ eeg_sensor_names = filter(
78
+ lambda s: not s.startswith("BIP"), eeg_sensor_names
79
+ )
80
+ eeg_sensor_names = filter(lambda s: not s.startswith("E"), eeg_sensor_names)
81
+ eeg_sensor_names = filter(
82
+ lambda s: not s.startswith("Microphone"), eeg_sensor_names
83
+ )
84
+ eeg_sensor_names = filter(
85
+ lambda s: not s.startswith("Breath"), eeg_sensor_names
86
+ )
87
+ eeg_sensor_names = filter(
88
+ lambda s: not s.startswith("GSR"), eeg_sensor_names
89
+ )
90
+ eeg_sensor_names = list(eeg_sensor_names)
91
+ assert (
92
+ len(eeg_sensor_names) == 128
93
+ or len(eeg_sensor_names) == 64
94
+ or len(eeg_sensor_names) == 32
95
+ or len(eeg_sensor_names) == 16
96
+ ), "Recheck this code if you have different sensors..."
97
+ self.load_sensor_names = eeg_sensor_names
98
+ chan_inds = self._determine_chan_inds(all_sensor_names, self.load_sensor_names)
99
+ return chan_inds, self.load_sensor_names
100
+
101
+ def _determine_samplingrate(self):
102
+ with h5py.File(self.filename, "r") as h5file:
103
+ fs = h5file["nfo"]["fs"][0, 0]
104
+ assert isinstance(fs, int) or fs.is_integer()
105
+ fs = int(fs)
106
+ return fs
107
+
108
+ @staticmethod
109
+ def _determine_chan_inds(all_sensor_names, sensor_names):
110
+ assert sensor_names is not None
111
+ chan_inds = [all_sensor_names.index(s) for s in sensor_names]
112
+ assert len(chan_inds) == len(sensor_names), "All" "sensors should be there."
113
+ assert len(set(chan_inds)) == len(chan_inds), "No" "duplicated sensors wanted."
114
+ return chan_inds
115
+
116
+ @staticmethod
117
+ def get_all_sensors(filename, pattern=None):
118
+ """
119
+ Get all sensors that exist in the given file.
120
+
121
+ Parameters
122
+ ----------
123
+ filename: str
124
+ pattern: str, optional
125
+ Only return those sensor names that match the given pattern.
126
+
127
+ Returns
128
+ -------
129
+ sensor_names: list of str
130
+ Sensor names that match the pattern or all sensor names in the file.
131
+ """
132
+ with h5py.File(filename, "r") as h5file:
133
+ clab_set = h5file["nfo"]["clab"][:].squeeze()
134
+ all_sensor_names = [
135
+ "".join(chr(c) for c in h5file[obj_ref]) for obj_ref in clab_set
136
+ ]
137
+ if pattern is not None:
138
+ all_sensor_names = filter(
139
+ lambda sname: re.search(pattern, sname), all_sensor_names
140
+ )
141
+ return all_sensor_names
142
+
143
+ def _add_markers(self, cnt):
144
+ with h5py.File(self.filename, "r") as h5file:
145
+ event_times_in_ms = h5file["mrk"]["time"][:].squeeze()
146
+ event_classes = h5file["mrk"]["event"]["desc"][:].squeeze().astype(np.int64)
147
+
148
+ # Check whether class names known and correct order
149
+ class_name_set = h5file["nfo"]["className"][:].squeeze()
150
+ all_class_names = [
151
+ "".join(chr(c) for c in h5file[obj_ref]) for obj_ref in class_name_set
152
+ ]
153
+
154
+ if self.check_class_names:
155
+ _check_class_names(all_class_names, event_times_in_ms, event_classes)
156
+
157
+ event_times_in_samples = event_times_in_ms * cnt.info["sfreq"] / 1000.0
158
+ event_times_in_samples = np.uint32(np.round(event_times_in_samples))
159
+
160
+ # Check if there are markers at the same time
161
+ previous_i_sample = -1
162
+ for i_event, (i_sample, id_class) in enumerate(
163
+ zip(event_times_in_samples, event_classes)
164
+ ):
165
+ if i_sample == previous_i_sample:
166
+ log.warning(
167
+ "Same sample has at least two markers.\n"
168
+ "{:d}: ({:.0f} and {:.0f}).\n".format(
169
+ i_sample, event_classes[i_event - 1], event_classes[i_event]
170
+ )
171
+ + "Marker codes will be summed."
172
+ )
173
+ previous_i_sample = i_sample
174
+
175
+ # Now create stim chan
176
+ stim_chan = np.zeros_like(cnt.get_data()[0])
177
+ for i_sample, id_class in zip(event_times_in_samples, event_classes):
178
+ stim_chan[i_sample] += id_class
179
+ info = mne.create_info(
180
+ ch_names=["STI 014"], sfreq=cnt.info["sfreq"], ch_types=["stim"]
181
+ )
182
+ stim_cnt = mne.io.RawArray(stim_chan[None], info, verbose="WARNING")
183
+ cnt = cnt.add_channels([stim_cnt])
184
+ event_arr = [
185
+ event_times_in_samples,
186
+ [0] * len(event_times_in_samples),
187
+ event_classes,
188
+ ]
189
+ cnt.info["events"] = np.array(event_arr).T
190
+ return cnt
191
+
192
+
193
+ def _check_class_names(all_class_names, event_times_in_ms, event_classes):
194
+ """
195
+ Checks if the class names are part of some known class names used in
196
+ translational neurotechnology lab, AG Ball, Freiburg.
197
+
198
+ Logs warning in case class names are not known.
199
+
200
+ Parameters
201
+ ----------
202
+ all_class_names: list of str
203
+ event_times_in_ms: list of number
204
+ event_classes: list of number
205
+
206
+ """
207
+ if all_class_names == ["Right Hand", "Left Hand", "Rest", "Feet"]:
208
+ pass
209
+ elif (
210
+ (
211
+ all_class_names
212
+ == [
213
+ "1",
214
+ "10",
215
+ "11",
216
+ "111",
217
+ "12",
218
+ "13",
219
+ "150",
220
+ "2",
221
+ "20",
222
+ "22",
223
+ "3",
224
+ "30",
225
+ "33",
226
+ "4",
227
+ "40",
228
+ "44",
229
+ "99",
230
+ ]
231
+ )
232
+ or (
233
+ all_class_names
234
+ == [
235
+ "1",
236
+ "10",
237
+ "11",
238
+ "12",
239
+ "13",
240
+ "150",
241
+ "2",
242
+ "20",
243
+ "22",
244
+ "3",
245
+ "30",
246
+ "33",
247
+ "4",
248
+ "40",
249
+ "44",
250
+ "99",
251
+ ]
252
+ )
253
+ or (all_class_names == ["1", "2", "3", "4"])
254
+ ):
255
+ pass # Semantic classes
256
+ elif all_class_names == ["Rest", "Feet", "Left Hand", "Right Hand"]:
257
+ # Have to swap from
258
+ # ['Rest', 'Feet', 'Left Hand', 'Right Hand']
259
+ # to
260
+ # ['Right Hand', 'Left Hand', 'Rest', 'Feet']
261
+ right_mask = event_classes == 4
262
+ left_mask = event_classes == 3
263
+ rest_mask = event_classes == 1
264
+ feet_mask = event_classes == 2
265
+ event_classes[right_mask] = 1
266
+ event_classes[left_mask] = 2
267
+ event_classes[rest_mask] = 3
268
+ event_classes[feet_mask] = 4
269
+ log.warn(
270
+ "Swapped class names {:s}... might cause problems...".format(
271
+ all_class_names
272
+ )
273
+ )
274
+ elif all_class_names == [
275
+ "Right Hand Start",
276
+ "Left Hand Start",
277
+ "Rest Start",
278
+ "Feet Start",
279
+ "Right Hand End",
280
+ "Left Hand End",
281
+ "Rest End",
282
+ "Feet End",
283
+ ]:
284
+ pass
285
+ elif all_class_names == [
286
+ "Right Hand",
287
+ "Left Hand",
288
+ "Rest",
289
+ "Feet",
290
+ "Face",
291
+ "Navigation",
292
+ "Music",
293
+ "Rotation",
294
+ "Subtraction",
295
+ "Words",
296
+ ]:
297
+ pass # robot hall 10 class decoding
298
+ elif all_class_names == [
299
+ "RightHand",
300
+ "Feet",
301
+ "Rotation",
302
+ "Words",
303
+ "\x00\x00",
304
+ "\x00\x00",
305
+ "\x00\x00",
306
+ "\x00\x00",
307
+ "\x00\x00",
308
+ "RightHand_End",
309
+ "\x00\x00",
310
+ "\x00\x00",
311
+ "\x00\x00",
312
+ "\x00\x00",
313
+ "\x00\x00",
314
+ "\x00\x00",
315
+ "\x00\x00",
316
+ "\x00\x00",
317
+ "\x00\x00",
318
+ "Feet_End",
319
+ "\x00\x00",
320
+ "\x00\x00",
321
+ "\x00\x00",
322
+ "\x00\x00",
323
+ "\x00\x00",
324
+ "\x00\x00",
325
+ "\x00\x00",
326
+ "\x00\x00",
327
+ "\x00\x00",
328
+ "Rotation_End",
329
+ "\x00\x00",
330
+ "\x00\x00",
331
+ "\x00\x00",
332
+ "\x00\x00",
333
+ "\x00\x00",
334
+ "\x00\x00",
335
+ "\x00\x00",
336
+ "\x00\x00",
337
+ "\x00\x00",
338
+ "Words_End",
339
+ ] or all_class_names == [
340
+ "RightHand",
341
+ "Feet",
342
+ "Rotation",
343
+ "Words",
344
+ "Rest",
345
+ "\x00\x00",
346
+ "\x00\x00",
347
+ "\x00\x00",
348
+ "\x00\x00",
349
+ "RightHand_End",
350
+ "\x00\x00",
351
+ "\x00\x00",
352
+ "\x00\x00",
353
+ "\x00\x00",
354
+ "\x00\x00",
355
+ "\x00\x00",
356
+ "\x00\x00",
357
+ "\x00\x00",
358
+ "\x00\x00",
359
+ "Feet_End",
360
+ "\x00\x00",
361
+ "\x00\x00",
362
+ "\x00\x00",
363
+ "\x00\x00",
364
+ "\x00\x00",
365
+ "\x00\x00",
366
+ "\x00\x00",
367
+ "\x00\x00",
368
+ "\x00\x00",
369
+ "Rotation_End",
370
+ "\x00\x00",
371
+ "\x00\x00",
372
+ "\x00\x00",
373
+ "\x00\x00",
374
+ "\x00\x00",
375
+ "\x00\x00",
376
+ "\x00\x00",
377
+ "\x00\x00",
378
+ "\x00\x00",
379
+ "Words_End",
380
+ "\x00\x00",
381
+ "\x00\x00",
382
+ "\x00\x00",
383
+ "\x00\x00",
384
+ "\x00\x00",
385
+ "\x00\x00",
386
+ "\x00\x00",
387
+ "\x00\x00",
388
+ "\x00\x00",
389
+ "Rest_End",
390
+ ]:
391
+ pass # weird stuff when we recorded cursor in robot hall
392
+ # on 2016-09-14 and 2016-09-16 :D
393
+
394
+ elif all_class_names == [
395
+ "0004",
396
+ "0016",
397
+ "0032",
398
+ "0056",
399
+ "0064",
400
+ "0088",
401
+ "0095",
402
+ "0120",
403
+ ]:
404
+ pass
405
+ elif all_class_names == ["0004", "0056", "0088", "0120"]:
406
+ pass
407
+ elif all_class_names == [
408
+ "0004",
409
+ "0016",
410
+ "0032",
411
+ "0048",
412
+ "0056",
413
+ "0064",
414
+ "0080",
415
+ "0088",
416
+ "0095",
417
+ "0120",
418
+ ]:
419
+ pass
420
+ elif all_class_names == ["0004", "0016", "0056", "0088", "0120", "__"]:
421
+ pass
422
+ elif all_class_names == ["0004", "0056", "0088", "0120", "__"]:
423
+ pass
424
+ elif all_class_names == [
425
+ "0004",
426
+ "0032",
427
+ "0048",
428
+ "0056",
429
+ "0064",
430
+ "0080",
431
+ "0088",
432
+ "0095",
433
+ "0120",
434
+ "__",
435
+ ]:
436
+ pass
437
+ elif all_class_names == ["0004", "0056", "0080", "0088", "0096", "0120", "__"]:
438
+ pass
439
+ elif all_class_names == [
440
+ "0004",
441
+ "0032",
442
+ "0056",
443
+ "0064",
444
+ "0080",
445
+ "0088",
446
+ "0095",
447
+ "0120",
448
+ ]:
449
+ pass
450
+ elif all_class_names == [
451
+ "0004",
452
+ "0032",
453
+ "0048",
454
+ "0056",
455
+ "0064",
456
+ "0080",
457
+ "0088",
458
+ "0095",
459
+ "0120",
460
+ ]:
461
+ pass
462
+ elif all_class_names == [
463
+ "0004",
464
+ "0016",
465
+ "0032",
466
+ "0048",
467
+ "0056",
468
+ "0064",
469
+ "0080",
470
+ "0088",
471
+ "0095",
472
+ "0096",
473
+ "0120",
474
+ ]:
475
+ pass
476
+ elif all_class_names == ["4", "16", "32", "56", "64", "88", "95", "120"]:
477
+ pass
478
+ elif all_class_names == ["4", "56", "88", "120"]:
479
+ pass
480
+ elif all_class_names == [
481
+ "4",
482
+ "16",
483
+ "32",
484
+ "48",
485
+ "56",
486
+ "64",
487
+ "80",
488
+ "88",
489
+ "95",
490
+ "120",
491
+ ]:
492
+ pass
493
+ elif all_class_names == ["0", "4", "56", "88", "120"]:
494
+ pass
495
+ elif all_class_names == ["0", "4", "16", "56", "88", "120"]:
496
+ pass
497
+ elif all_class_names == ["0", "4", "32", "48", "56", "64", "80", "88", "95", "120"]:
498
+ pass
499
+ elif all_class_names == ["0", "4", "56", "80", "88", "96", "120"]:
500
+ pass
501
+ elif all_class_names == ["4", "32", "56", "64", "80", "88", "95", "120"]:
502
+ pass
503
+ elif all_class_names == ["One", "Two", "Three", "Four"]:
504
+ pass
505
+ elif all_class_names == ["1", "10", "11", "12", "2", "20", "3", "30", "4", "40"]:
506
+ pass
507
+ elif all_class_names == ["1", "10", "12", "13", "2", "20", "3", "30", "4", "40"]:
508
+ pass
509
+ elif all_class_names == ["1", "10", "13", "2", "20", "3", "30", "4", "40", "99"]:
510
+ pass
511
+ elif all_class_names == [
512
+ "1",
513
+ "10",
514
+ "11",
515
+ "14",
516
+ "18",
517
+ "20",
518
+ "21",
519
+ "24",
520
+ "251",
521
+ "252",
522
+ "28",
523
+ "30",
524
+ "4",
525
+ "8",
526
+ ]:
527
+ pass
528
+ elif all_class_names == [
529
+ "1",
530
+ "10",
531
+ "11",
532
+ "14",
533
+ "18",
534
+ "20",
535
+ "21",
536
+ "24",
537
+ "252",
538
+ "253",
539
+ "28",
540
+ "30",
541
+ "4",
542
+ "8",
543
+ ]:
544
+ pass
545
+ elif len(event_times_in_ms) == len(all_class_names):
546
+ pass # weird neuroone(?) logic where class names have event classes
547
+ elif all_class_names == [
548
+ "Right_hand_stimulus_onset",
549
+ "Feet_stimulus_onset",
550
+ "Rotation_stimulus_onset",
551
+ "Words_stimulus_onset",
552
+ "Right_hand_stimulus_offset",
553
+ "Feet_stimulus_offset",
554
+ "Rotation_stimulus_offset",
555
+ "Words_stimulus_offset",
556
+ ]:
557
+ pass
558
+ else:
559
+ # remove this whole if else stuffs?
560
+ log.warn("Unknown class names {:s}".format(all_class_names))
561
+
562
+
563
+ def load_bbci_sets_from_folder(folder, runs="all"):
564
+ """
565
+ Load bbci datasets from files in given folder.
566
+
567
+ Parameters
568
+ ----------
569
+ folder: str
570
+ Folder with .BBCI.mat files inside
571
+ runs: list of int
572
+ If you only want to load specific runs.
573
+ Assumes filenames with such kind of part: S001R02 for Run 2.
574
+ Tries to match this regex: ``'S[0-9]{3,3}R[0-9]{2,2}_'``.
575
+
576
+ Returns
577
+ -------
578
+
579
+ """
580
+ bbci_mat_files = sorted(glob(os.path.join(folder, "*.BBCI.mat")))
581
+ if runs != "all":
582
+ file_run_numbers = [
583
+ int(re.search("S[0-9]{3,3}R[0-9]{2,2}_", f).group()[5:7])
584
+ for f in bbci_mat_files
585
+ ]
586
+ indices = [file_run_numbers.index(num) for num in runs]
587
+
588
+ wanted_files = np.array(bbci_mat_files)[indices]
589
+ else:
590
+ wanted_files = bbci_mat_files
591
+ cnts = []
592
+ for f in wanted_files:
593
+ log.info("Loading {:s}".format(f))
594
+ cnts.append(BBCIDataset(f).load())
595
+ return cnts