PyCollect is a software package for collecting data from the GE patient monitors, for the purpose of conducting research and preparing training materials.
%pylab inline
Populating the interactive namespace from numpy and matplotlib
git clone git clone [email protected]:gcpds/pycollect.git
cd pycollect
python setup.py install
pip install pycollect
There are two main modules, GEDevice
that handle the connection and data recollecting, and GEDecode
that parse and sort the received data strings.
from pycollect import GEDevice, GEDecode
device = GEDevice()
device.connect('/dev/ttyUSB0')
True
device.stop()
There are three subrecord types for the actual measurement data:
device.DISPL
for the displayed values.device.TREND_10S
for the 10 s trended values.device.TREND_60S
for the 60 s trended values.
import time
# device.request(subtype=device.DISPL)
# time.sleep(1)
device.request(subtype=device.TREND_10S)
# time.sleep(1)
# device.request(subtype=device.TREND_60S)
Depending on the total number of samples per second the monitor sends a waveform packet every 1000 ms, 500 ms or 250 ms.
Request up to 8 waveforms but total sample rate should be less than 600 samples/sec, sample rate for ECG is 300, INVP 100, EEG 100, PLETH 100, respiratory (CO2, O2, NO2...) 25 each.
device.request(interval=1, waveform_set=['PLETH', 'ECG1'])
#request more that 600 samples/sec generate an exception
try:
device.request(waveform_set=['ECG1', 'ECG2', 'ECG3'])
except Exception as error:
print(error)
Sample rate must be less than 600
from pycollect.modules import WAVEFORMS_DICT
for wave in WAVEFORMS_DICT:
print("{label}: {samps}".format(**WAVEFORMS_DICT[wave]))
ECG1: 300
ECG2: 300
ECG3: 300
INVP1: 100
INVP2: 100
INVP3: 100
INVP4: 1
INVP5: 100
INVP6: 100
PLETH: 100
CO2: 25
NO2: 25
AA: 25
AWP: 25
FLOW: 1
VOL: 25
RESP: 25
EEG1: 100
EEG2: 100
EEG3: 1
EEG4: 100
TONO_PRESS: 1
SPI_LOOP_STATUS: 1
ENT_100: 1
EEG_BIS: 1
The transmitted data is recollected asynchronously with a background thread and appended to the BUFFER
list.
device.collect(True)
Is possible to check the status of BUFFER
with:
print('Length: {} bytes'.format(len(device.BUFFER)))
print(device.BUFFER[:43])
# print(bytes(device.BUFFER))
# (device.READING)
import struct
# struct.unpack('>h', bytes([14, 10]))
[int(_) for _ in struct.pack('>h', 3660)]
Length: 3356 bytes
[126, 40, 0, 164, 10, 0, 0, 95, 178, 51, 91, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 126]
[14, 76]
Exception in thread Thread-9:
Traceback (most recent call last):
File "/usr/lib/python3.6/site-packages/serial/serialposix.py", line 501, in read
'device reports readiness to read but returned no data '
serial.serialutil.SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.6/threading.py", line 916, in _bootstrap_inner
self.run()
File "/usr/lib/python3.6/threading.py", line 864, in run
self._target(*self._args, **self._kwargs)
File "/home/yeison/Development/gcpds/pycollect/pycollect/device.py", line 258, in read
data = self.device.read(size)
File "/usr/lib/python3.6/site-packages/serial/serialposix.py", line 509, in read
raise SerialException('read failed: {}'.format(e))
serial.serialutil.SerialException: read failed: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
from datetime import datetime
file = open('{}.raw'.format(datetime.now()), 'wb')
file.write(bytes(device.BUFFER))
file.close()
for clear the buffer just:
device.clear_buffer()
for stop the reading:
device.collect(False)
decoder = GEDecode()
decoder.process(device.BUFFER)
print("Modules: ", decoder.MODULES)
print("Active modules: ", decoder.MODULES_ACTIVE)
Modules: ['INV-BP:p1', 'INV-BP:p2', 'TEMP:t1', 'ECG', 'NINV-BP', 'SpO2', 'NMT', 'ECG-EXTRA', 'ECG-ARRH', 'ECG-12', 'NMT2', 'ENTROPY']
Active modules: ['TEMP', 'ECG', 'NINV-BP', 'SpO2', 'NMT', 'ECG-EXTRA', 'ECG-ARRH', 'ECG-12', 'NMT2', 'ENTROPY']
The DATA_SUBRECORD
will contain the displayed values
decoder.DATA_SUBRECORD
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
date | TEMP | TEMP LBL | ECG HR | ECG ST1 | ECG ST2 | ECG ST3 | ECG IMP-RR | ECG: ASY | ECG HR SRC | ... | ECG-12 LEAD CH1 | ECG-12 LEAD CH2 | ECG-12 LEAD CH3 | NMT2 T1 | NMT2 T2 | NMT2 T3 | NMT2 T4 | ENTROPY EEG | ENTROPY EMG | ENTROPY BSR | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2018-06-27 15:43:00 | None | T4 | 71 | None | None | None | None | False | Not selected | ... | ECG I | ECG II | Not selected | None | None | None | None | None | None | None |
1 | 2018-06-27 15:44:00 | None | T4 | 74 | None | None | None | None | False | Not selected | ... | ECG I | ECG II | Not selected | None | None | None | None | None | None | None |
2 | 2018-06-27 15:45:00 | None | T4 | 69 | None | None | None | None | False | Not selected | ... | ECG I | ECG II | Not selected | None | None | None | None | None | None | None |
3 rows × 75 columns
decoder.DATA_SUBRECORD.columns;
decoder.DATA_SUBRECORD[['date', 'ECG HR', 'SpO2', 'TEMP', 'TEMP LBL']]
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
date | ECG HR | SpO2 | TEMP | TEMP LBL | |
---|---|---|---|---|---|
0 | 2018-06-27 15:43:00 | 71 | 94.54 | None | T4 |
DATA_WAVE_SUBRECORD
will contain the waveforms requested
decoder.DATA_WAVE_SUBRECORD.keys()
dict_keys([])
data = decoder.DATA_WAVE_SUBRECORD['PLETH']
pyplot.figure(None, figsize=(20, 7), dpi=100)
pyplot.plot(data)
pyplot.show()
Exception in thread Thread-23:
Traceback (most recent call last):
File "/usr/lib/python3.6/site-packages/serial/serialposix.py", line 501, in read
'device reports readiness to read but returned no data '
serial.serialutil.SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.6/threading.py", line 916, in _bootstrap_inner
self.run()
File "/usr/lib/python3.6/threading.py", line 864, in run
self._target(*self._args, **self._kwargs)
File "/home/yeison/Development/gcpds/pycollect/pycollect/device.py", line 258, in read
data = self.device.read(size)
File "/usr/lib/python3.6/site-packages/serial/serialposix.py", line 509, in read
raise SerialException('read failed: {}'.format(e))
serial.serialutil.SerialException: read failed: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
The data can be saved in two differents formats csv and edf, each type of data will be saved with their own sufix: .wave for waveforms, .trend10s and .trend60s for trends.
decoder.save_as_csv('data_out')
The edf format need extra patient information.
decoder.set_edf_header(
admincode = '',
birthdate = date(1900, 1, 1), #datetime object
equipment = '',
gender = 0, #0 for male, 1 for female
patientcode = '',
patientname = '',
patient_additional = '',
recording_additional = '',
technician = '',
)
decoder.save_as_edf('data_out')