MiloSobral commited on
Commit
f74a1ac
·
1 Parent(s): 62323ee

Fixed bug with timing of the stimulation for offline

Browse files
portiloop/notebooks/test_EDF.ipynb ADDED
@@ -0,0 +1,346 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 70,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "from pyedflib import highlevel\n",
10
+ "from portiloop.src.demo.utils import xdf2array\n",
11
+ "import numpy as np\n",
12
+ "\n",
13
+ "filename_edf = '/home/ubuntu/portiloop-software/BSP_L22_Portiloop_EDF.edf'\n",
14
+ "filename_xdf = '/home/ubuntu/portiloop-software/BSP_L22_Portiloop_XDF.xdf'"
15
+ ]
16
+ },
17
+ {
18
+ "cell_type": "code",
19
+ "execution_count": 98,
20
+ "metadata": {},
21
+ "outputs": [
22
+ {
23
+ "data": {
24
+ "text/plain": [
25
+ "(1147000,)"
26
+ ]
27
+ },
28
+ "execution_count": 98,
29
+ "metadata": {},
30
+ "output_type": "execute_result"
31
+ }
32
+ ],
33
+ "source": [
34
+ "edf_read = highlevel.read_edf(filename_edf)\n",
35
+ "signal_edf = edf_read[0][1, :]\n",
36
+ "signal_edf.shape"
37
+ ]
38
+ },
39
+ {
40
+ "cell_type": "code",
41
+ "execution_count": 99,
42
+ "metadata": {},
43
+ "outputs": [],
44
+ "source": [
45
+ "data_whole, columns = xdf2array(filename_xdf, 2)"
46
+ ]
47
+ },
48
+ {
49
+ "cell_type": "code",
50
+ "execution_count": 100,
51
+ "metadata": {},
52
+ "outputs": [
53
+ {
54
+ "data": {
55
+ "text/plain": [
56
+ "(1142166,)"
57
+ ]
58
+ },
59
+ "execution_count": 100,
60
+ "metadata": {},
61
+ "output_type": "execute_result"
62
+ }
63
+ ],
64
+ "source": [
65
+ "signal_xdf = data_whole[:, columns.index(\"online_filtered_signal_portiloop\")]\n",
66
+ "signal_xdf.shape"
67
+ ]
68
+ },
69
+ {
70
+ "cell_type": "code",
71
+ "execution_count": 101,
72
+ "metadata": {},
73
+ "outputs": [
74
+ {
75
+ "data": {
76
+ "text/plain": [
77
+ "4834"
78
+ ]
79
+ },
80
+ "execution_count": 101,
81
+ "metadata": {},
82
+ "output_type": "execute_result"
83
+ }
84
+ ],
85
+ "source": [
86
+ "len(signal_edf) - len(signal_xdf)"
87
+ ]
88
+ },
89
+ {
90
+ "cell_type": "code",
91
+ "execution_count": 102,
92
+ "metadata": {},
93
+ "outputs": [
94
+ {
95
+ "data": {
96
+ "text/plain": [
97
+ "0"
98
+ ]
99
+ },
100
+ "execution_count": 102,
101
+ "metadata": {},
102
+ "output_type": "execute_result"
103
+ }
104
+ ],
105
+ "source": [
106
+ "np.isin(signal_edf, signal_xdf).sum()"
107
+ ]
108
+ },
109
+ {
110
+ "cell_type": "code",
111
+ "execution_count": 103,
112
+ "metadata": {},
113
+ "outputs": [
114
+ {
115
+ "name": "stdout",
116
+ "output_type": "stream",
117
+ "text": [
118
+ "-0.020828564888990615 != -0.3275071084499359\n"
119
+ ]
120
+ }
121
+ ],
122
+ "source": [
123
+ "print(f\"{signal_edf[10000]} != {signal_xdf[10000]}\")"
124
+ ]
125
+ },
126
+ {
127
+ "cell_type": "code",
128
+ "execution_count": 104,
129
+ "metadata": {},
130
+ "outputs": [
131
+ {
132
+ "data": {
133
+ "text/plain": [
134
+ "(array([], dtype=int64),)"
135
+ ]
136
+ },
137
+ "execution_count": 104,
138
+ "metadata": {},
139
+ "output_type": "execute_result"
140
+ }
141
+ ],
142
+ "source": [
143
+ "np.where(signal_edf == signal_xdf[100000])"
144
+ ]
145
+ },
146
+ {
147
+ "cell_type": "code",
148
+ "execution_count": 105,
149
+ "metadata": {},
150
+ "outputs": [],
151
+ "source": [
152
+ "# signal_xdf = np.concatenate([signal_xdf, np.zeros(len(signal_edf) - len(signal_xdf))])"
153
+ ]
154
+ },
155
+ {
156
+ "cell_type": "code",
157
+ "execution_count": 106,
158
+ "metadata": {},
159
+ "outputs": [],
160
+ "source": [
161
+ "# signals = np.concatenate((np.expand_dims(signal_edf, 0), np.expand_dims(signal_xdf, 0)), axis = 0)"
162
+ ]
163
+ },
164
+ {
165
+ "cell_type": "code",
166
+ "execution_count": 107,
167
+ "metadata": {},
168
+ "outputs": [
169
+ {
170
+ "data": {
171
+ "text/plain": [
172
+ "(2, 1147000)"
173
+ ]
174
+ },
175
+ "execution_count": 107,
176
+ "metadata": {},
177
+ "output_type": "execute_result"
178
+ }
179
+ ],
180
+ "source": [
181
+ "# signals.shape"
182
+ ]
183
+ },
184
+ {
185
+ "cell_type": "code",
186
+ "execution_count": 108,
187
+ "metadata": {},
188
+ "outputs": [
189
+ {
190
+ "data": {
191
+ "text/plain": [
192
+ "True"
193
+ ]
194
+ },
195
+ "execution_count": 108,
196
+ "metadata": {},
197
+ "output_type": "execute_result"
198
+ }
199
+ ],
200
+ "source": [
201
+ "# # Create and edf file with both signals:\n",
202
+ "# channel_names = ['EDF_Data', \"XDF_Data\"]\n",
203
+ "# signal_headers = highlevel.make_signal_headers(channel_names, sample_frequency=250)\n",
204
+ "# headers = highlevel.make_header(patientname='L22', gender='Male')\n",
205
+ "\n",
206
+ "\n",
207
+ "# highlevel.write_edf('edf_file.edf', signals, signal_headers, headers)"
208
+ ]
209
+ },
210
+ {
211
+ "cell_type": "code",
212
+ "execution_count": 145,
213
+ "metadata": {},
214
+ "outputs": [],
215
+ "source": [
216
+ "from portiloop.src.demo.utils import OfflineSleepSpindleRealTimeStimulator\n",
217
+ "from portiloop.src.detection import SleepSpindleRealTimeDetector\n",
218
+ "from portiloop.src.processing import FilterPipeline\n",
219
+ "\n",
220
+ "\n",
221
+ "filter = FilterPipeline(nb_channels=1, sampling_rate=250)\n",
222
+ "detector = SleepSpindleRealTimeDetector(threshold=0.82, channel=1) # always 1 because we have only one channel\n",
223
+ "stimulator = OfflineSleepSpindleRealTimeStimulator()"
224
+ ]
225
+ },
226
+ {
227
+ "cell_type": "code",
228
+ "execution_count": 143,
229
+ "metadata": {},
230
+ "outputs": [
231
+ {
232
+ "name": "stdout",
233
+ "output_type": "stream",
234
+ "text": [
235
+ "Running online filtering and detection...\n"
236
+ ]
237
+ }
238
+ ],
239
+ "source": [
240
+ "print(\"Running online filtering and detection...\")\n",
241
+ "\n",
242
+ "points = []\n",
243
+ "online_activations = []\n",
244
+ "delayed_stims = []\n",
245
+ "\n",
246
+ "# Go through the data\n",
247
+ "for index, point in enumerate(signal_xdf):\n",
248
+ " # Filter the data\n",
249
+ " filtered_point = filter.filter(np.array([point]))\n",
250
+ "\n",
251
+ " filtered_point = filtered_point.tolist()\n",
252
+ " points.append(filtered_point[0])\n",
253
+ " # Detect the spindles\n",
254
+ " result = detector.detect([[point]])\n",
255
+ "\n",
256
+ " # if stimulation_phase != \"Fast\":\n",
257
+ " # delayed_stim = stimulation_delayer.step_timesteps(filtered_point[0])\n",
258
+ " # if delayed_stim:\n",
259
+ " # delayed_stims.append(1)\n",
260
+ " # else:\n",
261
+ " # delayed_stims.append(0)\n",
262
+ "\n",
263
+ " # Stimulate if necessary\n",
264
+ " stim = stimulator.stimulate(result)\n",
265
+ " if stim:\n",
266
+ " online_activations.append(1)\n",
267
+ " else:\n",
268
+ " online_activations.append(0)"
269
+ ]
270
+ },
271
+ {
272
+ "cell_type": "code",
273
+ "execution_count": 144,
274
+ "metadata": {},
275
+ "outputs": [
276
+ {
277
+ "data": {
278
+ "text/plain": [
279
+ "1147000"
280
+ ]
281
+ },
282
+ "execution_count": 144,
283
+ "metadata": {},
284
+ "output_type": "execute_result"
285
+ }
286
+ ],
287
+ "source": [
288
+ "len(online_activations)"
289
+ ]
290
+ },
291
+ {
292
+ "cell_type": "code",
293
+ "execution_count": 141,
294
+ "metadata": {},
295
+ "outputs": [
296
+ {
297
+ "data": {
298
+ "text/plain": [
299
+ "31"
300
+ ]
301
+ },
302
+ "execution_count": 141,
303
+ "metadata": {},
304
+ "output_type": "execute_result"
305
+ }
306
+ ],
307
+ "source": [
308
+ "sum(online_activations)"
309
+ ]
310
+ },
311
+ {
312
+ "cell_type": "code",
313
+ "execution_count": null,
314
+ "metadata": {},
315
+ "outputs": [],
316
+ "source": []
317
+ }
318
+ ],
319
+ "metadata": {
320
+ "kernelspec": {
321
+ "display_name": "venv",
322
+ "language": "python",
323
+ "name": "python3"
324
+ },
325
+ "language_info": {
326
+ "codemirror_mode": {
327
+ "name": "ipython",
328
+ "version": 3
329
+ },
330
+ "file_extension": ".py",
331
+ "mimetype": "text/x-python",
332
+ "name": "python",
333
+ "nbconvert_exporter": "python",
334
+ "pygments_lexer": "ipython3",
335
+ "version": "3.10.6"
336
+ },
337
+ "orig_nbformat": 4,
338
+ "vscode": {
339
+ "interpreter": {
340
+ "hash": "dd88f1663b1efd7dd128096061ae4c3f92be53565689be8013239d96443491e7"
341
+ }
342
+ }
343
+ },
344
+ "nbformat": 4,
345
+ "nbformat_minor": 2
346
+ }
portiloop/src/demo/utils.py CHANGED
@@ -43,18 +43,21 @@ class OfflineSleepSpindleRealTimeStimulator(Stimulator):
43
  def __init__(self):
