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

Source Code for Module qubx.acquirefile

  1  #acquirefile.py: reads *.acquire data files.  By Chris Nicolai.  Thanks to Bruxton for sharing AcquireFormat.h.
 
  2  
 
  3  #// AcquireFormat.h
 
  4  #//
 
  5  #// Copyright (c) 1999 Bruxton Corporation
 
  6  #//
 
  7  #// Author: Joseph Grote
 
  8  #
 
  9  #// Bruxton Corporation Acquire data format.
 
 10  #
 
 11  #// The file is written with Intel byte ordering.
 
 12  #
 
 13  #// This file format is designed so that all values are 8 byte aligned.
 
 14  #
 
 15  #// Data is always written to the file in multiples of ACQUIRE_BLOCK_SIZE.
 
 16  #
 
 17  #// The data file has a hierarchical structure, organized as series, sweeps
 
 18  #// and segments. Within segments there are channels and data blocks.
 
 19  #
 
 20  #// The file format is as follows:
 
 21  #
 
 22  #//*****************************************************************
 
 23  #// header
 
 24  #// file prefix block
 
 25  #// sweep prefix block
 
 26  #// data block
 
 27  #// data block
 
 28  #//             .
 
 29  #//             .
 
 30  #// sweep block
 
 31  #// sweep prefix block
 
 32  #// data block
 
 33  #//             .
 
 34  #//             .
 
 35  #// series block
 
 36  #// sweep block
 
 37  #//             .
 
 38  #//             .
 
 39  #//             .
 
 40  #// series block
 
 41  #// control block
 
 42  #// header
 
 43  #// AcquirePrefix
 
 44  #//*****************************************************************
 
 45  #
 
 46  #// the header contains 
 
 47  #// AcquirePrefix
 
 48  #// AcquireHeader
 
 49  #
 
 50  #// AcquirePrefix is duplicated at the end of the file in an ACQUIRE_BLOCK_SIZE size block
 
 51  #// in order to be consistent with previous versions of the file format.
 
 52  #// DataAccess first checks the the last block to determine the file type and version.
 
 53  #
 
 54  #// The file prefix block contains:
 
 55  #
 
 56  #// array of channel records, grouped in the following order:
 
 57  #
 
 58  #// AcquireAnalogInChannelRecords
 
 59  #// AcquireAperiodicChannelRecords
 
 60  #
 
 61  #// A series block contains:
 
 62  #
 
 63  #// AcquireSeriesDescriptor
 
 64  #// directory of sweep prefix block offsets within the control block.
 
 65  #
 
 66  #// a sweep prefix block contains:
 
 67  #
 
 68  #// array of analog_in_channel_count AcquireSweepPrefixAnalogChannel
 
 69  #// array of aperiodic_channel_count AcquireSweepPrefixAperiodicChannel
 
 70  #
 
 71  #// a data block contains a block of data.
 
 72  #
 
 73  #// a sweep block contains:
 
 74  #
 
 75  #// AcquireSweepDescriptor
 
 76  #// AcquireChannelDescriptor    for the control channels
 
 77  #// AcquireBlockDescriptors for the control channels
 
 78  #// AcquireChannelDescriptor    for the control channel extended data
 
 79  #// AcquireBlockDescriptors for the control channel extended data
 
 80  #// Segment directory listing AcquireSegmentDescriptor offsets within the control block
 
 81  #// AcquireSegmentDescriptor
 
 82  #// Channel directory listing AcquireChannelDescriptor offsets within the control block
 
 83  #//    for the analog input channels
 
 84  #// AcquireChannelDescriptor
 
 85  #// AcquireBlockDescriptors
 
 86  #//             .
 
 87  #//             .
 
 88  #//             .
 
 89  #// AcquireSegmentDescriptor
 
 90  #// Channel directory
 
 91  #// AcquireChannelDescriptor
 
 92  #// AcquireBlockDescriptors
 
 93  #//             .
 
 94  #//             .
 
 95  #//             .
 
 96  #
 
 97  #// the control block contains:
 
 98  #
 
 99  #// array of channel records, grouped in the following order:
 
100  #
 
101  #// AcquireAnalogInChannelRecords
 
102  #// AcquireAperiodicChannelRecords
 
103  #
 
104  #// repeat of series, sweep prefix and sweep blocks (without individual block tags
 
105  #// and block boundary padding).
 
106  #// a directory of series block offsets within the control block
 
107  #
 
108  #// V6.1 Set data_size in tags for all block types except the header blocks.
 
109  #
 
110  
 
