Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 32 additions & 14 deletions sodetlib/operations/iv.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,17 @@ class IVAnalysis:
Array of shape (nbiases) containing the commanded bias-current
at each step (Amps)
resp : np.ndarray
Array of shape (nchans, nbiases) containing the squid response (Amps)
at each bias point
Array of shape (nchans, nbiases) containing the squid response
at each bias point, multiplied with the sc_off and contextless
c_norm corrections
applied to (hopefully accurately) convert it to actual [Amps].
That is, it's the original squid response phase data -contextless
c_norm everywhere and -sc_off in [:sc_idx].
i_tes_offset : np.ndarray
Array of shape (nchans) containing the (contextless) determination of
the proper phase offset correction
sc_offset : np.ndarray
Array of shape (nchans) containing the superconducting branch offset.
R : np.ndarray
Array of shape (nchans, nbiases) containing the TES Resistance of each
channel at each bias point
Expand Down Expand Up @@ -117,15 +126,16 @@ def __init__(self, S=None, cfg=None, run_kwargs=None, sid=None,
self.biases_cmd = np.sort(self.run_kwargs['biases'])
self.nbiases = len(self.biases_cmd)
self.bias_groups = self.run_kwargs['bias_groups']

am = self._load_am()
self.nchans= len(am.signal)
self.nchans = len(am.signal)

self.bands = am.ch_info.band
self.channels = am.ch_info.channel
self.v_bias = np.full((self.nbiases, ), np.nan)
self.i_bias = np.full((self.nbiases, ), np.nan)
self.resp = np.full((self.nchans, self.nbiases), np.nan)
self.c_norm = np.full((self.nchans, ), np.nan)
self.sc_off = np.full((self.nchans, ), np.nan)
self.R = np.full((self.nchans, self.nbiases), np.nan)
self.p_tes = np.full((self.nchans, self.nbiases), np.nan)
self.v_tes = np.full((self.nchans, self.nbiases), np.nan)
Expand All @@ -144,8 +154,8 @@ def save(self, path=None, update_cfg=False):
saved_fields = [
'meta', 'bands', 'channels', 'sid', 'start_times', 'stop_times',
'run_kwargs', 'biases_cmd', 'bias_groups', 'nbiases', 'nchans',
'bgmap', 'polarity', 'resp', 'v_bias', 'i_bias', 'R', 'R_n', 'R_L',
'idxs', 'p_tes', 'v_tes', 'i_tes', 'p_sat', 'si',
'bgmap', 'polarity', 'resp', 'c_norm', 'sc_off', 'v_bias', 'i_bias',
'R', 'R_n', 'R_L', 'idxs', 'p_tes', 'v_tes', 'i_tes', 'p_sat', 'si',
]
data = {
field: getattr(self, field, None) for field in saved_fields
Expand All @@ -167,13 +177,19 @@ def load(cls, path):
setattr(iva, key, val)
return iva

def _load_am(self, arc=None):
def _load_am(self, arc=None, base_dir='/data/so/timestreams'):
if self.am is None:
if arc:
self.am = arc.load_data(self.start_times[0],
self.stop_times[-1])
else:
self.am = sdl.load_session(self.meta['stream_id'], self.sid)
self.am = sdl.load_session(self.meta['stream_id'], self.sid,
base_dir=base_dir)
# check for if the file contains the attributes added after version 1.
# initialize any that are missing so analyze_iv doesn't crash.
for attr_name in ['c_norm','sc_off']:
if not hasattr(self, attr_name):
setattr(self, attr_name, np.full((self.nchans, ), np.nan))
Comment on lines +188 to +192
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might make a bit more sense to put this in the load function instead of _load_am

return self.am


Expand Down Expand Up @@ -307,22 +323,17 @@ def analyze_iv(iva, psat_level=0.9, save=False, update_cfg=False):
"""
am = iva._load_am()
R_sh = iva.meta['R_sh']

# Calculate phase response and bias_voltages / currents
for i in range(iva.nbiases):
# Start from back because analysis is easier low->high voltages
t0, t1 = iva.start_times[-(i+1)], iva.stop_times[-(i+1)]

m = (t0 < am.timestamps) & (am.timestamps < t1)
iva.resp[:, i] = np.mean(am.signal[:, m], axis=1)

# Assume all bias groups have the same bias during IV
bias_bits = np.median(am.biases[iva.bias_groups[0], m])
iva.v_bias[i] = bias_bits * 2 * iva.meta['rtm_bit_to_volt']

if iva.run_kwargs['high_current_mode']:
iva.v_bias *= iva.meta['high_low_current_ratio']

iva.i_bias = iva.v_bias / iva.meta['bias_line_resistance']

# Convert phase to Amps
Expand All @@ -349,6 +360,9 @@ def analyze_iv(iva, psat_level=0.9, save=False, update_cfg=False):

norm_fit = np.polyfit(iva.i_bias[nb_fit_idx:],
iva.resp[i, nb_fit_idx:], 1)
# save this phase_offset value as it's possible that the accurate
# one is the same for all ivs of the same detector&session.
iva.c_norm[i] = norm_fit[1]
iva.resp[i] -= norm_fit[1] # Put resp in real current units

sc_fit = np.polyfit(iva.i_bias[:sc_idx], iva.resp[i, :sc_idx], 1)
Expand All @@ -357,6 +371,9 @@ def analyze_iv(iva, psat_level=0.9, save=False, update_cfg=False):
# is probably due to an undetected phase wrap at the kink between
# the superconducting branch and the transition, so it is
# *probably* legitimate to remove it by hand.
# However, save its offset so original data can be reconstructed
# in cases where ex. sc_idx is clearly wrong.
iva.sc_off[i] = sc_fit[1]
iva.resp[i, :sc_idx] -= sc_fit[1]
sc_fit[1] = 0 # now change s.c. fit offset to 0 for plotting

Expand All @@ -376,6 +393,8 @@ def analyze_iv(iva, psat_level=0.9, save=False, update_cfg=False):

if save:
iva.save(update_cfg=update_cfg)



def plot_Rfracs(iva, Rn_range=(5e-3, 12e-3)):
"""
Expand Down Expand Up @@ -443,7 +462,6 @@ def plot_channel_iv(iva, rc):

b, c, bg = iva.bands[rc], iva.channels[rc], iva.bgmap[rc]
axes[0].set_title(f"Band: {b}, Chan: {c}, BG: {bg}", fontsize=18)

axes[-1].set_xlabel("Voltage (V)")
return fig, axes

Expand Down