A package which analyzes cavity transmission ringdown to find the finesse of a cavity
Project description
Ringdown
Introduction
This is a package for analyzing the timetrace of a cavity ringdown experiment.
Installation
Easiest way to use this is to install via pip:
pip install cavityringdown==0.0.1
For more details please visit the (https://pypi.org/project/cavityringdown/0.0.1/)[pypi] website.
Overview
A graphical summary or a cheatsheet of this package is as follows:
# Structure
# Ringdowns
# ├Ringdown
# ├Ringdown
# ├Ringdown
# ├Ringdown
# ├Ringdown
# Working with csv
experiment = Experiment('path/to/folder')
# path to folder has structure /folder/setting/ringdown{n}.csv
# Methods with Ringdown
ringdown = Ringdown(timetrace=timetrace, t=t)
popt, pcov = ringdown.fit(plot=True)
# Methods with Ringdowns
ringdowns = Ringdowns(name="name", ringdowns=[ringdown1, ringdown2,...])
taus, tau_err = ringdowns.get_taus()
ringdowns.plot_taus()
Usage
This package makes no assumptions about how to run your experiments and how you store your data. What it requires is an array of time and array of the intensity. By passing on these two arrays, in other words the $x$ and $y$ of your experiment, it can fit to it and tell you the decay time constants of experiment.
Imports
The structure of the directory is as follows:
analysis
├── loading.py
├── ringdown.py
└── ringdowns.py
To import the package to run in your script you can for example run:
from ringdown.analysis.ringdowns import Ringdowns
from ringdown.analysis.ringdown import Ringdown
Optionally, if your data structure permits (to be explained later):
from ringdown.analysis.loading import Experiment
This offers a class to help you read into your experimental data and partition them into Ringdown and Ringdowns.
Basic Usage
Loading in a Ringdown
The basic of classes are a Ringdown class, which is created by passing an array for time and an array for the timetrace.
ringdown = Ringdown(timetrace=timetrace, t=t)
The numpy arrays timetrace and t could be obtained from your experimental data. For demonstration purposes, we can also generate a timetrace and 'load' it into an instance of the Ringdown class.
# helper function in ringdown.py to generate a time trace
# used in the unit test
def generate_test_timetrace(a, tau, c, noise_sd, tEnd=2e-6, tInc=2.5e-10):
'''Generates a timetrace of an exponential with a, tau, c
and sprinkle in a normally distributed noise with a noise_sd.'''
t = np.arange(0, tEnd, tInc)
trace = a*np.exp(-t/tau) + c
trace += np.random.normal(0, noise_sd, len(trace))
return t, trace
# generate time array and timetrace
a, tau, c = [0.8, 1.2e-6, 0.]
t, trace = self.generate_timetrace(a, tau, c, a/80)
# instantiate a ringdown class
ringdown = Ringdown(timetrace=trace, t=t)
Fitting and Plotting
Upon instantiating the Ringdown class, the class would automatically set a window or a region of interest in which a fit can be performed. This is performed by identifying the start time of the decay, in which case is identified by the time at which the intensity has the maximum value. The window is set to a default value of 1.5 $\mu$s, but this can be adjusted manually either by directly accessing the attribute or by passing window as a parameter to the fit() method.
Once the class is instantiated, a fit can be performed. This is simply performed by the method fit(), which is called as follows:
ringdown = Ringdown(timetrace=timetrace, t=t)
popt, pcov = ringdown.fit()
We assume that the cavity ringdown is described by an exponential:
$$ I(t) = I_0 \exp(-\frac{t}{\tau}) + C $$
Programmatically, we denote $I_0$ by a, $\tau$ by tau and $C$ by offset. We also take the natural log of the decay to perform a (close to) linear fit using the scipy.optimize.curve_fit function. Thus, the fitting function, defined in the method fit_func is defined by np.log(a*np.exp(-t/tau)+c), and calling the fit method performs a fit and returns the best fit parameters popt and the covariance matrix pcov. The order of the parameters are given as follows.
popt, pcov = ringdown.fit(plot=True)
a, tau, c = popt
sigma_a, sigma_tau, sigma_c = np.sqrt(np.diag(pcov))
Passing plot=True as a parameter would also generate a graph with the following layout:
|---------------|
| | |
| | 2. |
| | |
| |-------|
| | 3. |
| 1. |-------|
| | |
| | 4. |
| | |
| |-------|
| | 5. |
|---------------|
In this figure:
- Corresponds to a plot of the full timetrace with lines showing the window / region of interest (ROI)
- Displays the log of the timetrace in the ROI and the fit over it
- Displays the residuals of 2.
- Displays the crop and normalized timetrace over the ROI and an intensity trace built by the best fit parameters, for visual inspection
- Displays the residuals of 4.
Collection of Ringdowns
As with most experiments, you never only do one measurements. You often repeatedly take many such ringdowns with the same experimental parameters. For example, for our ringdown measurements, we keep all parameters the same except for the angle of polarizer situated right before our detector. Therefore, we would repeat a ringdown measurement 50 times for having a polarizer at an oritentation of $50^\circ$. It would be inconvenient to instantiate a ringdown for each of the 50 measurements, say by running:
# NOT RECOMMENDED but possible
ringdown1 = Ringdown(t=t0, timetrace=timetrace0)
ringdown1 = Ringdown(t=t1, timetrace=timetrace1)
ringdown2 = Ringdown(t=t2, timetrace=timetrace2)
ringdown3 = Ringdown(t=t3, timetrace=timetrace3)
ringdown4 = Ringdown(t=t4, timetrace=timetrace4)
# ... until 50, or ad infinitum
As such there is another class which allows you create a 'collection' of Ringdown. This class is known as Ringdowns and works like a python list, supporting in-place addition or appending with the append and __add__ method. To instantiate Ringdowns, you pass in a name as an argument (which is also optional), and you can either incrementally add to its lists of Ringdown or instantiate it by passing the list to it already:
import numpy as np
# lets say I generate a nested list of 50 time arrays and 50 timetraces
# define 50 tries, set parameters for my decay
n = 50
a = np.random.normal(0.7, 0.001, n)
taus = np.random.normal(1.9e-6, 1e-8, n)
c = 0.1
# instantiate my collection instance
ringdowns = Ringdowns(name='Polarizer 50deg')
for i in range(n):
# generate t and timetrace
t, trace = generate_test_timetrace(a[i], taus[i], c, noise_sd)
# store into ringdown
ringdown = Ringdown(timetrace=trace, t=t)
# place into ringdowns
ringdowns += ringdown
Upon instantiating a Ringdowns class, individual Ringdown can be accessed from this instance with list indexing. Each of the Ringdown can also have their methods be called.
Getting the distribution of fitted decay times
A reason why one would want to repeat measurements is to obtain an average and error for the fitted decay times over the many presumably identical measurements. This can be done by the following methods:
get_taus()returns a tuple(taus, tau_errs), in which the first elementtausis a list of the fitted decay time and the second element is a list of the errors associated from each of the fitted decay time obtained from the covariance matrix (see section 7.2 of Hughes and Hase).get_mean_taus()andget_std_taus()calculates the sample mean and sample standard deviation of the decay times.plot_taus()outputs a plot of the decay times with their error bars. Helpful for visualization and locating where the mean is.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cavityringdown-0.0.2.tar.gz.
File metadata
- Download URL: cavityringdown-0.0.2.tar.gz
- Upload date:
- Size: 19.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
36d0851e32546e2ab21df77a79a53cdcbf74af85635518cdac06fde50c31d406
|
|
| MD5 |
2dcc755af22d8029b5a03a0ee55cf038
|
|
| BLAKE2b-256 |
e095b5da39a0567cab13e1efe706a446a03c0fa04cd98e676421853fc96496b5
|
File details
Details for the file cavityringdown-0.0.2-py3-none-any.whl.
File metadata
- Download URL: cavityringdown-0.0.2-py3-none-any.whl
- Upload date:
- Size: 10.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7bf27d7da86e62bb7cd7c4454a7dd3a9a0da3d4de01b44f5fd86edf48af866c4
|
|
| MD5 |
ad5c129f8e25d7304abc954d55e963f0
|
|
| BLAKE2b-256 |
cd38696593f23b8a6d27b883be4afc70702aea33b6457e618c1c793cdaba6e22
|