-
Notifications
You must be signed in to change notification settings - Fork 9
/
tools.py
234 lines (197 loc) · 6 KB
/
tools.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#!/usr/bin/env python
#-----------------------------------------------------------------------------
# Title : pysmurf util tools
#-----------------------------------------------------------------------------
# File : pysmurf/util/tools.py
# Created : 2018-08-29
#-----------------------------------------------------------------------------
# This file is part of the pysmurf software package. It is subject to
# the license terms in the LICENSE.txt file found in the top-level directory
# of this distribution and at:
# https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.
# No part of the pysmurf software package, including this file, may be
# copied, modified, propagated, or distributed except according to the terms
# contained in the LICENSE.txt file.
#-----------------------------------------------------------------------------
import numpy as np
from scipy.optimize import curve_fit
def skewed_lorentzian(x, bkg, bkg_slp, skw, mintrans, res_f, Q):
""" Skewed Lorentzian model.
Parameters
----------
x : float
The x-data to build the skewed Lorentzian
bkg : float
The DC value of the skewed Lorentzian
bkg_slp : float
The slope of the skewed Lorentzian
skw : float
The skewness of the Lorentzian
mintrans : float
The minimum of the trans. This is associated with the skewness term.
res_f : float
The center frequency of the resonator (the center of the Lorentzian)
Q : float
The Q of the resonator
Returns
-------
float
The model of the Lorentzian
"""
return bkg + bkg_slp*(x-res_f)-(mintrans+skw*(x-res_f))/\
(1+4*Q**2*((x-res_f)/res_f)**2)
def fit_skewed_lorentzian(f, mag):
""" Fits frequency and magnitude data with a skewed lorentzian.
Args
----
f : float array
The frequency array
mag : float array
The resonator response array
Returns
-------
fit_params : float array
The fit parameters
"""
# define the initial values
bkg = (mag[0]+mag[-1])/2
bkg_slp = (mag[-1]-mag[0])/(f[-1]-f[0])
skw = 0
mintrans = bkg-mag.min()
res_f = f[mag.argmin()]
Q = 1e4
low_bounds = [bkg/2, -1e-3, -1, 0, f[0], 1e2]
up_bounds = [bkg*2, 1e-3, 1, 30, f[-1], 1e5]
try:
popt, pcov = curve_fit(skewed_lorentzian, f, mag,
p0=[bkg, bkg_slp, skw,mintrans, res_f, Q], method='lm')
if popt[5] < 0:
popt, pcov = curve_fit(skewed_lorentzian, f, mag,
p0=[bkg, bkg_slp, skw, mintrans, res_f, Q],
bounds=(low_bounds, up_bounds))
except RuntimeError:
popt = np.zeros((6,))
except ValueError:
popt = np.zeros((6,))
return popt
def limit_phase_deg(phase, minphase=-180):
""" Limits the phase in degrees
Brazenly stolen from
https://stackoverflow.com/questions/2320986/easy-way-to-keeping-angles-between-179-and-180-degrees
Args
----
phase : float
The input phase
minphase : float
The minimum phase
Returns
-------
phase_limited : float
The phase information with the limited phase
"""
phase_limited = np.copy(phase)
while phase_limited <= minphase:
phase_limited += 360
while phase_limited > minphase + 360:
phase_limited -= 360
return phase_limited
def P_singleMode(f_center, bw, T):
'''
Optical power in a single mode in a bandwidth bw centered on frequency
f_center from an optical load of temperature T. SI units.
Args
----
f_center : float
The center frequency
bw : float
The bandwidth in SI units
T : float
The temperature
Returns
-------
float
The optical power
'''
h = 6.63e-34
kB = 1.38e-23
df = bw/1000.
f_array = np.arange(f_center-bw/2., f_center+bw/2.+df, df)
P = 0.
# Integrate over frequency bandwidth
for i in range(len(f_array)):
f = f_array[i]
P += df*h*f/(np.exp(h*f/(kB*T))-1.)
return P
def dPdT_singleMode(f_center, bw, T):
'''
Change in optical power per change in temperature (dP/dT) in a single mode
in a bandwidth bw centered on frequency f_center from an optical load of
temperature T. SI units.
'''
dT = T/1e6
dP = P_singleMode(f_center, bw, T+dT) - P_singleMode(f_center, bw, T)
return dP/dT
def load_yaml(filename):
""" Load the yml yaml file
Args
----
filename : str
Full path to the yaml file
Returns
-------
yaml_file_object
The yaml file
"""
import yaml
with open(filename, 'r') as stream:
dat = yaml.safe_load(stream)
return dat
def yaml_parse(yml, cmd):
""" Gets the values out of the yaml file
Args
----
yml : yaml_file
The input yaml file, loaded with load_yaml
cmd : str
The full epics path in the yaml file
Returns
-------
val
The value associated with the requested cmd
"""
cmd = cmd.split(':')[1:] # First is epics root. Throw out
def get_val(yml, c):
""" Extracts the values.
This is a convenience function that calls itself recursively.
Args
----
yml : yaml_file
The input yaml_file
c : str
The epics path
Returns
-------
val
The value associated with input param c
"""
if np.size(c) == 1 and c[0] in yml.keys():
return yml[c[0]]
elif np.size(c) > 1 and c[0] in yml.keys():
return get_val(yml[c[0]], c[1:])
return np.nan
return get_val(yml, cmd)
def utf8_to_str(d):
"""
Many of the rogue variables are returned as UTF8 formatted byte
arrays by default. This function changes them from UTF8 to a
string
Args
----
d : int array
An integer array with each element equal to a character.
Returns
-------
str
The string associated with input d.
"""
return ''.join([str(s, encoding='UTF-8') for s in d])