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:
#+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
On the right peak on can see that there might be something fish going
on. This is ~data/24_05_24/nice_transient2~.
[[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 #
###############################################################################
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 not isinstance(smoothe_output, int):
smoothe_output_data = 60
smoothe_output = 60
window = len(output_data) // smoothe_output
output_data = uniform_filter1d(output_data, window)
@ -101,7 +101,10 @@ def plot_scan(
if isinstance(steps, bool) and 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(
data.time[peak],
color=lighten_color(lines[0].get_color()),
@ -109,6 +112,15 @@ def plot_scan(
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
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]
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)