Bias Steps and Bias Group Maps

Bias steps are when we take small steps in the detector bias voltage and measure the detector response. These are a fantastic tool for calibrating detectors and can be used to estimate detector parameters such as resistance, responsivity, effective time constant, and can also be used to quickly generate a bias-group mapping.

Usage

Generating a Bias Group Map

To generate a bias-group map, use the function take_bgmap from the bias_steps module. This will run the bias-steps function with parameters optimal for generating a bias-group map, will create a bgmap file, and save the filepath to the device cfg. This function returns a bias step analysis object.

import sodetlib.operations as ops

bsa = ops.take_bgmap(S, cfg)

To generate the bgmap, this function will set detectors to superconducting and play a series of small bias-steps. Because the detectors are superconducting, we expect a very clear bias-group correlation, and we expect the estimated resistance to be very small. By default, channels will be “unassigned” from the bgmap if the bg-correlation factor is less than 0.9 or if the estimated resistance is larger than 10 mOhms to avoid picking up crosstalk channels. These cuts can be modified by setting the corresponding keyword arguments manually in the analysis_kwargs parameter, for example:

from sodetlib.operations import bias_steps

analysis_kwargs = {
    'assignment_thresh': 0.5,
    'R0_thresh': 5e-3
}
bsa = bias_steps.take_bgmap(S, cfg, analysis_kwargs=analysis_kwargs)

The bgmap file stores key metadata along with information about which channels were run to produce the map, the bias-group assignments of each channel, and the polarity of each channel, or whether the squid response steps in the same or opposite direction of the bias current. The bgmap file contains:

  • meta:

    Dictionary of metadata returned by the get_metadata funciton in sodetlib.util

  • sid:

    Session-id of bgmap data

  • bands:

    Array containing the smurf-band number for each channel

  • channels:

    Array containing the smurf-channel number for each channel

  • bgmap:

    Array containing the assigned bias group of each channel. This will be -1 if unassigned.

  • polarity:

    Array containing the polarity of the channel with respect to the bias line. This will be +1 if the signal steps in the same direction as \(\Delta V\) and -1 if the signal steps in the opposite direction.

To load a bgmap for a set of channels, you can use the load_bgmap function.

import sodetlib as sdl

sid = sdl.take_g3_data(S, 30)
am = sdl.load_session(cfg.stream_id, sid)

bgmap, polarity = sdl.load_bgmap(
    am.ch_info.band, am.ch_info.channel, cfg.dev.exp['bgmap_file']
)

Running Bias Steps

The sodetlib function take_bias_steps can be used to take bias steps and run the analysis to calculate the detector parameters mentioned above. The default parameters should be good enough for the full analysis, for example, one can simply run

from sodetlib.operations.bias_steps import take_bias_steps

bsa = take_bias_steps(S, cfg)

If all goes well, the returned object bsa is a fully analyzed instance of the BiasStepAnalysis class. This means that all the detector parameter fields (such as R0, I0, Pj, tau_eff etc.) exist and can be examined. If the analysis failed for whatever reason, the BiasStepAnalysis class will still be returned, however most of the derived parameters will not exist as attributes. However the axis manager will still be loaded (bsa.am) so you can use that to investigate why the analysis may have failed.

You can re-run the analysis without retaking the data by running

bsa.run_analysis()

Sometimes playing with the analysis keywords (see the API for more details) will give you better results.

Running in Low Current Mode

It is possible to run this function in low-current-mode, which might be desirable if switching to high-current-mode is causing excess heating for whatever reason. Since the low-current-mode has a bias-line filter which increases the signal decay time, in order to get an accurate reading of the TES resistance / responsivity you need to increase the step_duration to at least a couple of seconds. This will make the function take much longer (~2-3 minutes) so this mode of operation may not be as useful. For example, this should work:

bsa = take_bias_steps(
    S, cfg, high_current_mode=False, step_duration=2,
    nsteps=5, analysis_kwargs={'step_window': 2}
)

How it works

Data Taking

With the default parameters, the take_bias_steps function will play nsteps on each of the specified bias groups one at a time.

Generating the Bias Group Map

To generate the bias group assignment for a given channel, we measure the TES change in phase \(\Delta \Phi\) in response to the sweep bias steps. We add \(\pm \Delta \Phi\) for each of the “sweep steps” on a given bias group, where we use + if it’s a rising step and - for a falling step. If a channel has a strong dependence on a particular bias group, the TES responses will co-add and give you a large summed response, and if there is no dependence on a bias group the rising and falling edges will cancel, even if there is a global trend resulting in a small summed response. For a given channel, the summed responses for each bias group are normalized such that they all add to 1, giving us a “normalized correlation factor” (stored in the bg_corr array).

