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,406 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import numpy as np
|
|
3
|
+
import sodetlib as sdl
|
|
4
|
+
from sodetlib.operations.tracking import relock_tracking_setup
|
|
5
|
+
from sodetlib.operations import uxm_setup, bias_steps
|
|
6
|
+
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
import os
|
|
9
|
+
if not os.environ.get('NO_PYSMURF', False):
|
|
10
|
+
from pysmurf.client.base.smurf_control import SmurfControl
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@sdl.set_action()
|
|
15
|
+
def reload_tune(S, cfg, bands, setup_notches=False,
|
|
16
|
+
new_master_assignment=False, tunefile=None, update_cfg=True):
|
|
17
|
+
"""
|
|
18
|
+
Reloads an existing tune, runs setup-notches and serial grad descent
|
|
19
|
+
and eta scan.
|
|
20
|
+
|
|
21
|
+
Args
|
|
22
|
+
-----
|
|
23
|
+
S : SmurfControl
|
|
24
|
+
Pysmurf instance
|
|
25
|
+
cfg : DetConfig
|
|
26
|
+
Det config instance
|
|
27
|
+
bands : list, optional
|
|
28
|
+
List of bands to run
|
|
29
|
+
setup_notches : bool
|
|
30
|
+
Whether to run setup_notches
|
|
31
|
+
new_master_assignment : bool
|
|
32
|
+
Whether to create a new master assignment
|
|
33
|
+
tunefile : str
|
|
34
|
+
Tunefile to load. Defaults to the tunefile in the device cfg.
|
|
35
|
+
update_cfg : bool
|
|
36
|
+
If true, will update the device cfg with the tunefile created by
|
|
37
|
+
setup notches.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
if tunefile is None:
|
|
41
|
+
tunefile = cfg.dev.exp['tunefile']
|
|
42
|
+
|
|
43
|
+
S.load_tune(tunefile)
|
|
44
|
+
|
|
45
|
+
for band in bands:
|
|
46
|
+
sdl.stop_point(S)
|
|
47
|
+
bcfg = cfg.dev.bands[band]
|
|
48
|
+
S.set_att_uc(band, bcfg['uc_att'])
|
|
49
|
+
S.set_att_dc(band, bcfg['dc_att'])
|
|
50
|
+
sdl.pub_ocs_log(S, f"Relocking tune: Band {band}")
|
|
51
|
+
if setup_notches:
|
|
52
|
+
S.log(f"Setup notches, new_master_assignment={new_master_assignment}")
|
|
53
|
+
S.setup_notches(band, new_master_assignment=new_master_assignment)
|
|
54
|
+
else:
|
|
55
|
+
S.relock(band)
|
|
56
|
+
|
|
57
|
+
if setup_notches and update_cfg:
|
|
58
|
+
# Update tunefile
|
|
59
|
+
cfg.dev.update_experiment({'tunefile': S.tune_file}, update_file=True)
|
|
60
|
+
|
|
61
|
+
run_grad_descent_and_eta_scan(S, cfg, bands=bands, update_tune=False)
|
|
62
|
+
|
|
63
|
+
return True, None
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@sdl.set_action()
|
|
67
|
+
def run_grad_descent_and_eta_scan(
|
|
68
|
+
S, cfg, bands=None, update_tune=False, force_run=False, max_iters=None,
|
|
69
|
+
gain=None):
|
|
70
|
+
"""
|
|
71
|
+
This function runs serial gradient and eta scan for each band.
|
|
72
|
+
Critically, it pulls in gradient descent tune parameters from the device
|
|
73
|
+
config and uses them to setup the grad descent operation before running.
|
|
74
|
+
|
|
75
|
+
Args
|
|
76
|
+
----
|
|
77
|
+
S : SmurfControl
|
|
78
|
+
Pysmurf instance
|
|
79
|
+
cfg : DetConfig
|
|
80
|
+
Det config instance
|
|
81
|
+
bands : list, optional
|
|
82
|
+
List of bands to run on. Defaults to all 8
|
|
83
|
+
update_tune : bool
|
|
84
|
+
If this is set to True, the new resonance frequency and eta parameters
|
|
85
|
+
will be loaded into the smurf tune, and a new tunefile will be written
|
|
86
|
+
based on the new measurements.
|
|
87
|
+
force_run : bool
|
|
88
|
+
If True, will reset the ``etaScanInProgress`` variable to force it
|
|
89
|
+
to re-run. This might be necessary if serial gradient descent failed out.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
if bands is None:
|
|
93
|
+
bands = cfg.dev.exp['active_bands']
|
|
94
|
+
bands = np.atleast_1d(bands)
|
|
95
|
+
|
|
96
|
+
for b in bands:
|
|
97
|
+
sdl.stop_point(S)
|
|
98
|
+
in_progress_reg = S._cryo_root(b) + 'etaScanInProgress'
|
|
99
|
+
if S._caget(in_progress_reg):
|
|
100
|
+
if force_run:
|
|
101
|
+
S._caput(in_progress_reg, 0)
|
|
102
|
+
else:
|
|
103
|
+
raise RuntimeError(
|
|
104
|
+
"Failed during grad descent -- scan already in progress"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
bcfg = cfg.dev.bands[b]
|
|
108
|
+
|
|
109
|
+
if max_iters is None:
|
|
110
|
+
max_iters = bcfg['gradientDescentMaxIters']
|
|
111
|
+
if gain is None:
|
|
112
|
+
gain = bcfg['gradientDescentGain']
|
|
113
|
+
|
|
114
|
+
S.set_gradient_descent_step_hz(b, bcfg['gradientDescentStepHz'])
|
|
115
|
+
S.set_gradient_descent_max_iters(b, max_iters)
|
|
116
|
+
S.set_gradient_descent_gain(b, gain)
|
|
117
|
+
S.set_gradient_descent_converge_hz(b, bcfg['gradientDescentConvergeHz'])
|
|
118
|
+
S.set_gradient_descent_beta(b, bcfg['gradientDescentBeta'])
|
|
119
|
+
|
|
120
|
+
S.log(f"Running grad descent and eta scan on band {b}")
|
|
121
|
+
|
|
122
|
+
init_scale_array = S.get_amplitude_scale_array(b)
|
|
123
|
+
init_center_freq_array = S.get_center_frequency_array(b)
|
|
124
|
+
S.run_serial_gradient_descent(b)
|
|
125
|
+
|
|
126
|
+
if (S.get_amplitude_scale_array(b) != init_scale_array).any():
|
|
127
|
+
S.log("Grad descent errored out! Resetting state")
|
|
128
|
+
S.set_amplitude_scale_array(b, init_scale_array)
|
|
129
|
+
S.set_center_frequency_array(b, init_center_freq_array)
|
|
130
|
+
S._caput(in_progress_reg, 0)
|
|
131
|
+
raise RuntimeError(
|
|
132
|
+
"Failed during grad descent -- check smurf-streamer logs"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
S.run_serial_eta_scan(b)
|
|
136
|
+
|
|
137
|
+
if update_tune:
|
|
138
|
+
# This basically does the inverse of what's in the relock function
|
|
139
|
+
band_center_mhz = S.get_band_center_mhz(b)
|
|
140
|
+
subband_offset = S.get_tone_frequency_offset_mhz(b)
|
|
141
|
+
center_freq_array = S.get_center_frequency_array(b)
|
|
142
|
+
eta_phase_array = S.get_eta_phase_array(b)
|
|
143
|
+
eta_mag_array = S.get_eta_mag_array(b)
|
|
144
|
+
res_freqs = band_center_mhz + subband_offset + center_freq_array
|
|
145
|
+
|
|
146
|
+
for res in S.freq_resp[b]['resonances'].values():
|
|
147
|
+
ch = res['channel']
|
|
148
|
+
f0 = res['freq']
|
|
149
|
+
# Pysmurf does this to ignore channels with bad freqs so I
|
|
150
|
+
# guess we will too
|
|
151
|
+
for ll, hh in S._bad_mask:
|
|
152
|
+
if ll < f0 < hh:
|
|
153
|
+
ch = -1
|
|
154
|
+
|
|
155
|
+
res['freq'] = res_freqs[ch]
|
|
156
|
+
res['offset'] = center_freq_array[ch]
|
|
157
|
+
res['eta_phase'] = eta_phase_array[ch]
|
|
158
|
+
res['eta_scaled'] = eta_mag_array[ch]
|
|
159
|
+
|
|
160
|
+
if update_tune:
|
|
161
|
+
S.log("Saving tune!")
|
|
162
|
+
S.save_tune()
|
|
163
|
+
cfg.dev.exp['tunefile'] = S.tune_file
|
|
164
|
+
cfg.dev.update_file()
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def get_full_band_sweep(S, cfg, band, chan):
|
|
168
|
+
"""
|
|
169
|
+
This runs full_band_ampl_sweep to get the resonator response around a single
|
|
170
|
+
channel. This is useful for debugging bad channels.
|
|
171
|
+
|
|
172
|
+
Args
|
|
173
|
+
-----
|
|
174
|
+
S : SmurfControl
|
|
175
|
+
Pysmurf instance
|
|
176
|
+
cfg : DetConfig
|
|
177
|
+
Det Config instance
|
|
178
|
+
band : int
|
|
179
|
+
smurf-band of channel
|
|
180
|
+
channel : int
|
|
181
|
+
smurf-channel of channel
|
|
182
|
+
|
|
183
|
+
Returns
|
|
184
|
+
----------
|
|
185
|
+
fs : np.ndarray
|
|
186
|
+
Array of frequencies that were swept over
|
|
187
|
+
resp : np.ndarray
|
|
188
|
+
Complex transmission across the frequency range
|
|
189
|
+
"""
|
|
190
|
+
sb = S.get_subband_from_channel(band, chan)
|
|
191
|
+
tone_power = cfg.dev.bands[band]['tone_power']
|
|
192
|
+
center_freq_array = S.get_center_frequency_array(band)
|
|
193
|
+
amp_scale_array = S.get_amplitude_scale_array(band)
|
|
194
|
+
eta_phase_array = S.get_eta_phase_array(band)
|
|
195
|
+
eta_mag_array = S.get_eta_mag_array(band)
|
|
196
|
+
fb_enable = S.get_feedback_enable(band)
|
|
197
|
+
fb_enable_arr = S.get_feedback_enable_array(band)
|
|
198
|
+
|
|
199
|
+
try:
|
|
200
|
+
fs, resp = S.full_band_ampl_sweep(band, [sb], tone_power, 2, n_step=256)
|
|
201
|
+
finally:
|
|
202
|
+
S.set_center_frequency_array(band, center_freq_array)
|
|
203
|
+
S.set_amplitude_scale_array(band, amp_scale_array)
|
|
204
|
+
S.set_eta_phase_array(band, eta_phase_array)
|
|
205
|
+
S.set_eta_mag_array(band, eta_mag_array)
|
|
206
|
+
S.set_feedback_enable(band, fb_enable)
|
|
207
|
+
S.set_feedback_enable_array(band, fb_enable_arr)
|
|
208
|
+
return fs, resp
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def plot_channel_resonance(S, cfg, band, chan):
|
|
212
|
+
"""
|
|
213
|
+
Measures and plots resonator properties for a single smurf channel.
|
|
214
|
+
This will perform a scan around the specified channel, and will plot the
|
|
215
|
+
resonance dip along with where smurf thinks the resonance frequency is.
|
|
216
|
+
This is very useful for debugging why a channel isn't reading out properly.
|
|
217
|
+
|
|
218
|
+
Args
|
|
219
|
+
-----
|
|
220
|
+
S : (SmurfControl)
|
|
221
|
+
pysmurf instance
|
|
222
|
+
cfg : (DetConfig)
|
|
223
|
+
DetConfig instance
|
|
224
|
+
band : (int)
|
|
225
|
+
smurf band number
|
|
226
|
+
chan : (int)
|
|
227
|
+
smurf channel number
|
|
228
|
+
"""
|
|
229
|
+
res_freq = S.channel_to_freq(band, chan)
|
|
230
|
+
fs, resp = get_full_band_sweep(S, cfg, band, chan)
|
|
231
|
+
|
|
232
|
+
fs = fs.ravel() + S.get_band_center_mhz(band)
|
|
233
|
+
resp = resp.ravel()
|
|
234
|
+
fs = fs[np.abs(resp) > 0]
|
|
235
|
+
resp = resp[np.abs(resp) > 0]
|
|
236
|
+
|
|
237
|
+
fig, axes = plt.subplots(2, 1, figsize=(10, 10))
|
|
238
|
+
|
|
239
|
+
# Res-dip plot
|
|
240
|
+
ax = axes[0]
|
|
241
|
+
ax.plot(fs, np.abs(resp))
|
|
242
|
+
ax = ax.twinx()
|
|
243
|
+
ax.plot(fs, np.unwrap(np.angle(resp)), color='C1')
|
|
244
|
+
ax.axvline(res_freq, color='grey', ls='--')
|
|
245
|
+
|
|
246
|
+
# Circ plot
|
|
247
|
+
eta_phase = S.get_eta_phase_array(band)[chan]
|
|
248
|
+
eta = np.exp(1.0j * eta_phase * (2*np.pi) / 360)
|
|
249
|
+
Q = np.real(resp * eta)
|
|
250
|
+
I = -np.imag(resp * eta)
|
|
251
|
+
|
|
252
|
+
ax = axes[1]
|
|
253
|
+
ax.axvline(0, color='grey')
|
|
254
|
+
ax.axhline(0, color='grey')
|
|
255
|
+
ax.scatter(I, Q, c=np.abs(resp))
|
|
256
|
+
ax.scatter(np.real(resp), np.imag(resp), c=np.abs(resp), alpha=0.3)
|
|
257
|
+
|
|
258
|
+
return fig, axes
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
@sdl.set_action()
|
|
262
|
+
def uxm_relock(
|
|
263
|
+
S, cfg, bands=None, show_plots=False,
|
|
264
|
+
setup_notches=False, new_master_assignment=False, reset_rate_khz=None,
|
|
265
|
+
nphi0=None, skip_setup_amps=False):
|
|
266
|
+
"""
|
|
267
|
+
Relocks resonators by running the following steps:
|
|
268
|
+
|
|
269
|
+
1. Reset state (all off, disable waveform, etc.)
|
|
270
|
+
2. Set amps and check tolerance
|
|
271
|
+
3. load tune, setup_notches, serial grad descent and eta scan
|
|
272
|
+
4. Tracking setup
|
|
273
|
+
5. Measure noise
|
|
274
|
+
|
|
275
|
+
Args
|
|
276
|
+
-----
|
|
277
|
+
S : SmurfControl
|
|
278
|
+
Pysmurf instance
|
|
279
|
+
cfg : DetConfig
|
|
280
|
+
Det config instance
|
|
281
|
+
bands : list, optional
|
|
282
|
+
List of bands to run on. Defaults to all 8
|
|
283
|
+
setup_notches : bool
|
|
284
|
+
If True, will run setup notches instead of relocking
|
|
285
|
+
new_master_assignment : bool
|
|
286
|
+
Whether to run setup_notches with new_master_assignment.
|
|
287
|
+
Defaults to False
|
|
288
|
+
reset_rate_khz : float, optional
|
|
289
|
+
Flux Ramp Reset Rate to set (kHz), defaults to the value in the dev cfg
|
|
290
|
+
nphi0 : int, optional
|
|
291
|
+
Number of phi0's to ramp through. Defaults to the value that was used
|
|
292
|
+
during setup.
|
|
293
|
+
show_plots : bool
|
|
294
|
+
If True will show plots
|
|
295
|
+
skip_setup_amps : bool
|
|
296
|
+
If True will skip amplifier setup.
|
|
297
|
+
|
|
298
|
+
Returns
|
|
299
|
+
--------
|
|
300
|
+
summary : dict
|
|
301
|
+
Dictionary containing a summary of all run operations.
|
|
302
|
+
"""
|
|
303
|
+
if bands is None:
|
|
304
|
+
bands = cfg.dev.exp['active_bands']
|
|
305
|
+
bands = np.atleast_1d(bands)
|
|
306
|
+
|
|
307
|
+
exp = cfg.dev.exp
|
|
308
|
+
|
|
309
|
+
#############################################################
|
|
310
|
+
# 1. Reset to known state
|
|
311
|
+
#############################################################
|
|
312
|
+
S.all_off() # Turn off Flux ramp, tones, and biases
|
|
313
|
+
S.set_rtm_arb_waveform_enable(0)
|
|
314
|
+
S.set_filter_disable(0)
|
|
315
|
+
S.set_downsample_factor(exp['downsample_factor'])
|
|
316
|
+
if exp['coupling_mode'] == 'dc':
|
|
317
|
+
S.set_mode_dc()
|
|
318
|
+
else:
|
|
319
|
+
S.set_mode_ac()
|
|
320
|
+
|
|
321
|
+
for band in bands:
|
|
322
|
+
band_cfg = cfg.dev.bands[band]
|
|
323
|
+
S.set_synthesis_scale(band, exp['synthesis_scale'])
|
|
324
|
+
S.set_att_uc(band, band_cfg['uc_att'])
|
|
325
|
+
S.set_att_dc(band, band_cfg['dc_att'])
|
|
326
|
+
S.set_band_delay_us(band, band_cfg['band_delay_us'])
|
|
327
|
+
S.amplitude_scale[band] = band_cfg['tone_power']
|
|
328
|
+
|
|
329
|
+
summary = {}
|
|
330
|
+
summary['timestamps'] = []
|
|
331
|
+
#############################################################
|
|
332
|
+
# 2. Setup amps
|
|
333
|
+
#############################################################
|
|
334
|
+
sdl.stop_point(S)
|
|
335
|
+
if not skip_setup_amps:
|
|
336
|
+
summary['timestamps'].append(('setup_amps', time.time()))
|
|
337
|
+
sdl.set_session_data(S, 'timestamps', summary['timestamps'])
|
|
338
|
+
success, summary['amps'] = uxm_setup.setup_amps(S, cfg)
|
|
339
|
+
|
|
340
|
+
if not success:
|
|
341
|
+
return False, summary
|
|
342
|
+
else:
|
|
343
|
+
print("Skipping amp setup")
|
|
344
|
+
|
|
345
|
+
#############################################################
|
|
346
|
+
# 3. Load tune
|
|
347
|
+
#############################################################
|
|
348
|
+
sdl.stop_point(S)
|
|
349
|
+
summary['timestamps'].append(('load_tune', time.time()))
|
|
350
|
+
sdl.set_session_data(S, 'timestamps', summary['timestamps'])
|
|
351
|
+
success, summary['reload_tune'] = reload_tune(
|
|
352
|
+
S, cfg, bands, setup_notches=setup_notches,
|
|
353
|
+
new_master_assignment=new_master_assignment)
|
|
354
|
+
|
|
355
|
+
sdl.set_session_data(S, 'reload_tune', summary['reload_tune'])
|
|
356
|
+
if not success:
|
|
357
|
+
return False, summary
|
|
358
|
+
|
|
359
|
+
#############################################################
|
|
360
|
+
# 4. Tracking Setup
|
|
361
|
+
#############################################################
|
|
362
|
+
sdl.stop_point(S)
|
|
363
|
+
summary['timestamps'].append(('tracking_setup', time.time()))
|
|
364
|
+
sdl.set_session_data(S, 'timestamps', summary['timestamps'])
|
|
365
|
+
|
|
366
|
+
# Ensure feedback is enabled
|
|
367
|
+
for b in bands:
|
|
368
|
+
S.set_feedback_enable(b, 1)
|
|
369
|
+
|
|
370
|
+
tr = relock_tracking_setup(
|
|
371
|
+
S, cfg, bands, show_plots=show_plots,
|
|
372
|
+
reset_rate_khz=reset_rate_khz, nphi0=nphi0
|
|
373
|
+
)
|
|
374
|
+
summary['tracking_setup_results'] = tr
|
|
375
|
+
|
|
376
|
+
#############################################################
|
|
377
|
+
# 5. Noise
|
|
378
|
+
#############################################################
|
|
379
|
+
sdl.stop_point(S)
|
|
380
|
+
summary['timestamps'].append(('noise', time.time()))
|
|
381
|
+
sdl.set_session_data(S, 'timestamps', summary['timestamps'])
|
|
382
|
+
am, summary['noise'] = sdl.noise.take_noise(S, cfg, 30,
|
|
383
|
+
show_plot=show_plots,
|
|
384
|
+
save_plot=True,
|
|
385
|
+
g3_tag='post_relock')
|
|
386
|
+
summary['noise']['am'] = am
|
|
387
|
+
|
|
388
|
+
sdl.set_session_data(S, 'noise', {
|
|
389
|
+
'band_medians': summary['noise']['band_medians']
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
#############################################################
|
|
393
|
+
# 6. Bias group mapping
|
|
394
|
+
#############################################################
|
|
395
|
+
sdl.stop_point(S)
|
|
396
|
+
summary['timestamps'].append(('bg_map', time.time()))
|
|
397
|
+
sdl.set_session_data(S, 'timestamps', summary['timestamps'])
|
|
398
|
+
|
|
399
|
+
bsa = bias_steps.take_bgmap(S, cfg,
|
|
400
|
+
show_plots=show_plots)
|
|
401
|
+
summary['bg_map'] = bsa
|
|
402
|
+
|
|
403
|
+
summary['timestamps'].append(('end', time.time()))
|
|
404
|
+
sdl.set_session_data(S, 'timestamps', summary['timestamps'])
|
|
405
|
+
|
|
406
|
+
return True, summary
|