212 lines
6.8 KiB
Python
212 lines
6.8 KiB
Python
import pyvisa
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
if __package__ is None:
|
|
# make relative imports work as described here: https://peps.python.org/pep-0366/#proposed-change
|
|
__package__ = "photoreflectance"
|
|
from os import path
|
|
filepath = path.realpath(path.abspath(__file__))
|
|
sys.path.insert(0, 'C:\\Users\Administrator\Desktop\Software\Python\Python\github')
|
|
|
|
from time import sleep, time as now
|
|
|
|
import numpy as np
|
|
import matplotlib.pyplot as plt
|
|
from Bentham import Bentham
|
|
from prsctrl.devices.lamp.impl.xenon import Xenon
|
|
from prsctrl.devices.shutter import ShutterProbe
|
|
|
|
from .update_funcs import Monitor
|
|
from prsctrl.devices.lock_in.impl.sr830 import SR830
|
|
import logging
|
|
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format="%(asctime)s [%(levelname)s] [%(name)s] %(message)s",
|
|
handlers=[
|
|
# logging.FileHandler(log_path),
|
|
logging.StreamHandler()
|
|
]
|
|
)
|
|
log = logging.getLogger(__name__)
|
|
|
|
def set_measurement_params(lockin: SR830, p: dict={}, **kwargs):
|
|
params = p | kwargs
|
|
key_to_setter = {
|
|
"time_constant_s": lockin.set_time_constant_s,
|
|
"filter_slope": lockin.set_filter_slope,
|
|
"sync_filter": lockin.set_sync_filter,
|
|
"reserve": lockin.set_reserve,
|
|
"sensitivity_volt": lockin.set_sensitivity_volt,
|
|
}
|
|
for k, v in params.items():
|
|
if k not in key_to_setter.keys():
|
|
raise KeyError(f"Invalid parameter {k}")
|
|
key_to_setter[k](v)
|
|
|
|
|
|
def set_offset_laser_only(lockin: SR830, shutter: ShutterProbe, wait_time_s):
|
|
"""
|
|
Set the R offset from the signal when only the laser is on.
|
|
This signal should be stray laser light and laser induced PL
|
|
:return: Offset as percentage of the full scale R
|
|
"""
|
|
log.info("Setting offset when the lamp is off.")
|
|
shutter.close_()
|
|
sleep(wait_time_s + 10)
|
|
lockin.run("AOFF 3") # auto offset R
|
|
R_offset_fs = float(lockin.query("OEXP? 3").split(",")[0]) # returns R offset and expand
|
|
return R_offset_fs
|
|
|
|
|
|
def _measure_both_sim(monochromator: Bentham, lockin: SR830, shutter: ShutterProbe, wl=550, aux_DC="Aux In 4", monitor=None):
|
|
data = {}
|
|
lockin_params = {
|
|
"time_constant_s": 10,
|
|
# "time_constant_s": 100e-3,
|
|
"sensitivity_volt": 50e-6,
|
|
"filter_slope": 12,
|
|
"sync_filter": 1,
|
|
"reserve": "Normal",
|
|
}
|
|
measurement_params = {
|
|
"measurement_time_s": 30,
|
|
"sample_rate_Hz": 512,
|
|
}
|
|
|
|
set_measurement_params(lockin, lockin_params)
|
|
|
|
measurement_time_s = measurement_params["measurement_time_s"]
|
|
sample_rate_AC = measurement_params["sample_rate_Hz"]
|
|
n_bins_AC = measurement_time_s * sample_rate_AC # x sec messen mit <sample_rate> werte pro sekunde
|
|
timeout_s = 60
|
|
timeout_interval = 0.5
|
|
# trigger on the falling edge, since the light comes through when the ref signal is low
|
|
# could of course also trigger on rising and apply 180° shift
|
|
lockin.run("RSLP 2")
|
|
# since we dont expect changes in our signal, we can use larger time constants and aggressive filter slope
|
|
# for better signal to noise
|
|
def run_lockin_cmd(cmd, n_try=2):
|
|
com_success = n_try
|
|
e = None
|
|
while com_success > 0:
|
|
try:
|
|
return cmd()
|
|
except pyvisa.VisaIOError as e:
|
|
lockin.try_recover_from_communication_error(e)
|
|
com_success -= 1
|
|
raise e
|
|
|
|
# 5s for setting buffer,
|
|
# 5s for get values and plot
|
|
input("Make sure the laser is turned off and press enter > ")
|
|
mon = monitor if monitor is not None else Monitor(r"$t$ [s]", [
|
|
dict(ax=0, ylabel=r"$R [V]$", color="green"),
|
|
])
|
|
data["lock-in-params"] = lockin_params
|
|
data["measurement-params"] = measurement_params
|
|
|
|
N_runs = 60
|
|
|
|
shutter.open_()
|
|
monochromator.drive(wl)
|
|
sleep(10)
|
|
|
|
t0 = now()
|
|
j = 0
|
|
data['R'] = []
|
|
data['t'] = []
|
|
for i in range(N_runs):
|
|
mon.set_ax_title(f"{i+1}/{N_runs}")
|
|
run_lockin_cmd(lambda: lockin.buffer_setup(CH1="R", CH2=aux_DC, length=n_bins_AC, sample_rate=sample_rate_AC))
|
|
ti = now() - t0
|
|
run_lockin_cmd(lambda: lockin.buffer_start_fill())
|
|
t = timeout_s
|
|
while t > 0:
|
|
t -= timeout_interval
|
|
sleep(timeout_interval)
|
|
if run_lockin_cmd(lambda: lockin.buffer_is_done()):
|
|
break
|
|
if t < 0: raise RuntimeError("Timed out waiting for buffer measurement to finish")
|
|
R = run_lockin_cmd(lambda: lockin.buffer_get_data(CH1=False, CH2=True))[0]
|
|
data['R'].append(R)
|
|
tdata = np.arange(n_bins_AC) * 1/sample_rate_AC * measurement_time_s + ti
|
|
data['t'].append(tdata)
|
|
mon.update_array(tdata, R)
|
|
mon.set_fig_title("Background")
|
|
mon.set_ax_title("")
|
|
return data, mon
|
|
|
|
lockin = None
|
|
lamp = None
|
|
mcm = None
|
|
shutter = None
|
|
|
|
def measure_both_sim(**kwargs):
|
|
return _measure_both_sim(mcm, lockin, shutter, **kwargs)
|
|
|
|
|
|
def _load_process():
|
|
import os; import pickle
|
|
with open(os.path.expanduser("~/Desktop/PR/2025-05-07_Xenon_1.pkl"), "rb") as file:
|
|
data = pickle.load(file)
|
|
process_data(data['R'], data['t'])
|
|
|
|
|
|
def process_data(data_R: list[np.ndarray], data_t: list[np.ndarray]) -> np.ndarray:
|
|
assert len(data_R) == len(data_t)
|
|
n_points_2 = 512 * 5
|
|
|
|
n_points_averaged = data_R[0].shape[0]-2*n_points_2
|
|
l = len(data_R) * n_points_averaged
|
|
# Rs = np.empty(l, dtype=float)
|
|
# ts = np.empty(l, dtype=float)
|
|
Rs = []
|
|
ts = []
|
|
|
|
fig, ax = plt.subplots()
|
|
ax.set_xlabel("$t$ [s]")
|
|
ax.set_ylabel(r"$R [V]$")
|
|
for i in range(len(data_R)):
|
|
Rs_i = moving_average(data_R[i], n_points_2)
|
|
new_t_data = np.arange(data_R[i].shape[0], dtype=int) /512 + (i * 30)
|
|
ts_i = new_t_data[n_points_2:-n_points_2]
|
|
# ts_i = data_t[i][n_points_2:-n_points_2]
|
|
# Rs[i*n_points_averaged:(i+1)*n_points_averaged] = Rs_i
|
|
# ts[i*n_points_averaged:(i+1)*n_points_averaged] = ts_i
|
|
Rs.append(Rs_i)
|
|
ts.append(ts_i)
|
|
ax.plot(ts_i, Rs_i, color="blue")
|
|
plt.show()
|
|
return fig
|
|
|
|
def moving_average(a: np.ndarray, n_points_2=2):
|
|
"""
|
|
|
|
:param a:
|
|
:param n_points_2: Number of points to take to the left and right of the averaged point, leading to 2*n_points+1 per value
|
|
:return:
|
|
"""
|
|
l = a.shape[0]
|
|
lret = l-2*n_points_2
|
|
ret = np.empty(lret)
|
|
for i in range(lret):
|
|
around_i = n_points_2 + i
|
|
begin = around_i - n_points_2
|
|
end = around_i + n_points_2 + 1
|
|
ret[i] = np.sum(a[begin:end]) / (2*n_points_2 + 1)
|
|
# print(i, begin, end, ret[i])
|
|
return ret
|
|
|
|
|
|
if __name__ == "__main__":
|
|
mcm = Bentham()
|
|
shutter = ShutterProbe()
|
|
# mcm.park()
|
|
lamp = Xenon()
|
|
#lockin = SR830.connect_device(SR830.enumerate_devices()[0])
|
|
# lockin = Model7260.connect_device(Model7260.enumerate_devices()[0])
|
|
# mcm = DummyBentham()
|
|
# shutter = DummyShutter()
|