MiloSobral commited on
Commit
476bded
·
1 Parent(s): a5c0535

Fixed issue with EDF recording

Browse files
Files changed (3) hide show
  1. portiloop/src/capture.py +1 -1
  2. portiloop/src/utils.py +92 -36
  3. setup.py +1 -0
portiloop/src/capture.py CHANGED
@@ -143,7 +143,7 @@ class Capture:
143
  self.record = False
144
  self.detect = False
145
  self.stimulate = False
146
- self.threshold = 0.5
147
  self.lsl = False
148
  self.display = False
149
  self.signal_input = "ADS"
 
143
  self.record = False
144
  self.detect = False
145
  self.stimulate = False
146
+ self.threshold = 0.82
147
  self.lsl = False
148
  self.display = False
149
  self.signal_input = "ADS"
portiloop/src/utils.py CHANGED
@@ -1,9 +1,12 @@
1
  from EDFlib.edfwriter import EDFwriter
 
2
  from portilooplot.jupyter_plot import ProgressPlot
3
  from pathlib import Path
4
  import numpy as np
5
  import csv
6
  import time
 
 
7
 
8
 
9
  EDF_PATH = Path.home() / 'workspace' / 'edf_recording'
@@ -22,52 +25,105 @@ class DummyAlsaMixer:
22
  self.volume = volume
23
 
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  class EDFRecorder:
26
  def __init__(self, signal_labels, filename, frequency):
 
 
27
  self.filename = filename
28
- self.nb_signals = len(signal_labels)
29
- self.samples_per_datarecord_array = frequency
30
- self.physical_max = 5
31
- self.physical_min = -5
32
  self.signal_labels = signal_labels
33
- self.edf_buffer = []
34
 
35
  def open_recording_file(self):
36
- nb_signals = self.nb_signals
37
- samples_per_datarecord_array = self.samples_per_datarecord_array
38
- physical_max = self.physical_max
39
- physical_min = self.physical_min
40
- signal_labels = self.signal_labels
41
-
42
- print(f"Will store edf recording in {self.filename}")
43
-
44
- self.edf_writer = EDFwriter(p_path=str(self.filename),
45
- f_file_type=EDFwriter.EDFLIB_FILETYPE_EDFPLUS,
46
- number_of_signals=nb_signals)
47
-
48
- for signal in range(nb_signals):
49
- assert self.edf_writer.setSampleFrequency(signal, samples_per_datarecord_array) == 0
50
- assert self.edf_writer.setPhysicalMaximum(signal, physical_max) == 0
51
- assert self.edf_writer.setPhysicalMinimum(signal, physical_min) == 0
52
- assert self.edf_writer.setDigitalMaximum(signal, 32767) == 0
53
- assert self.edf_writer.setDigitalMinimum(signal, -32768) == 0
54
- assert self.edf_writer.setSignalLabel(signal, signal_labels[signal]) == 0
55
- assert self.edf_writer.setPhysicalDimension(signal, 'V') == 0
56
 
57
  def close_recording_file(self):
58
- assert self.edf_writer.close() == 0
59
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  def add_recording_data(self, data):
61
- self.edf_buffer += data
62
- if len(self.edf_buffer) >= self.samples_per_datarecord_array:
63
- datarecord_array = self.edf_buffer[:self.samples_per_datarecord_array]
64
- self.edf_buffer = self.edf_buffer[self.samples_per_datarecord_array:]
65
- datarecord_array = np.array(datarecord_array).transpose()
66
- assert len(datarecord_array) == self.nb_signals, f"len(data)={len(data)}!={self.nb_signals}"
67
- for d in datarecord_array:
68
- assert len(d) == self.samples_per_datarecord_array, f"{len(d)}!={self.samples_per_datarecord_array}"
69
- assert self.edf_writer.writeSamples(d) == 0
70
 
 
71
 
72
  class LiveDisplay():
73
  def __init__(self, channel_names, window_len=100):
 
1
  from EDFlib.edfwriter import EDFwriter
2
+ from pyedflib import highlevel
3
  from portilooplot.jupyter_plot import ProgressPlot
4
  from pathlib import Path
5
  import numpy as np
6
  import csv
7
  import time
8
+ import os
9
+ import warnings
10
 
11
 
12
  EDF_PATH = Path.home() / 'workspace' / 'edf_recording'
 
25
  self.volume = volume
26
 
27
 