When there is a very clear correlation, (like if the detector is superconducting), there will be one bias group with a correlation value close to 1 and the rest will be close to 0. If it is less clear, for instance if the detectors are in transition and there is a non-linear trend in the detector timestream (from heating for example), the maximum correlation factor will be smaller (like 0.3-0.9) but the maximum will usually still give you the correct bias group. If the maximum correlation factor is less than the assignment_thresh value, the channel is unassigned from all bias groups.

Note

A channel that is perfectly uncorrelated to all bias groups will have a correlation factor of 1/NBiasGroups for each bias-group. Though this is not optimal for determining which bias groups are not connected to any bias-line, an additional cut is made after calculating the TES resistance, which is a better metric for determining which channels should be left unassigned. Any channel that has an estimated resistance larger than the R0_thresh parameter will be considered noise or crosstalk and unassigned from all bias-groups.

Estimating Detector Parameters

First, the detector responses for each of the steps taken are averaged to give us a “mean response” that has a large signal-to-noise ratio and can be used for fitting and DC calculations.

There are two methods of calculating the DC detector parameters, one that assumes the detector is well into transition and that the bias power is constant over the step, and the other that assumes the detector is out of the transition (either super-conducting or normal), and \(R_\mathrm{TES}\) is constant over the step.

The BiasStepAnalysis determines which method should be used based on the bias voltage level. If the transition parameter is set to be a tuple (V0, V1), then the analysis will use the transition method whenever V0 < Vbias < V1. The parameter can also be set to true/false, which will force the analysis to use the transition calculation.

In Transition

In the transition, it is assumed that the ratio of \(dI_\mathrm{rat} = \frac{dI_\mathrm{TES}}{dI_\mathrm{bias}}\) is negative due to the loop gain being larger than 1. See Michael Niemack’s thesis (Section 4.3.1) and Emily Grace’s thesis (Section 4.2.4) for the derivation. The bias power, TES current, and TES resistance are then given by

\[P_J = \frac{I_\mathrm{bias}^2 R_\mathrm{sh} dI_\mathrm{rat}(dI_\mathrm{rat} - 1)}{(1 - 2 dI_\mathrm{rat})^2}\]
\[R_\mathrm{TES} = R_\mathrm{sh} \frac{ I_\mathrm{bias} + \sqrt{I_\mathrm{bias}^2 - 4 P_J / R_\mathrm{sh}} }{ I_\mathrm{bias} - \sqrt{I_\mathrm{bias}^2 - 4 P_J / R_\mathrm{sh}} }\]
\[I_\mathrm{TES} = \sqrt{P_J / R_\mathrm{TES}} = \frac{1}{2} \left( I_\mathrm{bias} - \sqrt{I_\mathrm{bias}^2 - 4 P_J / R_\mathrm{sh}} \right)\]

Out of transition

Outside of the transition, we assume that \(dI_\mathrm{rat} > 0\), and using the assumption that R is constant over the step, we have:

\[R_\mathrm{TES} = R_\mathrm{sh}\left( \frac{dI_\mathrm{bias}}{dI_\mathrm{TES}} - 1 \right)\]
\[I_\mathrm{TES} = \frac{I_\mathrm{bias} R_\mathrm{sh}} {R_\mathrm{TES} + R_\mathrm{sh}}\]
\[P_J = I_\mathrm{TES}^2 R_\mathrm{TES}\]

API

Take Bias Steps

sodetlib.operations.bias_steps.take_bgmap(S, cfg, bgs=None, dc_voltage=0.3, step_voltage=0.01, step_duration=0.05, nsteps=20, high_current_mode=True, hcm_wait_time=0, analysis_kwargs=None, dacs='pos', use_waveform=True, show_plots=True, g3_tag=None, enable_compression=False)

Function to easily create a bgmap. This will set all bias group voltages to 0 (since this is best for generating the bg map), and run bias-steps with default parameters optimal for creating a bgmap.

Parameters
  • (SmurfControl) (S) – Pysmurf control instance

  • (DetConfig) (cfg) – Detconfig instance

  • int (bgs () – Bias groups to run steps on, defaulting to all 12. It is recommended that this isn’t modified unless necessary to create a full bg-map.

  • list – Bias groups to run steps on, defaulting to all 12. It is recommended that this isn’t modified unless necessary to create a full bg-map.

  • optional) – Bias groups to run steps on, defaulting to all 12. It is recommended that this isn’t modified unless necessary to create a full bg-map.

  • (float) (hcm_wait_time) – Step voltage in Low-current-mode units. (i.e. this will be divided by the high-low-ratio before running the steps in high-current mode)

  • (float) – Duration in seconds of each step

  • (int) (nsteps) – Number of steps to run

  • (bool) (high_current_mode) – If true, switches to high-current-mode. If False, leaves in LCM which runs through the bias-line filter, so make sure you extend the step duration to be like >2 sec or something

  • (float) – Time to wait after switching to high-current-mode.

  • dacs (str) – Which group of DACs to play bias-steps on. Can be ‘pos’, ‘neg’, or ‘both’

  • use_waveform (bool) – If True will use the waveform generator instead of stepping DAC’s manually.

  • (dict (analysis_kwargs) – Keyword arguments to be passed to the BiasStepAnalysis run_analysis function.

  • optional) – Keyword arguments to be passed to the BiasStepAnalysis run_analysis function.

  • g3_tag (string, optional) – Tag to attach to g3 stream.

  • enable_compression (bool, optional) – If True, will tell the smurf-streamer to compress G3Frames. Defaults to False because this dominates frame-processing time for high data-rate streams.

