RESULT: get the results of the 11_07 data in order

This commit is contained in:
Valentin Boettcher 2024-07-17 15:17:04 -04:00
parent 8b4d0ec1bf
commit 5ec5eab39a
28 changed files with 448 additions and 0 deletions

View file

@ -0,0 +1,116 @@
from rabifun.system import *
from rabifun.plots import *
from rabifun.utilities import *
from rabifun.analysis import *
from ringfit.data import ScanData
from ringfit.plotting import *
import gc
path = "../../data/11_07_24/second_signal"
scan = ScanData.from_dir(path, extension="npz")
# %% plot scan
gc.collect()
fig = plt.figure("interactive", constrained_layout=True, figsize=(20, 3 * 5))
fig.clf()
(ax_signal, ax_window, ax_spectrum) = fig.subplot_mosaic("AA;BC").values()
plot_scan(scan, ax=ax_signal, linewidth=0.5, every=1000)
# %% window
# here we select a step that is resonant with a hybridized peak and
# then plot the full photodiode voltage trace and just the window
T_step = 0.0002
N = 100
t_scan_peak = 0.0057815 + 0.1e-6 # T * N_steps
t_scan_peak = 0.0057815 - 0.09e-6 + 11 * T_step # T * N_steps
t_peak = t_scan_peak + N * T_step
win_length = 5e-05
window = t_scan_peak, t_scan_peak + win_length * 0.3
ax_signal.axvline(t_peak, color="r", linestyle="--")
ax_signal.axvline(t_scan_peak, color="r", linestyle="--")
ax_signal.axvspan(*window, color="r", linestyle="--")
ax_signal.set_title("Full photodiode voltage trace")
ax_signal.set_xlabel("Time [s]")
ax_signal.set_ylabel("Voltage [arb]")
mask = (scan.time > window[0]) & (scan.time < window[1])
ax_window.clear()
ax_window.plot(scan.time[mask], scan.output[mask], linewidth=0.1)
ax_window.set_title("Windowed photodiode voltage trace")
ax_window.set_xlabel("Time [s]")
# %% detect peaks
## herein we detect the pertinent peaks and refine them using a lorentzian fit
ringdown_params = RingdownParams(
fω_shift=0,
mode_window=(0, 5),
fΩ_guess=12.9e6,
fδ_guess=0.2 * 12.9e6,
η_guess=0.5e6,
absolute_low_cutoff=2e6,
)
peak_info = find_peaks(scan, ringdown_params, window, prominence=0.08)
peak_info = refine_peaks(peak_info, ringdown_params)
plot_spectrum_and_peak_info(ax_spectrum, peak_info, ringdown_params, annotate=True)
# %% hand-crafted interpretation
b1, b2, b3, reflected = peak_info.peak_freqs[[0, 1, 3, 2]]
Ω = b3 - b2
δ = abs(b3 - 3 * Ω)
δ_2 = reflected - 2 * Ω
detuning = (δ + δ_2) / 2
alt_Ω = b2 - b1
hyb_amp = peak_info.power[peak_info.peaks[3]] / (np.sqrt(2) * 5) ** 2
hyb_width = peak_info.peak_widths[3] * 5
hyb_freq = 2 * detuning
ax_spectrum.plot(
peak_info.freq,
lorentzian(peak_info.freq, hyb_amp, hyb_freq, hyb_width),
color="C3",
label="hybridized mode?",
)
ax_spectrum.legend()
fig.suptitle(
f"""
Analysis of the data from the 11/07.
We modulated at the FSR (13MHz) and FSR-δ and 2δ.
In the bottom right a Fourier transform of the windowed signal in the bottom left is shown.
The first large peak is the first bath mode after the hybridized mode. It has a distance from the second bath mode of {alt_Ω*1e-6:.2f}MHz.
The second and third peaks have a distance of {Ω*1e-6:.2f}MHz, hence the first bath mode also hybridizes with the small loop! In the second half of the trace
up top we can see that the first bath mode is broader the n the second and so on, corroborating this interpretation. From there we can also surmise that the decay rate
of the hybridized mode is about 3.5 times that of the bath modes. Using this, we can estimate the amplitude of the hybridized mode and its width, which we then plot as
a lorentzian. (If the bath mode was excited to the same degree as the third bath mode which is unlikely.)
The width of the thrid peak is {peak_info.peak_widths[3]*1e-6:.2f}MHz. The estimated decay rate of the hybridized mode is {hyb_width*1e-6:.2f}MHz.
"""
)
# %% save
if __name__ == "__main__":
save_figure(fig, "003_11_07_analysis")
quick_save_pickle(
dict(
window=window,
peak_info=peak_info,
ringdown_parms=ringdown_params,
detuning=detuning,
),
"003_results",
)