28
+ # class EDFRecorder:
29
+ # def __init__(self, signal_labels, filename, frequency):
30
+ # self.filename = filename
31
+ # self.nb_signals = len(signal_labels)
32
+ # self.samples_per_datarecord_array = frequency
33
+ # self.physical_max = 5000000
34
+ # self.physical_min = -5000000
35
+ # self.signal_labels = signal_labels
36
+ # self.edf_buffer = []
37
+
38
+ # def open_recording_file(self):
39
+ # nb_signals = self.nb_signals
40
+ # samples_per_datarecord_array = self.samples_per_datarecord_array
41
+ # physical_max = self.physical_max
42
+ # physical_min = self.physical_min
43
+ # signal_labels = self.signal_labels
44
+
45
+ # print(f"Will store edf recording in {self.filename}")
46
+
47
+ # self.edf_writer = EDFwriter(p_path=str(self.filename),
48
+ # f_file_type=EDFwriter.EDFLIB_FILETYPE_EDFPLUS,
49
+ # number_of_signals=nb_signals)
50
+
51
+ # for signal in range(nb_signals):
52
+ # assert self.edf_writer.setSampleFrequency(signal, samples_per_datarecord_array) == 0
53
+ # assert self.edf_writer.setPhysicalMaximum(signal, physical_max) == 0
54
+ # assert self.edf_writer.setPhysicalMinimum(signal, physical_min) == 0
55
+ # assert self.edf_writer.setDigitalMaximum(signal, 32767) == 0
56
+ # assert self.edf_writer.setDigitalMinimum(signal, -32768) == 0
57
+ # assert self.edf_writer.setSignalLabel(signal, signal_labels[signal]) == 0
58
+ # assert self.edf_writer.setPhysicalDimension(signal, 'uV') == 0
59
+
60
+ # def close_recording_file(self):
61
+ # assert self.edf_writer.close() == 0
62
+
63
+ # def add_recording_data(self, data):
64
+ # self.edf_buffer += data
65
+ # if len(self.edf_buffer) >= self.samples_per_datarecord_array:
66
+ # datarecord_array = self.edf_buffer[:self.samples_per_datarecord_array]
67
+ # self.edf_buffer = self.edf_buffer[self.samples_per_datarecord_array:]
68
+ # datarecord_array = np.array(datarecord_array).transpose()
69
+ # assert len(datarecord_array) == self.nb_signals, f"len(data)={len(data)}!={self.nb_signals}"
70
+ # for d in datarecord_array:
71
+ # assert len(d) == self.samples_per_datarecord_array, f"{len(d)}!={self.samples_per_datarecord_array}"
72
+ # assert self.edf_writer.writeSamples(d) == 0
73
+
74
  class EDFRecorder:
75
  def __init__(self, signal_labels, filename, frequency):
76
+ self.writing_buffer = []
77
+ self.max_write = 1000
78
  self.filename = filename
79
+ self.csv_filename = str(filename).split('.')[0] + '.csv'
 
 
 
80
  self.signal_labels = signal_labels
81
+ self.frequency = frequency
82
 
83
  def open_recording_file(self):
84
+ self.file = open(self.csv_filename, 'w')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
  def close_recording_file(self):
87
+ self.file.close()
88
+ data = np.genfromtxt(self.csv_filename, delimiter=',')
89
+ # Convert to float values
90
+ data = data.astype(np.float32)
91
+ data = data.transpose()
92
+ assert data.shape[0] == len(self.signal_labels), f"{data.shape[0]}!={len(self.signal_labels)}"
93
+ signal_headers = []
94
+ for row_i in range(data.shape[0]):
95
+ # If we only have zeros in that row, the channel was not activated so we must set the physical max and min manually
96
+ if np.all(data[row_i] == 0):
97
+ phys_max = 200
98
+ phys_min = -200
99
+ else:
100
+ phys_max = np.amax(data[row_i])
101
+ phys_min = np.amin(data[row_i])
102
+
103
+ # Create the signal header
104
+ signal_headers.append(highlevel.make_signal_header(
105
+ self.signal_labels[row_i],
106
+ sample_frequency=self.frequency,
107
+ physical_max=phys_max,
108
+ physical_min=phys_min,))
109
+ self.filename = str(self.filename)
110
+ print(f"Saving to {self.filename}")
111
+
112
+ with warnings.catch_warnings():
113
+ warnings.simplefilter("ignore")
114
+ highlevel.write_edf(str(self.filename), data, signal_headers)
115
+
116
+ os.remove(self.csv_filename)
117
+
118
  def add_recording_data(self, data):
119
+ self.writing_buffer += data
120
+ # write to file
121
+ if len(self.writing_buffer) >= self.max_write:
122
+ for point in self.writing_buffer:
123
+ self.file.write(','.join([str(elt) for elt in point]) + '\n')
124
+ self.writing_buffer = []
 
 
 
125
 
126
+
127
 
128
  class LiveDisplay():
129
  def __init__(self, channel_names, window_len=100):
setup.py CHANGED
@@ -11,6 +11,7 @@ def is_coral():
11
 
12
  requirements_list = ['wheel',
13
  'EDFlib-Python',
 
14
  'numpy',
15
  'portilooplot',
16
  'ipywidgets',
 
11
 
12
  requirements_list = ['wheel',
13
  'EDFlib-Python',
14
+ 'pyEDFLib',
15
  'numpy',
16
  'portilooplot',
17
  'ipywidgets',