Skip to content

Commit 1f24481

Browse files
add loading functions to xdc.util
To aid in using the functionality in #439
1 parent 83c1310 commit 1f24481

1 file changed

Lines changed: 274 additions & 0 deletions

File tree

src/openlifu/xdc/util.py

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,243 @@
11
from __future__ import annotations
22

33
import json
4+
import re
5+
6+
import pandas as pd
7+
import xarray as xa
48

59
from openlifu.util.types import PathLike
610
from openlifu.xdc.transducer import Transducer
711
from openlifu.xdc.transducerarray import TransducerArray
812

13+
FOCAL_GAIN_LUT = xa.DataArray.from_dict(
14+
{'dims': ('f0', 'crosstalk'),
15+
'attrs': {},
16+
'data': [[2.807589054107666,
17+
3.2286391258239746,
18+
3.649686813354492,
19+
3.8181092739105225,
20+
4.07073974609375,
21+
4.491786956787109,
22+
4.912837505340576,
23+
5.333885669708252,
24+
5.754938125610352,
25+
6.175983428955078,
26+
6.597033500671387,
27+
7.01808500289917],
28+
[2.90433931350708,
29+
3.3324313163757324,
30+
3.760524272918701,
31+
3.931760549545288,
32+
4.188616752624512,
33+
4.616710662841797,
34+
5.044803142547607,
35+
5.472893714904785,
36+
5.900986671447754,
37+
6.3290791511535645,
38+
6.757172107696533,
39+
7.185482501983643],
40+
[2.9909276962280273,
41+
3.428293466567993,
42+
3.865659713745117,
43+
4.040605068206787,
44+
4.3030242919921875,
45+
4.740390777587891,
46+
5.1777544021606445,
47+
5.615119934082031,
48+
6.052487373352051,
49+
6.489851951599121,
50+
6.927217483520508,
51+
7.364583969116211],
52+
[3.0771772861480713,
53+
3.5201354026794434,
54+
3.9643561840057373,
55+
4.142045497894287,
56+
4.408576965332031,
57+
4.852799415588379,
58+
5.297021865844727,
59+
5.741242408752441,
60+
6.185462474822998,
61+
6.629685878753662,
62+
7.073910713195801,
63+
7.518129348754883],
64+
[3.170368194580078,
65+
3.617199182510376,
66+
4.064029693603516,
67+
4.242762565612793,
68+
4.51104211807251,
69+
4.961826801300049,
70+
5.4126152992248535,
71+
5.863399505615234,
72+
6.314184665679932,
73+
6.764969825744629,
74+
7.215755462646484,
75+
7.666543960571289],
76+
[3.242729663848877,
77+
3.6979565620422363,
78+
4.153182506561279,
79+
4.335274696350098,
80+
4.6084089279174805,
81+
5.064931869506836,
82+
5.521984100341797,
83+
5.979033946990967,
84+
6.4360833168029785,
85+
6.89313268661499,
86+
7.350184440612793,
87+
7.8072357177734375],
88+
[3.327850103378296,
89+
3.783803701400757,
90+
4.245124340057373,
91+
4.429731845855713,
92+
4.706640720367432,
93+
5.168155193328857,
94+
5.6296706199646,
95+
6.091186046600342,
96+
6.552703380584717,
97+
7.014214992523193,
98+
7.475728988647461,
99+
7.937244415283203],
100+
[3.415055990219116,
101+
3.8783867359161377,
102+
4.341715335845947,
103+
4.527048110961914,
104+
4.8050456047058105,
105+
5.268375396728516,
106+
5.731706142425537,
107+
6.195037841796875,
108+
6.658364295959473,
109+
7.12183952331543,
110+
7.587955474853516,
111+
8.054073333740234],
112+
[5.705652713775635,
113+
5.966911792755127,
114+
6.2332234382629395,
115+
6.343565940856934,
116+
6.509076118469238,
117+
6.784928798675537,
118+
7.060781478881836,
119+
7.336633682250977,
120+
7.612486362457275,
121+
7.888339519500732,
122+
8.164192199707031,
123+
8.447998046875],
124+
[5.73893404006958,
125+
5.998416423797607,
126+
6.260423183441162,
127+
6.365228652954102,
128+
6.522432327270508,
129+
6.784440994262695,
130+
7.046449184417725,
131+
7.310236930847168,
132+
7.583878517150879,
133+
7.8575215339660645,
134+
8.131163597106934,
135+
8.404805183410645],
136+
[5.780664920806885,
137+
6.028132915496826,
138+
6.275601387023926,
139+
6.3745880126953125,
140+
6.523068904876709,
141+
6.777853965759277,
142+
7.03900146484375,
143+
7.300150394439697,
144+
7.561298370361328,
145+
7.822445869445801,
146+
8.083595275878906,
147+
8.350235939025879],
148+
[5.814091205596924,
149+
6.0464091300964355,
150+
6.284290313720703,
151+
6.383488178253174,
152+
6.532283306121826,
153+
6.780277252197266,
154+
7.028269290924072,
155+
7.27626371383667,
156+
7.524255752563477,
157+
7.772250175476074,
158+
8.040055274963379,
159+
8.318523406982422],
160+
[5.836524486541748,
161+
6.067535400390625,
162+
6.301788806915283,
163+
6.3954901695251465,
164+
6.536042213439941,
165+
6.770293712615967,
166+
7.00454568862915,
167+
7.238796710968018,
168+
7.482921600341797,
169+
7.740076541900635,
170+
8.005291938781738,
171+
8.270505905151367],
172+
[5.86801815032959,
173+
6.0880255699157715,
174+
6.308032989501953,
175+
6.396038055419922,
176+
6.528041839599609,
177+
6.749823093414307,
178+
6.9840264320373535,
179+
7.218224048614502,
180+
7.4528584480285645,
181+
7.70409631729126,
182+
7.955334663391113,
183+
8.206572532653809],
184+
[5.892360210418701,
185+
6.097702980041504,
186+
6.303044319152832,
187+
6.390904903411865,
188+
6.523708343505859,
189+
6.7450480461120605,
190+
6.966385841369629,
191+
7.187726020812988,
192+
7.417387962341309,
193+
7.661881923675537,
194+
7.91318941116333,
195+
8.164498329162598],
196+
[5.90617036819458,
197+
6.104805946350098,
198+
6.312875747680664,
199+
6.396102428436279,
200+
6.520944595336914,
201+
6.729012966156006,
202+
6.937082290649414,
203+
7.15734338760376,
204+
7.39542818069458,
205+
7.6335129737854,
206+
7.8715996742248535,
207+
8.1096830368042]],
208+
'coords': {'f0': {'dims': ('f0',),
209+
'attrs': {},
210+
'data': [130000.0,
211+
135000.0,
212+
140000.0,
213+
145000.0,
214+
150000.0,
215+
155000.0,
216+
160000.0,
217+
165000.0,
218+
375000.0,
219+
380000.0,
220+
385000.0,
221+
390000.0,
222+
395000.0,
223+
400000.0,
224+
405000.0,
225+
410000.0]},
226+
'crosstalk': {'dims': ('crosstalk',),
227+
'attrs': {},
228+
'data': [0.0,
229+
0.05,
230+
0.1,
231+
0.12,
232+
0.15000000000000002,
233+
0.2,
234+
0.25,
235+
0.30000000000000004,
236+
0.35000000000000003,
237+
0.4,
238+
0.45,
239+
0.5]}},
240+
'name': 'focal_gain'})
9241

