API
 
Loading...
Searching...
No Matches
utils.py
Go to the documentation of this file.
1import numpy as np
2import hcipy as hp
3import scipy
4from scipy.optimize import minimize
5from astropy.io import fits
6import time
7
8# TODO: should I throw this in utils?
10 #Is this bad form? they won't change
11 D = 6.5 # m
12 px_scale = 2.2 # mas / px
13 wavelength = 800e-9 # m
14 conv_rad_to_mas = 206264806 # rad / mas
15 """ This class holds the variable necessary to establish a fit to a camtip image """
16 def __init__(self, w_in=2, w_out=20, mod_r=3.0):
17 self.mod_r = mod_r
18 self.mod_r_px = self.calc_R_to_px(mod_r)
19 self.lab_fit = None # could use to compare against above value
20 self.data = None
21 self.data_bg_sub = None
22 self.data_fit = None
23 self.w_in = w_in
24 self.w_out = w_out
25 # I hardcode size before passing in data
26 self.size = 128
27 self.grid = hp.make_uniform_grid((self.size, self.size), (self.size,self.size)) # used in fitting
28
29 def calc_R_to_px(self, R):
30 # if god was kind, this would give the radius we expect
31 # except life is cruel, and pixel scales are sketchy, so this is not 100%
32 rads_to_mas = self.D / self.wavelength * self.conv_rad_to_mas
33 return R * rads_to_mas / self.px_scale
34
35 def set_data(self, data):
36 ''' data - frame from the camera
37 Subtracts first 100 pixels from the data...'''
38 self.data = data
39 self.data_bg_sub = sub_bg_img(data)
40
41 def clear(self):
42 self.data = None
43
44 def setup_lab(self, lab_dir, file):
45 self.lab_dir = lab_dir
46 self.lab_file = file
47 self.set_lab_data(lab_dir, file)
48 self.fit_lab(self.lab_data)
49 self.gen_fit_img()
50 self.set_lab_EE()
51 return
52
53 def set_lab_data(self, lab_dir, file):
54 #TODO: logic to choose the lab directory
55 lab_file_path = lab_dir + file
56 lab_avg = fits.open(lab_file_path)[0].data
57 #TODO: logic to choose lab flat
58 self.lab_data = lab_avg
59 return
60
61 def fit_lab(self, lab_data):
62 theta_opt = lab_fit_params(lab_data, self.grid)
63 self.set_lab(theta_opt['x'])
64 return
65
66 def set_lab(self, lab_fit):
67 '''Take a lab fit to compare for with SR'''
68 self.lab_fit = lab_fit # ideally would have radius
69 self.lab_sig = lab_fit[0]
70 self.lab_rad = lab_fit[1]
71 self.lab_amp = lab_fit[2]
72 return
73
74 def gen_fit_img(self):
75 #create an image of the optimal fit, but centered
76 ft = self.lab_fit
77 opt_fit = [ft[0], ft[1], ft[2], 0, 0]
78 # this optimum lab image can be used
79 self.lab_fit_img = make_rad_gaus_model(opt_fit, self.grid)
80 return
81
82 def set_lab_EE(self):
83 x0, y0 = self.lab_fit[3], self.lab_fit[4]
84 data = self.lab_data
85 self.lab_EE = calc_EE(data, x0, y0, self.grid, self.lab_rad, w_in=self.w_in, w_out = self.w_out)
86 return
87
88 def fit_data(self):
89 # partial fit
90 data_fit = fit_img_gauss(self.data_bg_sub, self.lab_rad, self.grid)
91 self.data_fit = data_fit
92 return
93
94 def calc_SR(self):
95 """
96 Calculate the SR, requires lab fits and sky fits
97 """
98 lab_sigma = self.lab_sig
99 sky_sigma = self.data_fit[0]
100 self.SR = lab_sigma / sky_sigma
101
102 # check quality of this fit, if invalid, not going to list.
103 # if self.SR > 1 or self.SR < 0:
104 # self.SR = 0
105
106 return self.SR
107
108 def calc_SR_dumb(self, m=64):
109 img = self.data_bg_sub
110 avg_max = np.average([np.max(img[m,:m]), np.max(img[m,m:]), np.max(img[:m,m]), np.max(img[m:,m])])
111 normed_peak = avg_max / np.sum(img)
112 self.SR_dumb = normed_peak
113 return normed_peak
114
115 def calc_SR_EE(self):
116 img = self.data_bg_sub
117 # use the lab image to determine shift
118 y0, x0 = calc_idx_shift(img, self.lab_fit_img, self.size)
119 self.y0 = y0
120 self.x0 = x0
121 # send shift into the calc SR EE image
122 self.sky_EE = calc_EE(img, x0, y0, self.grid, self.lab_rad, w_in=self.w_in, w_out=self.w_out)
123 # divide by the saved lab EE value
124 self.SR_EE = self.sky_EE / self.lab_EE
125
126 return self.SR_EE
127
128####### Helper funcitons ########
129
130def calc_idx_shift(data, kernel, width):
131 data_fft = np.fft.fft2(data)
132 kernel_fft = np.fft.fft2(kernel.shaped)
133 data_corr = np.fft.ifft2(data_fft*np.conj(kernel_fft))
134 idx_shift_raw = np.array(np.unravel_index(np.argmax(data_corr), data_corr.shape))
135 idx_shift = ((idx_shift_raw + width//2) % width) - width//2
136 return idx_shift
137
138def calc_idx_shift_stack(data_stack, kernel, width):
139 # fft kernel
140 kernel_fft = np.fft.fft2(kernel)
141 # fft the cube:
142 data_fft_stack = np.fft.fftn(data_stack, axes=(1,2))
143 data_corr_fft = data_fft_stack * kernel_fft[np.newaxis, :, :]
144 data_corr = np.fft.ifftn(data_corr_fft, axes=(1,2))
145 # unwravel the returned indexes
146 idx_shift_raw = np.array([np.unravel_index(np.argmax(data_corr[i]), data_corr[i].shape) for i in range(data_corr.shape[0])])
147 # accounts for negative shifts
148 idx_shift = ((idx_shift_raw + width//2) % width) - width//2
149 return np.array(idx_shift)
150
151def calc_EE(data, x0, y0, grid, rad, w_in=2, w_out=18):
152 R_mask_lab = make_R_filter(x0, y0, grid, rad, w=w_in)
153 R_mask_norm = make_R_filter(x0, y0, grid, rad, w=w_out)
154 R_EE = np.sum(data*R_mask_lab.shaped) / np.sum(data*R_mask_norm.shaped)
155 return R_EE
156
157def make_R_filter(x0, y0, grid, rad, w=2):
158 R = grid.shifted([-x0, -y0]).as_("polar").r
159 R_mask = hp.Field(np.where((R>rad-w) & (R<rad+w), 1, 0), grid)
160 return R_mask
161
162# specifically for smaller images
163def sub_bg_img(img):
164 bg_mask = np.zeros_like(img)
165 bg_mask[:, 0:5] = 1
166 bg_mask[:,-5:] = 1
167 # average ans subtract out background
168 bg_column = np.sum(img * bg_mask, axis=1, keepdims=True) / 10
169 # subtract of the bg:
170 return img - bg_column
171
172# "LAB" fits are full, radius also uknown
173
174def make_fit_func(img, grid):
175 """
176 Returns a fitting function
177 Based on the Gaussian rotation.
178 """
179 def fitting_func(theta):
180 # creating the model
181 rad_gaus = make_rad_gaus_model(theta, grid)
182 # returning the cost function of the difference of our model vs the guess
183 return np.sum((img.ravel() - rad_gaus)**2)
184 return fitting_func
185
186def make_rad_gaus_model(theta, grid):
187 # theta is a 1D array of parameters
188 sig = theta[0] #5
189 mod_rad = theta[1] #32.5
190 amp = theta[2] #1
191 x0 = theta[3] #0
192 y0 = theta[4] #1
193 # Create the shifted grid
194 R = grid.shifted([-x0, -y0]).as_("polar").r
195 # creating the
196 rad_gaus = hp.Field(amp*np.exp(-(R.ravel()-mod_rad)**2/sig**2), grid)
197 return rad_gaus
198
199def lab_fit_params(data, grid):
200 """
201 Lab fits radius in addition to sig, amp, x0, y0
202 """
203 # initial guess
204 theta0 = [5, 32, 1, 0, 0]
205 # seeding the funciton with lab image
206 rad_gaus_fn = make_fit_func(data, grid)
207 # optimizing the fit
208 theta_opt = scipy.optimize.minimize(rad_gaus_fn, theta0)
209 #creating an image from an optimized fit
210 return theta_opt
211
212# "SKY" fits are partial, radius is known
213
214def make_fit_func_sky(img, mod_rad, grid):
215 """ Sky fits use precalculated mod_radius"""
216 def fitting_func(phi):
217 # creating the model
218 rad_gaus = make_rad_gaus_model_sky(phi, mod_rad, grid)
219 # returning the cost function of the difference of our model vs the guess
220 # COST FUNCTION IS L2 NORM
221 return np.sum((img.ravel() - rad_gaus)**2)
222 return fitting_func
223
224def make_rad_gaus_model_sky(theta, mod_rad, grid):
225 # theta is a 1D array of parameters
226 sig = theta[0] #5
227 amp = theta[1]
228 x0 = theta[2]
229 y0 = theta[3]
230 # Create the shifted grid
231 R = grid.shifted([-x0, -y0]).as_("polar").r
232 # creating the
233 rad_gaus = hp.Field(amp*np.exp(-(R.ravel()-mod_rad)**2/sig**2), grid)
234 return rad_gaus
235
236def fit_img_gauss(img, lab_R, grid):
237 # sig, amp, x, y
238 img_sub = sub_bg_img(img)
239 # avoiding hotpixels
240 max_pix = np.quantile(img_sub, 0.98)
241 # INITIAL GUESS
242 phi0 = [5, max_pix, 0, 0]
243 # create the sky fitting function
244 rad_gaus_fn = make_fit_func_sky(img_sub, lab_R, grid)
245 # optimize parametets
246 theta_opt = scipy.optimize.minimize(rad_gaus_fn, phi0)
247 # just taking parameters, could also take jacobian later
248 return theta_opt['x']
setup_lab(self, lab_dir, file)
Definition utils.py:44
fit_lab(self, lab_data)
Definition utils.py:61
set_lab_data(self, lab_dir, file)
Definition utils.py:53
__init__(self, w_in=2, w_out=20, mod_r=3.0)
Definition utils.py:16
set_lab(self, lab_fit)
Definition utils.py:66
lab_fit_params(data, grid)
Definition utils.py:199
sub_bg_img(img)
Definition utils.py:163