RESULT: weird oscillations and fitting to the transients

This commit is contained in:
Valentin Boettcher 2024-05-09 10:55:28 -04:00
parent 18a0f8c846
commit e595fdef6e
8 changed files with 205 additions and 16 deletions

View file

@ -3,8 +3,36 @@
:END: :END:
#+title: Fitting Ringdown #+title: Fitting Ringdown
* Fitting transients
- one can solve the equation of motion for when a mode is in the
steady state and the laser is suddenly switched. one obtains a
decaying oscillation which can be fitted to the data.
- this works ok, when the system /was/ in the steady state before the jump
- see [[file:scripts/transients_without_amplification.py]]
- we obtain \(γ\approx\SI{2.2}{\kilo\hertz}\) but this can vary a lot
- the detuning frequency seems to be completely off
* Failure of the steady state * Failure of the steady state
On the right peak on can see that there might be something fish going On the right peak on can see that there might be something fish going
on. This is ~data/24_05_24/nice_transient2~. on. This is ~data/24_05_24/nice_transient2~.
[[file:figures/non_steady.png]] [[file:figures/non_steady.png]]
* Weird Oscillations :ATTACH:
- when turning on the amp while the laser is running we get some
oscillations at \(\sim \SI{40}{\kilo\hertz}\) which is a period of
\(\SI{25}{\micro\second}\). this is 500 times roundrip time :(). I
thought it might be a wave packet traveling around the loop, i.e
multiple modes together...
[[attachment:osci_closeup.png][osci_closeup.png]]
[[attachment:osci_far.png][osci_far.png]]
[[attachment:cleaned.png][cleaned.png]]
- it isn't close to the fsr though...
- fitting a sine to that gives pretty much the same, as does an fft
[[attachment:cleaned_fit.png][cleaned_fit.png]]
- it is pretty constant over all steps in [[file:data/09_05_24/Nicely_hybridised_2 2024,05,09, 15h57min00sec/][data]] as can be ascertained
from [[file:scripts/weird_oscillations.py][this script]]
- these are also present w/o the amp cutout!
[[attachment:osci_without.png][osci_without.png]]

View file

@ -1,3 +1,58 @@
############################################################################### ###############################################################################
# Fitting Routine # # Fitting Routine #
############################################################################### ###############################################################################
import numpy as np
import math
import scipy.optimize as opt
from scipy.ndimage import uniform_filter1d
from scipy.signal import find_peaks
def transient_model(t, Δω, γ, amplitude, phase):
comp_phase = np.exp(1j * phase)
osci = amplitude * comp_phase * (np.expm1((-1j * Δω - γ) * (t)))
return np.imag(osci)
def fit_transient(time: np.ndarray, transient: np.ndarray, window_size: int = 100):
"""
Fit a transient signal ``transient`` over ``time`` to a damped
oscillation model.
The smoothing window is calculated as the length of the transient
divided by the ``window_size``.
"""
# data_length = len(transient)
# begin, end = transient.argmax(), -int(data_length * 0.01)
# time = time[begin:end]
# output_data = transient[begin:end]
output_data = transient
window = len(output_data) // window_size
output_data = uniform_filter1d(output_data, window)
output_data -= output_data[0]
output_data /= abs(output_data).max()
scaled_time = np.linspace(0, 1, len(time))
popt, pcov = opt.curve_fit(
transient_model,
scaled_time,
output_data,
p0=[1, 1, 1, 0],
bounds=(
[-np.inf, 0, 0, -np.pi],
[np.inf, np.inf, np.pi, np.inf],
),
)
Δω, γ, amplitude, phase = popt
# convert back to units
Δω = Δω / (time[-1] - time[0])
γ = γ / (time[-1] - time[0])
return scaled_time, output_data, popt, np.sqrt(np.diag(pcov)), (Δω, γ)

View file

