Skip to content

Commit 3a5740b

Browse files
committed
Add support for PSI click ABRs
1 parent 6311f28 commit 3a5740b

File tree

4 files changed

+45
-32
lines changed

4 files changed

+45
-32
lines changed

abr/main_window.enaml

+4-1
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,10 @@ def add_dock_item(dock_area, model, presenter):
332332
items = dock_area.dock_items()
333333
n_items = len(items) - 1
334334
target = items[-1].name if n_items else ''
335-
title = f'{model.frequency * 1e-3:.2f} kHz - {model.parent.name}'
335+
if model.frequency == -1:
336+
title = f'Click - {model.parent.name}'
337+
else:
338+
title = f'{model.frequency * 1e-3:.2f} kHz - {model.parent.name}'
336339
item = MPLDockItem(dock_area, name='dock_{}'.format(n_items), title=title,
337340
presenter=presenter)
338341
op = InsertTab(item=item.name, target=target)

abr/parsers/PSI.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ def read_file(filename):
3838
line = fh.readline()
3939
if line.startswith('time'):
4040
break
41-
name, *keys = line.split(',')
41+
name, *keys = line.strip().split(',')
42+
keys = [-1 if k == 'click' else float(k) for k in keys]
4243
header[name] = np.array(keys).astype('f')
4344
data = pd.read_csv(fh, index_col=0, header=None)
4445

@@ -116,13 +117,14 @@ def get_series(self, filter_settings=None):
116117
series = ABRSeries(waveforms, self.frequency)
117118
series.filename = self.parent.filename
118119
series.id = self.parent.filename.parent.name
120+
series.dataset = self
119121
return series
120122

121123

122124
def iter_all(path):
123125
results = []
124126
path = Path(path)
125-
if path.stem.endswith('abr_io'):
127+
if 'abr_io' in path.stem:
126128
yield from PSIDataCollection(path).iter_frequencies()
127129
else:
128130
for subpath in path.glob('**/*abr_io'):

abr/parsers/__init__.py

+25-22
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,22 @@ def filter_string(waveform):
5353

5454
def load_analysis(fname):
5555
th_match = re.compile('Threshold \(dB SPL\): ([\w.-]+)')
56-
freq_match = re.compile('Frequency \(kHz\): ([\d.]+)')
56+
freq_match = re.compile('Frequency \(kHz\): ([\d.]+)|Stimulus: ([.\w]+)?')
5757
with open(fname) as fh:
5858
text = fh.readline()
5959
th = th_match.search(text).group(1)
6060
th = None if th == 'None' else float(th)
6161
text = fh.readline()
62-
freq = float(freq_match.search(text).group(1))
62+
63+
match = freq_match.search(text)
64+
if match.group(1) is not None:
65+
freq = float(match.group(1))
66+
else:
67+
freq = match.group(2)
68+
if freq == 'click':
69+
freq = -1
70+
else:
71+
freq = float(freq)
6372

6473
for line in fh:
6574
if line.startswith('NOTE'):
@@ -108,8 +117,6 @@ def parse_peaks(peaks, threshold):
108117

109118
class Parser(object):
110119

111-
filename_template = '{filename}-{frequency}kHz-{user}analyzed.txt'
112-
113120
def __init__(self, file_format, filter_settings, user=None):
114121
'''
115122
Parameters
@@ -124,24 +131,13 @@ def __init__(self, file_format, filter_settings, user=None):
124131
'''
125132
self._file_format = file_format
126133
self._filter_settings = filter_settings
127-
self._user = user
134+
self._rater = user
128135
self._module_name = f'abr.parsers.{file_format}'
129136
self._module = importlib.import_module(self._module_name)
130137

131138
def load(self, fs):
132139
return fs.get_series(self._filter_settings)
133140