111  import mmap 
112  import numpy 
113  import os 
114  import struct 
115  import traceback 
116  from math import * 
117  
 
118  ACQUIRE_FORMAT = 1 
119  ACQUIRE_BLOCK_SIZE = 1024 
120  ACQUIRE_FILE_COMMENT_SIZE = 256 
121  ACQUIRE_COMMENT_SIZE = 80 
122  ACQUIRE_FILE_TECHNIQUE_SIZE = 256 
123  ACQUIRE_TECHNIQUE_SIZE = 80 
124  ACQUIRE_SCREEN_SIZE = 80 
125  ACQUIRE_LABEL_SIZE = 16 
126  ACQUIRE_UNITS_SIZE = 16 
127  ACQUIRE_SIGNAL_SIZE = 32 
128  ACQUIRE_CONTROL_NAME_SIZE = 80 
129  ACQUIRE_USER_NAME_SIZE = 64 
130  ACQUIRE_COMPUTER_NAME_SIZE = 64 
131  
 
132  try: 
133      from qubx.fast.data import decode_acquirefile_samples 
134  except: 
135 - def decode_acquirefile_samples(src_8, src_16, src_16s, dest, size, count):
136 i_dest = 0 137 i_src = 0 138 val = 0 139 while i_src < size: 140 c = src[i_src] 141 if c == -128: 142 i_src += 1 143 if i_src % 2: 144 val = src_16s[i_src/2] 145 else: 146 val = src_16[i_src/2] 147 i_src += 2 148 else: 149 val += c 150 i_src += 1 151 dest[i_dest] = val 152 i_dest += 1
153 154 155
156 -def read_string8(buf, loc_bytes, count):
157 next = loc_bytes + count 158 s = str(buf[loc_bytes:next]) 159 terminator = s.find(chr(0)) 160 if terminator >= 0: 161 s = s[:terminator] 162 return s, next
163
164 -def read_string16(buf, loc_bytes, count):
165 next = loc_bytes+2*count 166 s = unicode(buf[loc_bytes:next], encoding='UTF-16') 167 terminator = s.find(chr(0)) 168 if terminator >= 0: 169 s = s[:terminator] 170 return s, next
171
172 -def read_struct(buf, loc_bytes, format):
173 bytes = struct.calcsize(format) 174 next = loc_bytes+bytes 175 return list(struct.unpack(format, buf[loc_bytes:next])) + [next]
176 177 # 178 #// AcquirePrefix contains information to go at the head of the file. 179 #// It contains the same fields for all file format versions. 180 # 181 #// Note that Acquire file format version 1 uses the reserved space 182 #// and is in Macintosh byte ordering. 183 #// See SKALARFormatV1.h. 184 # 185 #struct AcquirePrefix 186 #{ 187 # int8_t vendor[8]; // company name 188 # int32_t format; // application 189 # int32_t version; // version number 190 # int64_t minor_version; 191 # int64_t reserved[3]; 192 #};
193 -class AcquirePrefix(object):
194 - def __init__(self, buf, loc_bytes):
195 self.loc_bytes = loc_bytes 196 self.vendor, loc_bytes = read_string8(buf, loc_bytes, 8) 197 self.format, self.version, self.minor_version, r1, r2, r3, self.next_loc_bytes = read_struct(buf, loc_bytes, 'iiqqqq') 198 self.reserved = (r1, r2, r3)
199 # 200 ##ifndef __cplusplus 201 #typedef struct AcquirePrefix AcquirePrefix; 202 ##endif 203 # 204 #// AcquireHeader 205 # 206 #struct AcquireHeader 207 #{ 208 # 209 # int64_t date_time; // date/time created in 100 ns units from Jan 1 1601 210 # int64_t file_tag; // file tag used for reconstruction of damaged data 211 # // use the same value in mBlockTag 212 # int16_t comment[ACQUIRE_FILE_COMMENT_SIZE]; 213 # int16_t technique[ACQUIRE_FILE_TECHNIQUE_SIZE]; 214 # double clock_rate; // base clock rate in Hz 215 # int64_t frame_interval; // frame interval in clock ticks 216 # int64_t analog_in_channel_count; 217 # int64_t analog_in_maximum_block_size; // maximum possible size of a data block in bytes 218 # int64_t analog_in_maximum_data_count; // maximum data values per data block 219 # int64_t aperiodic_channel_count; 220 # int64_t aperiodic_maximum_block_size; // maximum possible size of a data block in bytes 221 # int64_t series_count; 222 # int64_t file_size; // file size in bytes 223 # int64_t control_size; // size of the control block in bytes 224 # int64_t control_position; // position of control block in the file 225 # int64_t directory_position; // series directory offset in control block 226 # int16_t user_name[ACQUIRE_USER_NAME_SIZE]; // Current logged in user. 227 # int16_t computer_name[ACQUIRE_USER_NAME_SIZE]; // Current logged in user. 228 #};
229 -class AcquireHeader(object):
230 - def __init__(self, buf, loc_bytes):
231 self.loc_bytes = loc_bytes 232 self.date_time, self.file_tag, loc_bytes = read_struct(buf, loc_bytes, 'qq') 233 self.comment, loc_bytes = read_string16(buf, loc_bytes, ACQUIRE_FILE_COMMENT_SIZE) 234 self.technique, loc_bytes = read_string16(buf, loc_bytes, ACQUIRE_FILE_TECHNIQUE_SIZE) 235 (self.clock_rate, 236 self.frame_interval, 237 self.analog_in_channel_count, 238 self.analog_in_maximum_block_size, 239 self.analog_in_maximum_data_count, 240 self.aperiodic_channel_count, 241 self.aperiodic_maximum_block_size, 242 self.series_count, 243 self.file_size, 244 self.control_size, 245 self.control_position, 246 self.directory_position, 247 loc_bytes) = read_struct(buf, loc_bytes, 'dqqqqqqqqqqq') 248 self.user_name, loc_bytes = read_string16(buf, loc_bytes, ACQUIRE_USER_NAME_SIZE) 249 self.computer_name, self.next_loc_bytes = read_string16(buf, loc_bytes, ACQUIRE_USER_NAME_SIZE)
250 # 251 ##ifndef __cplusplus 252 #typedef struct AcquireHeader AcquireHeader; 253 ##endif 254 # 255 #// AcquireSeriesDescriptor 256 # 257 #struct AcquireSeriesDescriptor 258 #{ 259 # int16_t comment[ACQUIRE_COMMENT_SIZE]; 260 # int16_t technique[ACQUIRE_TECHNIQUE_SIZE]; 261 # int64_t start_time; // time of start of series 100 ns units from Jan 1 1601 262 # int64_t sweep_count; 263 #};
264 -class AcquireSeriesDescriptor(object):
265 - def __init__(self, buf, loc_bytes):
266 self.loc_bytes = loc_bytes 267 self.comment, loc_bytes = read_string16(buf, loc_bytes, ACQUIRE_COMMENT_SIZE) 268 self.technique, loc_bytes = read_string16(buf, loc_bytes, ACQUIRE_TECHNIQUE_SIZE) 269 self.start_time, self.sweep_count, self.next_loc_bytes = read_struct(buf, loc_bytes, 'qq')
270 # 271 ##ifndef __cplusplus 272 #typedef struct AcquireSeriesDescriptor AcquireSeriesDescriptor; 273 ##endif 274 # 275 #// AcquireSweepPrefixAnalogChannel 276 # 277 #// Channel sweep prefix for analog channels. 278 #// Gain is the conversion from V to the SI units representing an external amplifier. 279 #// In version 6.0 offset is a place holder for potential amplifiers that supply an offset. 280 #// It should always be 0. 281 # 282 #struct AcquireSweepPrefixAnalogChannel 283 #{ 284 # double maximum_voltage; 285 # double minimum_voltage; 286 # int64_t maximum_value; 287 # int64_t minimum_value; 288 # double gain; 289 # double offset; 290 #};
291 -class AcquireSweepPrefixAnalogChannel(object):
292 - def __init__(self, buf, loc_bytes):
293 self.loc_bytes = loc_bytes 294 (self.maximum_voltage, self.minimum_voltage, 295 self.maximum_value, self.minimum_value, 296 self.gain, self.offset, 297 self.next_loc_bytes) = read_struct(buf, loc_bytes, 'ddqqdd')
298 # 299 ##ifndef __cplusplus 300 #typedef struct AcquireSweepPrefixAnalogChannel AcquireSweepPrefixAnalogChannel; 301 ##endif 302 # 303 #// AcquireSweepPrefixAperiodicChannel 304 # 305 #// Channel sweep prefix for control channels. 306 #// value is the control holding value. 307 # 308 #struct AcquireSweepPrefixAperiodicChannel 309 #{ 310 # double value; 311 # int64_t reserved[4]; 312 #};
313 -class AcquireSweepPrefixAperiodicChannel(object):
314 - def __init__(self, buf, loc_bytes):
315 self.loc_bytes = loc_bytes 316 self.value, r1, r2, r3, r4, self.next_loc_bytes = read_struct(buf, loc_bytes, 'dqqqq')
317 # 318 ##ifndef __cplusplus 319 #typedef struct AcquireSweepPrefixAperiodicChannel AcquireSweepPrefixAperiodicChannel; 320 ##endif 321 # 322 #// AcquireSweepDescriptor 323 # 324 #struct AcquireSweepDescriptor 325 #{ 326 # int16_t comment[ACQUIRE_COMMENT_SIZE]; 327 # int16_t technique[ACQUIRE_TECHNIQUE_SIZE]; 328 # int16_t screen[ACQUIRE_SCREEN_SIZE]; 329 # int64_t start_time; // time of start of sweep 100 ns units from Jan 1 1601 330 # int64_t segment_count; 331 # int64_t duration; // sweep duration in frames 332 # int64_t control_data_location; // Location of the control data channel descriptor in the control block. 333 # int64_t segment_location; // Location of the segment directory in the control block. 334 #};
335 -class AcquireSweepDescriptor(object):
336 - def __init__(self, buf, loc_bytes):
337 self.loc_bytes = loc_bytes 338 self.comment, loc_bytes = read_string16(buf, loc_bytes, ACQUIRE_COMMENT_SIZE) 339 self.technique, loc_bytes = read_string16(buf, loc_bytes, ACQUIRE_TECHNIQUE_SIZE) 340 self.screen, loc_bytes = read_string16(buf, loc_bytes, ACQUIRE_SCREEN_SIZE) 341 (self.start_time, self.segment_count, 342 self.duration, self.control_data_location, 343 self.segment_location, self.next_loc_bytes) = read_struct(buf, loc_bytes, 'qqqqq')
344 # 345 ##ifndef __cplusplus 346 #typedef struct AcquireSweepDescriptor AcquireSweepDescriptor; 347 ##endif 348 # 349 #// AcquireSegmentDescriptor 350 # 351 #struct AcquireSegmentDescriptor 352 #{ 353 # int64_t start; // start time in frames from the start of the sweep 354 # int64_t duration; // segment duration in frames 355 #};
356 -class AcquireSegmentDescriptor(object):
357 - def __init__(self, buf, loc_bytes):
358 self.loc_bytes = loc_bytes 359 self.start, self.duration, self.next_loc_bytes = read_struct(buf, loc_bytes, 'qq')
360 # 361 ##ifndef __cplusplus 362 #typedef struct AcquireSegmentDescriptor AcquireSegmentDescriptor; 363 ##endif 364 # 365 #// AcquireChannelDescriptor 366 # 367 #struct AcquireChannelDescriptor 368 #{ 369 # int64_t block_count; 370 #};
371 -class AcquireChannelDescriptor(object):
372 - def __init__(self, buf, loc_bytes):
373 self.loc_bytes = loc_bytes 374 self.block_count, self.next_loc_bytes = read_struct(buf, loc_bytes, 'q')
375 # 376 ##ifndef __cplusplus 377 #typedef struct AcquireChannelDescriptor AcquireChannelDescriptor; 378 ##endif 379 # 380 #// AcquireBlockDescriptor 381 # 382 #struct AcquireBlockDescriptor 383 #{ 384 # int64_t size; // block size in bytes 385 # int64_t data_count; 386 # int64_t data_size; // data size in bytes 387 # int64_t location; // data block location within the file 388 #};
389 -class AcquireBlockDescriptor(object):
390 - def __init__(self, buf, loc_bytes):
391 self.loc_bytes = loc_bytes 392 self.size, self.data_count, self.data_size, self.location, self.next_loc_bytes = read_struct(buf, loc_bytes, 'qqqq')
393 # 394 ##ifndef __cplusplus 395 #typedef struct AcquireBlockDescriptor AcquireBlockDescriptor; 396 ##endif 397 # 398 #// AcquireAnalogInChannelRecord 399 # 400 #// Channel record for analog input channels. 401 # 402 #// natural_scale is the power of 1000 to multiply the units to get the natural units. 403 #// E.g., if units are A and the natural units are pA, natural_scale is -4. 404 # 405 #struct AcquireAnalogInChannelRecord 406 #{ 407 # int16_t label[ACQUIRE_LABEL_SIZE]; // physical channel identification in wide chars 408 # int16_t signal[ACQUIRE_SIGNAL_SIZE]; // channel description in wide chars 409 # int16_t units[ACQUIRE_UNITS_SIZE]; // SI units of the data. 410 # int64_t natural_scale; // natural_scale scale conversion. 411 #};
412 -class AcquireAnalogInChannelRecord(object):
413 - def __init__(self, buf, loc_bytes):
414 self.loc_bytes = loc_bytes 415 self.label, loc_bytes = read_string16(buf, loc_bytes, ACQUIRE_LABEL_SIZE) 416 self.signal, loc_bytes = read_string16(buf, loc_bytes, ACQUIRE_SIGNAL_SIZE) 417 self.units, loc_bytes = read_string16(buf, loc_bytes, ACQUIRE_UNITS_SIZE) 418 self.natural_scale, self.next_loc_bytes = read_struct(buf, loc_bytes, 'q')
419 # 420 ##ifndef __cplusplus 421 #typedef struct AcquireAnalogInChannelRecord AcquireAnalogInChannelRecord; 422 ##endif 423 # 424 #// AcquireAperiodicChannelRecord 425 # 426 #struct AcquireAperiodicChannelRecord 427 #{ 428 # int64_t type; 429 # int16_t name[ACQUIRE_CONTROL_NAME_SIZE]; 430 # int16_t description[ACQUIRE_COMMENT_SIZE]; 431 # int16_t signal[ACQUIRE_SIGNAL_SIZE]; 432 # int16_t units[ACQUIRE_UNITS_SIZE]; 433 # int64_t natural_scale; // natural_scale scale conversion. 434 # int64_t reserved[8]; 435 #};
436 -class AcquireAperiodicChannelRecord(object):
437 - def __init__(self, buf, loc_bytes):
438 self.loc_bytes = loc_bytes 439 self.type, loc_bytes = read_struct(buf, loc_bytes, 'q') 440 self.name, loc_bytes = read_string16(buf, loc_bytes, ACQUIRE_CONTROL_NAME_SIZE) 441 self.description, loc_bytes = read_string16(buf, loc_bytes, ACQUIRE_COMMENT_SIZE) 442 self.signal, loc_bytes = read_string16(buf, loc_bytes, ACQUIRE_SIGNAL_SIZE) 443 self.units, loc_bytes = read_string16(buf, loc_bytes, ACQUIRE_UNITS_SIZE) 444 ints = read_struct(buf, loc_bytes, '9q') 445 self.natural_scale = ints[0] 446 self.reserved = ints[1:-1] 447 self.next_loc_bytes = ints[-1]
448 # 449 ##ifndef __cplusplus 450 #typedef struct AcquireAperiodicChannelRecord AcquireAperiodicChannelRecord; 451 ##endif 452 # 453 #// Aperiodic channel types. 454 # 455 #enum 456 #{ 457 ACQUIRE_APERIODIC_CHANNEL_CONTROL = 0 458 ACQUIRE_APERIODIC_CHANNEL_IMAGE = 1 459 #}; 460 # 461 #// AcquireAperiodicEntry 462 # 463 #// Entry for an aperidic channel. 464 #// The entry may contain an attached text string, data and extended data. 465 #// The int16_t text string immediately follows the marker in memory. 466 #// The text string is zero terminated. 467 #// The data immediately follows the text in memory. 468 #// The extended data is stored as a block in the extended data channel. 469 # 470 #struct AcquireAperiodicEntry 471 #{ 472 # int64_t entry_size; // size in bytes including the text string and data. 473 # int64_t control_channel; 474 # int64_t frame; 475 # double value; 476 # int64_t text_size; // size of the text string in characters including the terminating zero. 477 # int64_t data_size; // size of the data in bytes. 478 # int64_t extended_data_size; // size of the extended data in bytes. 479 # int64_t extended_block_index; // block index of the extended data. 480 #};
481 -class AcquireAperiodicEntry(object):
482 - def __init__(self, buf, loc_bytes):
483 self.loc_bytes = loc_bytes 484 (self.entry_size, self.control_channel, 485 self.frame, self.value, 486 self.text_size, self.data_size, 487 self.extended_data_size, self.extended_block_index, 488 self.next_loc_bytes) = read_struct(buf, loc_bytes, 'qqqdqqqq')
489 # 490 ##ifndef __cplusplus 491 #typedef struct AcquireAperiodicEntry AcquireAperiodicEntry; 492 ##endif 493 # 494 #// mBlockTag 495 # 496 #// A tag to prepend all blocks to be used in reconstruction 497 #// of damaged data files. 498 # 499 #struct AcquireBlockTag 500 #{ 501 # int64_t file_tag; // same as AcquireHeader.file_tag 502 # int64_t block_index; 503 # int64_t block_type; // block type, enumerated below 504 # int64_t block_size; // block size in bytes 505 # int64_t data_count; 506 # int64_t data_size; // data size in bytes 507 # int64_t channel; 508 # int64_t frame; 509 #};
510 -class AcquireBlockTag(object):
511 - def __init__(self, buf, loc_bytes):
512 self.loc_bytes = loc_bytes 513 (self.file_tag, self.block_index, 514 self.block_type, self.block_size, 515 self.data_count, self.data_size, 516 self.channel, self.frame, 517 self.next_loc_bytes) = read_struct(buf, loc_bytes, 'qqqqqqqq')
518 # 519 ##ifndef __cplusplus 520 #typedef struct AcquireBlockTag AcquireBlockTag; 521 ##endif 522 # 523 #// Block types. 524 # 525 #enum 526 # 527 ACQUIRE_DATA_BLOCK = 1 528 ACQUIRE_SWEEP_BLOCK = 2 529 ACQUIRE_CONTROL_BLOCK = 3 530 ACQUIRE_SERIES_BLOCK = 4 531 ACQUIRE_FILE_PREFIX_BLOCK = 5 532 ACQUIRE_SWEEP_PREFIX_BLOCK = 6 533 #; 534 # 535 ##endif 536
537 -def round_up(i, divisor):
538 return divisor * int(ceil(i*1.0/divisor))
539
540 -def ReadHeader(buf):
541 prefix = AcquirePrefix(buf, 0) 542 if prefix.format != ACQUIRE_FORMAT: 543 raise IOError('Unknown format or invalid file: format %i' % prefix.format) 544 if not (2 <= prefix.version <= 6): 545 raise IOError('Unknown version or invalid file: version %i' % prefix.version) 546 header = AcquireHeader(buf, prefix.next_loc_bytes) 547 header.prefix = prefix 548 return header, round_up(header.next_loc_bytes, ACQUIRE_BLOCK_SIZE)
549
550 -class Block(object):
551 - def __init__(self, tag):
552 self.tag = tag
553
554 -def ReadFilePrefix(buf, loc_bytes, block, header):
555 ai_ch, ap_ch = [], [] 556 for i in xrange(header.analog_in_channel_count): 557 chan = AcquireAnalogInChannelRecord(buf, loc_bytes) 558 ai_ch.append(chan) 559 loc_bytes = chan.next_loc_bytes 560 for i in xrange(header.aperiodic_channel_count): 561 chan = AcquireAperiodicChannelRecord(buf, loc_bytes) 562 ap_ch.append(chan) 563 loc_bytes = chan.next_loc_bytes 564 block.analog_in_channel_records = ai_ch 565 block.aperiodic_channel_records = ap_ch
566
567 -def ReadSweepPrefix(buf, loc_bytes, block, header):
568 ai_ch_pre, ap_ch_pre = [], [] 569 for i in xrange(header.analog_in_channel_count): 570 chan = AcquireSweepPrefixAnalogChannel(buf, loc_bytes) 571 ai_ch_pre.append(chan) 572 loc_bytes = chan.next_loc_bytes 573 for i in xrange(header.aperiodic_channel_count): 574 chan = AcquireSweepPrefixAperiodicChannel(buf, loc_bytes) 575 ap_ch_pre.append(chan) 576 loc_bytes = chan.next_loc_bytes 577 block.analog_in_channel_prefixes = ai_ch_pre 578 block.aperiodic_channel_prefixes = ap_ch_pre
579
580 -def ReadSweep(buf, loc_bytes, block, header):
581 sweep = AcquireSweepDescriptor(buf, loc_bytes) 582 sweep.ctrl_channels = [] 583 ctrl_channels = AcquireChannelDescriptor(buf, sweep.next_loc_bytes) 584 loc_bytes = ctrl_channels.next_loc_bytes 585 for i in xrange(ctrl_channels.block_count): 586 chan = AcquireBlockDescriptor(buf, loc_bytes) 587 loc_bytes = chan.next_loc_bytes 588 sweep.ctrl_channels.append(chan) 589 sweep.ctrl_channels_ext = [] 590 ctrl_channels_ext = AcquireChannelDescriptor(buf, loc_bytes) 591 loc_bytes = ctrl_channels_ext.next_loc_bytes 592 for i in xrange(ctrl_channels_ext.block_count): 593 chan = AcquireBlockDescriptor(buf, loc_bytes) 594 loc_bytes = chan.next_loc_bytes 595 sweep.ctrl_channels_ext.append(chan) 596 ints = read_struct(buf, loc_bytes, '%iq'%sweep.segment_count) 597 sweep.segment_dir, loc_bytes = ints[:-1], ints[-1] 598 ints = read_struct(buf, loc_bytes, '%iq'%header.analog_in_channel_count) 599 sweep.channel_dir, loc_bytes = ints[:-1], ints[-1] 600 sweep.segments = [] 601 for i in xrange(sweep.segment_count): 602 seg = AcquireSegmentDescriptor(buf, loc_bytes) 603 loc_bytes = seg.next_loc_bytes 604 seg.channels = [] 605 for j in xrange(header.analog_in_channel_count): 606 chan_d = AcquireChannelDescriptor(buf, loc_bytes) 607 loc_bytes = chan_d.next_loc_bytes 608 blocks = [] 609 for k in xrange(chan_d.block_count): 610 block_desc = AcquireBlockDescriptor(buf, loc_bytes) 611 loc_bytes = block_desc.next_loc_bytes 612 blocks.append(block_desc) 613 seg.channels.append(blocks) 614 sweep.segments.append(seg) 615 block.sweep = sweep
616
617 -def ReadSeries(buf, loc_bytes, block, header):
618 series = AcquireSeriesDescriptor(buf, loc_bytes) 619 loc_bytes = series.next_loc_bytes 620 ints = read_struct(buf, loc_bytes, '%iq'%series.sweep_count) 621 series.sweep_dir = ints[:-1] 622 block.series = series
623
624 -def ReadBlock(buf, loc_bytes, header):
625 tag = AcquireBlockTag(buf, loc_bytes) 626 block = Block(tag) 627 if tag.block_type == ACQUIRE_FILE_PREFIX_BLOCK: 628 ReadFilePrefix(buf, tag.next_loc_bytes, block, header) 629 elif tag.block_type == ACQUIRE_SWEEP_PREFIX_BLOCK: 630 ReadSweepPrefix(buf, tag.next_loc_bytes, block, header) 631 #elif tag.block_type == ACQUIRE_DATA_BLOCK: 632 elif tag.block_type == ACQUIRE_SWEEP_BLOCK: 633 ReadSweep(buf, tag.next_loc_bytes, block, header) 634 elif tag.block_type == ACQUIRE_SERIES_BLOCK: 635 ReadSeries(buf, tag.next_loc_bytes, block, header) 636 #elif tag.block_type == ACQUIRE_CONTROL_BLOCK: 637 return block, round_up(loc_bytes + tag.block_size, ACQUIRE_BLOCK_SIZE)
638 639 640 641 642
643 -class AcquireFile(object):
644 - def __init__(self, path):
645 size = os.stat(path)[6] 646 self.fileno = os.open(path, os.O_RDONLY) 647 self.mmap = mmap.mmap(self.fileno, size, access=mmap.ACCESS_READ) 648 self.ai_channels = [] 649 self.series = [] 650 self.data_by_loc_bytes = {} 651 self.header = None 652 self.file_prefix = None 653 self.control = None 654 try: 655 self.read_blocks() 656 except: 657 if not (self.header and self.file_prefix and self.series): 658 raise 659 else: 660 traceback.print_exc() 661 self.sampling_sec = self.header.frame_interval * 1.0 / self.header.clock_rate
662 - def __del__(self):
663 self.close()
664 - def close(self):
665 if self.mmap: 666 self.mmap.close() 667 self.mmap = None 668 os.close(self.fileno)
669 - def read_blocks(self):
670 self.header, loc_bytes = ReadHeader(self.mmap) 671 # collectors for this/next series: 672 self.sweep_prefix = None 673 self.sweeps = [] 674 while True: 675 block, next_loc_bytes = ReadBlock(self.mmap, loc_bytes, self.header) 676 if block.tag.block_type == ACQUIRE_FILE_PREFIX_BLOCK: 677 self.file_prefix = block 678 self.ai_channels = self.file_prefix.analog_in_channel_records 679 elif block.tag.block_type == ACQUIRE_SWEEP_PREFIX_BLOCK: 680 self.sweep_prefix = block 681 elif block.tag.block_type == ACQUIRE_DATA_BLOCK: 682 self.data_by_loc_bytes[loc_bytes] = block 683 elif block.tag.block_type == ACQUIRE_SWEEP_BLOCK: 684 self.sweeps.append(block) 685 block.prefix = self.sweep_prefix 686 self.sweep_prefix = None 687 elif block.tag.block_type == ACQUIRE_SERIES_BLOCK: 688 self.series.append(block) 689 block.sweeps = self.sweeps 690 self.sweeps = [] 691 elif block.tag.block_type == ACQUIRE_CONTROL_BLOCK: 692 self.control = block 693 break # no more useful blocks 694 loc_bytes = next_loc_bytes
695 - def read_data_int16(self, series, sweep, segment, channel, offset, count):
696 data = numpy.zeros(shape=(count,), dtype='int16') 697 ser = self.series[series] 698 swp = ser.sweeps[sweep] 699 seg = swp.sweep.segments[segment] 700 chn = seg.channels[channel] 701 at = 0 702 b = 0 703 while b < len(chn): 704 if offset < (at + chn[b].data_count): 705 break 706 else: 707 at += chn[b].data_count 708 b += 1 709 into = 0 710 while count and (b < len(chn)): 711 start = offset - at 712 count_here = min(count, chn[b].data_count - start) 713 segdata = self.decode(chn[b]) 714 data[into:into+count_here] = segdata[start:start+count_here] 715 into += count_here 716 count -= count_here 717 offset += count_here 718 at += chn[b].data_count 719 b += 1 720 return data
721 - def read_data_float32(self, series, sweep, segment, channel, offset, count):
722 ser = self.series[series] 723 swp = ser.sweeps[sweep] 724 ch_fi = self.file_prefix.analog_in_channel_records[channel] 725 ch_pre = swp.prefix.analog_in_channel_prefixes[channel] 726 idata = self.read_data_int16(series, sweep, segment, channel, offset, count) 727 fdata = idata.astype('float32') 728 fdata *= ( (1.0 / (ch_pre.gain * pow(1e3, ch_fi.natural_scale))) 729 * (ch_pre.maximum_voltage - ch_pre.minimum_voltage) / (ch_pre.maximum_value - ch_pre.minimum_value)) 730 return fdata
731 - def decode(self, block_desc):
732 count = block_desc.data_count 733 size = block_desc.data_size 734 block = self.data_by_loc_bytes[block_desc.location] 735 loc = block.tag.next_loc_bytes 736 src = numpy.frombuffer(self.mmap, 'int8', size, loc) 737 src_16 = numpy.frombuffer(self.mmap, numpy.dtype('>i2'), size/2, loc) 738 src_16s = numpy.frombuffer(self.mmap, numpy.dtype('>i2'), size/2, loc+1) 739 dest = numpy.zeros(shape=(count,), dtype='int16') 740 decode_acquirefile_samples(src, src_16, src_16s, dest, size, count) 741 return dest
742 743 744 # .acquire version _version_._minor_version_ by _vendor_ 745 # _date_time_ 746 # _comment_ 747 # _technique_ 748 # _user_name_ @ _computer_name_ 749 750 # Series _i_: 751 # _comment_ 752 # _technique_ 753 # [Sweep _j_: _comment_ / _technique_] 754 755 756 757 # segment relative dates 758 # channel nameL _label_ (_signal_) 759 # scaling and units 760 761 # qdf use scaling=scaling[0]; dcscaling[i] = scaling[i]/scaling[0] 762 763
764 -def ScaleUnit(value, sUnit=''):
765 """Returns a scaled value of "val" as function return with a single character unit 766 scaler from the metric scale set as a tuple of the form (Scaled Value, Scaler Char+sUnit)""" 767 if value: 768 SuffixIndex=int(floor(log10(abs(value))/3)) 769 if SuffixIndex!=0: 770 771 #Tack on the scale character. Note that SuffixIndex will be -1 for milli, -2 772 #for micro, etc. Since 'm' is the 6th character in the suffix array, we need 773 #to add 6 to get -1 (for milli) to point at the 6th character. It also means that 774 #we must limit the index to be between -6 (+6=0, the first character) and 4 775 #(+6=10, the last character). 776 777 SuffixIndex = EnsureRange(SuffixIndex,-6,4) 778 return (value*10**(-3*SuffixIndex),'afpnum%KMGT'[SuffixIndex+6]+sUnit); 779 return (value,sUnit)
780 781 782 783 if __name__ == '__main__': 784 import sys 785 from itertools import * 786 787 f = AcquireFile(sys.argv[1]) 788 for r, series in enumerate(f.series): 789 #print 'Series %i:' % (r+1) 790 for w, sweep in enumerate(series.sweeps): 791 #print 'Sweep %i:' % (w+1) 792 for g, seg in enumerate(sweep.sweep.segments): 793 #print 'Segment %i:' % (g+1) 794 at = 0 795 for chans in izip(*seg.channels): 796 bufs = [f.read_data_float32(r, w, g, c, at, block.data_count) for c, block in enumerate(chans)] 797 #bufs = [f.read_data_int16(r, w, g, c, at, block.data_count) for c, block in enumerate(chans)] 798 at += len(bufs[0]) 799 for nums in izip(*bufs): 800 print '\t'.join([str(x) for x in nums]) 801 print 802