@ -92,7 +92,7 @@ def plot_scan(
if smoothe_output: if smoothe_output:
if not isinstance(smoothe_output, int): if not isinstance(smoothe_output, int):
smoothe_output_data = 60 smoothe_output = 60
window = len(output_data) // smoothe_output window = len(output_data) // smoothe_output
output_data = uniform_filter1d(output_data, window) output_data = uniform_filter1d(output_data, window)
@ -101,7 +101,10 @@ def plot_scan(
if isinstance(steps, bool) and steps: if isinstance(steps, bool) and steps:
peaks = data.laser_steps() peaks = data.laser_steps()
for peak in peaks: peaks = [0, *peaks, len(data.time) - 1]
vertical = output_data.min()
for peak in peaks[1:-1]:
ax.axvline( ax.axvline(
data.time[peak], data.time[peak],
color=lighten_color(lines[0].get_color()), color=lighten_color(lines[0].get_color()),
@ -109,6 +112,15 @@ def plot_scan(
zorder=-10, zorder=-10,
) )
for i, (begin, end) in enumerate(zip(peaks[:-1], peaks[1:])):
ax.text(
(data.time[begin] + data.time[end]) / 2,
vertical,
f"{i}",
ha="center",
va="bottom",
)
@wrap_plot @wrap_plot
def plot_transmission(data: data.ScanData, timepoints=1000, ax=None, **kwargs): def plot_transmission(data: data.ScanData, timepoints=1000, ax=None, **kwargs):

View file

@ -31,3 +31,15 @@ def find_frequency_steps(laser: np.ndarray, window_fraction: int = 60) -> np.nda
peaks = find_peaks(step_diffs, height=0.5, distance=window)[0] peaks = find_peaks(step_diffs, height=0.5, distance=window)[0]
return peaks return peaks
def shift_and_normalize(array: np.ndarray) -> np.ndarray:
shifted = array - array.min()
return shifted / abs(shifted).max()
def smoothe_signal(signal: np.ndarray, window_size: float = 0.01) -> np.ndarray:
"""Smoothe the signal ``signal`` using a uniform filter with a window
size of ``window_size * len(signal)``."""
window = int(len(signal) * window_size)
return uniform_filter1d(signal, window)

View file

@ -1,14 +0,0 @@
import sys
sys.path.append("../")
from ringfit import data
import matplotlib.pyplot as plt
from ringfit.data import *
from ringfit.plotting import *
path = (
"/home/hiro/Documents/org/roam/code/fitting_ringdown/data/24_05_24/nice_transient_2"
)
scan = ScanData.from_dir(path, truncation=[0, 50])
fig, ax = plot_scan(scan, smoothe_output=10, steps=1)

View file

@ -0,0 +1,22 @@
import sys
sys.path.append("../")
from ringfit import data
import matplotlib.pyplot as plt
from ringfit.data import *
from ringfit.plotting import *
from ringfit.fit import *
path = "/home/hiro/Documents/org/roam/code/fitting_ringdown/data/09_05_24/Nicely_hybridised_2 2024,05,09, 15h57min00sec/"
scan = ScanData.from_dir(path, truncation=[0, 50])
fig, ax = plot_scan(scan, smoothe_output=50, normalize=True, laser=False, steps=True)
time, output, _ = scan.for_step(10)
t, o, params, cov, scaled = fit_transient(time, output, window_size=100)
plt.figure()
plt.plot(t, o)
plt.plot(t, transient_model(t, *params))
plt.title(
f"Transient 2, γ={scaled[1] / 10**3}kHz ω/2π={scaled[1] / (2*np.pi * 10**3)}kHz"
)

View file

@ -0,0 +1,30 @@
import sys
sys.path.append("../")
from ringfit import data
import matplotlib.pyplot as plt
from ringfit.data import *
from ringfit.plotting import *
from ringfit.fit import *
path = (
"/home/hiro/Documents/org/roam/code/fitting_ringdown/data/08_05_24/nice_transient_2"
)
scan = ScanData.from_dir(path, truncation=[0, 50])
STEPS = [2, 3, 5]
fig, ax = plot_scan(scan, smoothe_output=50, normalize=True, laser=False, steps=True)
for STEP in STEPS:
time, output, _ = scan.for_step(step=STEP)
t, o, params, cov, scaled = fit_transient(time, output, window_size=100)
plt.figure()
plt.plot(t, o)
plt.plot(t, transient_model(t, *params))
plt.title(
f"Transient 2, γ={scaled[1] / 10**3:.2f}kHz ({cov[1] / 10**3:.2f}kHz)\n ω/2π={scaled[0] / (2*np.pi * 10**3):.5f}kHz\n step={STEP}"
)
freq_unit = params[1] / scaled[1]
plt.plot(t, np.sin(2 * np.pi * 4 * 10**4 * t * freq_unit), alpha=0.1)

View file

@ -0,0 +1,44 @@
import sys
sys.path.append("../")
from ringfit import data
import matplotlib.pyplot as plt
from ringfit.data import *
from ringfit.plotting import *
from ringfit.fit import *
from ringfit.utils import *
path = "/home/hiro/Documents/org/roam/code/fitting_ringdown/data/09_05_24/Nicely_hybridised_2 2024,05,09, 15h57min00sec/"
scan = ScanData.from_dir(path, truncation=[0, 50])
STEPS = [2, 33, 12]
fig, (ax1, *axs) = plt.subplots(nrows=1, ncols=len(STEPS) + 1)
plot_scan(scan, smoothe_output=100, normalize=True, laser=False, steps=True, ax=ax1)
def fit_frequency(step, ax):
time, output, _ = scan.for_step(step)
l = len(time)
begin = int(0.5 * l)
end = int(0.8 * l)
time = time[begin:end]
output = output[begin:end]
output = smoothe_signal(output, 0.05)
output = shift_and_normalize(output)
output -= output.mean()
ax.plot(time, output)
ff = np.fft.rfftfreq(output.size, d=time[1] - time[0])
ft = np.fft.rfft(output)
freq_index = np.argmax(ft)
ax.plot(
time,
0.5 * np.sin(time * 2 * np.pi * ff[freq_index] + np.angle(ft[freq_index])),
)
ax.set_title(f"f={ff[freq_index]*10**(-3):.2f}kHz\n step={step}")
for step, ax in zip(STEPS, axs):
fit_frequency(step, ax)