By: Faustin Carter, 2016, updated 2018
This notebook imports the data from the Agilent files, creates resonator objects from each datafile, packs those objects into a list, runs a semi-intelligent fitting algorithm predicated on the fact that things don't change too much from one temperature to the next, and then plots the data and fit curves in a nice way.
Once you've understood this example, you should be able to replicate it with your own data simply be writing a custom process_file function and updating the code that finds the datafiles.
Note: Before starting this example, you'll want to read up on list comprehensions and Python's built-in map method if you aren't already familiar with them.
In [1]:
#Set up the notebook for inline plotting
%matplotlib inline
#For high-res figures. You can comment this out if you don't have a retina screen
%config InlineBackend.figure_format = 'retina'
#Because you should always import numpy!
import numpy as np
In [2]:
import os
#Add the scraps folder to the path. You can skip this if you used pip to install scraps.
import sys
sys.path.append(os.getcwd()+'scraps/')
#Load up the resonator code!
import scraps as scr
Lists are a great way to organize things. scraps includes a tool for easily indexing lists of Resonator objects by temperature and power. Each object has a value called itemp that is just the experiment temperature rounded to the nearest 5 mK. This helps a lot with organizing data taken at the 'same' temperature that has fluctuations.
In [3]:
#Path to data (you should look and see what it looks like)
dataPath = './ExampleData/'
#Define a resonator name. The data folder has data for RES-1, RES-2, RES-3, RES-4 so any of those will work.
#Try changing the name to one of the others and rerun the notebook.
resName = 'RES-1'
#We pass the process file and the path to the data, and the built-in routine spits out a list of Resonator objects!
resList = scr.makeResList(scr.process_file, dataPath, resName, skiprows=1)
#Create index vectors for all temps and pwrs in the experiment
#itemp = temp rounded to the nearest 5 mK
tempsList = np.unique([res.temp for res in resList])
pwrsList = np.unique([res.pwr for res in resList])
#Let's look at all the temperatures and powers in the experiment
print('number of resonators in list = ', len(resList))
print('temps = ', tempsList)
print('powers = ', pwrsList)
print('temps x powers = ', len(tempsList)*len(pwrsList))
#Can you figure out why the number of resonators in resList is different from temps*powers?
#Hint: look in the data folder at the names of the data files and compare temperatures.
In [4]:
for res in resList:
#Load in the params
res.load_params(scr.cmplxIQ_params)
#Do the fit
res.do_lmfit(scr.cmplxIQ_fit)
In [5]:
figA = scr.plotResListData(resList,
plot_types=['IQ', #Real vs Imaginary part of S21
'rIQ', #residual of fits in IQ plane
'LogMag', #Magnitude of S21 vs frequency
'Phase'], #Phase of S21 vs frequency
color_by='temps',
fig_size=4,
powers=[-20],
num_cols = 2,
force_square = True,
plot_fits = [False]*4) #<-- need to specify a boolean for each plot type
In [6]:
#Pack all of the fit data into resSweep, and use the 'block' index method
#to figure out which temperatures are nominally the same
resSweep = scr.ResonatorSweep(resList, index='block')
#Look at the first few frequencies:
print('\nf0\n',resSweep['f0'].head())
#and the first few reduced-chi-squared values
print('\nredchi\n',resSweep['redchi'].head())
In [7]:
#Now let's make a plot of some of the parameters!
figS = scr.plotResSweepParamsVsX(resSweep,
plot_keys=['gain0', 'f0', 'qi', 'qc', 'df', 'redchi'],
num_cols = 3,
xvals='temperature')
In [8]:
#Or maybe you just want to look at how Q varies with power at different temperatures:
figS2 = scr.plotResSweepParamsVsX(resSweep,
plot_keys=['qc', 'qi'],
fig_size = 5,
xvals='power')
In [9]:
#Now you should try running the emcee fitter on all the traces and compare the plots.
#You can get the mc output by asking to plot 'f0_mc' instead of 'f0', for instance.