sodetlib.operations.bias_steps.take_bias_steps(S, cfg, bgs=None, step_voltage=0.05, step_duration=0.05, nsteps=20, high_current_mode=True, hcm_wait_time=3, run_analysis=True, analysis_kwargs=None, dacs='pos', use_waveform=True, channel_mask=None, g3_tag=None, stream_subtype='bias_steps', enable_compression=False)

Takes bias step data at the current DC voltage. Assumes bias lines are already in low-current mode (if they are in high-current this will not run correction). This function runs bias steps and returns a BiasStepAnalysis object, which can be used to easily view and re-analyze data.

This function will first run a “bias group sweep”, running multiple steps on each bias-line one at a time. This data is used to generate a bgmap. After, <nsteps> bias steps are played on all channels simultaneously.

Parameters
  • S (SmurfControl) – Pysmurf control instance

  • cfg (DetConfig) – Detconfig instance

  • bgs (int, list, optional) – Bias groups to run steps on, defaulting to all 12. Note that the bias-group mapping generated by the bias step analysis will be restricted to the bgs set here so if you only run with a small subset of bias groups, the map might not be correct.

  • step_voltage (float) – Step voltage in Low-current-mode units. (i.e. this will be divided by the high-low-ratio before running the steps in high-current mode)

  • step_duration (float) – Duration in seconds of each step

  • nsteps (int) – Number of steps to run

  • high_current_mode (bool) – If true, switches to high-current-mode. If False, leaves in LCM which runs through the bias-line filter, so make sure you extend the step duration to be like >2 sec or something

  • hcm_wait_time (float) – Time to wait after switching to high-current-mode.

  • dacs – str Which group of DACs to play bias-steps on. Can be ‘pos’, ‘neg’, or ‘both’

  • run_analysis (bool) – If True, will attempt to run the analysis to calculate DC params and tau_eff. If this fails, the analysis object will still be returned but will not contain all analysis results.

  • analysis_kwargs (dict, optional) – Keyword arguments to be passed to the BiasStepAnalysis run_analysis function.

  • channel_mask – np.ndarray, optional Mask containing absolute smurf-channels to write to disk

  • g3_tag – string, optional Tag to attach to g3 stream.

  • stream_subtype – optional, string Stream subtype for this operation. This will default to ‘bias_steps’.

  • enable_compression – bool, optional If True, will tell the smurf-streamer to compress G3Frames. Defaults to False because this dominates frame-processing time for high data-rate streams.

BiasStepAnalysis

The BiasStepAnalysis is the class containing all info pertaining to the bias steps and analysis. It contains smurf parameters required to run the analysis (such as S.high_low_current_ratio, etc.), and analysis products.

Any analysis product that is per-detector will be stored in an array that is nchans long, where nchans is the number of channels being read out at the time, and is indexed by the “readout channel number” (or index of the channel in the axis-manager). The mapping from readout channel to absolute smurf channel number (band * 512 + channel) can be found in the bsa.abs_chans attribute.

class sodetlib.operations.bias_steps.BiasStepAnalysis(S=None, cfg=None, bgs=None, run_kwargs=None)

Container to manage analysis of bias steps taken with the take_bias_steps function. The main function is run_analysis and will do a series of analysis procedures to create a biasgroup map and calculate DC detector parameters and tau_eff:

  • Loads an axis manager with all the data

  • Finds locations of step edges for each bias group

  • Creates a bg map using the isolated bg step responses

  • Gets detector responses of each step and aligns them based on the time of the step

  • Computes DC params R0, I0, Pj, Si from step responses

  • Fits exponential to the average step response and estimates tau_eff.

Most analysis inputs and products will be saved to a npy file so they can be loaded and re-analyzed easily on another computer like simons1.

To load data from an saved step file, you can run:

bsa = BiasStepAnalysis.load(<path>)
tunefile

Path of the tunefile loaded by the pysmurf instance

Type

path

high_low_current_ratio

Ratio of high to low current

Type

float

R_sh

Shunt resistance loaded into pysmurf at time of creation