View file

@ -0,0 +1,261 @@
from rabifun.system import *
from rabifun.plots import *
from rabifun.utilities import *
from rabifun.analysis import *
from ringfit.data import ScanData
import functools
from scipy.ndimage import rotate
# %% interactive
def make_params_and_solve(
total_lifetimes,
eom_off_lifetime,
ω_c=0.1 / 2,
N=10,
g_0=1 / 4,
small_loop_detuning=0,
laser_detuning=0,
η=1.0,
η_hybrid=1.0,
drive_mode="all",
):
"""
Make a set of parameters for the system with the current
best-known settings.
"""
Ω = 13
params = Params(
η=η,
η_hybrid=η_hybrid,
Ω=Ω,
δ=1 / 4,
ω_c=ω_c,
g_0=g_0,
laser_detuning=laser_detuning,
N=N,
N_couplings=N,
measurement_detuning=0,
α=0,
rwa=False,
flat_energies=False,
correct_lamb_shift=0,
laser_off_time=0,
small_loop_detuning=small_loop_detuning,
)
params.laser_off_time = params.lifetimes(eom_off_lifetime)
params.drive_off_time = params.lifetimes(eom_off_lifetime)
match drive_mode:
case "hybrid":
params.drive_override = (
np.array([params.Ω * params.δ * 2]),
np.ones(1),
)
case "hybrid_to_one_bath":
params.drive_override = (
np.array([params.Ω * (1 - params.δ), params.Ω * params.δ * 2]),
np.ones(2),
)
case "bath":
params.drive_override = (
np.array([params.Ω]),
np.ones(1),
)
case _:
params.drive_override = (
np.array(
[params.Ω, params.Ω * (1 - params.δ), params.δ * 2 * params.Ω]
),
np.ones(3),
)
t = time_axis(params, lifetimes=total_lifetimes, resolution=0.001)
solution = solve(t, params)
return params, t, solution
def generate_phase_one_data(
drive_mode="full",
g_0=0.3,
off_factor=0.21,
noise=False,
extra_title="",
laser_detuning=0,
yscale="linear",
):
"""
This generates some intensity data for phase one of the
calibration protocol, where the aim is to extract the resonator
spectrum.
"""
total_lifetimes = 30
eom_off_lifetime = total_lifetimes * off_factor
fluct_size = 0.05
noise_amp = 0.3
params, t, solution = make_params_and_solve(
total_lifetimes,
eom_off_lifetime,
N=10,
g_0=g_0,
small_loop_detuning=0,
laser_detuning=laser_detuning,
η=0.18,
η_hybrid=0.18 * 5,
drive_mode=drive_mode,
)
rng = np.random.default_rng(seed=0)
raw_signal = output_signal(t, solution.y, params)
signal = raw_signal.copy()
if noise:
signal += noise_amp * rng.standard_normal(len(signal))
fig = make_figure(f"simulation_noise_{noise}", figsize=(20, 3 * 5))
ax_realtime, ax_rotating_bath, ax_rotating_system, ax_spectrum = (
fig.subplot_mosaic("""
AA
BC
DD
DD
""").values()
)
ax_rotating_system.sharey(ax_rotating_bath)
ax_rotating_system.sharex(ax_rotating_bath)
for mode in range(2):
ax_rotating_system.plot(
t[::50],
abs(np.imag(solution.y[mode, ::50])) ** 2
/ 2
* (params.η / params.η_hybrid) ** 2,
)
for mode in range(2, solution.y.shape[0]):
ax_rotating_bath.plot(t[::50], abs(np.imag(solution.y[mode, ::50])) ** 2)
for ax in [ax_rotating_bath, ax_rotating_system]:
ax.set_xlabel("Time")
ax.set_ylabel("Intensity")
ax_rotating_bath.set_title("Bath Modes")
ax_rotating_system.set_title(
"Hybridized Modes [corrected for magnitude visible in FFT]"
)
ax_realtime.plot(t[::50], signal[::50])
ax_realtime.axvline(params.drive_off_time, color="black", linestyle="--")
ax_realtime.set_xlabel("Time")
ax_realtime.set_ylabel("Intensity")
ax_realtime.set_title("Photo-diode AC Intensity")
# now we plot the power spectrum
window = (float(params.laser_off_time or 0), t[-1])
# window = (0, float(params.laser_off_time or 0))
ringdown_params = RingdownParams(
fω_shift=params.measurement_detuning,
mode_window=(5, 5),
fΩ_guess=params.Ω * (1 + rng.standard_normal() * fluct_size),
fδ_guess=params.Ω * params.δ * (1 + rng.standard_normal() * fluct_size),
η_guess=0.5, # params.η * (1 + rng.standard_normal() * fluct_size),
absolute_low_cutoff=2,
)
scan = ScanData(np.ones_like(signal), signal, t)
peak_info = find_peaks(scan, ringdown_params, window, prominence=0.01)
peak_info = refine_peaks(peak_info, ringdown_params)
plot_spectrum_and_peak_info(ax_spectrum, peak_info, ringdown_params)
runtime = RuntimeParams(params)
for i, freq in enumerate(runtime.Ωs.real):
pos = np.abs(
params.measurement_detuning
- freq / (2 * np.pi)
+ params.δ * params.Ω
+ params.laser_detuning,
)
ax_spectrum.axvline(
pos,
color="red",
linestyle="--",
zorder=-100,
)
ax_spectrum.annotate(mode_name(i), (pos + 0.1, peak_info.power.max()))
ax_spectrum.set_xlim(ringdown_params.low_cutoff, ringdown_params.high_cutoff)
ax_spectrum.set_yscale(yscale)
fig.suptitle(
f"""Calibration Phase One Demonstration {'with noise' if noise else ''}
N={params.N} * 2 + 2 modes g_0={params.g_0}Ω, Noise Amp={noise_amp}, η={params.η}MHz, η_hybrid={params.η_hybrid}MHz
"""
+ extra_title
)
return fig
# %% save
if __name__ == "__main__":
fig = generate_phase_one_data(
noise=True,
g_0=0.3,
extra_title="""A simulation for the 11_07 data with parameters chosen as known, or estimated so that the result looks as similar as possible.
At this level of drive and with these decay rates, the hybridized modes are hardly populated. The noise is (unphysical) random
gaussian noise added to simulated photodiode voltage. Nothing can be said with certainty about the drive strength.
""",
)
save_figure(fig, "004_01_11_07_simulation")
fig = generate_phase_one_data(
drive_mode="hybrid",
g_0=2,
noise=True,
extra_title="""
The same as the first simulation, but driving only at 2δ. With this decay rate, nothing can be excited.
""",
)
save_figure(fig, "004_02_11_07_simulation_only_a")
fig = generate_phase_one_data(
noise=True,
g_0=1,
extra_title="""Same as the first simulation but with larger drive strength.
Observe, how the amplitudes of the bath modes fluctuate with great amplitude.
""",
)
save_figure(fig, "004_03_11_07_simulation_more_drive")
fig = generate_phase_one_data(
noise=True,
g_0=1,
off_factor=0.3,
extra_title="""Same as number 04 but a different drive stop time.
Observe, how the amplitudes of the bath modes fluctuate with great amplitude.
""",
)
save_figure(fig, "004_04_11_07_simulation_more_drive_different_stop")
fig = generate_phase_one_data(
laser_detuning=13 * 0.8,
g_0=0.3,
yscale="log",
extra_title="""
The same as the first simulation, but with the laser at a bath mode. The hybridized modes gain no population.
""",
)
save_figure(fig, "004_05_11_07_simulation_only_a_drive_on_bath")

View file

@ -0,0 +1,8 @@
change_id: rxuqwvztlzswqyxoqznpmqxryltwylus
commit_id: 984c654e9cae56ee261952a1401e1fa22b4e0523
description: get the results of the 11_07 data in order
extra_meta: null
function: <module>
name: 003_11_07_analysis
refers_to: ./figs/003_11_07_analysis.pdf
source: scripts/ringdown_spectrum_analysis/003_11_07_data_analysis.py

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

View file

@ -0,0 +1,8 @@
change_id: rxuqwvztlzswqyxoqznpmqxryltwylus
commit_id: 2b802eaf83102e9e09df2a8cfcc1126dffc07ee2
description: get the results of the 11_07 data in order
extra_meta: null
function: <module>
name: 004_01_11_07_simulation
refers_to: ./figs/004_01_11_07_simulation.pdf
source: scripts/ringdown_spectrum_analysis/004_simulation_11_07.py

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

View file

@ -0,0 +1,8 @@
change_id: rxuqwvztlzswqyxoqznpmqxryltwylus
commit_id: b2f4c79ef52a9b9195efb8c8ea6dbc9ca9fcd5d6
description: get the results of the 11_07 data in order
extra_meta: null
function: <module>
name: 004_02_11_07_simulation_only_a
refers_to: ./figs/004_02_11_07_simulation_only_a.pdf
source: scripts/ringdown_spectrum_analysis/004_simulation_11_07.py

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

View file

@ -0,0 +1,8 @@
change_id: rxuqwvztlzswqyxoqznpmqxryltwylus
commit_id: a7cabde9a6e79e6da95e560d527ebb62460a1f61
description: get the results of the 11_07 data in order
extra_meta: null
function: <module>
name: 004_02_11_07_simulation_only_a_drive_on_bath
refers_to: ./figs/004_02_11_07_simulation_only_a_drive_on_bath.pdf
source: scripts/ringdown_spectrum_analysis/004_simulation_11_07.py

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

View file

@ -0,0 +1,8 @@
change_id: rxuqwvztlzswqyxoqznpmqxryltwylus
commit_id: 9c9f332c0ccc198b0a44e0a8d8119d38b055de79
description: get the results of the 11_07 data in order
extra_meta: null
function: <module>
name: 004_03_11_07_simulation_more_drive
refers_to: ./figs/004_03_11_07_simulation_more_drive.pdf
source: scripts/ringdown_spectrum_analysis/004_simulation_11_07.py

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

View file

@ -0,0 +1,8 @@
change_id: rxuqwvztlzswqyxoqznpmqxryltwylus
commit_id: 49cf4c2df3390eccf280655dcb4e5e0226ab39d6
description: get the results of the 11_07 data in order
extra_meta: null
function: <module>
name: 004_04_11_07_simulation_more_drive_different_stop
refers_to: ./figs/004_04_11_07_simulation_more_drive_different_stop.pdf
source: scripts/ringdown_spectrum_analysis/004_simulation_11_07.py

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

View file

@ -0,0 +1,8 @@
change_id: rxuqwvztlzswqyxoqznpmqxryltwylus
commit_id: 1e2260e32fcdb9af8ecb43be1fb05dd35ee10032
description: get the results of the 11_07 data in order
extra_meta: null
function: <module>
name: 004_05_11_07_simulation_only_a_drive_on_bath
refers_to: ./figs/004_05_11_07_simulation_only_a_drive_on_bath.pdf
source: scripts/ringdown_spectrum_analysis/004_simulation_11_07.py

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

View file

@ -0,0 +1,8 @@
change_id: rxuqwvztlzswqyxoqznpmqxryltwylus
commit_id: 90feb43de79adb6761517558939dfeeb220c6724
description: get the results of the 11_07 data in order
extra_meta: null
function: <module>
name: 004_11_07_simulation
refers_to: ./figs/004_11_07_simulation.pdf
source: scripts/ringdown_spectrum_analysis/004_simulation_11_07.py

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

View file

@ -0,0 +1,6 @@
change_id: rxuqwvztlzswqyxoqznpmqxryltwylus
commit_id: 60170ef1e3719c038cfca3e5cabd76e20f487ea5
description: get the results of the 11_07 data in order
function: <module>
refers_to: outputs/003_results.pkl
source: scripts/ringdown_spectrum_analysis/003_11_07_data_analysis.py

View file

@ -16,6 +16,7 @@ def noop_if_interactive(f):
@wraps(f)
def wrapped(*args, **kwargs):
if hasattr(sys, "ps1"):
print("NOOP as the session is interactive!")
return
return f(*args, **kwargs)