10242
def load_transducer_from_file(transducer_filepath : PathLike, convert_array:bool = True) -> Transducer|TransducerArray:
11243
"""Load a Transducer or TransducerArray from file, depending on the "type" field in the file.
@@ -28,3 +260,45 @@ def load_transducer_from_file(transducer_filepath : PathLike, convert_array:bool
28260
else:
29261
transducer = Transducer.from_file(transducer_filepath)
30262
return transducer
263+
264+
def read_test_report(filename: PathLike) -> pd.DataFrame:
265+
sections = [{"name": "info", "start_row": 3, "nrows": 3},
266+
{"name": "txm", "start_row": 9, "nrows": 5},
267+
{"name": "console", "start_row": 17, "nrows": 3},
268+
{"name": "scans", "start_row": 23, "nrows": 7},
269+
{"name": "freq", "start_row": 33, "nrows": 9},
270+
{"name": "voltage", "start_row": 45, "nrows": 7}]
271+
272+
all_data = []
273+
for section in sections:
274+
report_df = pd.read_excel(filename, sheet_name="Report", skiprows=section["start_row"], nrows=section["nrows"], index_col=0, usecols="A:C")
275+
report_df["Section"] = section["name"]
276+
all_data.append(report_df)
277+
278+
report_df = pd.concat(all_data)
279+
return report_df
280+
281+
def report_to_matrix_dict(report_df: pd.DataFrame, focal_gain_lut=FOCAL_GAIN_LUT) -> dict:
282+
ROW_SN = 'B.1'
283+
ROW_FREQ = 'B.2'
284+
ROW_VOLTAGE = 'E.1'
285+
LIFU_400 = {'id': r'txm_400_{sn}', 'name': r'TXM 400kHz (S/N {sn})', 'nx': 8, 'ny': 8, 'pitch': 5, 'frequency': 400e3, 'kerf': 0.3, 'crosstalk_frac': 0.12, 'crosstalk_dist': 5.05e-3}
286+
LIFU_155 = {'id': r'txm_155_{sn}', 'name': r'TXM 155kHz (S/N {sn})', 'nx': 8, 'ny': 8, 'pitch': 5, 'frequency': 155e3, 'kerf': 0.3, 'crosstalk_frac': 0.12, 'crosstalk_dist': 5.05e-3}
287+
LIFU_MODULES = {400: LIFU_400, 155: LIFU_155}
288+
freq_kHz = report_df.loc[ROW_FREQ]["Value"]
289+
voltage = report_df.loc[ROW_VOLTAGE]["Value"]
290+
sn = report_df.loc[ROW_SN]["Value"]
291+
pattern = r'[^a-zA-Z0-9\-\_]'
292+
replacement = ''
293+
sn = re.sub(pattern, replacement, sn)
294+
matrix_dict = LIFU_MODULES[freq_kHz]
295+
freq_df = report_df[report_df["Section"] == "freq"].copy().drop(columns=["Section"])
296+
freq_df = freq_df.rename(columns={"Value": "PNP"})
297+
freq_df = freq_df[freq_df['Item'].str.startswith("PNP")]
298+
freq_df["Frequency"] = freq_df['Item'].apply(lambda x: float(re.search(r"(?<=^PNP \()\d+(?= kHz\)$)", x).group(0)))
299+
freq_df['focal_gain'] = freq_df['Frequency'].apply(lambda f: focal_gain_lut.interp(f0=f*1e3, crosstalk=matrix_dict['crosstalk_frac']).item())
300+
freq_df['Sensitivity'] = freq_df['PNP'].astype(float)*1e6/freq_df['focal_gain']/voltage
301+
matrix_dict['sensitivity'] = {f*1e3:sens for f, sens, in zip(freq_df["Frequency"], freq_df['Sensitivity'])}
302+
matrix_dict['id'] = matrix_dict['id'].format(sn=sn.lower())
303+
matrix_dict['name'] = matrix_dict['name'].format(sn=sn)
304+
return matrix_dict

0 commit comments

Comments
 (0)