Source code for sparkle.data.ParsePST

"""This file is as close to a direct translation of ParsePST.m as possible. 
If you are trying to access Batlab data, make sure you don't a 
:meth:`sparkly version<sparkle.data.open.open_acqdata>` instead.
"""

import re


[docs]def parse_pst(filename): # just go ahead and read the whole file in one go with open(filename) as fh: file_contents = fh.read() # windows adds carriage returns in addition to newlines file_contents = file_contents.translate(None, '\r') lines = file_contents.split('\n') # print lines # %Static strings test_aborted = 'Test aborted.' end_id = 'End of ID information' end_test_parameters = 'End of test parameters' end_spike_data = 'End of spike data' end_auto_test = 'End of auto test' test_types = ['tone', 'fmsweep', 'synthesized_batsound', 'amsound', 'broad_band_noise', 'narrow_band_noise', 'click', 'vocalization', 'high_pass_noise', 'low_pass_noise', 'sine_wave_modulation', 'square_wave_modulation'] # %Indicates the current line being read. line_num = 1 # %Total lines in the PST file num_lines = len(lines) # %Offset into the raw data file raw_pos = 0 # %Collect experiment-wide data from ID section experiment = {} experiment['pst_filename'] = lines[0]; experiment['date'] = lines[1]; experiment['title'] = lines[2]; experiment['who'] = lines[3]; experiment['computername'] = lines[4]; experiment['program_date'] = lines[5]; experiment['test'] = [] # discard rest of ID section line_num = lines.index(end_id) + 1 while line_num < num_lines-1: # %Get the test type test = {} full_testtype = lines[line_num]; line_num += 1; # %Get the test number. # test_line = textscan(lines{line_num},'%n %*s %*s %*n %s',1); match = re.match('(\d+) (.*)', lines[line_num]) test['testnum'] = int(match.group(1)) test['time'] = match.group(2) # %This is the Batlab assigned test type, not the test type that Bat2Matlab uses test['full_testtype'] = full_testtype # %Store the beginning location of the test line_num += 1 # %Extract the test paramewters num_traces = int(re.match('\d+', lines[line_num]).group(0)) line_num += 1 # %Scan past the test parameter section line_num = lines.index(end_test_parameters) + 1 lines[line_num-1] = '' # %Get the position of the beginning of the test in the raw data file test['offset_in_raw_file'] = raw_pos test['trace'] = [] for trace_num in range(num_traces): trace_data = [int(x) for x in lines[line_num].split()] num_sweeps = trace_data[0] samplerate_da = trace_data[1]; samplerate_ad = trace_data[3]; duration = trace_data[4]; points = int((samplerate_ad/1000.)*duration) trace = {} trace['record_duration'] = duration trace['samplerate_da'] = samplerate_da trace['samplerate_ad'] = samplerate_ad trace['num_samples'] = num_sweeps # %The length of the trace in the raw data file trace_raw_data_length = points*num_sweeps*2 # %Store the trace raw offset and length trace['offset_in_raw_file'] = raw_pos trace['length_in_raw_file'] = trace_raw_data_length # %Increment the position in the raw data file raw_pos += trace_raw_data_length test_num = len(experiment['test']) # %Collect the stimulus parameters for all 4 channels stimulus_num = 0; test_stim_type = 0; #%Default stim = [] for channel_num in range(4): stimulus, stim_type = parse_pst_stimulus(lines[line_num - 1 + 5*channel_num],test_num,trace_num); if len(stimulus) != 0: #%&& stim_type ~= 5 %FIXME. Not adding BBN stimulus stimulus_num += 1 stim.append(stimulus) if test_stim_type == 0: test_stim_type = stim_type trace['stimulus'] = stim # %Set the test type based on the stimulus variety if test_stim_type == 0: test_type = 'control' elif test_stim_type ==1: if stimulus_num == 1: test_type = 'tone' elif stimulus_num == 2: test_type = 'twotone' elif stimulus_num == 3: test_type = 'threetone' elif stimulus_num == 4: test_type = 'fourtone' else: test_type = test_types[test_stim_type] test['testtype'] = test_type if test_stim_type > 0: trace['is_control'] = 0 else: trace['is_control'] = 1 line_num = lines.index(end_spike_data) + 1 lines[line_num-1] = '' test['trace'].append(trace) # %Assert that the spike data terminates with an end auto test statement if lines[line_num] != end_auto_test: raise Exception('No end of auto test found after spike data'); line_num += 1; # %Get the test comment test['comment'] = lines[line_num] line_num += 1; experiment['test'].append(test) return experiment
[docs]def parse_pst_stimulus(stim_text, test_num, trace_num): # print stim_text stim_data = stim_text.split() # print 'stim_data', stim_data if len(stim_data) == 0 or int(stim_data[0]) == 0: return [], 0 stim_type = int(stim_data[1]) stimulus = {} stimulus['attenuation'] = float(stim_data[2]) stimulus['duration'] = float(stim_data[3]) stimulus['delay'] = float(stim_data[4]) # %Static stimulus labels stim_types = ['tone', 'fmsweep', 'synthesized_batsound', 'amsound', 'broad_band_noise', 'narrow_band_noise', 'click', 'stored_vocal_call', 'high_pass_noise', 'low_pass_noise', 'sine_wave_modulation', 'square_wave_modulation']; # %Default values stimulus['frequency'] = []; stimulus['rise_fall'] = 0; stimulus['soundtype_name'] = []; stimulus['reverse_vocal_call'] = []; stimulus['vocal_call_file'] = []; stimulus['bandwidth'] = []; stimulus['usweep'] = []; if stim_type == 0: return stimulus, stim_type elif stim_type == 1: #tone stimulus['frequency'] = float(stim_data[5]); stimulus['rise_fall'] = float(stim_data[6]); stimulus['soundtype_name'] = 'tone'; elif stim_type == 2: #fmsweep stimulus['frequency'] = float(stim_data[5]); stimulus['bandwidth'] = float(stim_data[6]); stimulus['usweep'] = float(stim_data[7]); stimulus['rise_fall'] = float(stim_data[8]); stimulus['soundtype_name'] = 'fmsweep'; elif stim_type == 8: # vocalization # print 'vocalization', stim_data stimulus['soundtype_name'] = 'vocalization'; stimulus['reverse_vocal_call'] = int(stim_data[5]); if int(stim_data[6]) == 0: # %Old school # print 'stim_data 20', stim_data[20] stimulus['vocal_call_file'] = stim_data[20] else: # %New School # print stim_data[24], stim_data[33] + stim_data[35] # if len(stim_data[24]) > 1 and stim_data != '-1': # print 'WARNING: PST file generated between March and September 2007. \n No audio file extension information available. \n Using .call1' # else: stimulus['vocal_call_file'] = stim_data[33] + stim_data[35] else: stimulus['soundtype_name'] = stim_types[stim_type]; return stimulus, stim_type
if __name__ == '__main__': # parse_pst('/home/leeloo/testdata/Mouse 497/Mouse497.pst') parse_pst('C:/Users/Leeloo/testdata/Mouse 497/Mouse497.pst') parse_pst('C:/Users/Leeloo/testdata/August 5 2010/August 5 2010.pst')