Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
E
EST
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
osherso2
EST
Commits
012e5a23
Commit
012e5a23
authored
5 years ago
by
osherso2
Browse files
Options
Downloads
Patches
Plain Diff
Models TES object(s) on an island and simulates the thermal and electrical balance equations.
parent
ef3ba263
No related branches found
No related tags found
1 merge request
!1
S4 design
Pipeline
#184837
canceled
5 years ago
Stage: build
Stage: test
Changes
1
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
DET_model.py
+892
-0
892 additions, 0 deletions
DET_model.py
with
892 additions
and
0 deletions
DET_model.py
0 → 100644
+
892
−
0
View file @
012e5a23
from
detector_lib.TES_model
import
*
from
scipy.optimize
import
minimize
from
scipy.interpolate
import
interp1d
import
pickle
hbar
=
6.58212e-16
# eV s
kb
=
8.61733e-5
# eV / K
J_eV
=
6.2415091e18
# eV / J
class
detector
:
"""
A model of our TES detectors
"""
def
__init__
(
self
,
TESs
,
Tx
,
Cx
,
Gx
,
betaC
,
betaG
,
num_rows
,
Rsh
,
Rb
,
Rl
,
Rs
,
L
,
Vb
,
Tb
,
R
,
I
,
T
,
Popt
,
center_freq
,
bandwidth
):
"""
DEVICE DESCRIPTION
TESs: An array of TES objects. This MUST be in order of first superconducting to last!
Tx [K]: Reference temperature on which to measure heat capacity and thermal conductance.
Cx [J/K]: Heat capacity of the island at Tx.
Gx [W/K]: Thermal conductance of the island at Tx.
betaC: Power law parameter: C(T) = Cx(T/Tx)**betaC.
betaG: Power law parameter: G(T) = Gx(T/Tx)**betaG.
num_rows: Number of detectors in a row (used to compute the load on the bias voltage).
Rsh [Ohms]: Shunt resistor.
Rb [Ohms]: Bias resistor.
Rl [Ohms]: Parasitic resistance on the island.
Rs [Ohms]: Stray resistance off the island.
L [H]: Inductance coupled to the TESs.
DEVICE STATE
Vb [V]: Bias voltage.
Tb [K]: FPU temperature.
R [Ohms]: Resistance on the island.
I [A]: Current through the island.
T [K]: Temperature of the island.
LOADING
Popt [W]: Optical loading.
center_freq [Hz]: Center frequency of the band.
bandwidth [Hz]: Width of the band.
"""
# Thermal
self
.
Tx
=
float
(
Tx
)
# [K] The temperature at which Cx and Gx are measured.
self
.
Cx
=
float
(
Cx
)
# [J/K] Island heat capacity at Tx.
self
.
Gx
=
float
(
Gx
)
# [W/K] Leg heat conductance at Tx.
self
.
betaC
=
float
(
betaC
)
# Power law describing heat capacity: C = Cx * (T/Tx)**betaC.
self
.
betaG
=
float
(
betaG
)
# Power law describing leg conductance: G = Gx * (T/Tx)**betaG.
# Electrical
self
.
num_rows
=
num_rows
# Necessary to know the load on the bias voltage.
self
.
L
=
float
(
L
)
# [H] Inductance.
self
.
Rsh
=
float
(
Rsh
)
# [Ohm] Shunt resistor.
self
.
Rl
=
float
(
Rl
)
# [Ohm] Parasitic resistance on the island.
self
.
Rs
=
float
(
Rs
)
# [Ohm] Stray resistance NOT on the island.
self
.
Rb
=
float
(
Rb
)
# [Ohm] Bias resistor.
self
.
Rn
=
Rl
for
tes
in
TESs
:
self
.
Rn
+=
tes
.
Rn
# Highest possible resistance on the island.
# Environment / Loading
self
.
Popt
=
float
(
Popt
)
# [W] Optical loading.
self
.
center_freq
=
center_freq
# [Hz] Center of the band.
self
.
bandwidth
=
bandwidth
# [Hz] Width of the band.
# State
self
.
Vb
=
Vb
# [V] Bias of entire row (not the voltage across the TES).
self
.
Tb
=
Tb
# [K] Temperature of FPU (other side of the legs).
self
.
R
=
R
# [Ohms] Resistance of the island (Rs of all TESs + Rl).
self
.
I
=
I
# [A] Current flowing through the TESs.
self
.
T
=
T
# [K] Temperature of the island.
# Copying each TES onto the island.
self
.
TESs
=
[]
for
tes
in
TESs
:
tes_copy
=
tes
.
copy
()
tes
.
set_state
(
I
=
I
,
T
=
T
)
self
.
TESs
.
append
(
tes_copy
)
def
set_state
(
self
,
I
=
None
,
T
=
None
):
if
I
is
None
:
I
=
self
.
I
else
:
self
.
I
=
I
if
T
is
None
:
T
=
self
.
T
else
:
self
.
T
=
T
R
=
self
.
Rl
for
tes
in
self
.
TESs
:
tes
.
set_state
(
I
=
I
,
T
=
T
)
R
+=
tes
.
R_trans
(
I
=
I
,
T
=
T
)
self
.
R
=
R
def
get_Vb
(
self
,
R
=
None
,
I
=
None
):
if
R
is
None
:
R
=
self
.
R
if
I
is
None
:
I
=
self
.
I
Rsh
=
self
.
Rsh
Rs
=
self
.
Rs
Rb
=
self
.
Rb
N
=
self
.
num_rows
Rc
=
N
*
(
R
+
Rs
)
*
Rsh
/
(
R
+
Rs
+
Rsh
)
Ib
=
I
*
(
Rsh
+
Rs
+
R
)
/
Rsh
return
Ib
*
(
Rb
+
Rc
)
def
get_Ib
(
self
,
Vb
=
None
,
R
=
None
):
if
Vb
is
None
:
Vb
=
self
.
Vb
if
R
is
None
:
R
=
self
.
R
Rsh
=
self
.
Rsh
Rs
=
self
.
Rs
Rb
=
self
.
Rb
N
=
self
.
num_rows
Rc
=
N
*
(
R
+
Rs
)
*
Rsh
/
(
R
+
Rs
+
Rsh
)
Ib
=
Vb
/
(
Rb
+
Rc
)
return
Ib
def
get_R
(
self
,
I
=
None
,
T
=
None
):
if
I
is
None
:
I
=
self
.
I
if
T
is
None
:
T
=
self
.
T
R
=
self
.
Rl
for
tes
in
self
.
TESs
:
R
+=
tes
.
R_trans
(
I
=
I
,
T
=
T
)
return
R
def
get_I
(
self
,
R
=
None
,
Vb
=
None
):
if
Vb
is
None
:
Vb
=
self
.
Vb
if
R
is
None
:
R
=
self
.
R
Ib
=
self
.
get_Ib
(
Vb
=
Vb
,
R
=
R
)
I
=
Ib
*
self
.
Rsh
/
(
self
.
Rsh
+
self
.
Rs
+
R
)
return
I
def
get_G
(
self
,
T
=
None
):
if
T
is
None
:
T
=
self
.
T
return
self
.
Gx
*
(
self
.
T
/
self
.
Tx
)
**
self
.
betaG
def
get_C
(
self
,
T
=
None
):
if
T
is
None
:
T
=
self
.
T
return
self
.
Cx
*
(
self
.
T
/
self
.
Tx
)
**
self
.
betaC
def
get_alpha
(
self
,
I
=
None
,
T
=
None
):
if
I
is
None
:
I
=
self
.
I
if
T
is
None
:
T
=
self
.
T
alpha
=
0
for
tes
in
self
.
TESs
:
alpha
+=
tes
.
get_alpha
(
I
=
I
,
T
=
T
)
*
(
tes
.
R
/
self
.
R
)
return
alpha
def
get_beta
(
self
,
I
=
None
,
T
=
None
):
if
I
is
None
:
I
=
self
.
I
if
T
is
None
:
T
=
self
.
T
beta
=
0
for
tes
in
self
.
TESs
:
beta
+=
tes
.
get_beta
(
I
=
I
,
T
=
T
)
*
(
tes
.
R
/
self
.
R
)
return
beta
def
get_loop_gain
(
self
):
G
=
self
.
get_G
()
return
self
.
get_alpha
()
*
self
.
R
*
self
.
I
**
2.
/
(
G
*
self
.
T
)
def
get_Z
(
self
,
omega
):
R
=
self
.
R
beta
=
self
.
get_beta
()
loop_gain
=
self
.
get_loop_gain
()
G
=
self
.
get_G
()
C
=
self
.
get_C
()
tau_tm
=
(
C
/
G
)
/
(
1.
-
loop_gain
)
return
R
*
(
1.
+
beta
)
+
(
R
*
loop_gain
*
(
2.
+
beta
)
/
(
1.
-
loop_gain
))
/
(
1.
+
1.j
*
omega
*
tau_tm
)
def
get_taus
(
self
):
R
=
self
.
R
I
=
self
.
I
T
=
self
.
T
L
=
self
.
L
Rl
=
self
.
Rs
+
self
.
Rsh
Tx
=
self
.
Tx
alpha
=
self
.
get_alpha
()
beta
=
self
.
get_beta
()
loop_gain
=
self
.
get_loop_gain
()
gamma
=
Rl
/
R
G
=
self
.
get_G
()
C
=
self
.
get_C
()
tau_CG
=
C
/
G
tau_LR
=
L
/
R
tau_el
=
tau_LR
/
(
1
+
beta
+
gamma
)
tau_tm
=
tau_CG
/
(
1.
-
loop_gain
)
disc
=
((
tau_tm
-
tau_el
)
/
(
tau_tm
*
tau_el
))
**
2.
disc
-=
4.
*
R
*
loop_gain
*
(
2.
+
beta
)
/
(
L
*
tau_CG
)
disc
=
complex
(
disc
)
**
.
5
term
=
(
tau_tm
+
tau_el
)
/
(
tau_tm
*
tau_el
)
tau_p
=
2
/
(
term
+
disc
)
tau_m
=
2
/
(
term
-
disc
)
return
tau_p
,
tau_m
,
tau_el
,
tau_tm
def
stability
(
self
):
tau_p
,
tau_m
,
_
,
_
=
self
.
get_taus
()
if
numpy
.
isnan
(
tau_p
):
return
False
if
numpy
.
isnan
(
tau_m
):
return
False
if
tau_p
.
real
<=
0
or
tau_m
.
real
<=
0
:
return
False
return
True
def
over_damped
(
self
):
tau_p
,
tau_m
,
_
,
_
=
self
.
get_taus
()
if
abs
(
numpy
.
imag
(
tau_p
))
>
1e-12
:
return
False
if
abs
(
numpy
.
imag
(
tau_m
))
>
1e-12
:
return
False
return
self
.
stability
()
def
get_Lcrits
(
self
):
R
=
self
.
R
Rl
=
self
.
Rs
+
self
.
Rsh
gamma
=
Rl
/
R
beta
=
self
.
get_beta
()
tau
=
self
.
get_C
()
/
self
.
get_G
()
loop_gain
=
self
.
get_loop_gain
()
A
=
loop_gain
*
(
3.
+
beta
-
gamma
)
B
=
1.
+
beta
+
gamma
C
=
loop_gain
*
(
2.
+
beta
)
D
=
loop_gain
*
(
1.
-
gamma
)
E
=
2.
*
numpy
.
sqrt
(
C
*
(
D
+
B
))
F
=
R
*
tau
/
(
loop_gain
-
1.
)
**
2.
return
F
*
(
A
+
B
+
E
),
F
*
(
A
+
B
-
E
)
def
get_Lthresh
(
self
):
R
=
self
.
R
Rl
=
self
.
Rs
+
self
.
Rsh
gamma
=
Rl
/
R
beta
=
self
.
get_beta
()
tau
=
self
.
get_C
()
/
self
.
get_G
()
loop_gain
=
self
.
get_loop_gain
()
prefactor
=
(
1.
+
beta
+
gamma
)
/
(
loop_gain
-
1.
)
return
prefactor
*
R
*
tau
def
P_in
(
self
,
R
=
None
,
I
=
None
,
T
=
None
):
if
R
is
None
:
R
=
self
.
R
if
I
is
None
:
I
=
self
.
I
if
T
is
None
:
T
=
self
.
T
P_J
=
R
*
(
I
**
2.
)
return
P_J
+
self
.
Popt
def
P_out
(
self
,
R
=
None
,
I
=
None
,
T
=
None
):
if
R
is
None
:
R
=
self
.
R
if
I
is
None
:
I
=
self
.
I
if
T
is
None
:
T
=
self
.
T
eta
=
self
.
betaG
+
1.
return
self
.
Gx
*
(
T
**
eta
-
self
.
Tb
**
eta
)
/
(
eta
*
self
.
Tx
**
self
.
betaG
)
def
P_bal
(
self
,
R
=
None
,
I
=
None
,
T
=
None
):
return
self
.
P_in
(
R
=
R
,
I
=
I
,
T
=
T
)
-
self
.
P_out
(
R
=
R
,
I
=
I
,
T
=
T
)
def
delPdelI
(
self
,
R
=
None
,
I
=
None
,
T
=
None
):
if
R
is
None
:
R
=
self
.
R
if
I
is
None
:
I
=
self
.
I
if
T
is
None
:
T
=
self
.
T
derv
=
2.
*
R
*
I
for
tes
in
self
.
TESs
:
derv
+=
tes
.
delRdelI
(
I
=
I
,
T
=
T
)
*
(
I
**
2.
)
return
derv
def
delPdelT
(
self
,
R
=
None
,
I
=
None
,
T
=
None
):
if
R
is
None
:
R
=
self
.
R
if
I
is
None
:
I
=
self
.
I
if
T
is
None
:
T
=
self
.
T
derv
=
-
self
.
Gx
*
(
T
**
self
.
betaG
)
/
(
self
.
Tx
**
self
.
betaG
)
# dPlegs/dT
for
tes
in
self
.
TESs
:
derv
+=
tes
.
delRdelT
(
I
=
I
,
T
=
T
)
*
(
I
**
2.
)
# dPJoule/dT
return
derv
def
halfway_finder
(
self
,
TES_index
=
0
):
tess
=
numpy
.
array
(
self
.
TESs
)
assert
(
TES_index
<
len
(
tess
))
R
=
self
.
Rl
if
len
(
tess
[:
TES_index
])
>
1
:
for
tes
in
tess
[:
TES_index
]:
R
+=
tes
.
Rn
R
+=
tess
[
TES_index
].
Rn
/
2.
if
TES_index
==
0
:
T_arr
=
numpy
.
arange
(
0
,
tess
[
0
].
Tc
,
1e-3
)
else
:
T_arr
=
numpy
.
arange
(
tess
[
TES_index
-
1
].
Tc
,
tess
[
TES_index
].
Tc
,
1e-3
)
bG
=
self
.
betaG
Gx
=
self
.
Gx
Tx
=
self
.
Tx
Tc
=
self
.
TESs
[
TES_index
].
Tc
Ic
=
self
.
TESs
[
TES_index
].
Ic
Popt
=
self
.
Popt
Tb
=
self
.
Tb
p1
=
(
bG
+
1.
)
*
(
Tx
**
bG
)
/
Gx
PJ
=
lambda
T
:
R
*
Ic
**
2.
*
(
1.
-
T
/
Tc
)
**
3.
T
=
(
p1
*
(
PJ
(
T_arr
)
+
Popt
)
+
Tb
**
(
bG
+
1.
))
**
(
1.
/
(
bG
+
1.
))
ind
=
numpy
.
argmin
(
numpy
.
abs
(
T
-
T_arr
))
if
ind
==
0
:
ind
=
1
if
ind
==
len
(
T_arr
)
-
1
:
ind
-=
1
T_arr
=
numpy
.
linspace
(
T_arr
[
ind
-
1
],
T_arr
[
ind
+
1
],
5000
)
T
=
(
p1
*
(
PJ
(
T_arr
)
+
Popt
)
+
Tb
**
(
bG
+
1.
))
**
(
1.
/
(
bG
+
1.
))
T
=
T_arr
[
numpy
.
argmin
(
numpy
.
abs
(
T
-
T_arr
))]
I
=
Ic
*
(
1.
-
T
/
Tc
)
**
(
3.
/
2
)
Vb
=
self
.
get_Vb
(
R
=
R
,
I
=
I
)
self
.
Vb
=
Vb
;
self
.
set_state
(
I
=
I
,
T
=
T
)
self
.
halfway_point
=
(
Vb
,
Tb
)
def
stationary_point
(
self
,
R_frac
=
.
65
,
TES_index
=
0
,
method
=
"
hybr
"
,
weight
=
1e3
,
preserve
=
False
,
debug
=
False
):
if
TES_index
==
-
1
:
TES_index
=
len
(
self
.
TESs
)
-
1
if
not
preserve
:
self
.
halfway_finder
(
TES_index
=
TES_index
)
tess
=
self
.
TESs
assert
(
TES_index
<
len
(
tess
))
tes
=
tess
[
TES_index
]
Rc
=
self
.
Rl
if
len
(
tess
[:
TES_index
])
>
1
:
for
tes
in
tess
[:
TES_index
]:
Rc
+=
tes
.
Rn
target
=
R_frac
*
tes
.
Rn
+
Rc
def
err
(
I
,
T
):
R
=
self
.
get_R
(
I
,
T
)
return
(
R
/
target
-
1.
)
**
2.
def
pbal
(
I
,
T
):
R
=
self
.
get_R
(
I
,
T
)
return
self
.
P_bal
(
R
=
R
,
I
=
I
,
T
=
T
)
def
Lg
(
I
,
T
,
l
):
R
=
self
.
get_R
(
I
=
I
,
T
=
T
)
return
(
R
/
target
-
1.
)
**
2.
-
l
*
weight
*
self
.
P_bal
(
R
=
R
,
I
=
I
,
T
=
T
)
def
delLdelI
(
x
):
I
,
T
,
l
=
x
R
=
tes
.
R_trans
(
I
=
I
,
T
=
T
)
dEdI
=
2.
*
(
R
/
target
-
1.
)
*
tes
.
delRdelI
(
I
=
I
,
T
=
T
)
/
target
return
dEdI
-
weight
*
l
*
self
.
delPdelI
(
R
=
R
,
I
=
I
,
T
=
T
)
def
delLdelT
(
x
):
I
,
T
,
l
=
x
R
=
tes
.
R_trans
(
I
=
I
,
T
=
T
)
dEdT
=
2.
*
(
R
/
target
-
1.
)
*
tes
.
delRdelT
(
I
=
I
,
T
=
T
)
/
target
return
dEdT
-
weight
*
l
*
self
.
delPdelT
(
R
=
R
,
I
=
I
,
T
=
T
)
def
delLdell
(
x
):
I
,
T
,
li
=
x
R
=
tes
.
R_trans
(
I
=
I
,
T
=
T
)
return
-
weight
*
self
.
P_bal
(
R
=
R
,
I
=
I
,
T
=
T
)
DeltaT
=
tes
.
Tc
-
self
.
T
DeltaI
=
tes
.
Ic_correction
(
T
=
2.
*
self
.
T
-
tes
.
Tc
)
-
self
.
I
if
R_frac
>
.
5
:
I_bound
=
[
self
.
I
,
min
(
self
.
I
+
2.
*
DeltaI
,
tes
.
Ic
)]
T_bound
=
[
self
.
T
,
tes
.
Tc
]
elif
R_frac
<
.
5
:
I_bound
=
[
max
(
0
,
self
.
I
-
2.
*
DeltaI
),
self
.
I
]
T_bound
=
[
max
(
0
,
self
.
T
-
2.
*
DeltaT
),
self
.
T
]
l_bound
=
[
-
numpy
.
inf
,
numpy
.
inf
]
from
scipy.optimize
import
root
dL
=
lambda
x
:
[
delLdelI
(
x
),
delLdelT
(
x
),
delLdell
(
x
)]
res
=
root
(
dL
,
[
self
.
I
,
self
.
T
,
1.
],
method
=
method
)
curr_I
=
res
.
x
[
0
];
curr_T
=
res
.
x
[
1
];
curr_l
=
res
.
x
[
2
]
curr_R
=
tes
.
R_trans
(
I
=
curr_I
,
T
=
curr_T
)
curr_R
=
self
.
get_R
(
I
=
curr_I
,
T
=
curr_T
)
curr_Vb
=
self
.
get_Vb
(
R
=
curr_R
,
I
=
curr_I
)
self
.
Vb
=
curr_Vb
self
.
set_state
(
I
=
curr_I
,
T
=
curr_T
)
return
res
def
iterative_finder
(
self
,
R_frac
=
.
65
,
TES_index
=
0
,
preserve
=
True
,
N
=
3
,
M
=
4
,
dt
=
1e-8
):
if
TES_index
==
-
1
:
TES_index
=
len
(
self
.
TESs
)
-
1
if
not
preserve
:
self
.
halfway_finder
(
TES_index
=
TES_index
)
tess
=
self
.
TESs
assert
(
TES_index
<
len
(
tess
))
tes
=
tess
[
TES_index
]
Rc
=
self
.
Rl
if
len
(
tess
[:
TES_index
])
>
1
:
for
tes
in
tess
[:
TES_index
]:
Rc
+=
tes
.
Rn
target
=
R_frac
*
tes
.
Rn
+
Rc
for
i
in
range
(
N
):
time
=
numpy
.
arange
(
dt
,
dt
*
M
,
dt
)
self
.
sim
(
time
=
time
)
E
=
target
-
self
.
R
dI
=
self
.
I
*
E
/
(
self
.
R
*
self
.
get_beta
())
Vb
=
self
.
get_Vb
(
R
=
target
,
I
=
self
.
I
+
dI
)
self
.
set_state
(
I
=
self
.
I
+
dI
)
self
.
Vb
=
Vb
### SIMULATION ###
def
small_sig
(
self
,
dt
=
5e-8
,
I
=
None
,
T
=
None
,
Vb
=
None
,
Tb
=
None
):
"""
Simulates one step (of size dt) in time.
Input: dt (default 1e-6 seconds)
Output: dI, dT
"""
if
I
is
None
:
I
=
self
.
I
else
:
self
.
I
=
I
if
T
is
None
:
T
=
self
.
T
else
:
self
.
T
=
T
if
Vb
is
None
:
Vb
=
self
.
Vb
if
Tb
is
None
:
Tb
=
self
.
Tb
# Current state
R
=
self
.
get_R
(
I
=
I
,
T
=
T
)
# Electrical impulse
Rsh
=
self
.
Rsh
Rs
=
self
.
Rs
L
=
self
.
L
Ib
=
self
.
get_Ib
(
Vb
=
Vb
,
R
=
R
)
LdIdt
=
Ib
*
Rsh
-
I
*
(
Rsh
+
R
+
Rs
)
dI
=
LdIdt
*
dt
/
L
# Thermal impulse
CdTdt
=
self
.
P_bal
(
R
=
R
,
I
=
I
,
T
=
T
)
dT
=
CdTdt
*
dt
/
self
.
get_C
(
T
=
T
)
return
dI
,
dT
def
sim
(
self
,
time
,
I
=
None
,
T
=
None
,
prog
=
False
):
"""
Runs self.small_sig a lot to simulate detector response.
Input: an array for time representing the incremental steps to simulate.
Output: time, R, I, T
"""
Vb
=
self
.
Vb
Tb
=
self
.
Tb
R_arr
=
[]
I_arr
=
[]
T_arr
=
[]
if
I
is
None
:
I
=
self
.
I
if
T
is
None
:
T
=
self
.
T
curr_p
=
-
1
dtime
=
numpy
.
diff
(
time
)
dtime
=
numpy
.
append
(
dtime
,
dtime
[
-
1
])
for
i
,
dt
in
enumerate
(
dtime
):
if
prog
:
if
(
100
*
i
)
/
len
(
dtime
)
>
curr_p
:
print
"
%03d%%
"
%
int
((
100
*
i
)
/
len
(
dtime
))
curr_p
+=
10
sig
=
self
.
small_sig
(
I
=
I
,
T
=
T
,
dt
=
dt
)
dI
,
dT
=
sig
I
+=
dI
T
+=
dT
R
=
self
.
get_R
(
I
=
I
,
T
=
T
)
self
.
R
=
R
R_arr
=
numpy
.
append
(
R_arr
,
R
)
I_arr
=
numpy
.
append
(
I_arr
,
I
)
T_arr
=
numpy
.
append
(
T_arr
,
T
)
R_arr
=
numpy
.
array
(
R_arr
)
I_arr
=
numpy
.
array
(
I_arr
)
T_arr
=
numpy
.
array
(
T_arr
)
return
time
,
R_arr
,
I_arr
,
T_arr
def
settle
(
self
,
prog
=
False
):
"""
Runs self.sim for a time array appropriate to let the detector settle and converge.
Input:
Output: time, R, I, T
"""
time
=
numpy
.
append
(
numpy
.
ones
(
50000
)
*
1e-12
,
numpy
.
arange
(
1e-12
,
5e-8
,
1e-12
))
time
=
numpy
.
cumsum
(
time
)
return
self
.
sim
(
time
=
time
,
prog
=
prog
)
def
Tb_variation
(
self
,
arr_t
,
arr_T
,
time
=
None
,
plot
=
False
):
"""
Simulates detector response to changing FPU temperature (T_base).
Input: A array of FPU temperatures (arr_T) and the corresponding time array (arr_t)
Output: time, T_base, R, I, T
"""
Vb
=
self
.
Vb
Tb
=
interp1d
(
arr_t
,
arr_T
)
I
=
self
.
I
T
=
self
.
T
R_arr
=
[]
I_arr
=
[]
T_arr
=
[]
T_bath
=
[]
if
time
is
None
:
dt
=
1e-6
N
=
(
numpy
.
max
(
arr_t
)
-
numpy
.
min
(
arr_t
))
/
dt
N
=
numpy
.
floor
(
N
)
time
=
numpy
.
arange
(
N
)
*
dt
+
arr_t
[
0
]
dtime
=
numpy
.
diff
(
time
)
dtime
=
numpy
.
append
(
dtime
,
dtime
[
-
1
])
for
i
,
(
dt
,
t
)
in
enumerate
(
zip
(
dtime
,
time
)):
self
.
Tb
=
Tb
(
t
)
dI
,
dT
=
self
.
small_sig
(
I
=
I
,
T
=
T
,
dt
=
dt
)
I
+=
dI
T
+=
dT
R
=
self
.
get_R
(
I
=
I
,
T
=
T
)
self
.
R
=
R
R_arr
.
append
(
R
)
I_arr
.
append
(
I
)
T_arr
.
append
(
T
)
T_bath
.
append
(
Tb
(
t
))
R_arr
=
numpy
.
array
(
R_arr
)
I_arr
=
numpy
.
array
(
I_arr
)
T_arr
=
numpy
.
array
(
T_arr
)
T_bath
=
numpy
.
array
(
T_bath
)
return
time
,
T_bath
,
R_arr
,
I_arr
,
T_arr
def
Vb_variation
(
self
,
arr_t
,
arr_V
,
time
=
None
,
plot
=
False
):
"""
Simulates detector response to changing biasing voltage, V_bias.
Input: A array of voltage biases (arr_V) and the corresponding time array (arr_t)
Output: time, V_bias, R, I, T
"""
Vb
=
interp1d
(
arr_t
,
arr_V
)
Tb
=
self
.
Tb
I
=
self
.
I
T
=
self
.
T
R_arr
=
[]
I_arr
=
[]
T_arr
=
[]
V_bias
=
[]
if
time
is
None
:
dt
=
1e-6
N
=
(
numpy
.
max
(
arr_t
)
-
numpy
.
min
(
arr_t
))
/
dt
N
=
numpy
.
floor
(
N
)
time
=
numpy
.
arange
(
N
)
*
dt
+
arr_t
[
0
]
dtime
=
numpy
.
diff
(
time
)
dtime
=
numpy
.
append
(
dtime
,
dtime
[
-
1
])
for
i
,
(
dt
,
t
)
in
enumerate
(
zip
(
dtime
,
time
)):
self
.
Vb
=
Vb
(
t
)
dI
,
dT
=
self
.
small_sig
(
I
=
I
,
T
=
T
,
dt
=
dt
)
I
+=
dI
T
+=
dT
R
=
self
.
get_R
(
I
=
I
,
T
=
T
)
self
.
R
=
R
R_arr
.
append
(
R
)
I_arr
.
append
(
I
)
T_arr
.
append
(
T
)
V_bias
.
append
(
Vb
(
t
))
R_arr
=
numpy
.
array
(
R_arr
)
I_arr
=
numpy
.
array
(
I_arr
)
T_arr
=
numpy
.
array
(
T_arr
)
V_bias
=
numpy
.
array
(
V_bias
)
return
time
,
V_bias
,
R_arr
,
I_arr
,
T_arr
def
Edep
(
self
,
E
):
"""
Deposited energy onto the TES island like a cosmic ray would.
Input: E (in eV)
Output:
No output, but the TES state is changed - The TES island should have heated up.
"""
c
=
self
.
Cx
/
(
self
.
Tx
**
self
.
betaC
)
h
=
self
.
betaC
+
1.
T_dep
=
((
h
*
E
/
J_eV
/
c
)
+
self
.
T
**
h
)
**
(
1.
/
h
)
self
.
T
=
T_dep
for
tes
in
self
.
TESs
:
tes
.
T
=
self
.
T
def
cray
(
self
,
E
=
60e6
):
"""
Simulates a cosmic ray interaction. Runs self.Edep and then self.sim for a
predetermined time array I liked.
Input: E (in eV)
Output: time, R, I, T
"""
pre_time
=
numpy
.
ones
(
1000
)
*
1e-5
+
numpy
.
linspace
(
0
,
2e-5
,
1000
)
pre_time
=
numpy
.
cumsum
(
pre_time
)
t_arr
,
R_arr
,
I_arr
,
T_arr
=
self
.
sim
(
time
=
pre_time
)
time
=
[
8e-6
]
*
50000
;
time
=
numpy
.
cumsum
(
time
);
time
=
time
**
2
time
=
numpy
.
append
(
time
,
time
[
-
1
]
+
(
1.
+
numpy
.
arange
(
1000
))
*
5e-5
)
time
=
numpy
.
append
(
time
,
time
[
-
1
]
+
(
1.
+
numpy
.
arange
(
2000
))
*
1e-4
)
c
=
self
.
Cx
/
(
self
.
Tx
**
self
.
betaC
)
h
=
self
.
betaC
+
1.
T_dep
=
((
h
*
E
/
J_eV
/
c
)
+
self
.
T
**
h
)
**
(
1.
/
h
)
self
.
T
=
T_dep
for
tes
in
self
.
TESs
:
tes
.
T
=
self
.
T
time
,
R
,
I
,
T
=
self
.
sim
(
time
=
time
)
#return time, R, I, T
t_arr
=
numpy
.
append
(
pre_time
,
time
+
pre_time
[
-
1
])
R_arr
=
numpy
.
append
(
R_arr
,
R
)
I_arr
=
numpy
.
append
(
I_arr
,
I
)
T_arr
=
numpy
.
append
(
T_arr
,
T
)
return
t_arr
,
R_arr
,
I_arr
,
T_arr
def
loadcurve
(
self
,
Vb_max
=
None
,
Vb_min
=
None
,
Vb_step
=-
2e-4
,
step_t
=
.
01
):
"""
Simulates a loadcurve.
Input: Vb_max: max of V_bias,
Vb_min: min of V_bias,
Vb_step: V_bias step size,
step_t: the pause between steps.
Output: Vb, R, I, T, t1, t2
"""
self
.
lock_finder
(
R_frac
=
.
9
,
TES_index
=-
1
,
N
=
1
)
self
.
settle
()
truncate
=
False
if
Vb_max
is
None
:
Vb_max
=
self
.
Vb
if
Vb_min
is
None
:
Vb_min
=
0
;
truncate
=
True
Vb
=
numpy
.
arange
(
Vb_max
,
Vb_min
,
Vb_step
)
Vb
=
numpy
.
append
(
Vb
[
0
],
Vb
)
Vb
=
numpy
.
append
(
Vb
,
Vb
[
-
1
])
dt
=
1e-5
init
=
1.
/
numpy
.
arange
(
1
,
1000
)
init
=
dt
*
init
[::
-
1
]
rnge
=
numpy
.
arange
(
init
[
-
1
]
+
dt
,
step_t
,
dt
)
time
=
numpy
.
append
(
init
,
rnge
)
def
change_bias
(
vb
):
#print "bias: %.05f V" % vb
dV
=
self
.
Vb
-
vb
dI
=
dV
/
self
.
Rb
dI
=
dI
*
self
.
Rsh
/
(
self
.
Rsh
+
self
.
R
)
self
.
I
-=
dI
self
.
Vb
=
vb
for
tes
in
self
.
TESs
:
tes
.
set_state
(
I
=
self
.
I
,
T
=
self
.
T
)
self
.
sim
(
time
)
t
=
numpy
.
cumsum
([
step_t
]
*
len
(
Vb
))
-
step_t
R
=
[]
I
=
[]
T
=
[]
t1
=
[]
t2
=
[]
for
i
,
vb
in
enumerate
(
Vb
):
p
=
(
100.
*
i
)
/
len
(
Vb
)
#if (i % 100 == 0): print "%d %%" % p
change_bias
(
vb
)
R
.
append
(
self
.
R
)
I
.
append
(
self
.
I
)
T
.
append
(
self
.
T
)
tau_p
,
tau_m
,
_
,
_
=
self
.
get_taus
()
t1
.
append
(
tau_p
)
t2
.
append
(
tau_m
)
if
self
.
R
<
1e-3
*
self
.
TESs
[
0
].
Rn
:
if
truncate
:
Vb
=
Vb
[:
len
(
R
)]
break
R
=
numpy
.
array
(
R
)
I
=
numpy
.
array
(
I
)
T
=
numpy
.
array
(
T
)
t1
=
numpy
.
array
(
t1
)
t2
=
numpy
.
array
(
t2
)
return
Vb
,
R
,
I
,
T
,
t1
,
t2
def
bias_steps
(
self
,
Vb_amp
=
0.00019073486328125
,
step_len
=
.
5
,
N_steps
=
2
):
"""
Simulates taking bias steps from the current bias. So bias will
'
tick
'
between
current bias and current bias + bias step amplitude.
Input: Vb_amp: bias step amplitude.
step_len: time between
'
ticks
'
in the bias.
N_steps: number of bias steps
Output: time, Vb, R, I, T
"""
Vb_base
=
self
.
Vb
Vb_step
=
Vb_base
+
Vb_amp
Vb
=
([
Vb_base
,
Vb_step
]
*
N_steps
)
Vb
=
numpy
.
append
(
Vb
,
Vb_base
)
dt
=
1e-5
time
=
numpy
.
arange
(
0
,
step_len
,
dt
)
def
change_bias
(
vb
):
#print "bias: %.05f V" % vb
dV
=
self
.
Vb
-
vb
dI
=
dV
/
self
.
Rb
dI
=
dI
*
self
.
Rsh
/
(
self
.
Rsh
+
self
.
R
)
self
.
I
-=
dI
self
.
Vb
=
vb
for
tes
in
self
.
TESs
:
tes
.
set_state
(
I
=
self
.
I
,
T
=
self
.
T
)
return
self
.
sim
(
time
)
R
=
numpy
.
array
([])
I
=
numpy
.
array
([])
T
=
numpy
.
array
([])
tarr
=
numpy
.
array
([
0
])
Varr
=
numpy
.
array
([])
for
i
,
vb
in
enumerate
(
Vb
):
time
,
r
,
i
,
t
=
change_bias
(
vb
)
R
=
numpy
.
append
(
R
,
r
)
I
=
numpy
.
append
(
I
,
i
)
T
=
numpy
.
append
(
T
,
t
)
tarr
=
numpy
.
append
(
tarr
,
time
+
time
[
1
]
+
tarr
[
-
1
])
Varr
=
numpy
.
append
(
Varr
,
[
vb
]
*
len
(
r
))
return
tarr
[:
-
1
],
Varr
,
R
,
I
,
T
def
print_state
(
self
):
state
=
self
.
save_state
(
filename
=
None
)
for
k
in
state
.
keys
():
if
"
tes
"
in
k
:
continue
print
k
,
state
[
k
]
for
k
in
state
.
keys
():
if
"
tes
"
not
in
k
:
continue
tes
=
state
[
k
]
print
k
for
p
in
tes
.
keys
():
print
"
"
,
p
,
tes
[
p
]
def
save_state
(
self
,
filename
=
None
):
state
=
{}
for
i
,
tes
in
enumerate
(
self
.
TESs
):
state
[
"
tes_%02d
"
%
i
]
=
{}
state
[
"
tes_%02d
"
%
i
][
"
name
"
]
=
tes
.
name
state
[
"
tes_%02d
"
%
i
][
"
Ic
"
]
=
tes
.
Ic
state
[
"
tes_%02d
"
%
i
][
"
Tc
"
]
=
tes
.
Tc
state
[
"
tes_%02d
"
%
i
][
"
Rn
"
]
=
tes
.
Rn
state
[
"
tes_%02d
"
%
i
][
"
alpha0
"
]
=
tes
.
alpha0
state
[
"
tes_%02d
"
%
i
][
"
I
"
]
=
tes
.
I
state
[
"
tes_%02d
"
%
i
][
"
T
"
]
=
tes
.
T
state
[
"
Tx
"
]
=
self
.
Tx
state
[
"
Cx
"
]
=
self
.
Cx
state
[
"
Gx
"
]
=
self
.
Gx
state
[
"
betaC
"
]
=
self
.
betaC
state
[
"
betaG
"
]
=
self
.
betaG
state
[
"
num_rows
"
]
=
self
.
num_rows
state
[
"
L
"
]
=
self
.
L
state
[
"
Rsh
"
]
=
self
.
Rsh
state
[
"
Rb
"
]
=
self
.
Rb
state
[
"
Rl
"
]
=
self
.
Rl
state
[
"
Rs
"
]
=
self
.
Rs
state
[
"
Popt
"
]
=
self
.
Popt
state
[
"
center_freq
"
]
=
self
.
center_freq
state
[
"
bandwidth
"
]
=
self
.
bandwidth
state
[
"
Vb
"
]
=
self
.
Vb
state
[
"
Tb
"
]
=
self
.
Tb
state
[
"
R
"
]
=
self
.
R
state
[
"
I
"
]
=
self
.
I
state
[
"
T
"
]
=
self
.
T
if
not
filename
is
None
:
with
open
(
filename
,
'
a
'
)
as
savestate
:
pickle
.
dump
(
state
,
savestate
)
return
state
def
load_state
(
self
,
state
=
None
,
filename
=
None
):
if
filename
is
None
:
assert
(
not
state
is
None
)
else
:
with
open
(
filename
,
'
r
'
)
as
loadstate
:
state
=
pickle
.
load
(
loadstate
)
para
=
{
"
Rs
"
:
0.0
};
TESn
=
[]
for
k
in
state
.
keys
():
if
"
tes
"
in
k
:
TESn
.
append
(
k
)
continue
para
[
k
]
=
state
[
k
]
TESs
=
[]
for
tes
in
TESn
:
TESs
.
append
(
TES
(
**
state
[
tes
]))
para
[
"
TESs
"
]
=
TESs
return
detector
(
**
para
)
def
copy_TESs
(
self
):
TESs_copy
=
[]
for
tes
in
self
.
TESs
:
params
=
{}
params
[
"
Tc
"
]
=
float
(
tes
.
Tc
)
params
[
"
Ic
"
]
=
float
(
tes
.
Ic
)
params
[
"
Rn
"
]
=
float
(
tes
.
Rn
)
params
[
"
I
"
]
=
float
(
tes
.
I
)
params
[
"
T
"
]
=
float
(
tes
.
T
)
params
[
"
name
"
]
=
tes
.
name
params
[
"
alpha0
"
]
=
float
(
tes
.
alpha0
)
TESs_copy
.
append
(
TES
(
**
params
))
return
TESs_copy
def
copy_detector
(
self
):
return
detector
(
TESs
=
self
.
copy_TESs
(),
num_rows
=
self
.
num_rows
,
Tx
=
self
.
Tx
,
Cx
=
self
.
Cx
,
Gx
=
self
.
Gx
,
betaC
=
self
.
betaC
,
betaG
=
self
.
betaG
,
L
=
self
.
L
,
Rsh
=
self
.
Rsh
,
Popt
=
self
.
Popt
,
Rl
=
self
.
Rl
,
Rs
=
self
.
Rs
,
Rb
=
self
.
Rb
,
center_freq
=
self
.
center_freq
,
bandwidth
=
self
.
bandwidth
,
Vb
=
self
.
Vb
,
Tb
=
self
.
Tb
,
R
=
self
.
R
,
I
=
self
.
I
,
T
=
self
.
T
)
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment