sodetlib 0.6.1rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sodetlib/__init__.py +22 -0
- sodetlib/_version.py +21 -0
- sodetlib/constants.py +13 -0
- sodetlib/det_config.py +709 -0
- sodetlib/noise.py +624 -0
- sodetlib/operations/__init__.py +5 -0
- sodetlib/operations/bias_dets.py +551 -0
- sodetlib/operations/bias_steps.py +1248 -0
- sodetlib/operations/bias_wave.py +688 -0
- sodetlib/operations/complex_impedance.py +651 -0
- sodetlib/operations/iv.py +716 -0
- sodetlib/operations/optimize.py +189 -0
- sodetlib/operations/squid_curves.py +641 -0
- sodetlib/operations/tracking.py +624 -0
- sodetlib/operations/uxm_relock.py +406 -0
- sodetlib/operations/uxm_setup.py +783 -0
- sodetlib/py.typed +0 -0
- sodetlib/quality_control.py +415 -0
- sodetlib/resonator_fitting.py +508 -0
- sodetlib/stream.py +291 -0
- sodetlib/tes_param_correction.py +579 -0
- sodetlib/util.py +880 -0
- sodetlib-0.6.1rc1.data/scripts/jackhammer +761 -0
- sodetlib-0.6.1rc1.dist-info/LICENSE +25 -0
- sodetlib-0.6.1rc1.dist-info/METADATA +6 -0
- sodetlib-0.6.1rc1.dist-info/RECORD +28 -0
- sodetlib-0.6.1rc1.dist-info/WHEEL +5 -0
- sodetlib-0.6.1rc1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
from sodetlib.operations import uxm_relock, tracking, uxm_setup
|
|
2
|
+
from sodetlib import noise
|
|
3
|
+
import sodetlib as sdl
|
|
4
|
+
import numpy as np
|
|
5
|
+
import time
|
|
6
|
+
from tqdm.auto import tqdm
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
from pysmurf.client.base.smurf_control import SmurfControl
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def find_min_total_atten(S, band, atten_offset=2):
|
|
12
|
+
"""
|
|
13
|
+
Finds the minimum total atten level (UC + DC) required for the ADCs not to
|
|
14
|
+
be saturated. This assumes tones are already enabled.
|
|
15
|
+
|
|
16
|
+
Args
|
|
17
|
+
-----
|
|
18
|
+
S : SmurfControl
|
|
19
|
+
Pysmurf instance
|
|
20
|
+
band : int
|
|
21
|
+
Band number
|
|
22
|
+
atten_offset : int
|
|
23
|
+
Int to add to total attens to try to avoid ADC saturation.
|
|
24
|
+
"""
|
|
25
|
+
uc, dc = 0, 0
|
|
26
|
+
S.set_att_uc(band, 0)
|
|
27
|
+
S.set_att_dc(band, 0)
|
|
28
|
+
|
|
29
|
+
for uc in range(0, 31, 2):
|
|
30
|
+
S.set_att_uc(band, uc)
|
|
31
|
+
if not S.check_adc_saturation(band):
|
|
32
|
+
return min(uc + dc + atten_offset, 60)
|
|
33
|
+
time.sleep(0.05)
|
|
34
|
+
|
|
35
|
+
for dc in range(0, 31, 2):
|
|
36
|
+
S.set_att_dc(band, dc)
|
|
37
|
+
if not S.check_adc_saturation(band):
|
|
38
|
+
return min(uc + dc + atten_offset, 60)
|
|
39
|
+
time.sleep(0.05)
|
|
40
|
+
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
@sdl.set_action()
|
|
44
|
+
def optimize_band_atten(S: SmurfControl, cfg, band, meas_time=30,
|
|
45
|
+
total_att=None, ucs=None, show_pb=False, bgs=None, full_tune=False):
|
|
46
|
+
"""
|
|
47
|
+
This function will optimize values for uc and dc attenuators. First, it
|
|
48
|
+
will find the minimum total attenuation required to avoid saturating ADCs.
|
|
49
|
+
Then it loops through values of UC attenuators (keeping the total atten
|
|
50
|
+
constant), runs gradient descent, tracking setup, and the takes noise.
|
|
51
|
+
It will chose the optimal attenuation to minimize the white noise level.
|
|
52
|
+
After this is run, you should re-run grad-descent and tracking functions
|
|
53
|
+
before taking data.
|
|
54
|
+
|
|
55
|
+
Args
|
|
56
|
+
-----
|
|
57
|
+
S : SmurfControl
|
|
58
|
+
Pysmurf instance
|
|
59
|
+
cfg : DetConfig
|
|
60
|
+
DetConfig instance
|
|
61
|
+
meas_time : float
|
|
62
|
+
Duration (sec) for noise measurement
|
|
63
|
+
total_atts : list
|
|
64
|
+
Total attenuations for each specified band. If this is not passed,
|
|
65
|
+
it will calculate this automatically
|
|
66
|
+
ucs : list
|
|
67
|
+
List of UC attenuations to loop over
|
|
68
|
+
show_pb : bool
|
|
69
|
+
If True, will display a progress bar.
|
|
70
|
+
bgs : list
|
|
71
|
+
List of bias lines to overbias. This must at least contain detectors on
|
|
72
|
+
the band that is being optimized. If None is specified, will just
|
|
73
|
+
overbias all detectors at each step.
|
|
74
|
+
full_tune : bool
|
|
75
|
+
If True, will run ``setup_tune``, which performs find freq and setup
|
|
76
|
+
otches, at each step. This is the way to get the most accurate
|
|
77
|
+
optimization, as eta and the resonance frequency change as you adjust
|
|
78
|
+
the uc attenuation. If your uc step is small enough (1 or maybe 2), then
|
|
79
|
+
the gradient descent and eta scan functions may be sufficient and you
|
|
80
|
+
might not need to do a full tune at each step.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
if total_att is None:
|
|
84
|
+
total_att = find_min_total_atten(S, band)
|
|
85
|
+
S.log(f"Total att for band {band}: {total_att}")
|
|
86
|
+
|
|
87
|
+
if bgs is None:
|
|
88
|
+
bgs = cfg.dev.exp['active_bgs']
|
|
89
|
+
bgs = np.atleast_1d(bgs)
|
|
90
|
+
|
|
91
|
+
if ucs is None:
|
|
92
|
+
ucs = np.arange(0, 31, 3)
|
|
93
|
+
|
|
94
|
+
nsteps = len(ucs)
|
|
95
|
+
sids = np.zeros(nsteps)
|
|
96
|
+
wls = np.full(nsteps, np.nan)
|
|
97
|
+
|
|
98
|
+
wls_full = [None for _ in range(nsteps)]
|
|
99
|
+
tunefiles = [None for _ in range(nsteps)]
|
|
100
|
+
|
|
101
|
+
for i, uc in enumerate(tqdm(ucs, disable=not show_pb)):
|
|
102
|
+
dc = max(total_att - uc, 0)
|
|
103
|
+
if dc <= 30:
|
|
104
|
+
S.set_att_uc(band, uc)
|
|
105
|
+
S.set_att_dc(band, dc)
|
|
106
|
+
else:
|
|
107
|
+
continue
|
|
108
|
+
|
|
109
|
+
S.log(f"Running UC={uc}")
|
|
110
|
+
|
|
111
|
+
S.flux_ramp_off()
|
|
112
|
+
S.set_flux_ramp_dac(0)
|
|
113
|
+
for bg in bgs:
|
|
114
|
+
S.set_tes_bias_bipolar(bg, 0)
|
|
115
|
+
|
|
116
|
+
if full_tune:
|
|
117
|
+
uxm_setup.setup_tune(S, cfg, bands=band, update_cfg=False)
|
|
118
|
+
else:
|
|
119
|
+
uxm_relock.run_grad_descent_and_eta_scan(S, cfg, bands=[band])
|
|
120
|
+
|
|
121
|
+
tunefiles[i] = S.tune_file
|
|
122
|
+
tracking.relock_tracking_setup(S, cfg, band)
|
|
123
|
+
S.overbias_tes_all(bgs)
|
|
124
|
+
_, res = noise.take_noise(S, cfg, meas_time, plot_band_summary=False, show_plot=False, save_plot=False)
|
|
125
|
+
sids[i] = res['sid']
|
|
126
|
+
wls[i] = res['band_medians'][band]
|
|
127
|
+
wls_full[i] = res['noise_pars'][:, 0]
|
|
128
|
+
|
|
129
|
+
fname = sdl.make_filename(S, f'atten_optimization_b{band}.npy')
|
|
130
|
+
try:
|
|
131
|
+
wls_full = np.array(wls_full)
|
|
132
|
+
except:
|
|
133
|
+
print('Error: not all wls_full entries are of same shape. Could be due to different number of resonators on each step')
|
|
134
|
+
wls_full = None
|
|
135
|
+
data = dict(
|
|
136
|
+
band=band, total_att=total_att, ucs=ucs, sids=sids, wls=wls,
|
|
137
|
+
wls_full=wls_full, path=fname, tunefiles=tunefiles, meta=sdl.get_metadata(S, cfg)
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
np.save(fname, data, allow_pickle=True)
|
|
141
|
+
S.log(f"Saving {fname}")
|
|
142
|
+
S.pub.register_file(fname, 'atten_optimzation', format='npy')
|
|
143
|
+
|
|
144
|
+
fig, _ = plot_atten_optimization(data)
|
|
145
|
+
fname = sdl.make_filename(S, 'atten_optimization.png', plot=True)
|
|
146
|
+
S.log(f"Saving {fname}")
|
|
147
|
+
fig.savefig(fname)
|
|
148
|
+
S.pub.register_file(fname, 'atten_optimzation', format='png')
|
|
149
|
+
|
|
150
|
+
return data
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def plot_atten_optimization(data, ax=None, ylim=None, text_loc=(0.02, 0.03)):
|
|
154
|
+
"""
|
|
155
|
+
Plots the results of the optimize_attens function.
|
|
156
|
+
|
|
157
|
+
Args
|
|
158
|
+
-----
|
|
159
|
+
data : dict
|
|
160
|
+
Results from the ``optimize_band_atten`` function
|
|
161
|
+
ax : Matplotlib axis
|
|
162
|
+
Axis to plot on. If None this will create a new figure.
|
|
163
|
+
ylim : tuple
|
|
164
|
+
ylim to set
|
|
165
|
+
text_loc : tuple
|
|
166
|
+
Location of the textbox
|
|
167
|
+
"""
|
|
168
|
+
if ax is None:
|
|
169
|
+
fig, ax = plt.subplots()
|
|
170
|
+
else:
|
|
171
|
+
fig = ax.figure
|
|
172
|
+
|
|
173
|
+
ax.plot(data['ucs'], data['wls'])
|
|
174
|
+
|
|
175
|
+
imin = np.nanargmin(data['wls'])
|
|
176
|
+
opt_uc = data['ucs'][imin]
|
|
177
|
+
opt_dc = max(data['total_att'] - opt_uc, 0)
|
|
178
|
+
ax.plot([opt_uc], [data['wls'][imin]], marker='x', color='red')
|
|
179
|
+
ax.set_title(f"Band {data['band']}, total_att={data['total_att']}")
|
|
180
|
+
txt = '\n'.join([
|
|
181
|
+
f"Min = {data['wls'][imin]:.1f} pA/rt(Hz)",
|
|
182
|
+
f"Opt (UC, DC) = ({opt_uc}, {opt_dc})"
|
|
183
|
+
])
|
|
184
|
+
ax.text(*text_loc, txt, transform=ax.transAxes,
|
|
185
|
+
bbox=dict(facecolor='wheat', alpha=0.2))
|
|
186
|
+
if ylim is not None:
|
|
187
|
+
ax.set_ylim(*ylim)
|
|
188
|
+
|
|
189
|
+
return fig, ax
|