Type

float

pA_per_phi0

pA_per_phi0, as loaded in pysmurf at time of creation

Type

float

rtm_bit_to_volt

Conversion between bias dac bit and volt

Type

float

bias_line_resistance

Bias line resistance loaded in pysmurf at time of creation

Type

float

high_current_mode

If high-current-mode was used

Type

bool

stream_id

stream_id of the streamer this was run on.

Type

string

sid

Session-id of streaming session

Type

int

start, stop

start and stop time of all steps

Type

float

edge_idxs

Array containing indexes (wrt axis manager) of bias group steps for each bg

Type

array(ints) of shape (nbgs, nsteps)

edge_signs

Array of signs of each step, denoting whether step is rising or falling

Type

array(+/-1) of shape (nbgs, nsteps)

bg_corr

Bias group correlation array, stating likelihood that a given channel belongs on a given bias group determined from the isolated steps

Type

array (float) of shape (nchans, nbgs)

bgmap

Map from readout channel to assigned bias group. -1 means not assigned (that the assignment threshold was not met for any of the 12 bgs)

Type

array (int) of shape (nchans)

abs_chans

Array of the absolute smurf channel number for each channel in the axis manager.

Type

array (int) of shape (nchans)

resp_times

Shared timestamps for each of the step responses in <step_resp> and <mean_resp> with respect to the bg-step location, with the step occuring at t=0.

Type

array (float) shape (nbgs, npts)

mean_resp

Step response averaged accross all bias steps for a given channel in Amps.

Type

array (float) shape (nchans, npts)

step_resp

Each individual step response for a given channel in amps

Type

array (float) shape (nchans, nsteps, npts)

Ibias

DC bias current of each bias group (amps)

Type

array (float) shape (nbgs)

Vbias

DC bias voltage of each bias group (volts in low-current mode)

dIbias

Step current for each bias group (amps)

Type

array (float) shape (nbgs)

dVbias

Step voltage for each bias group (volts in low-current mode)

Type

array (float) shape (nbgs)

dItes

Array of tes step heigh for each channel (amps)

Type

array (float) shape (nchans)

R0

Computed TES resistances for each channel (ohms)

Type

array (float) shape (nchans)

I0

Computed TES currents for each channel (amps)

Type

array (float) shape (nchans)

Pj

Bias power computed for each channel

Type

array (float) shape (nchans)

Si

Responsivity computed for each channel

Type

array (float) shape (nchans)

step_fit_tmin

Time after bias step to start fitting exponential (sec)

Type

float

step_fit_popts

Optimal fit parameters (A, tau, b) for the exponential fit of each channel

Type

array (float) of shape (nchans, 3)

step_fit_pcovs

Fit covariances for each channel

Type

array (float) shape (nchans, 3, 3)

tau_eff

Tau_eff for each channel (sec). Same as step_fit_popts[:, 1].

Type

array (float) shape (nchans)

R_n_IV

Array of normal resistances for each channel pulled from IV in the device cfg.

Type

array (float) shape (nchans)

Rfrac

Rfrac of each channel, determined from R0 and the channel’s normal resistance.

Type

array (float) shape (nchans)

run_analysis(create_bg_map=False, assignment_thresh=0.3, save_bg_map=True, arc=None, base_dir='/data/so/timestreams', step_window=0.03, fit_tmin=0.0015, transition=None, R0_thresh=0.03, save=False, bg_map_file=None)

Runs the bias step analysis.

Parameters
  • create_bg_map (bool) – If True, will create a bg map from the step data. If False, will use the bgmap from the device cfg

  • assignment_thresh (float) – Correlation threshold for which channels should be assigned to particular bias groups.

  • save_bg_map (bool) – If True, will save the created bgmap to disk and set it as the bgmap path in the device cfg.

  • arc (optional, G3tSmurf) – G3tSmurf archive. If specified, will attempt to load axis-manager using archive instead of sid.

  • base_dir (optiional, str) – Base directory where timestreams are stored. Defaults to /data/so/timestreams.

  • step_window (float) – Time after the bias step (in seconds) to use for the analysis.

  • fit_tmin (float) – tmin used for the fit

  • transition – (tuple, bool, optional) Range of voltage bias values (in low-cur units) where the “in-transition” resistance calculation should be used. If True, or False, will use in-transition or normal calc for all channels. Will default to cfg.dev.exp['transition_range'] or (1, 8) if that does not exist or if self._cfg is not set.

  • R0_thresh (float) – Any channel with resistance greater than R0_thresh will be unassigned from its bias group under the assumption that it’s crosstalk

  • save (bool) – If true will save the analysis to a npy file.

  • bg_map_file (optional, path) – If create_bg_map is false and this file is not None, use this file to load the bg_map.

References

Below are some valuable references for information on bias steps and their uses: