Skip to main content

A package which analyzes cavity transmission ringdown to find the finesse of a cavity

Project description

test status

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:

  1. Corresponds to a plot of the full timetrace with lines showing the window / region of interest (ROI)
  2. Displays the log of the timetrace in the ROI and the fit over it
  3. Displays the residuals of 2.
  4. Displays the crop and normalized timetrace over the ROI and an intensity trace built by the best fit parameters, for visual inspection
  5. 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 element taus is 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() and get_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

cavityringdown-0.0.3.tar.gz (19.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cavityringdown-0.0.3-py3-none-any.whl (10.5 kB view details)

Uploaded Python 3

File details

Details for the file cavityringdown-0.0.3.tar.gz.

File metadata

  • Download URL: cavityringdown-0.0.3.tar.gz
  • Upload date:
  • Size: 19.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.10.12

File hashes

Hashes for cavityringdown-0.0.3.tar.gz
Algorithm Hash digest
SHA256 100422d272a03b49c99b8e2a904173140210b167e523c9a3ed4ef1ec85e1f7ba
MD5 9e5f01cc38ae2659a5173a0b251e6106
BLAKE2b-256 fb676e250d1255b2f8dc67e50c91528aa5bec6e19b1f73725a60edf591629abc

See more details on using hashes here.

File details

Details for the file cavityringdown-0.0.3-py3-none-any.whl.

File metadata

  • Download URL: cavityringdown-0.0.3-py3-none-any.whl
  • Upload date:
  • Size: 10.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.10.12

File hashes

Hashes for cavityringdown-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 434428eca7414b34115ef3b77e30e98738b78380b08ea90b41542da8680031e3
MD5 7937ef326d148fb7aae278098caf00e7
BLAKE2b-256 77fbc691995477eb1a70846deba23713351cee9907c33369072a40d571e0cfe4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page