1 """
2 Reads Axon binary data using ABFFIO.dll, if available.
3
4 Copyright 2008-2013 Research Foundation State University of New York
5 This file is part of QUB Express.
6
7 QUB Express is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 QUB Express is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License,
18 named LICENSE.txt, in the QUB Express program directory. If not, see
19 <http://www.gnu.org/licenses/>.
20
21 """
22
23 from qubx.data_types import *
24 from ctypes import *
25
26 c_uint_p = POINTER(c_uint)
27 c_short_p = POINTER(c_short)
28
29 try:
30 abffio = windll.LoadLibrary("ABFFIO.dll")
31 from ctypes.wintypes import *
32
33 ABF_ADCCOUNT = 16
34 ABF_DACCOUNT = 4
35 ABF_EPOCHCOUNT = 10
36 ABF_ADCUNITLEN = 8
37 ABF_ADCNAMELEN_USER = 8
38 ABF_ADCNAMELEN = 10
39 ABF_DACUNITLEN = 8
40 ABF_DACNAMELEN = 10
41 ABF_USERLISTLEN = 256
42 ABF_USERLISTCOUNT = 4
43 ABF_OLDFILECOMMENTLEN = 56
44 ABF_FILECOMMENTLEN = 128
45 ABF_PATHLEN = 256
46 ABF_CREATORINFOLEN = 16
47 ABF_ARITHMETICOPLEN = 2
48 ABF_ARITHMETICUNITSLEN = 8
49 ABF_TAGCOMMENTLEN = 56
50 ABF_BLOCKSIZE = 512
51 PCLAMP6_MAXSWEEPLENGTH = 16384
52 PCLAMP7_MAXSWEEPLEN_PERCHAN = 1032258
53 ABF_MAX_SWEEPS_PER_AVERAGE = 65500
54 ABF_MAX_TRIAL_SAMPLES = 0x7FFFFFFF
55
56
57
58 ABF_DATAFILE = 0
59
60 ABF_STATS_REGIONS = 8
61 ABF_BASELINE_REGIONS = 1
62 ABF_STATS_NUM_MEASUREMENTS = 18
63
64 - class GUID(Structure):
65 _fields_ = [('Data1', c_uint),
66 ('Data2', c_ushort),
67 ('Data3', c_ushort),
68 ('Data4', c_ubyte * 8)]
69
71 _pack_ = 1
72 _fields_ = [('fFileVersionNumber', c_float),
73 ('nOperationMode', c_short),
74 ('lActualAcqLength', c_long),
75 ('nNumPointsIgnored', c_short),
76 ('lActualEpisodes', c_long),
77 ('uFileStartDate', c_uint),
78 ('uFileStartTimeMS', c_uint),
79 ('lStopwatchTime', c_long),
80 ('fHeaderVersionNumber', c_float),
81 ('nFileType', c_short),
82
83 ('lDataSectionPtr', c_long),
84 ('lTagSectionPtr', c_long),
85 ('lNumTagEntries', c_long),
86 ('lScopeConfigPtr', c_long),
87 ('lNumScopes', c_long),
88 ('lDeltaArrayPtr', c_long),
89 ('lNumDeltas', c_long),
90 ('lVoiceTagPtr', c_long),
91 ('lVoiceTagEntries', c_long),
92 ('lSynchArayPtr', c_long),
93 ('lSynchArraySize', c_long),
94 ('nDataFormat', c_short),
95 ('nSimultaneousScan', c_short),
96 ('lStatisticsConfigPtr', c_long),
97 ('lAnnotationSectionPtr', c_long),
98 ('lNumAnnotations', c_long),
99 ('lDACFilePtr', c_long * ABF_DACCOUNT),
100 ('lDACFileNumEpisodes', c_long * ABF_DACCOUNT),
101
102 ('nADCNumChannels', c_short),
103 ('fADCSequenceInterval', c_float),
104 ('uFileCompressionRatio', c_uint),
105 ('bEnableFileCompression', c_byte),
106 ('fSynchTimeUnit', c_float),
107 ('fSecondsPerRun', c_float),
108 ('lNumSamplesPerEpisode', c_long),
109 ('lPreTriggerSamples', c_long),
110 ('lEpisodesPerRun', c_long),
111 ('lRunsPerTrial', c_long),
112 ('lNumberOfTrials', c_long),
113 ('nAveragingMode', c_short),
114 ('nUndoRunCount', c_short),
115 ('nFirstEpisodeInRun', c_short),
116 ('fTriggerThreshold', c_float),
117 ('nTriggerSource', c_short),
118 ('nTriggerAction', c_short),
119 ('nTriggerPolarity', c_short),
120 ('fScopeOutputInterval', c_float),
121 ('fEpisodeStartToStart', c_float),
122 ('fRunStartToStart', c_float),
123 ('fTrialStartToStart', c_float),
124 ('lAverageCount', c_long),
125 ('nAutoTriggerStrategy', c_short),
126 ('fFirstRunDelayS', c_float),
127
128 ('nDataDisplayMode', c_short),
129 ('nChannelStatsStrategy', c_short),
130 ('lSamplesPerTrace', c_long),
131 ('lStartDisplayNum', c_long),
132 ('lFinishDisplayNum', c_long),
133 ('nShowPNRawData', c_short),
134 ('fStatisticsPeriod', c_float),
135 ('lStatisticsMeasurements', c_long),
136 ('nStatisticsSaveStrategy', c_short),
137
138 ('fADCRange', c_float),
139 ('fDACRange', c_float),
140 ('lADCResolution', c_long),
141 ('lDACResolution', c_long),
142 ('nDigitizerADCs', c_short),
143 ('nDigitizerDACs', c_short),
144 ('nDigitizerTotalDigitalOuts', c_short),
145 ('nDigitizerSynchDigitalOuts', c_short),
146 ('nDigitizerType', c_short),
147
148 ('nExperimentType', c_short),
149 ('nManualInfoStrategy', c_short),
150 ('fCellID1', c_float),
151 ('fCellID2', c_float),
152 ('fCellID3', c_float),
153 ('sProtocolPath', c_char * ABF_PATHLEN),
154 ('sCreatorInfo', c_char * ABF_CREATORINFOLEN),
155 ('sModifierInfo', c_char * ABF_CREATORINFOLEN),
156 ('nCommentsEnable', c_short),
157 ('sFileComment', c_char * ABF_FILECOMMENTLEN),
158 ('nTelegraphEnable', c_short * ABF_ADCCOUNT),
159 ('nTelegraphInstrument', c_short * ABF_ADCCOUNT),
160 ('fTelegraphAdditGain', c_float * ABF_ADCCOUNT),
161 ('fTelegraphFilter', c_float * ABF_ADCCOUNT),
162 ('fTelegraphMembraneCap', c_float * ABF_ADCCOUNT),
163 ('fTelegraphAccessResistance', c_float * ABF_ADCCOUNT),
164 ('nTelegraphMode', c_short * ABF_ADCCOUNT),
165 ('nTelegraphDACScaleFactorEnable', c_short * ABF_DACCOUNT),
166
167 ('nAutoAnalyseEnable', c_short),
168
169 ('FileGUID', GUID),
170 ('fIntstrumentHoldingLevel', c_float * ABF_DACCOUNT),
171 ('ulFileCRC', c_ulong),
172 ('nCRCEnable', c_short),
173
174 ('nSignalType', c_short),
175 ('nADCPtoLChannelMap', c_short * ABF_ADCCOUNT),
176 ('nADCSamplingSeq', c_short * ABF_ADCCOUNT),
177 ('fADCProgrammableGain', c_float * ABF_ADCCOUNT),
178 ('fADCDisplayAmplification', c_float * ABF_ADCCOUNT),
179 ('fADCDisplayOffset', c_float * ABF_ADCCOUNT),
180 ('fInstrumentScaleFactor', c_float * ABF_ADCCOUNT),
181 ('fInstrumentOffset', c_float * ABF_ADCCOUNT),
182 ('fSignalGain', c_float * ABF_ADCCOUNT),
183 ('fSignalOffset', c_float * ABF_ADCCOUNT),
184 ('fSignalLowpassFilter', c_float * ABF_ADCCOUNT),
185 ('fSignalHighpassFilter', c_float * ABF_ADCCOUNT),
186 ('nLowpassFilterType', c_char * ABF_ADCCOUNT),
187 ('nHighpassFilterType', c_char * ABF_ADCCOUNT),
188
189 ('sADCChannelName', (c_char * ABF_ADCNAMELEN) * ABF_ADCCOUNT),
190 ('sADCUnits', (c_char * ABF_ADCUNITLEN) * ABF_ADCCOUNT),
191 ('fDACScaleFactor', c_float * ABF_DACCOUNT),
192 ('fDACHoldingLevel', c_float * ABF_DACCOUNT),
193 ('fDACCalibrationFactor', c_float * ABF_DACCOUNT),
194 ('fDACCalibrationOffset', c_float * ABF_DACCOUNT),
195 ('sDACChannelName', (c_char * ABF_DACNAMELEN) * ABF_DACCOUNT),
196 ('sDACChannelUnits', (c_char * ABF_DACUNITLEN) * ABF_DACCOUNT),
197
198 ('nDigitalEnable', c_short),
199 ('nActiveDACChannel', c_short),
200 ('nDigitalDACChannel', c_short),
201 ('nDigitalHolding', c_short),
202 ('nDigitalInterEpisode', c_short),
203 ('nDigitalTrainActiveLogic', c_short),
204 ('nDigitalValue', c_short * ABF_EPOCHCOUNT),
205 ('nDigitalTrainValue', c_short * ABF_EPOCHCOUNT),
206 ('bEpochCompression', c_byte * ABF_EPOCHCOUNT),
207 ('nWaveformEnable', c_short * ABF_DACCOUNT),
208 ('nWaveformSource', c_short * ABF_DACCOUNT),
209 ('nInterEpisodeLevel', c_short * ABF_DACCOUNT),
210 ('nEpochType', (c_short * ABF_EPOCHCOUNT) * ABF_DACCOUNT),
211 ('fEpochInitLevel', (c_float * ABF_EPOCHCOUNT) * ABF_DACCOUNT),
212 ('fEpochLevelInc', (c_float * ABF_EPOCHCOUNT) * ABF_DACCOUNT),
213 ('lEpochInitDuration', (c_long * ABF_EPOCHCOUNT) * ABF_DACCOUNT),
214 ('lEpochDurationInc', (c_long * ABF_EPOCHCOUNT) * ABF_DACCOUNT),
215
216 ('fDACFileScale', c_float * ABF_DACCOUNT),
217 ('fDACFileOffset', c_float * ABF_DACCOUNT),
218 ('lDACFileEpisodeNum', c_long * ABF_DACCOUNT),
219 ('nDACFileADCNum', c_short * ABF_DACCOUNT),
220 ('sDACFilePath', (c_char * ABF_PATHLEN) * ABF_DACCOUNT),
221
222 ('nConditEnable', c_short * ABF_DACCOUNT),
223 ('lConditNumPulses', c_long * ABF_DACCOUNT),
224 ('fBaselineDuration', c_float * ABF_DACCOUNT),
225 ('fBaselineLevel', c_float * ABF_DACCOUNT),
226 ('fStepDuration', c_float * ABF_DACCOUNT),
227 ('fStepLevel', c_float * ABF_DACCOUNT),
228 ('fPostTrainPeriod', c_float * ABF_DACCOUNT),
229 ('fPostTrainLevel', c_float * ABF_DACCOUNT),
230 ('nMembTestEnable', c_short * ABF_DACCOUNT),
231 ('fMembTestPreSettlingTimeMS', c_float * ABF_DACCOUNT),
232 ('fMembTestPostSettlingTimeMS', c_float * ABF_DACCOUNT),
233
234 ('nULEnable', c_short * ABF_USERLISTCOUNT),
235 ('nULParamToVary', c_short * ABF_USERLISTCOUNT),
236 ('nULRepeat', c_short * ABF_USERLISTCOUNT),
237 ('sULParamValueList', (c_char * ABF_USERLISTLEN) * ABF_USERLISTCOUNT),
238
239 ('nStatsEnable', c_short),
240 ('nStatsActiveChannels', c_ushort),
241 ('nStatsSearchRegionFlags', c_ushort),
242 ('nStatsSmoothing', c_short),
243 ('nStatsSmoothingEnable', c_short),
244 ('nStatsBaseline', c_short),
245 ('nStatsBaselineDAC', c_short),
246 ('lStatsBaselineStart', c_long),
247 ('lStatsBaselineEnd', c_long),
248 ('lStatsMeasurements', c_long * ABF_STATS_REGIONS),
249 ('lStatsStart', c_long * ABF_STATS_REGIONS),
250 ('lStatsEnd', c_long * ABF_STATS_REGIONS),
251 ('nRiseBottomPercentile', c_short * ABF_STATS_REGIONS),
252 ('nRiseTopPercentile', c_short * ABF_STATS_REGIONS),
253 ('nDecayBottomPercentile', c_short * ABF_STATS_REGIONS),
254 ('nDecayTopPercentile', c_short * ABF_STATS_REGIONS),
255 ('nStatsChannelPolarity', c_short * ABF_STATS_REGIONS),
256 ('nStatsSearchMode', c_short * ABF_STATS_REGIONS),
257 ('nStatsSearchDAC', c_short * ABF_STATS_REGIONS),
258
259 ('nArithmeticEnable', c_short),
260 ('nArithmeticExpression', c_short),
261 ('fArithmeticUpperLimit', c_float),
262 ('fArithmeticLowerLimit', c_float),
263 ('nArithmeticADCNumA', c_short),
264 ('nArithmeticADCNumB', c_short),
265 ('fArithmeticK1', c_float),
266 ('fArithmeticK2', c_float),
267 ('fArithmeticK3', c_float),
268 ('fArithmeticK4', c_float),
269 ('fArithmeticK5', c_float),
270 ('fArithmeticK6', c_float),
271 ('sArithmeticOperator', c_char * ABF_ARITHMETICOPLEN),
272 ('sArithmeticUnits', c_char * ABF_ARITHMETICUNITSLEN),
273
274 ('nPNPosition', c_short),
275 ('nPNNumPulses', c_short),
276 ('nPNPolarity', c_short),
277 ('fPNSettlingTime', c_float),
278 ('fPNInterpulse', c_float),
279 ('nLeakSubtractType', c_short * ABF_DACCOUNT),
280 ('fPNHoldingLevel', c_float * ABF_DACCOUNT),
281 ('nLeakSubtractADCIndex', c_short * ABF_DACCOUNT),
282
283 ('nLevelHysteresis', c_short),
284 ('lTimeHysteresis', c_long),
285 ('nAllowExternalTags', c_short),
286 ('nAverageAlgorithm', c_short),
287 ('fAverageWeighting', c_float),
288 ('nUndoPromptStrategy', c_short),
289 ('nTrialTriggerSource', c_short),
290 ('nStatisticsDisplayStrategy', c_short),
291 ('nExternalTagType', c_short),
292 ('lHeaderSize', c_long),
293 ('nStatisticsClearStrategy', c_short),
294
295 ('lEpochPulsePeriod', (c_long * ABF_EPOCHCOUNT) * ABF_DACCOUNT),
296 ('lEpochPulseWidth', (c_long * ABF_EPOCHCOUNT) * ABF_DACCOUNT),
297
298 ('nCreatorMajorVersion', c_short),
299 ('nCreatorMinorVersion', c_short),
300 ('nCreatorBugfixVersion', c_short),
301 ('nCreatorBuildVersion', c_short),
302 ('nModifierMajorVersion', c_short),
303 ('nModifierMinorVersion', c_short),
304 ('nModifierBugfixVersion', c_short),
305 ('nModifierBuildVersion', c_short),
306
307 ('nLTPType', c_short),
308 ('nLTPUsageOfDAC', c_short * ABF_DACCOUNT),
309 ('nLTPPresynapticPulses', c_short * ABF_DACCOUNT),
310
311 ('nScopeTriggerOut', c_short),
312
313 ('nAlternateDACOutputState', c_short),
314 ('nAlternateDigitalOutputState', c_short),
315 ('nAlternateDigitalValue', c_short * ABF_EPOCHCOUNT),
316 ('nAlternateDigitalTrainValue', c_short * ABF_EPOCHCOUNT),
317
318 ('fPostProcessLowpassFilter', c_float * ABF_ADCCOUNT),
319 ('nPostProcessLowpassFilterType', c_ubyte * ABF_ADCCOUNT),
320
321 ('fLegacyADCSequenceInterval', c_float),
322 ('fLegacyADCSecondSequenceInterval', c_float),
323 ('lLegacyClockChange', c_long),
324 ('lLegacyNumSamplesPerEpisode', c_long),
325 ('padding_in_case_more_bogus', c_long*10)]
326 P_ABFFileHeader = POINTER(ABFFileHeader)
327
328 abffio.ABF_IsABFFile.argtypes = (c_char_p, c_int_p, c_int_p)
329 abffio.ABF_IsABFFile.restype = BOOL
330
331 abffio.ABF_ReadOpen.argtypes = (c_char_p, c_int_p, c_uint, P_ABFFileHeader, c_uint_p, c_uint_p, c_int_p)
332 abffio.ABF_ReadOpen.restype = BOOL
333
334 abffio.ABF_Close.argtypes = (c_int, c_int_p)
335 abffio.ABF_Close.restype = BOOL
336
337 abffio.ABF_GetNumSamples.argtypes = (c_int, P_ABFFileHeader, c_uint, c_uint_p, c_int_p)
338 abffio.ABF_GetNumSamples.restype = BOOL
339
340 abffio.ABF_ReadChannel.argtypes = (c_int, P_ABFFileHeader, c_int, c_uint, c_float_p, c_uint_p, c_int_p)
341 abffio.ABF_ReadChannel.restype = BOOL
342
343 abffio.ABF_GetWaveform.argtypes = (c_int, P_ABFFileHeader, c_uint, c_uint, c_float_p, c_int_p)
344 abffio.ABF_GetWaveform.restype = BOOL
345
346 abffio.ABF_BuildErrorText.argtypes = (c_int, c_char_p, c_char_p, c_uint)
347 abffio.ABF_BuildErrorText.restype = BOOL
348
349 except:
350 abffio = None
351
352
360 - def read(self, first, last, latency=0, skip=1):
361 ifirst, ilast = [self.data.segmentation.index_at(x) for x in (first, last)]
362 if ifirst != ilast:
363 raise Exception("ABF: can't read() from multiple segments at once")
364 segfirst = self.data.segmentation.segments[ifirst][0]
365 seglast = self.data.segmentation.segments[ifirst][1]
366 return read_with_latency(self.read_in_seg, first, last, latency, skip, ifirst, segfirst, seglast)
367
368
370 - def __init__(self, data, channel, abfchannel, lNumSamplesPerEpisode):
371 """
372 @param data: L{QubData_QDF}
373 @param channel: integer 0-based signal index
374 @param abfchannel: == nADCSamplingSeq[channel]
375 """
376 QubData_ABF_Signal.__init__(self, data)
377 self.channel = channel
378 self.abfchannel = abfchannel
379 self.lNumSamplesPerEpisode = lNumSamplesPerEpisode
381 samples = numpy.zeros(dtype='float32', shape=(max(self.data.segmentation.segments[iseg][2], self.lNumSamplesPerEpisode),))
382 uNumSamples = c_uint()
383 print iseg, first, last, skip, samples.shape
384 abffio.ABF_ReadChannel(self.data.file, self.data.phdr, self.abfchannel, iseg+1,
385 samples.ctypes.data_as(c_float_p), byref(uNumSamples), self.data.pnError)
386 samples = numpy.array(samples[first:last+1], dtype='float32', copy=True)
387 scale = self.data.signals.get(self.channel, 'Scale')
388 if scale != 1.0:
389 samples *= scale
390 offset = self.data.signals.get(self.channel, 'Offset')
391 if offset != 0.0:
392 samples += offset
393 return samples
394
416
417
419 """One open Axon binary file.
420
421 @ivar file: c_int: file handle
422 @ivar nDataFormat: c_int
423 @ivar nError: c_int
424 @ivar hdr: L{ABFFileHeader}
425 """
427 QubData.__init__(self)
428 self.path = path
429 self.file = c_int()
430 self.hdr = ABFFileHeader()
431 self.phdr = pointer(self.hdr)
432 self.nDataFormat = c_int()
433 self.nError = c_int()
434 self.pnError = pointer(self.nError)
435 self.uMaxSamples = c_uint()
436 self.dwMaxEpi = c_uint()
437
438 if not abffio.ABF_IsABFFile(path, byref(self.nDataFormat), self.pnError):
439 raise Exception('%s is not an ABF file: '+self.last_error())
440 if not abffio.ABF_ReadOpen(path, byref(self.file), ABF_DATAFILE, self.phdr,
441 byref(self.uMaxSamples), byref(self.dwMaxEpi), self.pnError):
442 raise Exception('ABF_ReadOpen: '+self.last_error())
443 self.sampling = self.hdr.fADCSequenceInterval * 1e-6;
444
445 for c in xrange(self.hdr.nADCNumChannels):
446 c_abf = self.hdr.nADCSamplingSeq[c]
447 self.signals.append({'Name' : self.hdr.sADCChannelName[c_abf].value.strip(),
448 'Units' : self.hdr.sADCUnits[c_abf].value.strip()})
449 self.set_analog(c, QubData_ABF_Analog(self, c, c_abf, self.hdr.lNumSamplesPerEpisode))
450
451 seglen = c_uint()
452 abffio.ABF_GetNumSamples(self.file, self.phdr, 1, byref(seglen), self.pnError)
453 testbuf = (c_float * seglen.value)()
454
455 for c in xrange(ABF_DACCOUNT):
456 if abffio.ABF_GetWaveform(self.file, self.phdr, c, 1, testbuf, self.pnError):
457 self.signals.append({'Name': self.hdr.sDACChannelName[c].value.strip(),
458 'Units' : self.hdr.sDACChannelUnits[c].value.strip()})
459 self.set_analog(self.signals.size-1, QubData_ABF_Waveform(self, c, self.hdr.lNumSamplesPerEpisode))
460
461 last = -1
462 for i in xrange(1, self.dwMaxEpi.value + 1):
463 abffio.ABF_GetNumSamples(self.file, self.phdr, i, byref(seglen), self.pnError)
464 first = last + 1
465 last = first + seglen.value - 1
466 self.segmentation.add_seg(first, last, self.sampling*1e3*first)
467
468 base, ext = os.path.splitext(path)
469 sess = qubx.tree.Open(base+'.qsf', True)
470 sess.close()
471
472
473 for chan in qubx.tree.children(sess.find('DataChannels'), 'Channel'):
474 chan['Scaling'].data = 1.0
475 chan['Offset'].data = 0.0
476
477 self.read_session(sess, progressf)
478
481
487
489 buf = create_string_buffer(maxlen)
490 abffio.ABF_BuildErrorText(self.nError, self.path, buf, maxlen-1)
491 return buf.value.strip()
492
493
494 fallback_reader = None
495
504
505 if abffio:
506 fallback_reader = SetReader('.dat', 'DAT files', QubData_ABF_Open)
507 SetReader('.abf', 'Axon binary files', QubData_ABF_Open)
508