sqil-core 0.0.2__py3-none-any.whl → 1.0.0__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.
Files changed (41) hide show
  1. sqil_core/__init__.py +6 -2
  2. sqil_core/config.py +13 -0
  3. sqil_core/config_log.py +42 -0
  4. sqil_core/experiment/__init__.py +11 -0
  5. sqil_core/experiment/_analysis.py +95 -0
  6. sqil_core/experiment/_events.py +25 -0
  7. sqil_core/experiment/_experiment.py +553 -0
  8. sqil_core/experiment/data/plottr.py +778 -0
  9. sqil_core/experiment/helpers/_function_override_handler.py +111 -0
  10. sqil_core/experiment/helpers/_labone_wrappers.py +12 -0
  11. sqil_core/experiment/instruments/__init__.py +2 -0
  12. sqil_core/experiment/instruments/_instrument.py +190 -0
  13. sqil_core/experiment/instruments/drivers/SignalCore_SC5511A.py +515 -0
  14. sqil_core/experiment/instruments/local_oscillator.py +205 -0
  15. sqil_core/experiment/instruments/server.py +175 -0
  16. sqil_core/experiment/instruments/setup.yaml +21 -0
  17. sqil_core/experiment/instruments/zurich_instruments.py +55 -0
  18. sqil_core/fit/__init__.py +38 -0
  19. sqil_core/fit/_core.py +1084 -0
  20. sqil_core/fit/_fit.py +1191 -0
  21. sqil_core/fit/_guess.py +232 -0
  22. sqil_core/fit/_models.py +127 -0
  23. sqil_core/fit/_quality.py +266 -0
  24. sqil_core/resonator/__init__.py +13 -0
  25. sqil_core/resonator/_resonator.py +989 -0
  26. sqil_core/utils/__init__.py +85 -5
  27. sqil_core/utils/_analysis.py +415 -0
  28. sqil_core/utils/_const.py +105 -0
  29. sqil_core/utils/_formatter.py +259 -0
  30. sqil_core/utils/_plot.py +373 -0
  31. sqil_core/utils/_read.py +262 -0
  32. sqil_core/utils/_utils.py +164 -0
  33. {sqil_core-0.0.2.dist-info → sqil_core-1.0.0.dist-info}/METADATA +40 -7
  34. sqil_core-1.0.0.dist-info/RECORD +36 -0
  35. {sqil_core-0.0.2.dist-info → sqil_core-1.0.0.dist-info}/WHEEL +1 -1
  36. {sqil_core-0.0.2.dist-info → sqil_core-1.0.0.dist-info}/entry_points.txt +1 -1
  37. sqil_core/utils/analysis.py +0 -68
  38. sqil_core/utils/const.py +0 -38
  39. sqil_core/utils/formatter.py +0 -134
  40. sqil_core/utils/read.py +0 -156
  41. sqil_core-0.0.2.dist-info/RECORD +0 -10
@@ -1,6 +1,86 @@
1
- from .analysis import *
2
- from .formatter import *
3
- from .read import *
1
+ from ._analysis import (
2
+ compute_snr_peaked,
3
+ estimate_linear_background,
4
+ find_closest_index,
5
+ find_first_minima_idx,
6
+ line_between_2_points,
7
+ linear_interpolation,
8
+ remove_linear_background,
9
+ remove_offset,
10
+ soft_normalize,
11
+ )
12
+ from ._const import ONE_TONE_PARAMS, PARAM_METADATA, TWO_TONE_PARAMS
13
+ from ._formatter import (
14
+ ParamDict,
15
+ ParamInfo,
16
+ enrich_qubit_params,
17
+ format_fit_params,
18
+ format_number,
19
+ get_name_and_unit,
20
+ get_relevant_exp_parameters,
21
+ param_info_from_schema,
22
+ )
23
+ from ._plot import (
24
+ build_title,
25
+ finalize_plot,
26
+ get_x_id_by_plot_dim,
27
+ guess_plot_dimension,
28
+ plot_mag_phase,
29
+ plot_projection_IQ,
30
+ reset_plot_style,
31
+ set_plot_style,
32
+ )
33
+ from ._read import (
34
+ extract_h5_data,
35
+ extract_mapped_data,
36
+ get_data_and_info,
37
+ get_measurement_id,
38
+ map_data_dict,
39
+ read_json,
40
+ read_qpu,
41
+ read_yaml,
42
+ )
4
43
 
5
- __all__ = []
6
- __all__.extend(name for name in dir() if not name.startswith("_"))
44
+ __all__ = [
45
+ # Analysis
46
+ "remove_offset",
47
+ "estimate_linear_background",
48
+ "remove_linear_background",
49
+ "linear_interpolation",
50
+ "line_between_2_points",
51
+ "soft_normalize",
52
+ "find_closest_index",
53
+ "compute_snr_peaked",
54
+ "find_first_minima_idx",
55
+ # Const
56
+ "PARAM_METADATA",
57
+ "ONE_TONE_PARAMS",
58
+ "TWO_TONE_PARAMS",
59
+ # Formatter
60
+ "format_number",
61
+ "get_name_and_unit",
62
+ "format_fit_params",
63
+ "ParamInfo",
64
+ "ParamDict",
65
+ "param_info_from_schema",
66
+ "enrich_qubit_params",
67
+ "get_relevant_exp_parameters",
68
+ # Plot
69
+ "set_plot_style",
70
+ "reset_plot_style",
71
+ "get_x_id_by_plot_dim",
72
+ "build_title",
73
+ "guess_plot_dimension",
74
+ "plot_mag_phase",
75
+ "plot_projection_IQ",
76
+ "finalize_plot",
77
+ # Read
78
+ "extract_h5_data",
79
+ "map_data_dict",
80
+ "extract_mapped_data",
81
+ "read_json",
82
+ "read_yaml",
83
+ "read_qpu",
84
+ "get_measurement_id",
85
+ "get_data_and_info",
86
+ ]
@@ -0,0 +1,415 @@
1
+ import numpy as np
2
+ from scipy.signal import argrelextrema
3
+
4
+
5
+ def remove_offset(data: np.ndarray, avg: int = 3) -> np.ndarray:
6
+ """Removes the initial offset from a data matrix or vector by subtracting
7
+ the average of the first `avg` points. After applying this function,
8
+ the first point of each column of the data will be shifted to (about) 0.
9
+
10
+ Parameters
11
+ ----------
12
+ data : np.ndarray
13
+ Input data, either a 1D vector or a 2D matrix
14
+ avg : int, optional
15
+ The number of initial points to average when calculating
16
+ the offset, by default 3
17
+
18
+ Returns
19
+ -------
20
+ np.ndarray
21
+ The input data with the offset removed
22
+ """
23
+ is1D = len(data.shape) == 1
24
+ if is1D:
25
+ return data - np.mean(data[0:avg])
26
+ return data - np.mean(data[:, 0:avg], axis=1).reshape(data.shape[0], 1)
27
+
28
+
29
+ def estimate_linear_background(
30
+ x: np.ndarray,
31
+ data: np.ndarray,
32
+ points_cut: float = 0.1,
33
+ cut_from_back: bool = False,
34
+ ) -> list:
35
+ """
36
+ Estimates the linear background for a given data set by fitting a linear model to a subset of the data.
37
+
38
+ This function performs a linear regression to estimate the background (offset and slope) from the
39
+ given data by selecting a portion of the data as specified by the `points_cut` parameter. The linear
40
+ fit is applied to either the first or last `points_cut` fraction of the data, depending on the `cut_from_back`
41
+ flag. The estimated background is returned as the coefficients of the linear fit.
42
+
43
+ Parameters
44
+ ----------
45
+ x : np.ndarray
46
+ The independent variable data.
47
+ data : np.ndarray
48
+ The dependent variable data, which can be 1D or 2D (e.g., multiple measurements or data points).
49
+ points_cut : float, optional
50
+ The fraction of the data to be considered for the linear fit. Default is 0.1 (10% of the data).
51
+ cut_from_back : bool, optional
52
+ Whether to use the last `points_cut` fraction of the data (True) or the first fraction (False).
53
+ Default is False.
54
+
55
+ Returns
56
+ -------
57
+ list
58
+ The coefficients of the linear fit: a list with two elements, where the first is the offset (intercept)
59
+ and the second is the slope.
60
+
61
+ Notes
62
+ -----
63
+ - If `data` is 2D, the fit is performed on each column of the data separately.
64
+ - The function assumes that `x` and `data` have compatible shapes.
65
+
66
+ Examples
67
+ --------
68
+ >>> import numpy as np
69
+ >>> x = np.linspace(0, 10, 100)
70
+ >>> data = 3 * x + 2 + np.random.normal(0, 1, size=(100,))
71
+ >>> coefficients = estimate_linear_background(x, data, points_cut=0.2)
72
+ >>> print("Estimated coefficients:", coefficients)
73
+ """
74
+ is1D = len(data.shape) == 1
75
+ points = data.shape[0] if is1D else data.shape[1]
76
+ cut = int(points * points_cut)
77
+
78
+ # Consider just the cut points
79
+ if not cut_from_back:
80
+ x_data = x[0:cut] if is1D else x[:, 0:cut]
81
+ y_data = data[0:cut] if is1D else data[:, 0:cut]
82
+ else:
83
+ x_data = x[-cut:] if is1D else x[:, -cut:]
84
+ y_data = data[-cut:] if is1D else data[:, -cut:]
85
+
86
+ ones_column = np.ones_like(x_data[0, :]) if not is1D else np.ones_like(x_data)
87
+ X = np.vstack([ones_column, x_data[0, :] if not is1D else x_data]).T
88
+ # Linear fit
89
+ coefficients, residuals, _, _ = np.linalg.lstsq(
90
+ X, y_data if is1D else y_data.T, rcond=None
91
+ )
92
+
93
+ return coefficients.T
94
+
95
+
96
+ def remove_linear_background(
97
+ x: np.ndarray, data: np.ndarray, points_cut=0.1
98
+ ) -> np.ndarray:
99
+ """Removes a linear background from the input data (e.g. the phase background
100
+ of a spectroscopy).
101
+
102
+
103
+ Parameters
104
+ ----------
105
+ data : np.ndarray
106
+ Input data. Can be a 1D vector or a 2D matrix.
107
+
108
+ Returns
109
+ -------
110
+ np.ndarray
111
+ The input data with the linear background removed. The shape of the
112
+ returned array matches the input `data`.
113
+ """
114
+ coefficients = estimate_linear_background(x, data, points_cut)
115
+
116
+ # Remove background over the whole array
117
+ is1D = len(data.shape) == 1
118
+ ones_column = np.ones_like(x[0, :]) if not is1D else np.ones_like(x)
119
+ X = np.vstack([ones_column, x[0, :] if not is1D else x]).T
120
+ return data - (X @ coefficients.T).T
121
+
122
+
123
+ def linear_interpolation(
124
+ x: float | np.ndarray, x1: float, y1: float, x2: float, y2: float
125
+ ) -> float | np.ndarray:
126
+ """
127
+ Performs linear interpolation to estimate the value of y at a given x.
128
+
129
+ This function computes the interpolated y-value for a given x using two known points (x1, y1) and (x2, y2)
130
+ on a straight line. It supports both scalar and array inputs for x, enabling vectorized operations.
131
+
132
+ Parameters
133
+ ----------
134
+ x : float or np.ndarray
135
+ The x-coordinate(s) at which to interpolate.
136
+ x1 : float
137
+ The x-coordinate of the first known point.
138
+ y1 : float
139
+ The y-coordinate of the first known point.
140
+ x2 : float
141
+ The x-coordinate of the second known point.
142
+ y2 : float
143
+ The y-coordinate of the second known point.
144
+
145
+ Returns
146
+ -------
147
+ float or np.ndarray
148
+ The interpolated y-value(s) at x.
149
+
150
+ Notes
151
+ -----
152
+ - If x1 and x2 are the same, the function returns y1 to prevent division by zero.
153
+ - Assumes that x lies between x1 and x2 for meaningful interpolation.
154
+
155
+ Examples
156
+ --------
157
+ >>> linear_interpolation(3, 2, 4, 6, 8)
158
+ 5.0
159
+ >>> x_vals = np.array([3, 4, 5])
160
+ >>> linear_interpolation(x_vals, 2, 4, 6, 8)
161
+ array([5., 6., 7.])
162
+ """
163
+ if x1 == x2:
164
+ return y1
165
+ return y1 + (x - x1) * (y2 - y1) / (x2 - x1)
166
+
167
+
168
+ def line_between_2_points(
169
+ x1: float, y1: float, x2: float, y2: float
170
+ ) -> tuple[float, float]:
171
+ """
172
+ Computes the equation of a line passing through two points.
173
+
174
+ Given two points (x1, y1) and (x2, y2), this function returns the y-intercept and slope of the line
175
+ connecting them. If x1 and x2 are the same, the function returns y1 as the intercept and a slope of 0
176
+ to avoid division by zero.
177
+
178
+ Parameters
179
+ ----------
180
+ x1 : float
181
+ The x-coordinate of the first point.
182
+ y1 : float
183
+ The y-coordinate of the first point.
184
+ x2 : float
185
+ The x-coordinate of the second point.
186
+ y2 : float
187
+ The y-coordinate of the second point.
188
+
189
+ Returns
190
+ -------
191
+ tuple[float, float]
192
+ A tuple containing:
193
+ - The y-intercept (float), which is y1.
194
+ - The slope (float) of the line passing through the points.
195
+
196
+ Notes
197
+ -----
198
+ - If x1 and x2 are the same, the function assumes a vertical line and returns a slope of 0.
199
+ - The returned y-intercept is based on y1 for consistency in edge cases.
200
+
201
+ Examples
202
+ --------
203
+ >>> line_between_2_points(1, 2, 3, 4)
204
+ (2, 1.0)
205
+ >>> line_between_2_points(2, 5, 2, 10)
206
+ (5, 0)
207
+ """
208
+ if x1 == x2:
209
+ return np.inf, y1
210
+ slope = (y2 - y1) / (x2 - x1)
211
+ intercept = y1 - slope * x1
212
+ return slope, intercept
213
+
214
+
215
+ def soft_normalize(data: np.ndarray) -> np.ndarray:
216
+ """
217
+ Apply soft normalization to a 1D or 2D array with optional NaNs.
218
+
219
+ This function performs z-score normalization followed by a smooth
220
+ non-linear compression using a hyperbolic tangent (tanh) function.
221
+ It is designed to reduce the effect of outliers while preserving
222
+ the dynamic range of typical data values. The result is rescaled to [0, 1].
223
+
224
+ For 2D arrays, normalization is done row-wise, but compression is
225
+ based on a global threshold across all non-NaN entries.
226
+
227
+ Parameters
228
+ ----------
229
+ data : np.ndarray
230
+ Input data, must be a 1D or 2D NumPy array. Can contain NaNs.
231
+
232
+ Returns
233
+ -------
234
+ np.ndarray
235
+ Normalized data, same shape as input, with values scaled to [0, 1].
236
+ NaNs are preserved.
237
+
238
+ Raises
239
+ ------
240
+ ValueError
241
+ If `data` is not 1D or 2D.
242
+
243
+ Notes
244
+ -----
245
+ - Z-score normalization is done using nanmean and nanstd.
246
+ - Outliers are compressed using a tanh centered at a scaled threshold.
247
+ - Output values are guaranteed to be in [0, 1] range, except NaNs.
248
+ - Rows with zero standard deviation are flattened to 0.5.
249
+ """
250
+
251
+ if data.ndim not in [1, 2]:
252
+ raise ValueError("Input must be 1D or 2D")
253
+
254
+ data = np.array(data, dtype=np.float64)
255
+ nan_mask = np.isnan(data)
256
+
257
+ if data.ndim == 1:
258
+ mean = np.nanmean(data)
259
+ std = np.nanstd(data)
260
+ std = 1.0 if std == 0 else std
261
+ abs_z = np.abs((data - mean) / std)
262
+ else:
263
+ mean = np.nanmean(data, axis=1, keepdims=True)
264
+ std = np.nanstd(data, axis=1, keepdims=True)
265
+ std = np.where(std == 0, 1.0, std)
266
+ abs_z = np.abs((data - mean) / std)
267
+
268
+ # Flatten over all values for global thresholding
269
+ flat_abs_z = abs_z[~nan_mask]
270
+ if flat_abs_z.size == 0:
271
+ return np.full_like(data, 0.5)
272
+
273
+ threshold = 4.0 * np.mean(flat_abs_z)
274
+ alpha = 1.0 / (4.0 * np.std(flat_abs_z)) if np.std(flat_abs_z) != 0 else 1.0
275
+
276
+ compressed = np.tanh(alpha * (abs_z - threshold))
277
+
278
+ # Rescale to [0, 1]
279
+ compressed[nan_mask] = np.nan
280
+ min_val = np.nanmin(compressed)
281
+ max_val = np.nanmax(compressed)
282
+ if max_val == min_val:
283
+ rescaled = np.full_like(compressed, 0.5)
284
+ else:
285
+ rescaled = (compressed - min_val) / (max_val - min_val)
286
+
287
+ rescaled[nan_mask] = np.nan
288
+ return rescaled
289
+
290
+
291
+ def find_closest_index(arr, target):
292
+ """
293
+ Find the index of the element in `arr` closest to the `target` value.
294
+ """
295
+
296
+ return np.abs(arr - target).argmin()
297
+
298
+
299
+ def compute_snr_peaked(
300
+ x_data: np.ndarray,
301
+ y_data: np.ndarray,
302
+ x0: float,
303
+ fwhm: float,
304
+ noise_region_factor: float = 2.5,
305
+ min_points: int = 20,
306
+ ) -> float:
307
+ """
308
+ Computes the Signal-to-Noise Ratio (SNR) for a peaked function (e.g., Lorentzian, Gaussian)
309
+ based on the provided fit parameters. The SNR is calculated by comparing the signal strength
310
+ at the peak (x0) with the noise level estimated from a region outside the peak.
311
+
312
+ Parameters
313
+ ----------
314
+ x_data : np.ndarray
315
+ Array of x values (independent variable), typically representing frequency or position.
316
+
317
+ y_data : np.ndarray
318
+ Array of y values (dependent variable), representing the measured values (e.g., intensity, amplitude).
319
+
320
+ x0 : float
321
+ The location of the peak (center of the distribution), often the resonance frequency or peak position.
322
+
323
+ fwhm : float
324
+ The Full Width at Half Maximum (FWHM) of the peak. This defines the width of the peak and helps determine
325
+ the region for noise estimation.
326
+
327
+ noise_region_factor : float, optional, default=2.5
328
+ The factor used to define the width of the noise region as a multiple of the FWHM. The noise region is
329
+ considered outside the interval `(x0 - noise_region_factor * fwhm, x0 + noise_region_factor * fwhm)`.
330
+
331
+ min_points : int, optional, default=20
332
+ The minimum number of data points required in the noise region to estimate the noise level. If the number
333
+ of points in the noise region is smaller than this threshold, a warning is issued.
334
+
335
+ Returns
336
+ -------
337
+ float
338
+ The computed Signal-to-Noise Ratio (SNR), which is the ratio of the signal strength at `x0` to the
339
+ standard deviation of the noise. If the noise standard deviation is zero, the SNR is set to infinity.
340
+
341
+ Notes
342
+ -----
343
+ - The function assumes that the signal has a clear peak at `x0` and that the surrounding data represents noise.
344
+ - If the noise region contains fewer than `min_points` data points, a warning is raised suggesting the adjustment of `noise_region_factor`.
345
+
346
+ Example
347
+ -------
348
+ >>> x_data = np.linspace(-10, 10, 1000)
349
+ >>> y_data = np.exp(-(x_data**2)) # Example Gaussian
350
+ >>> x0 = 0
351
+ >>> fwhm = 2.0
352
+ >>> snr = compute_snr_peaked(x_data, y_data, x0, fwhm)
353
+ >>> print(snr)
354
+ """
355
+
356
+ # Signal strength at x0
357
+ signal = y_data[np.argmin(np.abs(x_data - x0))]
358
+
359
+ # Define noise region (outside noise_region_factor * FWHM)
360
+ noise_mask = (x_data < (x0 - noise_region_factor * fwhm)) | (
361
+ x_data > (x0 + noise_region_factor * fwhm)
362
+ )
363
+ noise_data = y_data[noise_mask]
364
+
365
+ # Check if there are enough data points for noise estimation
366
+ if len(noise_data) < min_points:
367
+ Warning(
368
+ f"Only {len(noise_data)} points found in the noise region. Consider reducing noise_region_factor."
369
+ )
370
+
371
+ # Compute noise standard deviation
372
+ noise_std = np.std(noise_data)
373
+
374
+ # Compute SNR
375
+ snr = signal / noise_std if noise_std > 0 else np.inf # Avoid division by zero
376
+
377
+ return snr
378
+
379
+
380
+ def find_first_minima_idx(data):
381
+ """
382
+ Find the index of the first local minimum in a 1D array.
383
+
384
+ Parameters
385
+ ----------
386
+ data : array-like
387
+ 1D sequence of numerical values.
388
+
389
+ Returns
390
+ -------
391
+ int or None
392
+ Index of the first local minimum, or None if no local minimum is found.
393
+
394
+ Notes
395
+ -----
396
+ A local minimum is defined as a point that is smaller than its immediate neighbors.
397
+ Uses `scipy.signal.argrelextrema` to detect local minima.
398
+
399
+ Examples
400
+ --------
401
+ >>> data = [3, 2, 4, 1, 5]
402
+ >>> find_first_minima_idx(data)
403
+ 1
404
+ """
405
+ data = np.array(data)
406
+ minima_indices = argrelextrema(data, np.less)[0]
407
+
408
+ # Check boundaries for minima (optional)
409
+ if data.size < 2:
410
+ return None
411
+
412
+ if len(minima_indices) > 0:
413
+ return minima_indices[0]
414
+
415
+ return None
@@ -0,0 +1,105 @@
1
+ import numpy as np
2
+
3
+ _EXP_UNIT_MAP = {
4
+ -15: "p",
5
+ -12: "f",
6
+ -9: "n",
7
+ -6: r"\mu ",
8
+ -3: "m",
9
+ 0: "",
10
+ 3: "k",
11
+ 6: "M",
12
+ 9: "G",
13
+ 12: "T",
14
+ 15: "P",
15
+ }
16
+
17
+ PARAM_METADATA = {
18
+ "readout_resonator_frequency": {
19
+ "name": "Readout frequency",
20
+ "symbol": "f_{RO}",
21
+ "unit": "Hz",
22
+ "scale": 1e-9,
23
+ "precision": 5,
24
+ },
25
+ "readout_range_out": {
26
+ "name": "Readout power offset",
27
+ "symbol": "P_0^{RO}",
28
+ "unit": "dBm",
29
+ "scale": 1,
30
+ },
31
+ "readout_amplitude": {
32
+ "name": "Readout amplitude",
33
+ "symbol": "A_{RO}",
34
+ "unit": "",
35
+ "scale": 1,
36
+ },
37
+ "readout_length": {
38
+ "name": "Readout length",
39
+ "symbol": "T_{RO}",
40
+ "unit": "s",
41
+ "scale": 1e6,
42
+ },
43
+ "readout_lo_frequency": {
44
+ "name": "Internal readout LO frequency",
45
+ "symbol": "f_{LO-int}^{RO}",
46
+ "unit": "Hz",
47
+ "scale": 1e-9,
48
+ },
49
+ "readout_external_lo_frequency": {
50
+ "name": "External LO frequency",
51
+ "symbol": "f_{LO}^{Ext}",
52
+ "unit": "Hz",
53
+ "scale": 1e-9,
54
+ },
55
+ "readout_external_lo_power": {
56
+ "name": "External LO power",
57
+ "symbol": "P_{LO}^{Ext}",
58
+ "unit": "dBm",
59
+ "scale": 1,
60
+ },
61
+ "readout_kappa_tot": {"symbol": r"\kappa_{tot}", "unit": "Hz", "scale": "MHz"},
62
+ "resonance_frequency_ge": {
63
+ "name": "Readout frequency",
64
+ "symbol": "f_{ge}",
65
+ "unit": "Hz",
66
+ "scale": 1e-9,
67
+ "precision": 5,
68
+ },
69
+ "resonance_frequency_ef": {
70
+ "name": "Readout frequency",
71
+ "symbol": "f_{ef}",
72
+ "unit": "Hz",
73
+ "scale": 1e-9,
74
+ "precision": 5,
75
+ },
76
+ "spectroscopy_amplitude": {
77
+ "name": "Spectroscopy amplitude",
78
+ "symbol": "A_{sp}",
79
+ "unit": "",
80
+ "scale": 1,
81
+ },
82
+ "ge_drive_amplitude_pi": {
83
+ "name": "Drive amplitude pi ge",
84
+ "symbol": r"A_{\pi}^{ge}",
85
+ "unit": "",
86
+ "scale": 1,
87
+ },
88
+ "ge_drive_length": {
89
+ "name": "Drive length ge",
90
+ "symbol": r"T_{\pi}^{ge}",
91
+ "unit": "s",
92
+ "scale": 1e9,
93
+ },
94
+ }
95
+
96
+ ONE_TONE_PARAMS = np.array(
97
+ [
98
+ "readout_amplitude",
99
+ "readout_length",
100
+ "readout_external_lo_frequency",
101
+ "readout_external_lo_power",
102
+ ]
103
+ )
104
+
105
+ TWO_TONE_PARAMS = np.array(["spectroscopy_amplitude"])