Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Biasstep rebias #362

Merged
merged 31 commits into from
Sep 3, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bc1a609
first version biasstep rebiading
Jan 12, 2023
a3a1176
first version biasstep rebiading
Jan 12, 2023
f87db7a
Remove unrelated local changes
Jan 17, 2023
3e3eefc
fix R_n, R_n_IV yet again
Jan 17, 2023
d27467b
update biasstep_rebias script
yuhanwyhan May 3, 2023
14bbfd6
update biasstep_rebias
yuhanwyhan May 3, 2023
42c66fd
update biasstep_rebias
yuhanwyhan May 4, 2023
dde5a01
Update bias_dets.py
yuhanwyhan May 4, 2023
2dd275d
Update bias_dets.py
yuhanwyhan May 4, 2023
043eea5
Update bias_dets.py
yuhanwyhan Jun 19, 2023
4122222
Update bias_dets.py
yuhanwyhan Jun 19, 2023
858bcec
Update bias_dets.py
yuhanwyhan Jun 19, 2023
e480145
Update bias_dets.py
yuhanwyhan Jun 20, 2023
db0b073
Update bias_dets.py
yuhanwyhan Jun 20, 2023
d06ad93
Update bias_dets.py
yuhanwyhan Jun 20, 2023
77df01c
Update bias_dets.py
yuhanwyhan Jun 20, 2023
ce45d67
Update bias_dets.py
yuhanwyhan Jun 20, 2023
56ee133
Update bias_dets.py
yuhanwyhan Jun 20, 2023
aefe183
Update bias_dets.py
yuhanwyhan Jun 20, 2023
05fea5d
Update bias_dets.py
yuhanwyhan Jun 20, 2023
87fbf18
Update bias_dets.py
yuhanwyhan Jun 20, 2023
e651ce4
Update bias_dets.py
yuhanwyhan Jun 20, 2023
92e29a8
Update bias_dets.py
yuhanwyhan Jun 20, 2023
ef1f259
Update det_config.py for adding in 'testbed_100mK_bias_voltage' that …
yuhanwyhan Jun 20, 2023
2d3b2fb
Update det_config.py
yuhanwyhan Jun 20, 2023
076db68
Update det_config.py
yuhanwyhan Jun 20, 2023
6dd0517
Update det_config.py
yuhanwyhan Jun 20, 2023
01fd395
Update bias_dets.py
yuhanwyhan Jun 20, 2023
1327af0
Makes biasstep_rebias an action, and simple docs page
jlashner Sep 2, 2023
b2b6101
Change g3_tag for bias_step functions
jlashner Sep 2, 2023
7e25878
fix remaining hardcoded g3_tag
jlashner Sep 3, 2023
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
346 changes: 345 additions & 1 deletion sodetlib/operations/bias_dets.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import time
import matplotlib.pyplot as plt
from sodetlib.operations.iv import IVAnalysis

from sodetlib.operations import uxm_setup, uxm_relock, tracking, bias_steps, iv, bias_dets
dpdutcher marked this conversation as resolved.
Show resolved Hide resolved
np.seterr(all="ignore")


Expand Down Expand Up @@ -201,3 +201,347 @@ def bias_to_rfrac(S, cfg, rfrac=0.5, bias_groups=None, iva=None,

return biases

def biasstep_rebias(
Copy link
Member

Choose a reason for hiding this comment

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

Could we set this function as an action? We will want this to be categorized as a single detector operation instead of "many many" bias steps in the data packaging. We'll also want to change the default tags getting added to these .g3 files.

S, cfg, target_percentage_rn = 0.5, bias_groups=None,
math_only=False):
dpdutcher marked this conversation as resolved.
Show resolved Hide resolved

"""
Scripts work well when detectors are already in transistion. For extreme cases
such as detectors are all in SC, it takes a few run to put them perfectly in
transition. Next step is making this script can handle extreme cases faster

Copy link
Collaborator

Choose a reason for hiding this comment

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

Docstring should have purpose of the function and description of args/kwarrgs. This note is fine to put after those items.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also an overview of how the script works would be nice.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed


"""

## take the initial biasstep
S.log("taking the first biasstep")
intical_current_biasvoltage = S.get_tes_bias_bipolar_array()
S.log(f"current biasvoltage {intical_current_biasvoltage}")
dpdutcher marked this conversation as resolved.
Show resolved Hide resolved
bsa_0 = bias_steps.take_bias_steps(S, cfg)
if not math_only:
bias_steps.plot_Rfrac(bsa_0)

## load IV analysis result so can use dynamic step size
iva = iv.IVAnalysis.load(bsa_0.meta['iv_file'])

repeat_biasstep = False
## check for script failue
for bl in bias_groups:
mask_bg = np.where(bsa_0.bgmap==bl)[0]
per_bl_R0 = bsa_0.R0[mask_bg]
if np.isnan(np.nanmedian(per_bl_R0)):
## the yield is very low, could it be the biasstep analysis script failed? repeat again
repeat_biasstep = True
S.log("the biasstep script might have failed, going to repeat the measurement")

if repeat_biasstep:
S.log("retaking biasstep due to failure")
bsa_0 = bias_steps.take_bias_steps(S, cfg)
repeat_biasstep = False
Copy link
Collaborator

@jlashner jlashner Jun 20, 2023

Choose a reason for hiding this comment

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

I don't really like that this is forcing a retake of the bias steps, especially since if it fails a second time it will just continue on as if everything's ok. I think instead if the first bias steps fails, this should raise an exception with a useful error message so a user can take control and figure out the issue.

Do you know how often this fails / why? We should try to fix in the bias step function directly instead of building fixes into this function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

bias step failure has been noticed in multiple places including at the site in LATR, in Chicago LATRt, TSAT and Cornell. One of the failure mode might due to the if statement here:

if not transition:

Tho repeating the biasstep is not ideal, it is a working method given the current circumstances.

Copy link
Collaborator

@jlashner jlashner Jun 20, 2023

Choose a reason for hiding this comment

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

I don't see how repeating it changes anything though... If we want, we can pass an arg that forces it to use the transition estimation of resistance if we think it should be in the transition state. also I believe Yaqiong is also working on a better way to determine whether a channel is in transition.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

but simply repeating it worked. yes Yaqiong and I have been reviewing some functions together.In my opinion I think the if statement can just be removed as we don't really rely on a accurate tes resistance from the biasstep when TES is not in-transition.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you think it's mostly failing when a large fraction of detectors are superconducting? I notice you don't have retries for other times you call bias steps.

Copy link
Contributor Author

@yuhanwyhan yuhanwyhan Jun 20, 2023

Choose a reason for hiding this comment

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

I added in a retry for each bias step except the last one I think. I think the failing can happen either when a large fraction of detectors are superconducting or being normal.
also repeating biasstep twice is like a old voodoo from my ACT days. I think such fix might make sense if one imagines some ADC needs to be 'waken'. I am not sure but I agree this can be redundant and can be removed after better understanding later.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Screenshot 2023-06-20 at 6 57 13 PM Screenshot 2023-06-20 at 6 57 38 PM this is one of the failure case I just found after taking another bias_step this is fixed this is taken in LATRt, on Uv31, I believe the session id is 1687298049

Copy link
Contributor Author

@yuhanwyhan yuhanwyhan Jun 20, 2023

Choose a reason for hiding this comment

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

failure:
Screenshot 2023-06-20 at 7 02 57 PM

Screenshot 2023-06-20 at 7 03 11 PM Screenshot 2023-06-20 at 7 03 22 PM

after repeating
Screenshot 2023-06-20 at 7 01 39 PM
Screenshot 2023-06-20 at 7 01 52 PM
Screenshot 2023-06-20 at 7 02 01 PM

Copy link
Collaborator

Choose a reason for hiding this comment

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

awesome, that's really interesting. are these files all on simons1? I'll take a look tomorrow.


percentage_rn_0 = bsa_0.R0/bsa_0.R_n_IV
## add in checks if detectors are SC
bg_overbias_needed = []
overbias_needed = False
for bl in bias_groups:
mask_bg = np.where(bsa_0.bgmap==bl)[0]
per_bl_percentage_rn_0 = percentage_rn_0[mask_bg]
## mask for SC
mask_sc = np.where((per_bl_percentage_rn_0 < 0.1) & (per_bl_percentage_rn_0 > -0.1))
## if more than 10 percent of the detectors are SC
if len(mask_sc[0]) > 0.1*len(mask_bg):
bg_overbias_needed.append(bl)
overbias_needed = True

## add in check if detectors are normal, hence we should increase the drop step
bg_detectors_normal = []
drop_from_normal = False
for bl in bias_groups:
mask_bg = np.where(bsa_0.bgmap==bl)[0]
per_bl_percentage_rn_0 = percentage_rn_0[mask_bg]
## mask for normal
mask_normal = np.where((per_bl_percentage_rn_0 > 0.9) | (per_bl_percentage_rn_0 < -0.9))
dpdutcher marked this conversation as resolved.
Show resolved Hide resolved
## if more than half of the detectors are normal
if len(mask_normal[0]) > 0.5*len(mask_bg):
bg_detectors_normal.append(bl)
drop_from_normal = True


if overbias_needed:
S.log(f"some BL: {bg_overbias_needed} are stuck in SC, going to over bias them, this takes about 5mins")
previous_dc_biases = S.get_tes_bias_bipolar_array()

sdl.overbias_dets(S, cfg, bias_groups=bg_overbias_needed)
##force wait time 5 mins for UFM to reach equalibrium
for sleep_index in range(5):
time.sleep(60)
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 the sleep-time after overbiasing should be a configurable parameter, ideally settable in the dev-cfg

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah good idea.

safe_dc_biases = previous_dc_biases.copy()
for replace_bg in bg_overbias_needed:
safe_dc_biases[replace_bg] = cfg.dev.bias_groups[replace_bg]["testbed_100mK_bias_voltage"]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is that a standard entry in the config file? In other words, is it guaranteed to exist?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is not a standard entry but should be added in.
the purpose for this entry is so the script has a reference of what bias_voltage to use such that the detectors won't be in SC state at the site. This can also be understood as the bias_voltages at the minimum loading.
since all modules are tested in Princeton first, the dark detector bias_voltages are naturally the bias_voltages at the minimum loading. If this info is missing for some reason, user can put in some high numbers such as 15V for Uv31 as a start point.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you do some combination of (a) adding that parameter to det_config.py (b) using a .get() call here to return a sensible default if no matching entry is found?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I second this. If you add it to the bg_defaults it will always be loaded and you won't need the get call though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

is there a way in the current det_config.py such that we can load different numbers for 90s and 150s?

Copy link
Member

Choose a reason for hiding this comment

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

Could we name this something other than testbed bias voltage? I saw "testbed" and was very confused about why that was useful on-site until I saw you explanation here.

"dark_bias_voltage" or even "reference_bias_voltage" could make this clearer. And it would (correctly) imply that we could change these numbers later as we start to know the UFMs and on-sky loading better.


S.set_tes_bias_bipolar_array(safe_dc_biases)
bsa_0 = bias_steps.take_bias_steps(S, cfg)
bias_steps.plot_Rfrac(bsa_0)
dpdutcher marked this conversation as resolved.
Show resolved Hide resolved

## add in check if detectors are normal now
percentage_rn_0 = bsa_0.R0/bsa_0.R_n_IV
drop_from_normal = False
for bl in bg_overbias_needed:
mask_bg = np.where(bsa_0.bgmap==bl)[0]
per_bl_percentage_rn_0 = percentage_rn_0[mask_bg]
## mask for normal
mask_normal = np.where((per_bl_percentage_rn_0 > 0.9) | (per_bl_percentage_rn_0 < -0.9))
## if more than half of the detectors are normal
if len(mask_normal[0]) > 0.5*len(mask_bg):
bg_detectors_normal.append(bl)
drop_from_normal = True
Comment on lines +330 to +341
Copy link
Collaborator

Choose a reason for hiding this comment

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

This code block is repeated from before (I think). Could be tidied up to avoid repetition.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This code block is not repeated. this code block is designed to be ran again if over_biasing is needed. After the overbiasing, the script has to choose some bias_voltage to land on, in order to be safe from dropping to SC again, the script will choose the biasvoltage recorded in the config file as "testbed_100mK_bias_voltage", this however might land the detectors in normal state. Hence this code block is for catching this after the overbiasing.

Copy link
Collaborator

Choose a reason for hiding this comment

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

What I'm trying to point out is that

mask_bg = np.where(bsa_0.bgmap==bl)[0]
per_bl_percentage_rn_0 = percentage_rn_0[mask_bg]
## mask for normal
mask_normal = np.where((per_bl_percentage_rn_0 > 0.9) | (per_bl_percentage_rn_0 < -0.9))
## if more than half of the detectors are normal
if len(mask_normal[0]) > 0.5*len(mask_bg):
bg_detectors_normal.append(bl)
drop_from_normal = True
are the exact same lines as
mask_bg = np.where(bsa_0.bgmap==bl)[0]
per_bl_percentage_rn_0 = percentage_rn_0[mask_bg]
## mask for normal
mask_normal = np.where((per_bl_percentage_rn_0 > 0.9) | (per_bl_percentage_rn_0 < -0.9))
## if more than half of the detectors are normal
if len(mask_normal[0]) > 0.5*len(mask_bg):
bg_detectors_normal.append(bl)
drop_from_normal = True

so it could be, for example, condensed into a helper function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oh yeah yeah good point... but I am hoping it is ok to just leave it like this as it just used only twice


## drop normal detector into transition first
while drop_from_normal:
S.log(f"some biaslines are still in normal state: {bg_detectors_normal}")
percentage_rn_0 = bsa_0.R0/bsa_0.R_n_IV
S.log("droping detectors from normal to transition")
previous_dc_biases_dfn = S.get_tes_bias_bipolar_array()

S.log(f"current tes bias voltages are: {previous_dc_biases_dfn}")
for bl in bg_detectors_normal:
mask_bg = np.where(bsa_0.bgmap==bl)[0]
v_sc = iva.v_bias[iva.idxs[[mask_bg], 0]]
v_norm = iva.v_bias[iva.idxs[[mask_bg], 1]]
v_spread = np.nanmedian(v_norm) - np.nanmedian(v_sc)
if previous_dc_biases_dfn[bl] > v_spread:
previous_dc_biases_dfn[bl] = previous_dc_biases_dfn[bl] - 0.5 * v_spread
else:
previous_dc_biases_dfn[bl] = previous_dc_biases_dfn[bl] - 0.3 * v_spread
bg_detectors_normal.remove(bl)
S.log(f'biasline {bl} is approching 0 voltage, a confirmation new IV curve is recommended')

S.set_tes_bias_bipolar_array(previous_dc_biases_dfn)
S.log(f"applying: {previous_dc_biases_dfn}")
S.log(f"waiting 10s for dissipation of UFM local heating")
time.sleep(10)
bsa_0 = bias_steps.take_bias_steps(S, cfg)
Copy link
Collaborator

Choose a reason for hiding this comment

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

If you do not need to run on all bias lines, you can specify the bgs arg here to just run on a selection of them. This may speed up the function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is a good idea, but I think this should be added into the next generation of this code. This is because I currently rely on bg map for all 12 biaslines in this version of code.

percentage_rn_0 = bsa_0.R0/bsa_0.R_n_IV
drop_from_normal = False
for bl in bg_detectors_normal:
mask_bg = np.where(bsa_0.bgmap==bl)[0]
per_bl_percentage_rn_0 = percentage_rn_0[mask_bg]
## mask for normal
mask_normal = np.where((per_bl_percentage_rn_0 > 0.9) | (per_bl_percentage_rn_0 < -0.9))
## if more than half of the detectors are normal
if len(mask_normal[0]) > 0.5*len(mask_bg):
drop_from_normal = True
else:
bg_detectors_normal.remove(bl)
for bl in bg_detectors_normal:
if previous_dc_biases_dfn[bl] < 0.5:
bg_detectors_normal.remove(bl)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you explain a bit about what this is doing? I don't quite understand how you're chosing the bias voltage step sizes, and also it's not clear to me from the code how many times this runs on average, but seems like it could be a lot of bias step measurements. Do you think this is mainly what's dominating the function's runtime?

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 we might want to brainstorm other ways to drop into the transition. I think if we're taking small enough step sizes we may not need to take bias steps every time, since we're unlikely to induce tracking skips.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is looping down the bias voltages until a certain bias line is no longer in normal state and TES start to be in-transtion. The step size being the 50% of the transition region from the latest IV such that the bias_line won't be dropped into SC due to step being too large or the script takes too long due to the step being to small. Notice the latest IV doesn't necessary provides good estimation as the I-V won't be taken as frequently as the bias-step, so a larger step size here can be dangerous.
in the field I think the function runtime is dominated by the bias-step analysis itself. This is because in the field the sky loading changes gradually and slowly. the longest runtime will be the wait time of biasing detectors out of SC state, but this shouldn't happen if the re-biasing is done frequently enough nor should dropping from normal state happen frequently.




##preparing for the 2nd step
initial_dc_biases = S.get_tes_bias_bipolar_array()
new_bias_voltage = initial_dc_biases.copy()




for bl in bias_groups:
mask_bg = np.where(bsa_0.bgmap==bl)[0]

per_bl_percentage_rn_0 = percentage_rn_0[mask_bg]

med_per_bl_percentage_rn = np.nanmedian(per_bl_percentage_rn_0)

## use the latest IV to decide the step size, might be tricky to get a good step size in field
v_sc = iva.v_bias[iva.idxs[[mask_bg], 0]]
v_norm = iva.v_bias[iva.idxs[[mask_bg], 1]]
v_spread = np.nanmedian(v_norm) - np.nanmedian(v_sc)
## take 15% of the spread as the step size, so the next biasstep will be taken from 0.25 ~ 0.75 percent Rn after considering the spread
delta_dc_bias = 0.15 * v_spread


## if the current bias point is below 50% Rn, increase V_biaa
if med_per_bl_percentage_rn < 0.5:
new_bias_voltage[bl] = initial_dc_biases[bl] + delta_dc_bias
if med_per_bl_percentage_rn >= 0.5:
new_bias_voltage[bl] = initial_dc_biases[bl] - delta_dc_bias

S.log(f"applying new voltage for 2nd biasstep {new_bias_voltage}")
S.set_tes_bias_bipolar_array(new_bias_voltage)

## taking the second bias step
S.log("taking the 2nd biasstep")
bsa_1 = bias_steps.take_bias_steps(S, cfg)
if not math_only:
bias_steps.plot_Rfrac(bsa_1)

## check for script failue
for bl in bias_groups:
mask_bg = np.where(bsa_1.bgmap==bl)[0]
per_bl_R0 = bsa_1.R0[mask_bg]
if np.isnan(np.nanmedian(per_bl_R0)):
## the yield is very low, could it be the biasstep analysis script failed? repeat again
repeat_biasstep = True
S.log("the biasstep script might have failed, going to repeat the measurement")

if repeat_biasstep:
bsa_1 = bias_steps.take_bias_steps(S, cfg)
repeat_biasstep = False

percentage_rn_1 = bsa_1.R0/bsa_1.R_n_IV

target_percentage_rn_array = target_percentage_rn * np.ones(len(percentage_rn_0))
## getting result from the previous 2
v0 = np.zeros(bsa_0.bgmap.shape[0])
for bl in range(12):
dpdutcher marked this conversation as resolved.
Show resolved Hide resolved
mask_bl = np.where(bsa_0.bgmap==bl)[0]
v0[mask_bl] = initial_dc_biases[bl]

v1 = np.zeros(bsa_1.bgmap.shape[0])
for bl in range(12):
mask_bl = np.where(bsa_1.bgmap==bl)[0]
v1[mask_bl] = new_bias_voltage[bl]
## deciding the new bias point
vbias_estimate_array = (v0*(target_percentage_rn_array-percentage_rn_1) + v1*(percentage_rn_0 - target_percentage_rn_array)) / (percentage_rn_0 - percentage_rn_1)

vbias_estimate = initial_dc_biases.copy()
for bl in bias_groups:
mask_bg = np.where(bsa_0.bgmap==bl)[0]

per_bl_vbias_estimate = vbias_estimate_array[mask_bg]
med_per_bl_vbias_estimate = np.nanmedian(per_bl_vbias_estimate)
if np.isnan(med_per_bl_vbias_estimate):
med_per_bl_vbias_estimate = (v1 + v0)/2
vbias_estimate[bl] = med_per_bl_vbias_estimate

S.log("applying the new bias voltages")
S.set_tes_bias_bipolar_array(vbias_estimate)
S.log(f"applying {vbias_estimate}")
S.log("taking the final biasstep")
bsa_2 = bias_steps.take_bias_steps(S, cfg)

## check for script failue
for bl in bias_groups:
mask_bg = np.where(bsa_2.bgmap==bl)[0]
per_bl_R0 = bsa_2.R0[mask_bg]
if np.isnan(np.nanmedian(per_bl_R0)):
## the yield is very low, could it be the biasstep analysis script failed? repeat again
repeat_biasstep = True
S.log("the biasstep script might have failed, going to repeat the measurement")

if repeat_biasstep:
bsa_2 = bias_steps.take_bias_steps(S, cfg)
repeat_biasstep = False

if not math_only:
bias_steps.plot_Rfrac(bsa_2)


S.log("confirming if the current result is close to the target")
percentage_rn_confirm = bsa_2.R0/bsa_2.R_n_IV
succeeded_bl = []
un_succeeded_bl = []
for bl in bias_groups:
mask_bg = np.where(bsa_2.bgmap==bl)[0]
per_bl_percentage_rn_confirm = np.nanmedian(percentage_rn_confirm[mask_bg])
if per_bl_percentage_rn_confirm > target_percentage_rn - 0.05 and per_bl_percentage_rn_confirm < target_percentage_rn + 0.05:
succeeded_bl.append(bl)
else:
un_succeeded_bl.append(bl)
S.log(f"succeeded bl: {succeeded_bl}")
S.log(f"unsucceeded bl: {un_succeeded_bl}")

if len(un_succeeded_bl)==0:
bsa_final = bsa_2
vbias_estimate_final = vbias_estimate


if len(un_succeeded_bl)!=0:
extra_step_bias_voltage = vbias_estimate.copy()
S.log("fine tunning unsucceeded bl")
for bl in un_succeeded_bl:
mask_bg = np.where(bsa_2.bgmap==bl)[0]
per_bl_percentage_rn_confirm = percentage_rn_confirm[mask_bg]
med_per_bl_percentage_confirm = np.nanmedian(per_bl_percentage_rn_confirm)

## use the latest IV to decide the step size, might be tricky to get a good step size in field
v_sc = iva.v_bias[iva.idxs[[mask_bg], 0]]
v_norm = iva.v_bias[iva.idxs[[mask_bg], 1]]
v_spread = np.nanmedian(v_norm) - np.nanmedian(v_sc)
## take 15% of the spread as the step size, so the next biasstep will be taken from 0.25 ~ 0.75 percent Rn after considering the spread
delta_dc_bias = 0.15 * v_spread
## if the current bias point is below 50% Rn, increase V_biaa
if med_per_bl_percentage_confirm < 0.5:
extra_step_bias_voltage[bl] = vbias_estimate[bl] + delta_dc_bias
if med_per_bl_percentage_confirm >= 0.5:
extra_step_bias_voltage[bl] = vbias_estimate[bl] - delta_dc_bias

S.log(f"applying new voltage for extra step biasstep {extra_step_bias_voltage}")
S.set_tes_bias_bipolar_array(extra_step_bias_voltage)

## taking the extra bias step
S.log("taking the extra biasstep")
bsa_extra = bias_steps.take_bias_steps(S, cfg)

## check for script failue
for bl in bias_groups:
mask_bg = np.where(bsa_extra.bgmap==bl)[0]
per_bl_R0 = bsa_extra.R0[mask_bg]
if np.isnan(np.nanmedian(per_bl_R0)):
## the yield is very low, could it be the biasstep analysis script failed? repeat again
repeat_biasstep = True
S.log("the biasstep script might have failed, going to repeat the measurement")

if repeat_biasstep:
bsa_extra = bias_steps.take_bias_steps(S, cfg)
repeat_biasstep = False

if not math_only:
bias_steps.plot_Rfrac(bsa_extra)

percentage_rn_extra = bsa_extra.R0/bsa_extra.R_n_IV

## getting result from the previous 2
v0 = np.zeros(bsa_2.bgmap.shape[0])
for bl in range(12):
mask_bl = np.where(bsa_2.bgmap==bl)[0]
v0[mask_bl] = vbias_estimate[bl]

v1 = np.zeros(bsa_extra.bgmap.shape[0])
for bl in range(12):
mask_bl = np.where(bsa_extra.bgmap==bl)[0]
v1[mask_bl] = extra_step_bias_voltage[bl]
## deciding the new bias point
vbias_estimate_array_extra = (v0*(target_percentage_rn_array-percentage_rn_extra) + v1*(percentage_rn_confirm - target_percentage_rn_array)) / (percentage_rn_confirm - percentage_rn_extra)

vbias_estimate_final = initial_dc_biases.copy()
for bl in bias_groups:
mask_bg = np.where(bsa_2.bgmap==bl)[0]

per_bl_vbias_estimate = vbias_estimate_array_extra[mask_bg]
med_per_bl_vbias_estimate = np.nanmedian(per_bl_vbias_estimate)
if np.isnan(med_per_bl_vbias_estimate):
med_per_bl_vbias_estimate = (v1 + v0)/2
vbias_estimate_final[bl] = med_per_bl_vbias_estimate


S.log("applying the new bias voltages")
S.set_tes_bias_bipolar_array(vbias_estimate_final)
S.log(f"applying {vbias_estimate_final}")
S.log("taking the final biasstep")
bsa_final = bias_steps.take_bias_steps(S, cfg)
if not math_only:
bias_steps.plot_Rfrac(bsa_final)


return bsa_final,vbias_estimate_final








2 changes: 1 addition & 1 deletion sodetlib/operations/bias_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -960,7 +960,7 @@ def plot_Rfrac(bsa, text_loc=(0.6, 0.8)):
chmap = sdl.map_band_chans(bsa.bands, bsa.channels,
iva.bands, iva.channels)

Rfracs = bsa.R0 / iva.R_n_IV[chmap]
Rfracs = bsa.R0 / iva.R_n[chmap]
dpdutcher marked this conversation as resolved.
Show resolved Hide resolved
lim = (-0.1, 1.2)
nbins=30
bins = np.linspace(*lim, nbins)
Expand Down