134-
def get_save_filename(self, filename, frequency):
135-
# Round frequency to nearest 8 places to minimize floating-point
136-
# errors.
137-
user_name = self._user + '-' if self._user else ''
138-
frequency = round(frequency * 1e-3, 8)
139-
save_filename = self.filename_template.format(
140-
filename=filename.with_suffix(''),
141-
frequency=frequency,
142-
user=user_name)
143-
return Path(save_filename)
144-
145141
def save(self, model):
146142
# Assume that all waveforms were filtered identically
147143
filter_history = filter_string(model.waveforms[-1])
@@ -157,14 +153,21 @@ def save(self, model):
157153
columns = '\t'.join(columns)
158154
spreadsheet = '\n'.join(waveform_string(w) \
159155
for w in reversed(model.waveforms))
156+
157+
if model.freq == -1:
158+
stimulus = 'Stimulus: click'
159+
else:
160+
stimulus = f'Stimulus: {model.freq*1e-3:.2f} kHz'
161+
160162
content = CONTENT.format(threshold=model.threshold,
161-
frequency=model.freq*1e-3,
163+
stimulus=stimulus,
162164
filter_history=filter_history,
163165
columns=columns,
164166
spreadsheet=spreadsheet,
165167
version=abr.__version__)
166168

167-
filename = self.get_save_filename(model.filename, model.freq)
169+
170+
filename = model.dataset.get_analyzed_filename(self._rater)
168171
with open(filename, 'w') as fh:
169172
fh.writelines(content)
170173

@@ -173,12 +176,12 @@ def iter_all(self, path):
173176

174177
def find_processed(self, path):
175178
for ds in self.iter_all(path):
176-
if self.get_save_filename(ds.filename, ds.frequency).exists():
179+
if ds.get_analyzed_filename(self._rater).exists():
177180
yield ds
178181

179182
def find_unprocessed(self, path):
180183
for ds in self.iter_all(path):
181-
if not self.get_save_filename(ds.filename, ds.frequency).exists():
184+
if not ds.get_analyzed_filename(self._rater).exists():
182185
yield ds
183186

184187
def find_analyses(self, study_directory):
@@ -215,9 +218,9 @@ def load_analyses(self, study_directory):
215218

216219
CONTENT = '''
217220
Threshold (dB SPL): {threshold:.2f}
218-
Frequency (kHz): {frequency:.2f}
221+
{stimulus}
219222
Filter history (zpk format): {filter_history}
220-
file_format_version: 0.0.2
223+
file_format_version: 0.0.3
221224
code_version: {version}
222225
NOTE: Negative latencies indicate no peak. NaN for amplitudes indicate peak was unscorable.
223226
{columns}

abr/parsers/dataset.py

+12-7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import re
44

55

6-
P_RATER = re.compile('.*kHz(?:-(\w+))?-analyzed.txt')
6+
P_RATER = re.compile('.*(?:kHz|click)(?:-(\w+))?-analyzed.txt')
77

88

99
def get_rater(filename):
@@ -41,7 +41,7 @@ def iter_frequencies(self):
4141
@functools.total_ordering
4242
class Dataset:
4343

44-
filename_template = '{filename}-{frequency}kHz-{rater}analyzed.txt'
44+
filename_template = '{filename}-{frequency}-{rater}analyzed.txt'
4545

4646
def __init__(self, parent, frequency):
4747
self.parent = parent
@@ -59,16 +59,19 @@ def get_series(self, filter_settings=None):
5959
raise NotImplementedError
6060

6161
def get_analyzed_filename(self, rater):
62-
frequency = round(self.frequency * 1e-3, 8)
62+
if self.frequency == -1:
63+
frequency = 'click'
64+
else:
65+
frequency = round(self.frequency * 1e-3, 8)
66+
frequency = f'{frequency}kHz'
67+
6368
filename = self.filename.with_suffix('')
6469
if rater != '*':
6570
rater = rater + '-'
66-
return self.filename_template\
71+
return self.filename_template \
6772
.format(filename=filename, frequency=frequency, rater=rater)
6873

6974
def find_analyzed_files(self):
70-
frequency = round(self.frequency * 1e-3, 8)
71-
filename = self.filename.with_suffix('')
7275
glob_pattern = self.get_analyzed_filename('*')
7376
path = Path(glob_pattern)
7477
return list(path.parent.glob(path.name))
@@ -78,7 +81,9 @@ def list_raters(self):
7881

7982
def load_analysis(self, rater):
8083
from . import load_analysis
81-
return load_analysis(self.get_analyzed_filename(rater))
84+
r = load_analysis(self.get_analyzed_filename(rater))
85+
print(r)
86+
return r
8287

8388
def __lt__(self, other):
8489
if not isinstance(other, Dataset):

0 commit comments

Comments
 (0)