44
  self.last_detected_ts = time.time()
45
  self.wait_t = 0.4 # 400 ms
 
46
  self.delayer = None
 
47
 
48
  def stimulate(self, detection_signal):
 
49
  stim = False
50
  for sig in detection_signal:
51
  # We detect a stimulation
52
  if sig:
53
  # Record time of stimulation
54
- ts = time.time()
55
 
56
  # Check if time since last stimulation is long enough
57
- if ts - self.last_detected_ts > self.wait_t:
58
  if self.delayer is not None:
59
  # If we have a delayer, notify it
60
  self.delayer.detected()
@@ -86,7 +89,6 @@ def xdf2array(xdf_path, channel):
86
 
87
  # Add all samples from raw and filtered signals
88
  csv_list = []
89
- diffs = []
90
  shortest_stream = min(int(filtered_stream['footer']['info']['sample_count'][0]),
91
  int(raw_stream['footer']['info']['sample_count'][0]))
92
  for i in range(shortest_stream):
@@ -99,7 +101,6 @@ def xdf2array(xdf_path, channel):
99
  datapoint = [filtered_stream['time_stamps'][i],
100
  float(filtered_stream['time_series'][i, channel-1]),
101
  raw_stream['time_series'][i, channel-1]]
102
- diffs.append(abs(filtered_stream['time_stamps'][i] - raw_stream['time_stamps'][i]))
103
  csv_list.append(datapoint)
