Package qubx :: Module data_gpatch
[hide private]
[frames] | no frames]

Source Code for Module qubx.data_gpatch

  1  """Reads .gpatch data files. 
  2   
  3  Copyright 2008-2011 Research Foundation State University of New York  
  4  This file is part of QUB Express.                                           
  5   
  6  QUB Express is free software; you can redistribute it and/or modify           
  7  it under the terms of the GNU General Public License as published by  
  8  the Free Software Foundation, either version 3 of the License, or     
  9  (at your option) any later version.                                   
 10   
 11  QUB Express is distributed in the hope that it will be useful,                
 12  but WITHOUT ANY WARRANTY; without even the implied warranty of        
 13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         
 14  GNU General Public License for more details.                          
 15   
 16  You should have received a copy of the GNU General Public License,    
 17  named LICENSE.txt, in the QUB Express program directory.  If not, see         
 18  <http://www.gnu.org/licenses/>.                                       
 19   
 20  """ 
 21   
 22  import mmap 
 23  import os 
 24  import re 
 25  import sys 
 26  from qubx.data_types import * 
 27  from ctypes import * 
 28   
 29  c_uint_p = POINTER(c_uint) 
 30  c_short_p = POINTER(c_short) 
 31   
32 -class GPatchWSweep(Structure):
33 _pack_ = 1 34 _fields_ = [('amp', c_short * 8), 35 ('pulseFilter', c_short), 36 ('decimFactor', c_short), 37 ('dur', c_int * 9), 38 ('dummy0', c_float), # Gain1 39 ('durAP', c_int), 40 ('durBP', c_int), 41 ('durSP', c_int), 42 ('cyclePeriod', c_float), 43 ('numSweeps', c_short), 44 ('numSubPul', c_short), 45 ('numPulses', c_short), 46 ('triggerPulse', c_short), 47 ('dummy1', c_short), # Trigger2Pulse 48 ('triggerDelay', c_int), 49 ('dummy2', c_int), # Trigger2Delay 50 ('ampHP', c_short), 51 ('ampSH', c_short), 52 ('dummy3', c_short), # Temperature 53 ('dummy8', c_short), # switched with gain? 54 ('acqFilter', c_short), 55 ('numAver', c_short), 56 ('acqRate', c_float), # microseconds per sample 57 ('year', c_short), 58 ('date', c_byte * 2), 59 ('time', c_byte * 4), 60 ('photonCounter', c_short), 61 ('multiplexer', c_short), 62 ('dummy4', c_short), # Trigger2Pulse ??? 63 ('dummy5', c_int), # GPatchMSymbol 64 ('dummy6', c_short), 65 ('dummy7', c_short), 66 ('gain', c_float), # real gain * 10 67 ('units', c_float), 68 ('aDRange', c_float), 69 ('extra', c_char * 16)]
70 71 GPM_headerSize = 2048 #// Size of the header in bytes 72 GPM_maxPulses = 64 #// Number of pulses reflected in the header 73 GPM_maxTriggers = 8 #// Number of triggers reflected in the header 74 GPM_maxCharSize = 16 #// Maximum size for char variables 75 GPM_currSizeUsed = 1336 #// Currently used space of the header 76
77 -class GPatchMSweep(Structure):
78 _pack_ = 1 79 _fields_ = [('magicField', c_char * GPM_maxCharSize), 80 ('sweepGroupSign', c_int), 81 ('dateDay', c_int), 82 ('dateMonth', c_int), 83 ('dateYear', c_int), 84 ('timeHours', c_int), 85 ('timeMinuts', c_int), 86 ('timeSeconds', c_int), 87 ('timeHundredOfSec', c_int), 88 ('acqNumPoints', c_int), 89 ('acqAcqRate', c_float), 90 ('acqDecimation', c_int), 91 ('acqTemperature', c_float), 92 ('acqNumAverages', c_int), 93 ('acqDataType', c_int), 94 ('acqAcqFilter', c_float), 95 ('acqPulseFilter', c_float), 96 ('acqGain', c_float), 97 ('acqUnits', c_float), 98 ('pulNumPulses', c_int), 99 ('pulDurBP', c_int), 100 ('pulDurAP', c_int), 101 ('pulDurCP', c_int), 102 ('pulAmpHP', c_float), 103 ('pulAmp', c_float * GPM_maxPulses), 104 ('pulDur', c_int * GPM_maxPulses), 105 ('pulIsRamp', c_int * GPM_maxPulses), 106 ('pulRampEnd', c_float * GPM_maxPulses), 107 ('trPulse', c_int * GPM_maxTriggers), 108 ('trDelay', c_int * GPM_maxTriggers), 109 ('trGate', c_int * GPM_maxTriggers), 110 ('trEndGate', c_int * GPM_maxTriggers), 111 ('trIsActive', c_int * GPM_maxTriggers), 112 ('subNumSP', c_int), 113 ('subAmpSH', c_float), 114 ('subDurBwSP', c_int), 115 ('setBoardType', c_char * GPM_maxCharSize), 116 ('setDACGain', c_float), 117 ('setADRange', c_int), 118 ('setADMax', c_int), 119 ('setMembrOrient', c_int)]
120
121 -class QubData_Gpatch_Analog(QubData_Analog):
122 - def __init__(self, data, channel):
123 """ 124 @param data: L{QubData_GPatch} 125 """ 126 QubData_Analog.__init__(self) 127 self.data = data 128 self.channel = channel
129 - def read(self, first, last, latency=0, skip=1):
130 ifirst, ilast = [self.data.segmentation.index_at(x) for x in (first, last)] 131 if ifirst != ilast: 132 raise Exception("ABF: can't read() from multiple segments at once") 133 segfirst = self.data.segmentation.segments[ifirst][0] 134 seglast = self.data.segmentation.segments[ifirst][1] 135 return read_with_latency(self.read_in_seg, first, last, latency, skip, ifirst, segfirst, seglast)
136 - def read_in_seg(self, iseg, first, last, skip):
137 samples = numpy.zeros(dtype='float32', shape=(self.data.segmentation.segments[iseg][2],)) 138 uNumSamples = c_uint() 139 samples = self.data.segbufs_of_signal[self.channel][iseg][first:last+1:skip].astype('float32') 140 scale = self.data.signals.get(self.channel, 'Scale') 141 if scale != 1.0: 142 samples *= scale 143 offset = self.data.signals.get(self.channel, 'Offset') 144 if offset != 0.0: 145 samples += offset 146 return samples
147 148 # supposedly you can make GPatchWSweep.from_buffer{_copy}(map, offset) 149 150 # open all _ch%(i+1)i files 151 # first look for M-magic at beginning; 152 # list offset, count, struct of sweep, for all channels 153 # else step backwards bytewise from (end - w_size), until GPatchMSymbol == -12345 154 # list offset, count, struct of sweep, for all channels 155 # add the signals, segments, and analog-handlers 156
157 -def open_mmap_readonly(path):
158 exists = os.path.exists(path) 159 size = 0 160 if exists: 161 #st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid, st_size, st_atime, st_mtime, st_ctime = os.stat(path) 162 size = os.stat(path)[6] 163 if size: 164 fileno = os.open(path, os.O_RDONLY) 165 map = mmap.mmap(fileno, size, access=mmap.ACCESS_READ) 166 return fileno, size, map 167 return None, None
168 169 GPATCH_MAX_SIGNALS = 8 170
171 -class QubData_GPatch(QubData):
172 """One open GPATCH dat file. 173 174 @ivar segbufs_of_signal: array[signal_ix][seg_ix] of numpy.array (float32) 175 @ivar sweeps: array[seg_ix] of GPatchWSweep or GPatchMSweep 176 """
177 - def __init__(self, path, progressf):
178 QubData.__init__(self) 179 self.path = path 180 self.fileno = [] 181 self.filesize = [] 182 self.mmap = [] 183 self.segbufs_of_signal = [] 184 self.sweeps = [] 185 186 match = re.match(r"(.*_ch)\d+(.*)", path) 187 if match: 188 for i in xrange(GPATCH_MAX_SIGNALS): 189 fileno, filesize, map = open_mmap_readonly("%s%d%s" % (match.group(1), i+1, match.group(2))) 190 if not (map is None): 191 self.signals.append({'Name' : 'ch%d' % (i+1)}) 192 self.fileno.append(fileno) 193 self.filesize.append(filesize) 194 self.mmap.append(map) 195 self.segbufs_of_signal.append([]) 196 else: 197 fileno, filesize ,map = open_mmap_readonly(path) 198 if not (map is None): 199 self.signals.append({'Name' : 'Current'}) 200 self.fileno.append(fileno) 201 self.filesize.append(filesize) 202 self.mmap.append(map) 203 self.segbufs_of_signal.append([]) 204 if not self.mmap: 205 raise Exception('No data signals found.') 206 207 # read_val = lambda map, offset, typ: numpy.frombuffer(map, typ, 1, offset)[0] 208 map = self.mmap[0] 209 segm = [] # (offset, count, struct) 210 offset = 0 211 try: 212 while map[offset:offset+GPM_maxCharSize] == "gpatch_m ": 213 offset += GPM_headerSize 214 struct = GPatchMSweep.from_buffer_copy(map, offset) 215 count = struct.acqNumPoints 216 segm.append((offset, count, struct)) 217 offset += 2*count 218 except: 219 pass 220 if not segm: # W-style? 221 offset = self.filesize[0] - sizeof(GPatchWSweep) 222 while offset >= 0: 223 struct = GPatchWSweep.from_buffer_copy(map, offset) 224 if struct.dummy5 == -12345: 225 print 'amp: ', struct.amp[:] 226 print 'pulseFilter: ', struct.pulseFilter 227 print 'decimFactor: ', struct.decimFactor 228 print 'dur: ', struct.dur[:] 229 print 'dummy0: ', struct.dummy0 230 print 'durAP: ', struct.durAP 231 print 'durBP: ', struct.durBP 232 print 'durSP: ', struct.durSP 233 print 'cyclePeriod: ', struct.cyclePeriod 234 print 'numSweeps: ', struct.numSweeps 235 print 'numSubPul: ', struct.numSubPul 236 print 'numPulses: ', struct.numPulses 237 print 'triggerPulse: ', struct.triggerPulse 238 print 'dummy1: ', struct.dummy1 239 print 'triggerDelay: ', struct.triggerDelay 240 print 'dummy2: ', struct.dummy2 241 print 'ampHP: ', struct.ampHP 242 print 'ampSH: ', struct.ampSH 243 print 'dummy3: ', struct.dummy3 244 print 'gain: ', struct.gain 245 print 'acqFilter: ', struct.acqFilter 246 print 'numAver: ', struct.numAver 247 print 'acqRate: ', struct.acqRate 248 print 'year: ', struct.year 249 print 'date: ', struct.date[:] 250 print 'time: ', struct.time[:] 251 print 'photonCounter: ', struct.photonCounter 252 print 'multiplexer: ', struct.multiplexer 253 print 'dummy4: ', struct.dummy4 254 print 'dummy5: ', struct.dummy5 255 print 'dummy6: ', struct.dummy6 256 print 'dummy7: ', struct.dummy7 257 print 'dummy8: ', struct.dummy8 258 print 'units: ', struct.units 259 print 'aDRange: ', struct.aDRange 260 print 'extra: ', struct.extra 261 offset -= sizeof(GPatchWSweep) 262 else: 263 offset -= 1 264 265 #>>> res{dur[9]} / ((gain/10) * adrange / 2) 266 #327.68000000000001 = scaling 267 268 # 269 # self.segmentation.add_seg(points, points+nsample-1, start) 270 # self.segbuf.append(numpy.frombuffer(self.map, '<i2', nsample, offset+2*segpad)) 271 # points += nsample 272 # offset += 2*(nsample+2*segpad) 273 # 274 # self.analog[0] = QubData_LDT_Analog(self) 275 # 276 base, ext = os.path.splitext(path) 277 sess = qubx.tree.Open(base+'.qsf', True) 278 sess.close() # release file, keep in mem 279 self.qsf = sess 280 281 self.read_session(sess, progressf)
282
283 - def __del__(self):
284 for map in self.mmap: 285 if map: 286 map.close() 287 for fileno in self.fileno: 288 if fileno: 289 os.close(fileno)
290 291 ## SetReader('.abf', 'Axon binary files', QubData_ABF) 292 ## TODO: dispatch .dat to gpatch, patchmaster, binary, text 293 294 295 # durations: 1000, 200000, 20000 -> 210 ms of data ? 296 # multi sweeps in W file? sample count? 297 # scaling? offset? 298