Commit e9a729cc authored by Yb Tweezer's avatar Yb Tweezer
Browse files

add AM/FM control back in for green probe beams; reorganize tweezer optim script a bit

parent d66e65d9
......@@ -55,6 +55,8 @@ from .system import (
AD5791_DAC,
MOT3_GREEN_AOM_FM,
MOT3_GREEN_AOM_AM,
PROBE_GREEN_AOM_FM,
PROBE_GREEN_AOM_AM,
)
from .dataio import (
get_timestamp,
......
......@@ -85,8 +85,8 @@ CONNECTIONS = ConnectionLayout(
probe_blue_aom = Digital(0, 5, 0),
probe_blue_sh = Digital(1, 1, 0),
probe_green_aom = Digital(0, 11, 1), # HIGH == off for Time Base RF generator
probe_green_aom_am = Analog(5, 0.53),
probe_green_aom_fm = Analog(6, 0.00),
probe_green_aom_am = Analog(5, -0.58),
probe_green_aom_fm = Analog(6, 0.02),
probe_green_sh = Digital(1, 9, 0),
tweezer_green_aom = Digital(1, 15, 0),
tweezer_green_sh = Digital(1, 1, 0),
......@@ -139,7 +139,7 @@ def MOT3_GREEN_AOM_FM_10(f: float) -> float:
def MOT3_GREEN_AOM_FM_11(f: float) -> float:
f0 = 92.0
if f - f0 < -6.1 or f - f0 > 6.5:
raise Exception("MOT3_GREEN_AOM_FM: frequency out of range")
raise Exception(f"MOT3_GREEN_AOM_FM: frequency {f:g} out of range")
a = [
+0.00955450,
+1.30363916,
......@@ -156,10 +156,35 @@ def MOT3_GREEN_AOM_FM(f: float) -> float:
# 29.0 nominal; -60 offset on driver
def MOT3_GREEN_AOM_AM(p: float) -> float:
if p < -25.0 or p > 29.5:
raise Exception("MOT3_GREEN_AOM_AM: power out of range")
raise Exception(f"MOT3_GREEN_AOM_AM: power {p:g} out of range")
A = +421.384083
P0 = +45.7474511
B = -1.10711219
return A / (p - P0)**2 + B
RAMAN_GREEN_AOM_AM = lambda p: (p - 15.0) / 15.01 # 29.0 nominal; -73 offset on controller
# 90.0 nominal; depth = 13.1072 MHz (n = 12)
def PROBE_GREEN_AOM_FM_12(f: float) -> float:
f0 = 90.0
if f - f0 < -12.1 or f - f0 > 13.0:
raise Exception(f"PROBE_GREEN_AOM_FM: frequency {f:g} out of range")
a = [
+0.01515528,
+0.65945606,
+0.00000000,
-6.8786e-05,
+0.00000000,
+9.6312e-07,
]
return sum(ak * (f - f0)**k for k, ak in enumerate(a))
def PROBE_GREEN_AOM_FM(f: float) -> float:
return PROBE_GREEN_AOM_FM_12(f) # change this call depending on the FM settings
# 27.0 nominal; -66 offset on driver
def PROBE_GREEN_AOM_AM(p: float) -> float:
if p < -26.0 or p > 27.0:
raise Exception(f"PROBE_GREEN_AOM_AM: power {p:g} out of range")
A = +330.627240
P0 = +39.9950831
B = -1.06714622
return A / (p - P0)**2 + B
......@@ -12,9 +12,9 @@ import toml
# print(timestamp)
# outdir = DATADIRS.tweezer_atoms.joinpath(timestamp)
_save = False
_label = "hist_det-probe=93.40_p-probe=14.0_tau-probe=150.0_disp=4.2_tau-preprobe=150"
_counter = 0
_save = True
_label = "mF=p1h_B=5G_probe-scan"
_counter = 11
date = get_timestamp().split("_")[0].replace("-", "")
datadir = DATADIRS.tweezer_atoms.joinpath(date)
......@@ -24,7 +24,6 @@ while datadir.joinpath(f"{_label}_{_counter:03.0f}").is_dir():
outdir = datadir.joinpath(f"{_label}_{_counter:03.0f}")
comments = """
no loading block
"""[1:-1]
# CAMERA OPTIONS
......@@ -49,7 +48,7 @@ flir_config = {
## MAIN SEQUENCE PARAMETERS
# general
reps: int = 800 # repeat shots for statistics
reps: int = 20 # repeat shots for statistics
clk_freq: float = 10e6 # serial_bits clock frequency; Hz
take_background: bool = False # include a background image
flir_two_shots: bool = False # use the Flir to take two shots
......@@ -122,14 +121,11 @@ T_COMP = t0 + tau_comp + np.linspace(0.0, 4e-3, 51) # compression ramp times
tau_pause = 0.75e-3 # pause between ncool and load; s
tau_twzr_load = 0e-3 # time to load into tweezers; s
tau_disperse = 30e-3 # wait for CMOT atoms to disperse
# TAU_PREPROBE = np.array([0.5e-3, 5e-3, 10e-3, 30e-3, 50e-3, 75e-3, 100e-3, 125e-3, 150e-3, 175e-3, 200e-3, 250e-3, 300e-3]) # hold with CMOT or probe beams at imaging (proxy) frequency
TAU_PREPROBE = np.linspace(100e-3, 400e-3, 13)
TAU_PREPROBE = np.array([150e-3])
# TAU_PREPROBE = np.array([0.0, 5.0, 10.0, 20.0, 40.0, 80.0, 160.0, 320.0, 500.0, 1000.0, 1500.0, 2000.0]) * 1e-3
TAU_PP = np.array([0e-3]) # parity projection pulse time; s
TAU_PREPROBE = np.array([0.0e-3]) # hold with CMOT or probe beams at imaging (proxy) frequency
# TAU_PREPROBE = np.array([0.5, 1.0, 2.0, 5.0, 10.0, 50.0, 100.0, 200.0, 300.0, 400.0, 500.0]) * 1e-3
TAU_PP = np.array([0.0e-3]) # parity projection pulse time; s
tau_dark_open = 27e-3 # shutter opening time for EMCCD; s
TAU_PROBE = np.array([100e-3])
# TAU_PROBE = np.array([0.5e-3, 1e-3, 2e-3, 5e-3, 10e-3, 50e-3, 100e-3, 200e-3, 300e-3, 400e-3, 500e-3, 700e-3]) # probe beam time; s
TAU_PROBE = np.array([100e-3]) # probe beam time; s
tau_image = TAU_PROBE.max() # EMCCD exposure time; s
tau_dark_close = 40e-3 # shutter closing time for EMCCD; s
......@@ -148,10 +144,11 @@ bits_Bset = int(20) # number of bits in a servo setting
bits_DACset = int(4) # number of bits in a DAC-mode setting
B_COMP = np.linspace(B_green, B_green * 1.8, T_COMP.shape[0]) # compression ramp values
shims_ud_pp = 0 # bias field for parity projection: B = 0.4 * 4.92 * V
SHIMS_UD_PROBE = np.linspace(2.54, 2.54, 1) # bias field during probing (imaging) time: B = 0.4 * 4.92 * V
# detunings
DET_PREPROBE = np.linspace(3.4, 3.4, 1) # preprobe imaging conditions proxy using CMOT or probe beams (rel. to AOM center); MHz
DET_PROBE = np.linspace(3.4, 3.4, 1) # probe beam detuning for imaging (rel. to AOM center); MHz
DET_PROBE = np.linspace(7.0, 8.5, 16) # probe beam detuning for imaging (rel. to AOM center); MHz
DET_LOAD = np.linspace(-0.0, +0.0, 1) # green MOT detuning for tweezer loading (rel. to CMOT); MHz
DET_PP = np.linspace(-3.58, +0.42, 1) # green MOT detuning for partity projection (rel. to CMOT); MHz
det_556_tweezer = 3.68 # detuning on the 556 tweezer (probe) path (rel. to AOM center); MHz
......@@ -172,6 +169,7 @@ nu_ramp = 3.58 # extent of ramp; MHz
# power parameters
p_ramp_beg = 29.0 # start of ramp; dBm
p_ramp_end = -11.0 # end of ramp; dBm
p_preprobe = 14.0 # power in pre-probe pulse; dBm
p_probe = 14.0 # power in probe beam AOMs; dBm
p_556_tweezer = -10.0 # power in the 556 tweezer (probe) AOM; dBm
p_pp = 17.0 # parity projection pulse AOM (CMOT) power; dBm
......@@ -195,9 +193,11 @@ def make_sequence(
det_load: float,
det_preprobe: float,
det_pp: float,
shim_fb: float,
shim_lr: float,
shim_ud: float,
det_probe: float,
shims_fb: float,
shims_lr: float,
shims_ud: float,
shims_ud_probe: float,
tau_preprobe: float,
tau_pp: float,
tau_probe: float,
......@@ -307,32 +307,32 @@ def make_sequence(
).with_color("C0"),
"FB/LR/UD shims": (Sequence()
+ [
+ Sequence([
Event.digital1(**c, s=not c.default)
@ (t0 - 4.5e-3 + k * 1e-16) # 4.5ms delay with offset from simultaneity
for k, (c, v) in enumerate([
(C.shim_coils_p_fb, shim_fb),
(C.shim_coils_p_lr, shim_lr),
(C.shim_coils_p_ud, shim_ud)
(C.shim_coils_p_fb, shims_fb),
(C.shim_coils_p_lr, shims_lr),
(C.shim_coils_p_ud, shims_ud)
])
if v < 0.0
]
+ [
])
+ Sequence([
Event.analog(**c, s=abs(s)) @ (t0 + k * 1e-16) # have to offset times from e/o
for k, (c, s) in enumerate([
(C.shim_coils_fb, shim_fb),
(C.shim_coils_lr, shim_lr),
(C.shim_coils_ud, shim_ud)
(C.shim_coils_fb, shims_fb),
(C.shim_coils_lr, shims_lr),
(C.shim_coils_ud, shims_ud)
])
]
+ [
])
+ Sequence([
Event.analog(**c, s=0.0)
@ (t0 + tau_ncool + k * 1e-16) # have to offset times from e/o
for k, c in enumerate([
C.shim_coils_fb, C.shim_coils_lr, C.shim_coils_ud
])
]
+ [
])
+ Sequence([
Event.analog(
**C.shim_coils_ud, s=shims_ud_pp
) @ (t0
......@@ -352,24 +352,24 @@ def make_sequence(
+ tau_preprobe
+ tau_pp
),
]
+ [
])
+ Sequence([
Event.analog(**c, s=c.default) # have to offset times from e/o
@ (t0 + tau_all + k * 1e-16)
for k, c in enumerate([
C.shim_coils_fb, C.shim_coils_lr, C.shim_coils_ud
])
]
+ [
])
+ Sequence([
Event.digital1(**c, s=c.default)
@ (t0 + tau_all - 4.5e-3 + k * 1e-16) # 4.5ms delay with offset from simultaneity
for k, (c, v) in enumerate([
(C.shim_coils_p_fb, shim_fb),
(C.shim_coils_p_lr, shim_lr),
(C.shim_coils_p_ud, shim_ud)
(C.shim_coils_p_fb, shims_fb),
(C.shim_coils_p_lr, shims_lr),
(C.shim_coils_p_ud, shims_ud)
])
if v < 0.0
]
])
).with_color("C8"),
"Green MOT(s)": (Sequence()
......@@ -516,6 +516,64 @@ def make_sequence(
tau_probe,
invert=True
)
+ Sequence([
Event.analog(**C.probe_green_aom_fm, s=PROBE_GREEN_AOM_FM(90.0 + det_probe))
@ (t0
+ tau_ncool
+ tau_pause
+ tau_twzr_load
+ tau_disperse
+ tau_preprobe
+ tau_pp
+ tau_dark_open
),
Event.analog(**C.probe_green_aom_am, s=PROBE_GREEN_AOM_AM(p_probe))
@ (t0
+ tau_ncool
+ tau_pause
+ tau_twzr_load
+ tau_disperse
+ tau_preprobe
+ tau_pp
+ tau_dark_open
),
])
+ Sequence([
Event.digital1(**C.shim_coils_ud_p, s=1)
@ (t0
+ tau_ncool
+ tau_pause
+ tau_twzr_load
+ tau_disperse
+ tau_preprobe
+ tau_pp
+ tau_dark_open
- 4.5e-3 # 4.5ms delay
)
] if shims_ud_probe < 0.0 else list())
+ Sequence([
Event.analog(**C.shim_coils_ud, s=abs(shims_ud_probe))
@ (t0
+ tau_ncool
+ tau_pause
+ tau_twzr_load
+ tau_disperse
+ tau_preprobe
+ tau_pp
+ tau_dark_open
),
Event.analog(**C.shim_coils_ud, s=0.0)
@ (t0
+ tau_ncool
+ tau_pause
+ tau_twzr_load
+ tau_disperse
+ tau_preprobe
+ tau_pp
+ tau_dark_open
+ tau_probe
),
] if shims_ud_probe != 0.0 else list())
# + Sequence.digital_pulse(
# *C.probe_green_sh,
# t0 + tau_ncool + tau_pause - 2e-3, # account for 2 ms shutter delay
......@@ -553,20 +611,59 @@ def make_sequence(
tau_preprobe,
invert=True
)
+ Sequence([
Event.analog(
**C.probe_green_aom_fm,
s=PROBE_GREEN_AOM_FM(90.0 + det_preprobe)
) @ (t0 + tau_ncool + tau_pause + tau_twzr_load + tau_disperse),
Event.analog(
**C.probe_green_aom_am,
s=PROBE_GREEN_AOM_AM(p_preprobe)
) @ (t0 + tau_ncool + tau_pause + tau_twzr_load + tau_disperse),
])
).with_color("g")
else:
SEQ["Pre-probe"] = (Sequence()
+ Sequence([ # proxy-test the in-tweezer cooling frequency
# Event.digital1(**C.mot3_green_aom, s=1)
# @ (t0 + tau_ncool + tau_pause + tau_twzr_load),
# Event.digital1(**C.mot3_green_aom, s=0)
# @ (t0 + tau_ncool + tau_pause + tau_twzr_load + tau_disperse),
Event.analog(
**C.mot3_green_aom_fm,
s=MOT3_GREEN_AOM_FM(90.0 + det_preprobe)
) @ (t0 + tau_ncool + tau_pause + tau_twzr_load + tau_disperse),
Event.analog(
**C.mot3_green_aom_am,
s=MOT3_GREEN_AOM_AM(p_preprobe)
) @ (t0 + tau_ncool + tau_pause + tau_twzr_load + tau_disperse)
])
).with_color("g")
SEQ["Pre-probe"] = (SEQ["Pre-probe"]
+ Sequence([
Event.digital1(**C.shim_coils_ud_p, s=1)
@ (t0
+ tau_ncool
+ tau_pause
+ tau_twzr_load
+ tau_disperse
- 4.5e-3 # 4.5ms delay
)
] if shims_ud_probe < 0.0 else list())
+ Sequence([
Event.analog(**C.shim_coils_ud, s=abs(shims_ud_probe))
@ (t0
+ tau_ncool
+ tau_pause
+ tau_twzr_load
+ tau_disperse
),
Event.analog(**C.shim_coils_ud, s=0.0)
@ (t0
+ tau_ncool
+ tau_pause
+ tau_twzr_load
+ tau_disperse
+ tau_preprobe
),
] if shims_ud_probe != 0.0 else list())
).with_color("g")
SEQ["Sequence"] = ( # dummy sequence; ensures that EW backend stays in-sequence
Sequence.digital_hilo(
......@@ -615,102 +712,25 @@ seq_bkgd = SuperSequence(
}, CONNECTIONS)
# DEFINE MOGRF SEQUENCE
def make_mot_mogtable(mot_det: float, probe_proxy_det: float, pp_det: float):
# def make_mot_mogtable(mot_det: float):
# ramp_N is number of steps, not points, so use ramp_N + 1 for number of points
RAMP_T = np.linspace(tau_ramp - tau_ref, tau_ramp - tau_ref + tau_rampdur, ramp_N + 1)
RAMP_F = np.linspace(f_ramp, f_ramp + nu_ramp, ramp_N + 1)
RAMP_P = np.linspace(p_ramp_beg, p_ramp_end, ramp_N + 1)
mogtable = MOGTable()
mogtable \
<< MOGEvent(frequency=RAMP_F[0], power=RAMP_P[0]) \
@ (0.0 - tau_ref) # make sure the frequency/power is right at t0
for t, f, p in zip(RAMP_T, RAMP_F, RAMP_P):
mogtable << MOGEvent(frequency=f, power=p) @ t
(mogtable
# apply detuning for loading
<< MOGEvent(frequency=RAMP_F[-1] + mot_det)
@ (-tau_ref + tau_ncool + tau_pause + 1.7e-3) # unknown source of timing error
)
if use_cmot_preprobe:
(mogtable
# switch to imaging frequency to test in-tweezer cooling
<< MOGEvent(frequency=90.0 + probe_proxy_det)
@ (-tau_ref + tau_ncool + tau_pause + tau_twzr_load + 1.7e-3) # unknown source of timing error
)
(mogtable
# apply detuning for parity projection
<< MOGEvent(frequency=90.0 + pp_det)
@ (-tau_ref
+ tau_ncool
+ tau_pause
+ tau_twzr_load
+ use_cmot_preprobe * tau_preprobe
+ 1.7e-3 # unknown source of timing error
)
# detune and depower the MOT beams for loading tweezers after the CMOT ramp
# is finished
<< MOGEvent(frequency=RAMP_F[-1] + det_block, power=-50.0)
@ (-tau_ref
+ tau_ncool
+ tau_pause
+ tau_twzr_load
+ use_cmot_preprobe * tau_preprobe
+ tau_pp
+ 1.7e-3 # unknown source of timing error
)
)
return MOGSuperTable(
outdir.joinpath("mot_mogtables"),
(
f"mot-det={mot_det:.5f}"
f"_probe-proxy-det={probe_proxy_det:.5f}"
f"_pp-det={pp_det:.5f}"
),
{
"cmot beam control": mogtable
}
)
# SCRIPT CONTROLLER
class NarrowCoolingTweezerAlignment(Controller):
def precmd(self, *args):
self.comp = MAIN.connect()
self.comp.set_defaults().def_digital(*C.probe_green_sh, 1)
# )
self.tb = TIMEBASE.connect()
self.tb.set_amplitude(p_probe)
def run_sequence(self, *args):
if _save:
if not datadir.is_dir():
print(f":: mkdir -p {datadir}")
datadir.mkdir(parents=True, exist_ok=True)
if not outdir.is_dir():
print(f":: mkdir -p {outdir}")
outdir.mkdir(parents=True, exist_ok=True)
with outdir.joinpath("params.toml").open('w') as outfile:
toml.dump(params, outfile)
with outdir.joinpath("comments.txt").open('w') as outfile:
outfile.write(comments)
N_probe = len(DET_PROBE)
N_ew = np.prod([
self.N_ew = np.prod([
len(X) for X in [
DET_LOAD,
DET_PREPROBE,
DET_PP,
DET_PROBE,
SHIMS_FB,
SHIMS_LR,
SHIMS_UD,
SHIMS_UD_PROBE,
TAU_PREPROBE,
TAU_PP,
TAU_PROBE,
......@@ -718,12 +738,12 @@ class NarrowCoolingTweezerAlignment(Controller):
]
])
N = [reps, N_probe, N_ew]
NN = [np.prod(N[-k:]) for k in range(1, len(N))][::-1] + [1]
TOT = np.prod(N)
self.N = [reps, self.N_ew]
self.NN = [np.prod(self.N[-k:]) for k in range(1, len(self.N))][::-1] + [1]
self.TOT = np.prod(self.N)
fmt = (" "
+ " ".join(f"{{:{int(np.log10(n)) + 1:.0f}}}/{n}" for n in N)
self.fmt = (" "
+ " ".join(f"{{:{int(np.log10(n)) + 1:.0f}}}/{n}" for n in self.N)
+ " ({:6.2f}%) \r"
)
......@@ -731,30 +751,39 @@ class NarrowCoolingTweezerAlignment(Controller):
self.ssequences = lambda: (
make_sequence(*X)
for X in product(
DET_LOAD, DET_PREPROBE, DET_PP,
SHIMS_FB, SHIMS_LR, SHIMS_UD,
DET_LOAD, DET_PREPROBE, DET_PP, DET_PROBE,
SHIMS_FB, SHIMS_LR, SHIMS_UD, SHIMS_UD_PROBE,
TAU_PREPROBE, TAU_PP, TAU_PROBE, TAU_ANDOR,
)
)
def run_sequence(self, *args):
if _save:
if not datadir.is_dir():
print(f":: mkdir -p {datadir}")
datadir.mkdir(parents=True, exist_ok=True)
if not outdir.is_dir():
print(f":: mkdir -p {outdir}")
outdir.mkdir(parents=True, exist_ok=True)
with outdir.joinpath("params.toml").open('w') as outfile:
toml.dump(params, outfile)
with outdir.joinpath("comments.txt").open('w') as outfile:
outfile.write(comments)
t0 = timeit.default_timer()
for rep in range(reps):
for i, d_probe in enumerate(DET_PROBE):
(self.tb
.set_frequency(90.0 + d_probe)
for i, seq in enumerate(self.ssequences()):
print(self.fmt.format(
rep + 1, i + 1,
100.0 * (
sum(q * nnq for q, nnq in zip([rep, i], self.NN)) + 1
) / self.TOT
), end="", flush=True)
(self.comp
.enqueue(seq.to_sequence())
.run(printflag=False)
.clear()
)
for j, seq in enumerate(self.ssequences()):
print(fmt.format(
rep + 1, i + 1, j + 1,
100.0 * (
sum(q * nnq for q, nnq in zip([rep, i, j], NN)) + 1
) / TOT
), end="", flush=True)
(self.comp
.enqueue(seq.to_sequence())
.run(printflag=False)
.clear()
)
print("")
if take_background:
print("background")
......@@ -767,10 +796,11 @@ class NarrowCoolingTweezerAlignment(Controller):
T = timeit.default_timer() - t0
print(
f" total elapsed time: {T:.2f} s"
f"\n average time per shot: {T / TOT:.2f} s"
f"\n average time per shot: {T / self.TOT:.2f} s"
)
self.comp.clear().disconnect()
self.tb.disconnect()
def on_error(self, ERR: Exception, *args):
# try to exit gracefully on error, even if it means this part is
......@@ -789,8 +819,8 @@ class NarrowCoolingTweezerAlignment(Controller):
def cmd_visualize(self, *args):
seq = make_sequence(
DET_LOAD.mean(), DET_PREPROBE.mean(), DET_PP.mean(),
SHIMS_FB.mean(), SHIMS_LR.mean(), SHIMS_UD.mean(),
DET_LOAD.mean(), DET_PREPROBE.mean(), DET_PP.mean(), DET_PROBE.mean(),
SHIMS_FB.mean(), SHIMS_LR.mean(), SHIMS_UD.mean(), SHIMS_UD_PROBE.mean(),
TAU_PREPROBE.mean(), TAU_PP.mean(), TAU_PROBE.mean(), TAU_ANDOR.mean(),
)
try:
......@@ -825,5 +855,40 @@ class NarrowCoolingTweezerAlignment(Controller):
)
sys.exit(0)
def cmd_dryrun(self, *args):
self._perform_actions("dryrun_", args)
def dryrun_sequence(self, *args):
print("DRY RUN")
if _save:
if not datadir.is_dir():
print(f"[dryrun] :: mkdir -p {datadir}")
if not outdir.is_dir():
print(f"[drurun] :: mkdir -p {outdir}")
print("[dryrun] write params.toml")
print("[dryrun] write comments.txt")
t0 = timeit.default_timer()
for rep in range(reps):
for i, seq in enumerate(self.ssequences()):
print(self.fmt.format(
rep + 1, i + 1,
100.0 * (
sum(q * nnq for q, nnq in zip([rep, i], self.NN)) + 1
) / self.TOT
), end="", flush=True)
print("")
if take_background:
print("background")
T = timeit.default_timer() - t0
print(
f" total elapsed time: {T:.2f} s"
f"\n average time per shot: {T / self.TOT:.2f} s"
)
self.comp.clear().disconnect()
self.tb.disconnect()
if __name__ == "__main__":
NarrowCoolingTweezerAlignment().RUN()
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment