Complex Impedance

The complex impedance measurement is a simple measurement that gives us access to many electrothermal properties of the TES.

Following the theory presented in Irwin and Hilton, the complex impedance is given by:

\[Z_\mathrm{tes}(\omega) = R(1 + \beta_I) + \frac{R \mathscr{L}_I}{1 - \mathscr{L}_I} nf. \frac{2 + \beta_I}{1 + i \omega \tau_I}\]

where \(\beta_I = \left.\frac{d \log R}{d\log I}\right|_{T_\mathrm{bath}}\) is the current sensitivity at constant temp, \(\mathscr{L}_I\) the loop-gain, and \(\tau_I\) the thermal time-constant at constant current. We are able to fit these parameters to our complex impedance measurement, and obtain derived parameters such as the effective thermal time-constant:

\[\tau_\mathrm{eff} = \tau_I (1 - \mathscr{L}_I) \left(1 + \frac{(1 - R_\mathrm{sh}/R) \mathscr{L}_I}{1 + \beta_I + R_\mathrm{sh}/R} \right)^{-1}\]

Measurement

The complex impedance can be measured via the complex transfer functions of the TES as a function of frequency. To do this we play a sine-wave on the bias line over a large frequency range, and measure the amplitude and phase (with respect to the commanded bias) as a function of frequency.

In order to remove parasitic contamination from the bias circuitry, we use measurements of the TES response while the detectors are in their superconducting and normal states to obtain the Thevenin equivalent voltage and impedance of the bias circuit (see Lindeman et al.). The equivalent voltage and impedance are given by:

\[V_\mathrm{th}(\omega) = \frac{R_\mathrm{N}} {I_\mathrm{ob}(\omega) - I_\mathrm{sc}(\omega)} \qquad Z_\mathrm{eq}(\omega) = \frac{V_\mathrm{th}(\omega)}{I_\mathrm{sc}(\omega)}\]

and the TES impedance given by

\[Z_\mathrm{TES} = V_\mathrm{th} / I - Z_\mathrm{eq}\]

Where \(V_\mathrm{th}\), \(I_\mathrm{ob}\), \(I_\mathrm{sc}\), \(I\) and \(Z_\mathrm{eq}\) are all complex phasors that are functions of frequency.

Operation

The complex impedance measurement consists of two parts. First, measuring the superconducting and overbiased transfer functions. This only needs to be done once per cooldown, and then the results can be used for any Ztes measurement. Then we measure the transfer functions while the detectors are in transition.

These measurements all use the same base function, take_complex_impedance which streams data for each bias-group while playing sine waves at different frequencies.

The function take_complex_impedance_ob_sc function will take CI data in the overbiased and superconducting states, and save their paths in the device config for later use.

For example, the following code will take SC, OB, and in-transition datasets:

import sodetlib.operations.complex_impedance as ci
from sodetlib.operations import bias_dets

freqs = np.logspace(0, np.log10(2e3), 80)
bgs = np.arange(12)
ci.take_complex_impedance_ob_sc(S, cfg, bgs, freqs=freqs, run_analysis=True)

bias_dets.bias_to_rfrac_range(S, cfg, (0.3, 0.6))
time.sleep(60)
ds = ci.take_complex_impedance(S, cfg, bgs, freqs=freqs, run_analysis=True)

The output ds (for dataset) is an AxisManager containing a bunch of fields including the complex-impedance for each detector. See the docstring for the analysis functions analyze_tods, get_ztes, fit_det_params to see what fields it contains.

On creation, the ds AxisManager is automatically loaded with superconducting and overbiased data from the files that are set in the device cfg. This means that the saved hdf5 file contains all the info needed for analysis, and there is no need to manually add sc and ob data on load. For instance, to load and plot data from a file, one can simply run:

from sotodlib.core import AxisManager
import sodetlib.operations.complex_impedance as ci

ds = AxisManager.load('/path/to/trans.h5')
# Plot transfer functions for channel with index 0.
ci.plot_transfers(ds, 0)

Note

The complex impedance dataset can only measure frequencies up to half the sampling rate. It can be very beneficial to measure out to higher frequencies to better constrain detector parameters, so if you are measuring high frqeuencies it is recommended to set a flux-ramp rate of 10 kHz or more before taking data. This can be done easily using the relock_tracking_setup function.

However, if you are running at high sample rates, analysis may take upwards of 20 min or so to run per dataset (for a ufm with 12 biasgroups). This time is dominated by the time it takes to load datafiles with high sample rates from G3.

API

sodetlib.operations.complex_impedance.analyze_seg(ds, tod, bg, i)

Analyze segment of CI data. The main goal of this is to calculate the Ites phasor, containing the amplitude (A) and phase (relative tot he commanded) of the TES response to an incoming sine wave. This performs the following steps:

  1. Restrict full TOD to a single excitation frequency. This will put everything units of A, correct for channel polarity. This will also correct timestamps based on the FrameCounter.

  2. Takes PSD of the bias data to obtain the reference freq. Filters signal using gaussian filter around reference freq.

  3. Use lock-in amplification with bias as reference to extract amplitude and phase of the filtered signal with respect to the commanded bias.

Parameters:
  • ds (AxisManager) – CI Dataset

  • tod (AxisManger) – axis-manager containing tod for a given bias group

  • bg (int) – Bias group that is being analyzed

  • i (int) – Freq index. 0 will analyze the first freq segment taken.

Returns:

am – Returns an souped-up tod axis-manager corresponding to this freq with the following fields:

  • timestmaps, biases, signal, ch_info. Standard tod axismanager stuff but with units converted into A, timestamps fixed, and offsets subtracted out.

  • sample_rate, cmd_freq: Floats with the sample rate and commanded freq

  • filt_sig: Filtered signal (using gaussian filter around commanded freq)

  • lockin_x, lockin_y: Lockin x and y signals, used to calc amp and phase across the tod

  • Ites: Phasor for Ites. Amplitude is the amp of the sine wave response, and angle is the phase relative to the commanded bias.

Return type:

AxisManager

sodetlib.operations.complex_impedance.analyze_tods(ds, bgs=None, tod=None, arc=None, show_pb=True)

Analyzes TODS for a CIData set. This will add the following fields to the dataset:

  • Ites(dets, steps): Ites phasor for each detector / frequency combination. Amplitude is the amp of the current response (A), and angle is the phase relative to commanded bias.

  • Ibias(biaslines): Amplitude (A) of the sinewave used for each biasline.

  • Ibias_dc(biaslines): DC bias current (A) for each biasline

  • res_freqs(dets): Resonance frequency of each channel detectors.

sodetlib.operations.complex_impedance.fit_det_params(ds, pb=False, fmax=None)

Fits detector params for a sweep.

Parameters:
  • ds (AxisManager) – CIData

  • pb (bool) – If True, wil display progressbar.

  • fmax (optional, float) – If set, will only fit using freq values less than fmax.

sodetlib.operations.complex_impedance.get_ztes(ds)

Calculates Ztes for in-transition CIData. Adds the following fields to the CI dataset:

  • Rn (dets): Normal resistances based off of low-f overbiased data points.

  • Rtes (dets): TES Resistance, based off of low-f in-transition segment

  • Vth (dets): Thevenin equiv voltage (V)

  • Zeq (dets): Equiv impedance

  • Ztes (dets): TES complex impedance

sodetlib.operations.complex_impedance.take_complex_impedance(S, cfg, bgs, freqs=None, state='transition', nperiods=500, max_meas_time=20.0, tickle_voltage=0.005, run_analysis=False)

Takes a complex impedance sweep. This will play sine waves on specified bias-groups over the current DC bias voltage. This returns a CISweep object.

Parameters:
  • S (SmurfControl) – Pysmurf Instance

  • cfg (DetConfig) – Det config instance

  • bgs (array, int) – List of bias groups to run on

  • freqs (array, optional) – List of frequencies to sweep over.

  • state (str) – Current detector state. Must be ‘ob’, ‘sc’, or ‘transition’

  • nperiods (float) – Number of periods to measure for at each frequency. If the meas_time ends up larger than max_meas_time, max_meas_time will be used instead. This makes it so we don’t spend unreasonably long amounts of time at higher freqs.

  • max_meas_time (float) – Maximum amount of time to wait at any given frequency

  • tickle_voltage (float) – Tickle amplitude in low-current-mode volts.

  • run_analysis (bool) – Perform the full CI analysis and save the results.

sodetlib.operations.complex_impedance.take_complex_impedance_ob_sc(S, cfg, bgs, overbias_voltage=19.9, tes_bias=15.0, overbias_wait=5.0, cool_wait=30.0, run_analysis=True, **ci_kwargs)

Takes overbiased and superconducting complex impedance sweeps. These are required to analyze any in-transition sweeps.

Parameters:
  • S (SmurfControl) – Pysmurf Instance

  • cfg (DetConfig) – Det config instance

  • bgs (array, int) – List of bias groups to run on

  • overbias_voltage (float) – Voltage to use to overbias detectors

  • tes_bias (float) – Voltage to set detectors to after overbiasing

  • overbias_wait (float) – Time to wait at the overbias_voltage

  • cool_wait (float) – Time to wait at the tes_bias after overbiasing

  • run_analysis (bool) – Perform the full CI analysis and save the results.

  • **ci_kwargs – Any additional kwargs will be passed directly to the take_complex_impedance function.

References