def _get_head(self): """Wraps EEGFile._get_head to modify the channel information""" # Retreive data head = super(MontageFile, self)._get_head() chan = head.chan # Check montage labels labels = [c.label for c in chan] labels_lower = [l.lower() for l in labels] new_chan = [] self.indices = [] for label in self.montage: # Montage could use different case from file elec1, elec2 = label.lower().split('-') elec1 = labels[labels_lower.index(elec1)] elec2 = labels[labels_lower.index(elec2)] # Create chan dict for new chan cnew = chan[labels.index(elec1)] label = elec1 + '-' + elec2 new_chan.append(cnew._replace(label=label)) # These are used in _get_blocks self.indices.append((label, elec1, elec2)) # descr = [(c.label, 'i2', c.nsblock) for c in new_chan] self._block_descriptor = BlockDescriptor(descr) return head._replace(chan=new_chan, nchan=len(new_chan))
def __init__(self, tstart, tend, samples, labels=None, name='samples'): """Create a SampleFile interface to the data in samples tstart : start time of file tend : end time of file samples : list of arrays of samples labels : names of channels """ # Establish the number of channels nchan = len(samples) # Invent labels if necessary if labels is None: labels = ['Chan {0}'.format(n) for n in range(1, nchan + 1)] # Enforce equal sample rates nsamples = len(samples[0]) if not all((len(x) == nsamples) for x in samples): raise EEGUnequalSamplesError("samples must be of equal length") # Check number of labels if len(labels) != nchan: msg = "Expected {0} labels found {1}" raise ValueError(msg.format(nchan, len(labels))) # Determine block size samplenos = [len(x) for x in samples] secsdur = self.as_seconds(tend, tstart) nblocks = _optimal_nblocks(secsdur, samplenos) # Determine the number of seconds in a block as an integer secsblock = secsdur / nblocks if secsblock == int(secsblock): secsblock = int(secsblock) # Create channel header structures chan = [] kwargs = {'calib':1, 'offset':0, 'dim':'uV'} for lab, sam in zip(labels, samples): nsblock = len(sam) // nblocks chan.append(Chan(label=lab, nsblock=nsblock, **kwargs)) # Create main header structure head = Head(tstart=tstart, secsblock=secsblock, chan=chan, nchan=len(chan), nblocks=nblocks) # Store what's needed for later self.__samples = samples self._head = head self.name = name # Used in _get_blocks descr = [(c.label, 'i2', c.nsblock) for c in chan] self._block_descriptor = BlockDescriptor(descr) # Initialise super(SampleFile, self).__init__(self)
def _read_head(self): """Read the main file header""" # Actually read the file: self._seek(0) wg1_head = self._fromfile(_head_descr)[0] # Extract channels nchan = int(wg1_head["nchan"]) raw_chan = wg1_head["wg1_chan"][:nchan] def as_chan(c): return Chan( label=c["label"].strip(), dim="uV", calib=1e-3 * c["calib"], offset=0, nsblock=_wg1_nsblock, finfo=c ) head = Head( pat_id="", rec_id=split(self.name)[1], tstart=self._wg1_datetime(wg1_head["wg1_daynum"], wg1_head["wg1_msnum"]), nblocks=-1, secsblock=_wg1_nsblock * 1e-6 * int(wg1_head["wg1_dtusec"]), nchan=int(wg1_head["nchan"]), chan=[as_chan(c) for c in raw_chan], fmt="wg1", finfo=wg1_head, ) # How the block will be represented in memory descr = [(c.label, "i2", c.nsblock) for c in head.chan] self._block_descr = BlockDescriptor(descr) # How the block appears on disk self._headlen = _wg1_headlen nchan = head.nchan ntotal, nbegin = wg1_head["wg1_ntotal"], wg1_head["wg1_nbegin"] self._blocklen = ntotal * _wg1_nsblock pad1 = _wg1_nsblock * nbegin - 4 * nchan pad2 = _wg1_nsblock * (ntotal - nbegin - nchan) pad1 = pad1 or "" pad2 = pad2 or "" self._block_descr_raw = HeadDescriptor( [ ("chan", HeadDescriptor([("offset", "i2"), ("pad", "u2")]), nchan), ("pad1", "S" + str(pad1)), ("bytes", str(_wg1_nsblock) + "u1", nchan), ("pad2", "S" + str(pad2)), ], nbytes=ntotal * _wg1_nsblock, ) return head
class ChanMapFile(EEGFile): """ChanMapFile class """ def __init__(self, infile, chanmap=None): """Store the chanmap and initialise""" self._chanmap = chanmap super(ChanMapFile, self).__init__(infile) def _setup_chanmap(self, channames, chanmap): """Returns a new chanmap based on the source chan info""" # If not provided fill the identity map here if chanmap is None: chanmap = zip(channames, channames) return chanmap def _get_head(self): """Override EEGFile._get_head to modify channels""" # Read original header head = super(ChanMapFile, self)._get_head() chan = head.chan # Finalise the chanmap based on the source channel list channames = [c.label for c in chan] self._chanmap = self._setup_chanmap(channames, self._chanmap) # Create new channel data chan_d = dict((c.label, c) for c in chan) new_chan = [] for c_old, c_new in self._chanmap: new_chan.append(chan_d[c_old]._replace(label=c_new)) # Prepare data blocks descr = [(c.label, 'i2', c.nsblock) for c in new_chan] self._block_descriptor = BlockDescriptor(descr) # Return head with modified information return head._replace(chan=new_chan, nchan=len(new_chan)) def _get_blocks(self, n1, n2): """Override EEGFile._get_blocks to modify channels""" # Read original blocks old_blocks = super(ChanMapFile, self)._get_blocks(n1, n2) # Map into the new block new_blocks = self._block_descriptor.new(len(old_blocks)) for c_old, c_new in self._chanmap: new_blocks[c_new] = old_blocks[c_old] return new_blocks
class MontageFile(EEGFile): def __init__(self, infile, montage, *args, **kwargs): """Set montage and initialise EEGFile object""" if not montage in MONTAGES: msg = "Unrecognised montage: '{0}'".format(montage) raise UnrecognisedMontageError(msg) self.montage = MONTAGES[montage] EEGFile.__init__(self, infile, *args, **kwargs) def _get_head(self): """Wraps EEGFile._get_head to modify the channel information""" # Retreive data head = super(MontageFile, self)._get_head() chan = head.chan # Check montage labels labels = [c.label for c in chan] labels_lower = [l.lower() for l in labels] new_chan = [] self.indices = [] for label in self.montage: # Montage could use different case from file elec1, elec2 = label.lower().split('-') elec1 = labels[labels_lower.index(elec1)] elec2 = labels[labels_lower.index(elec2)] # Create chan dict for new chan cnew = chan[labels.index(elec1)] label = elec1 + '-' + elec2 new_chan.append(cnew._replace(label=label)) # These are used in _get_blocks self.indices.append((label, elec1, elec2)) # descr = [(c.label, 'i2', c.nsblock) for c in new_chan] self._block_descriptor = BlockDescriptor(descr) return head._replace(chan=new_chan, nchan=len(new_chan)) def _get_blocks(self, n1, n2): """Wraps EEGFile._get_blocks to change the montage of the data""" block = EEGFile._get_blocks(self, n1, n2) new_block = self._block_descriptor.new(len(block)) for label, elec1, elec2 in self.indices: new_block[label] = block[elec2] - block[elec1] return new_block
def _get_head(self): """Override EEGFile._get_head to modify channels""" # Read original header head = super(ChanMapFile, self)._get_head() chan = head.chan # Finalise the chanmap based on the source channel list channames = [c.label for c in chan] self._chanmap = self._setup_chanmap(channames, self._chanmap) # Create new channel data chan_d = dict((c.label, c) for c in chan) new_chan = [] for c_old, c_new in self._chanmap: new_chan.append(chan_d[c_old]._replace(label=c_new)) # Prepare data blocks descr = [(c.label, 'i2', c.nsblock) for c in new_chan] self._block_descriptor = BlockDescriptor(descr) # Return head with modified information return head._replace(chan=new_chan, nchan=len(new_chan))
class Wg1File(IOFile): """Specialised for reading WG1 files""" # String for use when opening the file _binary = "b" def _read_head(self): """Read the main file header""" # Actually read the file: self._seek(0) wg1_head = self._fromfile(_head_descr)[0] # Extract channels nchan = int(wg1_head["nchan"]) raw_chan = wg1_head["wg1_chan"][:nchan] def as_chan(c): return Chan( label=c["label"].strip(), dim="uV", calib=1e-3 * c["calib"], offset=0, nsblock=_wg1_nsblock, finfo=c ) head = Head( pat_id="", rec_id=split(self.name)[1], tstart=self._wg1_datetime(wg1_head["wg1_daynum"], wg1_head["wg1_msnum"]), nblocks=-1, secsblock=_wg1_nsblock * 1e-6 * int(wg1_head["wg1_dtusec"]), nchan=int(wg1_head["nchan"]), chan=[as_chan(c) for c in raw_chan], fmt="wg1", finfo=wg1_head, ) # How the block will be represented in memory descr = [(c.label, "i2", c.nsblock) for c in head.chan] self._block_descr = BlockDescriptor(descr) # How the block appears on disk self._headlen = _wg1_headlen nchan = head.nchan ntotal, nbegin = wg1_head["wg1_ntotal"], wg1_head["wg1_nbegin"] self._blocklen = ntotal * _wg1_nsblock pad1 = _wg1_nsblock * nbegin - 4 * nchan pad2 = _wg1_nsblock * (ntotal - nbegin - nchan) pad1 = pad1 or "" pad2 = pad2 or "" self._block_descr_raw = HeadDescriptor( [ ("chan", HeadDescriptor([("offset", "i2"), ("pad", "u2")]), nchan), ("pad1", "S" + str(pad1)), ("bytes", str(_wg1_nsblock) + "u1", nchan), ("pad2", "S" + str(pad2)), ], nbytes=ntotal * _wg1_nsblock, ) return head # ReadBlock reads in and converts one block of EEG data # at a time. def _read_block(self, n): """Read in one datablock""" # Read raw block self._seek(self._headlen + n * self._blocklen) block_raw = self._fromfile(self._block_descr_raw) # Check against magic end value: if block_raw["chan"]["pad"][0][0] == _wg1_end: self.nblocks = n raise EOFError # Convert to standard block type chan = self.get_chan() sigs = block_raw["bytes"][0] block = self._block_descr.new(1) for n, c in enumerate(chan): label = c.label index = c.finfo["wg1_index"] sig = sigs[n] offset = block_raw["chan"]["offset"][0, n] diff = _wg1_conv[sig].cumsum() block[label] = diff - offset # import pdb; pdb.set_trace() return block def _read_blocks(self, n1, n2): blocks = [] for n in range(n1, n2): try: blocks.append(self._read_block(n)) except EOFError: if not blocks: raise else: break return self._block_descr.concatenate(blocks) def _wg1_datetime(self, daynum, millisecond): """Convert two numbers in wg1 file to datetime""" day = daynum - 0x250000 - 15755 - 1 timestamp = day * 86400 + millisecond / 1000.0 return datetime.fromtimestamp(timestamp)