5from pathlib
import Path
6from initialise
import load_pueoEvent_Dataset
8from calibration
import generate_antenna_phase_center_pairs_with_placeholders, load_dataset_and_measure_time_delays
9from calibration
import retrieve_relevant_antennas_from_all_pairs, compute_time_delay_residuals, objective_function, _plot_calibration_result
11from scipy.optimize
import minimize
12import matplotlib.pyplot
as plt
20if __name__ ==
"__main__":
28 files = glob.glob(f
"feather_data/pulser_directions_and_pairwise_time_delays_run*.feather")
30 pulser_directions_and_pairwise_time_delays = pl.concat([pl.read_ipc(f)
for f
in files])
33 corr = pulser_directions_and_pairwise_time_delays[
"max correlation"].to_numpy()
34 N_tot_pairs = len(corr)
35 print(
"N pairs before selections = ", N_tot_pairs)
37 pXX = np.percentile(corr, percentage)
38 print(f
"{percentage}th percentile =", pXX)
41 plt.figure(figsize=(8,5))
42 plt.hist(corr, bins=100)
43 plt.axvline(pXX, linestyle=
"--", linewidth=2, label=f
"{percentage}% = {pXX:.3f}")
44 plt.axvline(0.9, linestyle=
"--", linewidth=2)
45 plt.xlabel(
"max correlation")
49 os.makedirs(
"plot", exist_ok=
True)
50 plt.savefig(f
"plot/{ant_type}max_correlation.png")
53 pulser_directions_and_pairwise_time_delays = pulser_directions_and_pairwise_time_delays.filter(
54 ~pl.col(
"incoming pulse direction (Phi Theta)")
55 .arr.eval(pl.element().is_nan())
59 pulser_directions_and_pairwise_time_delays = pulser_directions_and_pairwise_time_delays.filter(pl.col(
"max correlation")> 0.90)
60 pulser_directions_and_pairwise_time_delays = pulser_directions_and_pairwise_time_delays.filter(pl.col(
"measured time delays (ns)").is_between(-16, 16))
62 pl.Config.set_tbl_rows(-1)
65 pulser_directions_and_pairwise_time_delays
67 "measured time delays (ns)",
69 pl.col("incoming pulse direction (Phi Theta)")
71 lambda x: np.rad2deg(np.array(x.to_list())),
72 return_dtype=pl.Array(pl.Float64, 2)
74 .alias("incoming pulse direction (deg)")
79 pulser_directions_and_pairwise_time_delays = pulser_directions_and_pairwise_time_delays.with_row_index(
"row_id")
80 N_pairs = pulser_directions_and_pairwise_time_delays.height
82 print(
"N total pairs after correlation seletion = ", N_pairs)
85 retrieve_relevant_antennas_from_all_pairs(
86 phase_center_pairs=pulser_directions_and_pairwise_time_delays
90 relevant_antennas = relevant_antennas.with_columns(
91 pl.col(
"AntNum").cast(pl.Utf8).cast(pl.Int64).alias(
"AntNum")
94 print(
"relevant_antennas=", relevant_antennas)
96 axis_list_initial = [
"Rho",
"Phi",
"Z",
"CableDelay"]
105 axis_list0.extend([[
"CableDelay"],[
"Rho"], [
"Phi"], [
"Z"]])
107 axis_list0.extend([[
"CableDelay"],[
"Z"]])
108 axis_list0.extend([[
"Rho"]])
113 axis_list.extend([[
"CableDelay"],[
"Rho"], [
"Phi"],[
"Z"]])
115 axis_list.extend([[
"CableDelay"],[
"Z"]])
116 axis_list.extend([[
"Rho"]])
119 for index, axis_label
in enumerate(axis_list_initial):
122 x0_randomguess[axis_label] = relevant_antennas[axis_label].to_numpy().copy()
123 fixed_antenna[axis_label] = x0_randomguess[axis_label][0]
125 x0_randomguess[axis_label][1:] = x0_randomguess[axis_label][1:] + np.random.uniform(-0.1, 0.1, size=len(relevant_antennas)-1)
127 elif axis_label==
'Phi':
128 x0_randomguess[axis_label][1:] = x0_randomguess[axis_label][1:] + np.random.uniform(-0.1, 0.1, size=len(relevant_antennas)-1)
130 elif axis_label==
'Rho':
131 x0_randomguess[axis_label][1:] = x0_randomguess[axis_label][1:] + np.random.uniform(-0.1, 0.1, size=len(relevant_antennas)-1)
133 elif axis_label==
'CableDelay':
134 x0_randomguess[axis_label][1:] = x0_randomguess[axis_label][1:] + np.random.uniform(-0.066, 0.066, size=len(relevant_antennas)-1)
136 pulser_directions_and_pairwise_time_delays = (
137 pulser_directions_and_pairwise_time_delays
139 pl.col(f
"A1_{axis_label} (placeholder)")
140 .replace_strict(relevant_antennas[f
"{axis_label} (placeholder)"], x0_randomguess[axis_label])
141 .alias(f
"A1_{axis_label}"),
143 pl.col(f
"A2_{axis_label} (placeholder)")
144 .replace_strict(relevant_antennas[f
"{axis_label} (placeholder)"], x0_randomguess[axis_label])
145 .alias(f
"A2_{axis_label}")
149 x0_randomguess[axis_label] = relevant_antennas[axis_label].to_numpy().copy()
150 fixed_antenna[axis_label] = x0_randomguess[axis_label][0]
152 print(
"x0_randomguess=", x0_randomguess)
154 fig1, ax1 = plt.subplots(figsize=(8, 5))
157 for index, axis_label
in enumerate(axis_list0):
160 x0 = x0_randomguess[AXIS]
164 placeholder = relevant_antennas[f
"{AXIS} (placeholder)"][1:]
167 placeholder = relevant_antennas[f
"{AXIS} (placeholder)"][1:]
170 bounds = [(1.0, 2.0)] * (len(x0))
172 bounds = [(-3.14, 3.14)] * (len(x0))
174 bounds =[(-12, -4)] * (len(x0))
175 if AXIS==
'CableDelay':
176 bounds =[(-1, 1)] * (len(x0))
178 result = minimize(fun=objective_function,
181 pulser_directions_and_pairwise_time_delays, AXIS,
'l2'),
182 method=
'Nelder-Mead',
184 options={
'maxiter': 50000})
190 pulser_directions_and_pairwise_time_delays = (
191 pulser_directions_and_pairwise_time_delays
193 pl.col(f
"A1_{AXIS} (placeholder)")
194 .replace_strict(placeholder, result.x, default=pl.col(f
"A1_{AXIS}"))
195 .alias(f
"A1_{AXIS}"),
197 pl.col(f
"A2_{AXIS} (placeholder)")
198 .replace_strict(placeholder, result.x, default = pl.col(f
"A1_{AXIS}"))
203 resultx = np.insert(result.x, 0, x0_randomguess[AXIS][0])
204 x0_randomguess[AXIS] = resultx
209 df_resid = compute_time_delay_residuals(
210 phase_center_guess=resultx,
211 phase_center_placeholders=relevant_antennas[f
"{AXIS} (placeholder)"],
212 pulser_directions_and_measured_time_delays=pulser_directions_and_pairwise_time_delays,
216 residuals = df_resid[
"residual (ns)"].to_numpy()
218 color = cmap(index / (len(axis_list0) - 1))
if len(axis_list0) > 1
else cmap(1.0)
221 bins = np.arange(residuals.min(), residuals.max() + bin_width, bin_width)
222 ax1.hist(residuals, bins=bins, alpha=1, label=f
'{index}:[{AXIS}]', color=color)
225 if (index>=12
and RemoveOutlier==
True):
227 row_before = df_resid.height
228 resid_col =
"residual (ns)"
230 mu = df_resid.select(pl.col(resid_col).mean()).item()
231 sigma = df_resid.select(pl.col(resid_col).std()).item()
241 print(f
"You're removing outlier over {Nsigma} sigma, mu=", mu,
"sigma=", sigma)
245 .filter((pl.col(resid_col) - mu).abs() <= Nsigma * sigma)
248 row_after = good_rows.height
250 print(
"Removing", row_before-row_after,
"rows")
251 pulser_directions_and_pairwise_time_delays = (
252 pulser_directions_and_pairwise_time_delays
253 .join(good_rows, on=
"row_id", how=
"inner")
257 ax1.set_xlabel(
"measured - expected (ns)")
258 ax1.set_ylabel(
"Counts")
259 ax1.set_title(
"Residual time delays")
260 ax1.grid(
True, alpha=0.3)
263 fig1.savefig(f
"plot/{ant_type}step_timediff_RemoveOutliers.png")
269 N_pairs = pulser_directions_and_pairwise_time_delays.height
270 print(
"N pairs after removing outliers = ", N_pairs)
278 result_cabledelay =
None
281 for index, axis_label
in enumerate(axis_list_initial):
284 x0_randomguess[axis_label] = relevant_antennas[axis_label].to_numpy().copy()
285 fixed_antenna[axis_label] = x0_randomguess[axis_label][0]
288 x0_randomguess[axis_label][1:] = x0_randomguess[axis_label][1:] + np.random.uniform(-0.1, 0.1, size=len(relevant_antennas)-1)
290 elif axis_label==
'Phi':
291 x0_randomguess[axis_label][1:] = x0_randomguess[axis_label][1:] + np.random.uniform(-0.1, 0.1, size=len(relevant_antennas)-1)
293 elif axis_label==
'Rho':
294 x0_randomguess[axis_label][1:] = x0_randomguess[axis_label][1:] + np.random.uniform(-0.1, 0.1, size=len(relevant_antennas)-1)
296 elif axis_label==
'CableDelay':
297 x0_randomguess[axis_label][1:] = x0_randomguess[axis_label][1:] + np.random.uniform(-0.066, 0.066, size=len(relevant_antennas)-1)
299 pulser_directions_and_pairwise_time_delays = (
300 pulser_directions_and_pairwise_time_delays
302 pl.col(f
"A1_{axis_label} (placeholder)")
303 .replace_strict(relevant_antennas[f
"{axis_label} (placeholder)"], x0_randomguess[axis_label])
304 .alias(f
"A1_{axis_label}"),
306 pl.col(f
"A2_{axis_label} (placeholder)")
307 .replace_strict(relevant_antennas[f
"{axis_label} (placeholder)"], x0_randomguess[axis_label])
308 .alias(f
"A2_{axis_label}")
313 fig1, ax1 = plt.subplots(figsize=(8, 5))
316 for index, axis_label
in enumerate(axis_list):
320 x0 = x0_randomguess[AXIS]
323 placeholder = relevant_antennas[f
"{AXIS} (placeholder)"][1:]
326 bounds = [(1.0, 2.0)] * (len(x0))
328 bounds = [(-3.14, 3.14)] * (len(x0))
330 bounds =[(-12, -4)] * (len(x0))
331 if AXIS==
'CableDelay':
332 bounds =[(-1, 1)] * (len(x0))
334 result = minimize(fun=objective_function,
337 pulser_directions_and_pairwise_time_delays, AXIS),
338 method=
'Nelder-Mead',
340 options={
'maxiter': 500_000})
343 tmp_trace.append(result.fun)
346 pulser_directions_and_pairwise_time_delays = (
347 pulser_directions_and_pairwise_time_delays
349 pl.col(f
"A1_{AXIS} (placeholder)")
350 .replace_strict(placeholder, result.x, default=pl.col(f
"A1_{AXIS}"))
351 .alias(f
"A1_{AXIS}"),
353 pl.col(f
"A2_{AXIS} (placeholder)")
354 .replace_strict(placeholder, result.x, default = pl.col(f
"A1_{AXIS}"))
359 resultx = np.insert(result.x, 0, x0_randomguess[AXIS][0])
360 x0_randomguess[AXIS] = resultx
362 df_resid = compute_time_delay_residuals(
363 phase_center_guess=resultx,
364 phase_center_placeholders=relevant_antennas[f
"{AXIS} (placeholder)"],
365 pulser_directions_and_measured_time_delays=pulser_directions_and_pairwise_time_delays,
368 residuals = df_resid[
"residual (ns)"].to_numpy()
370 color = cmap(index / (len(axis_list) - 1))
if len(axis_list) > 1
else cmap(1.0)
373 bins = np.arange(residuals.min(), residuals.max() + bin_width, bin_width)
374 ax1.hist(residuals, bins=bins, alpha=0.8, label=f
'{index}:[{AXIS}]', color=color)
378 result_rho = np.insert(result.x, 0, x0_randomguess[AXIS][0])
380 result_phi = np.insert(result.x, 0, x0_randomguess[AXIS][0])
382 result_z = np.insert(result.x, 0, x0_randomguess[AXIS][0])
383 elif AXIS ==
'CableDelay':
384 result_cabledelay = np.insert(result.x, 0, x0_randomguess[AXIS][0])
387 fig1.savefig(f
"plot/Minimization_plot.png")
389 print(
"Rho:", result_rho)
390 print(
"Phi:", np.rad2deg(result_phi))
391 print(
"Z:", result_z)
392 print(
"CableDelay:", result_cabledelay)