make proc sweep general
This commit is contained in:
parent
b1ec523aaa
commit
14ca15e96d
@ -43,6 +43,7 @@ from .measurement import measure_spectrum as _measure_spectrum, set_offsets_lase
|
|||||||
from .utility.prsdata import PrsData, plot_spectrum
|
from .utility.prsdata import PrsData, plot_spectrum
|
||||||
from .utility.config_file import ConfigFile
|
from .utility.config_file import ConfigFile
|
||||||
from .utility.device_select import select_device_interactive, connect_device_from_config_or_interactive
|
from .utility.device_select import select_device_interactive, connect_device_from_config_or_interactive
|
||||||
|
from .utility import duration_to_string
|
||||||
from .update_funcs import Monitor
|
from .update_funcs import Monitor
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@ -170,6 +171,7 @@ def measure_spectrum(metadata:dict={},
|
|||||||
# measure/set offset
|
# measure/set offset
|
||||||
full_scale_voltage = lockin_params["sensitivity_volt"]
|
full_scale_voltage = lockin_params["sensitivity_volt"]
|
||||||
def set_offsets(name):
|
def set_offsets(name):
|
||||||
|
# TODO: use multithreading and queues
|
||||||
shutter.close()
|
shutter.close()
|
||||||
plt_monitor.set_fig_title(f"Measuring baseline with lamp off")
|
plt_monitor.set_fig_title(f"Measuring baseline with lamp off")
|
||||||
R_offset_fs, phase_offset_deg = set_offsets_laser_only(lockin, shutter, measurement_params["wait_time_s"])
|
R_offset_fs, phase_offset_deg = set_offsets_laser_only(lockin, shutter, measurement_params["wait_time_s"])
|
||||||
@ -236,23 +238,24 @@ def measure_spectrum(metadata:dict={},
|
|||||||
|
|
||||||
|
|
||||||
def sweep_ref():
|
def sweep_ref():
|
||||||
wavelenghts = [500, 550, 650, 660, 670, 680]
|
wavelenghts = [500, 535, 565, 580, 700]
|
||||||
frequencies = list(range(27, 500, 5))
|
frequencies = list(range(27, 500, 2))
|
||||||
frequencies = [111, 444]
|
|
||||||
lockin_params = {
|
lockin_params = {
|
||||||
"time_constant_s": 10,
|
"time_constant_s": 10,
|
||||||
}
|
}
|
||||||
measurement_params = {
|
measurement_params = {
|
||||||
"wavelengths_nm": wavelenghts,
|
"wavelengths_nm": wavelenghts,
|
||||||
}
|
}
|
||||||
time_est = len(frequencies) * get_time_estimate(lockin_params=lockin_params, measurement_params=measurement_params, offset_with_laser_only=True, extra_wait_time_s=10)
|
time_est = 1.15 * len(frequencies) * get_time_estimate(lockin_params=lockin_params, measurement_params=measurement_params, offset_with_laser_only=True, extra_wait_time_s=10)
|
||||||
print(f"Estimated time: {time_est}")
|
print(f"Estimated time: {duration_to_string(time_est)}")
|
||||||
return
|
t_start = time.time()
|
||||||
for f in frequencies:
|
for f in frequencies:
|
||||||
dirname = f"2025-05-07_f-scan_f={f}_Hz"
|
dirname = f"2025-05-09_f-scan_f={f}_Hz"
|
||||||
lockin_params["frequency"] = f
|
lockin_params["frequency_Hz"] = f
|
||||||
measure_spectrum(lockin_params=lockin_params, measurement_params=measurement_params, dirname=dirname, name="Frequency scan $f = {f}$ Hz")
|
measure_spectrum(lockin_params=lockin_params, measurement_params=measurement_params, dirname=dirname, name="Frequency scan $f = {f}$ Hz")
|
||||||
plt.close('all')
|
plt.close('all')
|
||||||
|
duration = time.time() - t_start
|
||||||
|
print(f"Measurement took {duration_to_string(duration)} (estimate was {duration_to_string(time_est)})")
|
||||||
|
|
||||||
# DATA
|
# DATA
|
||||||
def data_load(dirname:str) -> tuple[np.ndarray, dict]:
|
def data_load(dirname:str) -> tuple[np.ndarray, dict]:
|
||||||
|
BIN
prsctrl/tests/__pycache__/spectrum_sweeps.cpython-311.pyc
Normal file
BIN
prsctrl/tests/__pycache__/spectrum_sweeps.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
87
prsctrl/tests/spectrum_sweeps.py
Normal file
87
prsctrl/tests/spectrum_sweeps.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
from prsctrl.utility.prsdata import PrsData
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import numpy as np
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
def process_results(
|
||||||
|
data_dir,
|
||||||
|
dir_regex=r".*",
|
||||||
|
out_dir=None,
|
||||||
|
get_varied_param=lambda data: data.metadata["lock-in_settings"]["frequency_Hz"],
|
||||||
|
fig_suptitle="Frequency scan: <qty>",
|
||||||
|
xlabel="$f$ [Hz]",
|
||||||
|
what=["theta", "stheta", "dR_R", "sdR_R"],
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Process the results of several spectra recorded with one varying measurement or lock-in parameter.
|
||||||
|
|
||||||
|
:param data_dir: Directory containing all data directories of the individual files
|
||||||
|
:param dir_regex: Regex for filtering data directories
|
||||||
|
:param out_dir: Directory into which the plots are saved
|
||||||
|
:param get_varied_param: lambda function getting the varied parameter value from a loaded PrsData object
|
||||||
|
:param fig_suptitle: Figure suptitle, <qty> will be replaced by the name of the quantity
|
||||||
|
:param xlabel: xlabel for the varied parameter
|
||||||
|
:param what: For which quantities to create plots
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
data_dir = os.path.expanduser(data_dir)
|
||||||
|
if out_dir is None:
|
||||||
|
out_dir = data_dir
|
||||||
|
paths = os.listdir(data_dir)
|
||||||
|
data_dirs = []
|
||||||
|
for p in paths:
|
||||||
|
full_path = os.path.join(data_dir, p)
|
||||||
|
if not os.path.isdir(full_path): continue
|
||||||
|
m = re.fullmatch(dir_regex, p)
|
||||||
|
if m:
|
||||||
|
data_dirs.append(full_path)
|
||||||
|
else:
|
||||||
|
print(f"Unmatched directory {p}")
|
||||||
|
assert len(data_dirs) > 0
|
||||||
|
data_dirs.sort()
|
||||||
|
|
||||||
|
varied_params = []
|
||||||
|
data = {}
|
||||||
|
shape = None
|
||||||
|
wls = None
|
||||||
|
for d in data_dirs:
|
||||||
|
print(f"Getting data from {d}")
|
||||||
|
pd = PrsData(load_data_path=d)
|
||||||
|
# f = pd.metadata["lock-in_settings"]["frequency_Hz"]
|
||||||
|
varied_param = get_varied_param(pd)
|
||||||
|
# print(d, f)
|
||||||
|
sdata = pd.get_spectrum_data()
|
||||||
|
print(pd.wavelengths)
|
||||||
|
print(pd.data.keys())
|
||||||
|
if wls is None: wls = sdata[:,0]
|
||||||
|
if shape is None: shape = sdata.shape
|
||||||
|
else:
|
||||||
|
if shape != sdata.shape:
|
||||||
|
print(f"ERROR Shape mismatch for param={varied_param}: {shape} != {sdata.shape}")
|
||||||
|
continue
|
||||||
|
# raise ValueError(f"Shape mismatch for {d}: {shape} != {sdata.shape}")
|
||||||
|
varied_params.append(varied_param)
|
||||||
|
data[varied_param] = sdata
|
||||||
|
data_per_wl_and_vp = np.empty((shape[0], len(varied_params), shape[1]))
|
||||||
|
varied_params.sort()
|
||||||
|
for i in range(shape[0]):
|
||||||
|
for j, f in enumerate(varied_params):
|
||||||
|
data_per_wl_and_vp[i, j, :] = data[f][i,:]
|
||||||
|
print(f"Found wavelengths: {wls}")
|
||||||
|
n_cols = 2
|
||||||
|
n_rows = wls.shape[0] // n_cols + wls.shape[0] % n_cols
|
||||||
|
for qty in what:
|
||||||
|
fig, axs = plt.subplots(n_rows, n_cols, figsize=(8, 8))
|
||||||
|
axs = axs.flatten()
|
||||||
|
qty_idx = PrsData.default_spectrum_columns.index(qty)
|
||||||
|
fig.suptitle(fig_suptitle.replace("<qty>", PrsData.key_names[qty]))
|
||||||
|
for i, wl in enumerate(wls):
|
||||||
|
ax = axs[i]
|
||||||
|
ax.set_xlabel(xlabel)
|
||||||
|
ax.set_ylabel(PrsData.labels[qty])
|
||||||
|
ax.plot(varied_params, data_per_wl_and_vp[i, :, qty_idx])
|
||||||
|
ax.set_title(f"$\\lambda = {wl}$ nm")
|
||||||
|
fig.tight_layout()
|
||||||
|
fig.savefig(os.path.join(out_dir, f"result_{qty}.pdf"))
|
||||||
|
print(varied_params)
|
@ -1,65 +0,0 @@
|
|||||||
from prsctrl.utility.prsdata import PrsData
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import numpy as np
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
|
|
||||||
def process_results(data_dir, dir_regex=r"202.-..-.._f-scan_f=(\d+)_Hz", out_dir=None):
|
|
||||||
data_dir = os.path.expanduser(data_dir)
|
|
||||||
if out_dir is None:
|
|
||||||
out_dir = data_dir
|
|
||||||
paths = os.listdir(data_dir)
|
|
||||||
data_dirs = []
|
|
||||||
for p in paths:
|
|
||||||
full_path = os.path.join(data_dir, p)
|
|
||||||
if not os.path.isdir(full_path): continue
|
|
||||||
m = re.fullmatch(dir_regex, p)
|
|
||||||
if m:
|
|
||||||
data_dirs.append(full_path)
|
|
||||||
else:
|
|
||||||
print(f"Unmatched directory {p}")
|
|
||||||
assert len(data_dirs) > 0
|
|
||||||
data_dirs.sort()
|
|
||||||
|
|
||||||
frequencies = []
|
|
||||||
data = {}
|
|
||||||
shape = None
|
|
||||||
wls = None
|
|
||||||
for d in data_dirs:
|
|
||||||
print(f"Getting data from {d}")
|
|
||||||
pd = PrsData(load_data_path=d)
|
|
||||||
f = pd.metadata["lock-in_settings"]["frequency_Hz"]
|
|
||||||
# print(d, f)
|
|
||||||
sdata = pd.get_spectrum_data()
|
|
||||||
print(pd.wavelengths)
|
|
||||||
print(pd.data.keys())
|
|
||||||
if wls is None: wls = sdata[:,0]
|
|
||||||
if shape is None: shape = sdata.shape
|
|
||||||
else:
|
|
||||||
if shape != sdata.shape:
|
|
||||||
print(f"ERROR Shape mismatch for f={f}: {shape} != {sdata.shape}")
|
|
||||||
continue
|
|
||||||
# raise ValueError(f"Shape mismatch for {d}: {shape} != {sdata.shape}")
|
|
||||||
frequencies.append(f)
|
|
||||||
data[f] = sdata
|
|
||||||
data_per_wl_and_f = np.empty((shape[0], len(frequencies), shape[1]))
|
|
||||||
frequencies.sort()
|
|
||||||
for i in range(shape[0]):
|
|
||||||
for j, f in enumerate(frequencies):
|
|
||||||
data_per_wl_and_f[i, j, :] = data[f][i,:]
|
|
||||||
print(f"Found wavelengths: {wls}")
|
|
||||||
n_cols = 2
|
|
||||||
for qty in ["theta", "stheta", "dR_R", "sdR_R"]:
|
|
||||||
fig, axs = plt.subplots(wls.shape[0]//n_cols, n_cols, sharex=True, figsize=(8, 8))
|
|
||||||
axs = axs.flatten()
|
|
||||||
qty_idx = PrsData.default_spectrum_columns.index(qty)
|
|
||||||
fig.suptitle(f"Frequency scan: {PrsData.key_names[qty]}")
|
|
||||||
axs[-1].set_xlabel("Modulation Frequency $f$ [Hz]")
|
|
||||||
for i, wl in enumerate(wls):
|
|
||||||
ax = axs[i]
|
|
||||||
ax.set_ylabel(PrsData.labels[qty])
|
|
||||||
ax.plot(frequencies, data_per_wl_and_f[i, :, qty_idx])
|
|
||||||
ax.set_title(f"$\\lambda = {wl}$ nm")
|
|
||||||
fig.tight_layout()
|
|
||||||
fig.savefig(out_dir + f"result_{qty}.pdf")
|
|
||||||
print(frequencies)
|
|
@ -0,0 +1,25 @@
|
|||||||
|
timedelta = [("d", 24*3600), ("h", 3600), ("m", 60), ("s", 1)]
|
||||||
|
def duration_to_string(duration: float) -> str:
|
||||||
|
"""
|
||||||
|
Convert a duration in seconds to a string of the form "<days>d <hours>h <minutes>m <seconds>s"
|
||||||
|
where only the largest units are included.
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
duration: float
|
||||||
|
Duration in seconds.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
String representation of the duration.
|
||||||
|
"""
|
||||||
|
include = False
|
||||||
|
s = ""
|
||||||
|
sign = 1 if duration > 0 else -1
|
||||||
|
time_left = abs(int(duration))
|
||||||
|
for i, (unit, unit_seconds) in enumerate(timedelta):
|
||||||
|
t = int(time_left / unit_seconds)
|
||||||
|
if t != 0 or include or unit == "s":
|
||||||
|
s += f"{sign*t:02}{unit} "
|
||||||
|
include = True
|
||||||
|
time_left %= unit_seconds
|
||||||
|
return s.strip()
|
Binary file not shown.
Binary file not shown.
@ -162,8 +162,11 @@ class PrsData:
|
|||||||
"dR": r"$\Delta R$ [V]",
|
"dR": r"$\Delta R$ [V]",
|
||||||
"R": r"$R$ [V]",
|
"R": r"$R$ [V]",
|
||||||
"theta": r"$\theta$ [°]",
|
"theta": r"$\theta$ [°]",
|
||||||
|
"sdR_R": r"$\sigma_{\Delta R/R}$",
|
||||||
|
"sdR": r"$\sigma_{\Delta R}$ [V]",
|
||||||
|
"sR": r"$\sigma_R$ [V]",
|
||||||
|
"stheta": r"$\sigma_\theta$ [°]",
|
||||||
}
|
}
|
||||||
labels |= {f"s{k}": f"$\sigma_{{{v[1:]}}}" for k, v in labels.items()}
|
|
||||||
def get_spectrum_data(self, wavelengths=None, keys=None) -> np.ndarray:
|
def get_spectrum_data(self, wavelengths=None, keys=None) -> np.ndarray:
|
||||||
"""
|
"""
|
||||||
Return the spectral data for the specified keys and wavelengths.
|
Return the spectral data for the specified keys and wavelengths.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user