def __init__(self, app_config): self.config = app_config self.hypnodensity = list() self.flatline = [] self.features = HypnodensityFeatures(app_config) self.edf: pyedflib.EdfFileReader = [] ''' encoded_data is a 1640 x N array (np.array) Rows represent stacked cross correlation values. The order is: Central, Occipital, EOG-L, EOG-R, EOG-L/R, and then chin The size of the cross correlation value is specied by app_config.cc_ssize, with a default of 2s (central), 2s (occipital), 4s, 4s, 4s (eog's), and 0.4s (chin). Each column, represents a 0.250 s lapse or shift in time from the start of the psg (i.e. t0 = 0.0s) Because the psg channels are resampled to 100 Hz, the PSG channels can be sliced as follows: Central - 0:199 Occipital - 200:399 EOG-L - 400:799 EOG-R - 800:1199 EOG-L/R - 1200:1599 Chin - 1600:1639 N can be determined as follows: N = (D-(max(cc_size)-delta_lapse))/delta_lapse where D is the maximum duration of the PSG in seconds which can be divided by 30 without giving a remainder, max(cc_size) is 4 s, and delta_lapse is 0.25s. N = (D-3.75)*4 Thus if a PSG is 30980s, then D = 30960 and N = 123825 ''' self.encoded_data = [] self._encoded_data_channel_slices = { 'central': range(0, 200), 'occipital': range(200, 400), 'eog-l': range(400, 800), 'eog-r': range(800, 1200), 'eog-lr': range(1200, 1600), 'chin': range(1600, 1640) } self._encoded_data_channel_offsets = { 'central': 0, 'occipital': 200, 'eog-l': 400, 'eog-r': 800, 'eog-lr': 1200, 'chin': 1600 } self.fs = int(app_config.fs) # Filter specifications for resampling from MATLAB try: filter_specs_path = resource_filename('_resources', 'filter_specs.json') with open(filter_specs_path, "r") as json_file: self.filter_specs = json.load(json_file) except FileNotFoundError: self.filter_specs = {} myprint( 'Unable to load filter specifications file. Default resampling filter coefficients will be used' ' instead.')
def resampling(self, c, fs): # ratio = np.float(self.fs)/np.round(np.float(fs)); myprint("original samplerate = ", fs); myprint("resampling to ", self.fs) numerator = [-0.0175636017706537, -0.0208207236911009, -0.0186368912579407, 0, 0.0376532652007562, 0.0894912177899215, 0.143586518157187, 0.184663795586300, 0.200000000000000, 0.184663795586300, 0.143586518157187, 0.0894912177899215, 0.0376532652007562, 0, -0.0186368912579407, -0.0208207236911009, -0.0175636017706537] # taken from matlab s = signal.dlti(numerator, [1], dt=1./self.fs) self.loaded_channels[c] = signal.decimate(self.loaded_channels[c], int(int(fs)/self.fs), ftype=s, zero_phase=False)
def filtering(self): myprint('Filtering remaining signals') fs = self.fs Fh = signal.butter(5, self.fsH / (fs / 2), btype='highpass', output='ba') Fl = signal.butter(5, self.fsL / (fs / 2), btype='lowpass', output='ba') for ch in self.loaded_channels: myprint('Filtering {}'.format(ch)) self.loaded_channels[ch] = signal.filtfilt(Fh[0], Fh[1], self.loaded_channels[ch]) if fs > (2 * self.fsL): self.loaded_channels[ch] = signal.filtfilt(Fl[0], Fl[1], self.loaded_channels[ch]).astype( dtype=np.float32)
def filtering(self): myprint('Filtering remaining signals') fs = self.fs Fh = signal.butter(5, self.fsH / (fs / 2), btype='highpass', output='ba') Fl = signal.butter(5, self.fsL / (fs / 2), btype='lowpass', output='ba') for ch, ch_idx in self.channels_used.items(): # Fix for issue 9: https://github.com/Stanford-STAGES/stanford-stages/issues/9 if isinstance(ch_idx, int): myprint('Filtering {}'.format(ch)) self.loaded_channels[ch] = signal.filtfilt(Fh[0], Fh[1], self.loaded_channels[ch]) if fs > (2 * self.fsL): self.loaded_channels[ch] = signal.filtfilt(Fl[0], Fl[1], self.loaded_channels[ch]).astype( dtype=np.float32)
def resampling(self, ch, fs): myprint("original samplerate = ", fs); myprint("resampling to ", self.fs) if fs==500 or fs==200: numerator = [[-0.0175636017706537, -0.0208207236911009, -0.0186368912579407, 0.0, 0.0376532652007562, 0.0894912177899215, 0.143586518157187, 0.184663795586300, 0.200000000000000, 0.184663795586300, 0.143586518157187, 0.0894912177899215, 0.0376532652007562, 0.0, -0.0186368912579407, -0.0208207236911009, -0.0175636017706537], [-0.050624178425469, 0.0, 0.295059334702992, 0.500000000000000, 0.295059334702992, 0.0, -0.050624178425469]] # from matlab if fs==500: s = signal.dlti(numerator[0], [1], dt=1. / self.fs) self.loaded_channels[ch] = signal.decimate(self.loaded_channels[ch], fs // self.fs, ftype=s, zero_phase=False) elif fs==200: s = signal.dlti(numerator[1], [1], dt=1. / self.fs) self.loaded_channels[ch] = signal.decimate(self.loaded_channels[ch], fs // self.fs, ftype=s, zero_phase=False) else: self.loaded_channels[ch] = signal.resample_poly(self.loaded_channels[ch], self.fs, fs, axis=0, window=('kaiser', 5.0))
def loadEDF(self): if not self.edf: try: self.edf = pyedflib.EdfReader(self.edf_pathname) except OSError as osErr: print("OSError:", "Loading", self.edf_pathname) raise (osErr) for ch in self.channels: # ['C3','C4','O1','O2','EOG-L','EOG-R','EMG','A1','A2'] myprint('Loading', ch) if isinstance(self.channels_used[ch], int): self.loaded_channels[ch] = self.edf.readSignal(self.channels_used[ch]) if self.edf.getPhysicalDimension(self.channels_used[ch]).lower() == 'mv': myprint('mv') self.loaded_channels[ch] *= 1e3 elif self.edf.getPhysicalDimension(self.channels_used[ch]).lower() == 'v': myprint('v') self.loaded_channels[ch] *= 1e6 fs = int(self.edf.samplefrequency(self.channels_used[ch])) # fs = Decimal(fs).quantize(Decimal('.0001'), rounding=ROUND_DOWN) print('fs', fs) self.resampling(ch, fs) print('Resampling done') # Trim excess self.trim(ch) else: print('channel[', ch, '] was empty (skipped)', sep='') del self.channels_used[ch]
def myprint(self, string, *args): if self.config.verbose: myprint(string, *args)
def evaluate(self): p = Path(self.edf_pathname) p = Path(p.with_suffix('.pkl')) h = Path(self.edf_pathname) h = Path(h.with_suffix('.hypno_pkl')) if (p.exists()): myprint('Loading previously saved encoded data') with p.open('rb') as fp: self.encodedD = pickle.load(fp) else: myprint('Load EDF') self.loadEDF() # myprint('Load noise level') # self.psg_noise_level() print('Encode') self.encoding() # pickle our file with p.open('wb') as fp: pickle.dump(self.encodedD, fp) myprint("pickling done") if (h.exists()): myprint('Loading previously saved hynpodesnity') with h.open('rb') as fp: self.hypnodensity = pickle.load(fp) else: myprint('Score data') self.score_data() # pickle our file with h.open('wb') as fp: pickle.dump(self.hypnodensity, fp) myprint("Hypnodensity pickled")
def encoding(self): count = -1 enc = [] # Central, Occipital, EOG and chin numIterations = 4; # there are actually 5 for CC, but this is just for displaying progress numConcatenates = 5; for c in self.channels: # ['C3','C4','O1','O2','EOG-L','EOG-R','EMG','A1','A2'] start_time = time.time() if isinstance(self.channels_used[c], int): count += 1 n = int(self.fs * self.CCsize[c]) p = int(self.fs * (self.CCsize[c] - 0.25)) # TODO: There is an error in this buffer somewhere // Alex B1 = self.buffering(self.loaded_channels[c], n, p) print(B1.shape) zeroP = np.zeros([int(B1.shape[0] / 2), B1.shape[1]]) B1 = np.concatenate([zeroP, B1, zeroP], axis=0) n = int(self.fs * self.CCsize[c] * 2) p = int(self.fs * (self.CCsize[c] * 2 - 0.25)) B2 = self.buffering(np.concatenate([np.zeros(int(n / 4)), self.loaded_channels[c], np.zeros(int(n / 4))]), n, p) B2 = B2[:, :B1.shape[1]] start_time = time.time() F = np.fft.fft(B1, axis=0) C = np.conj(np.fft.fft(B2, axis=0)) elapsed_time = time.time() - start_time myprint("Finished FFT %d of %d\nTime elapsed = %0.2f" % (count + 1, len(self.channels), elapsed_time)); start_time = time.time() CC = np.real(np.fft.fftshift(np.fft.ifft(np.multiply(F, C), axis=0), axes=0)) elapsed_time = time.time() - start_time myprint("Finished CC 1 %d of %d\nTime elapsed = %0.2f" % (count + 1, len(self.channels), elapsed_time)); start_time = time.time() CC[np.isnan(CC)] = 0 CC[np.isinf(CC)] = 0 CC = CC[int(CC.shape[0] / 4):int(CC.shape[0] * 3 / 4), :] sc = np.max(CC, axis=0) sc = np.multiply(np.sign(sc), np.log((np.abs(sc) + 1) / (self.CCsize[c] * self.fs))) / (sc + 1e-10) CC = np.multiply(CC, sc) CC.astype(np.float32) if len(enc) > 0: enc = np.concatenate([enc, CC]) else: enc = CC if count == 2: eog1 = F if count == 3: PS = eog1 * C CC = np.real(np.fft.fftshift(np.fft.ifft(PS, axis=0), axes=0)) CC = CC[int(CC.shape[0] / 4):int(CC.shape[0] * 3 / 4), :] sc = np.max(CC, axis=0) sc = np.multiply(np.sign(sc), np.log((np.abs(sc) + 1) / (self.CCsize[c] * self.fs))) / (sc + 1e-10) CC = np.multiply(CC, sc) CC.astype(np.float32) enc = np.concatenate([enc, CC]) # pdb.set_trace() elapsed_time = time.time() - start_time myprint("Finished enc concatenate %d of %d\nTime elapsed = %0.2f" % ( count + 1, len(self.channels), elapsed_time)) self.encodedD = enc if isinstance(self.lightsOff, int): self.encodedD = self.encodedD[:, 4 * 30 * self.lightsOff:4 * 30 * self.lightsOn]