104
 
105
  # Add markers
 
43
  def __init__(self):
44
  self.last_detected_ts = time.time()
45
  self.wait_t = 0.4 # 400 ms
46
+ self.wait_timesteps = int(self.wait_t * 250)
47
  self.delayer = None
48
+ self.index = 0
49
 
50
  def stimulate(self, detection_signal):
51
+ self.index += 1
52
  stim = False
53
  for sig in detection_signal:
54
  # We detect a stimulation
55
  if sig:
56
  # Record time of stimulation
57
+ ts = self.index
58
 
59
  # Check if time since last stimulation is long enough
60
+ if ts - self.last_detected_ts > self.wait_timesteps:
61
  if self.delayer is not None:
62
  # If we have a delayer, notify it
63
  self.delayer.detected()
 
89
 
90
  # Add all samples from raw and filtered signals
91
  csv_list = []
 
92
  shortest_stream = min(int(filtered_stream['footer']['info']['sample_count'][0]),
93
  int(raw_stream['footer']['info']['sample_count'][0]))
94
  for i in range(shortest_stream):
 
101
  datapoint = [filtered_stream['time_stamps'][i],
102
  float(filtered_stream['time_series'][i, channel-1]),
103
  raw_stream['time_series'][i, channel-1]]
 
104
  csv_list.append(datapoint)
105
 
106
  # Add markers