42 from typing
import List
45 """ WFS handler for compass simulation
48 sources : (List) : List of SutraSource instances used for raytracing
50 _wfs : (sutraWrap.Wfs) : SutraSensors instance
52 _context : (carmaContext) : CarmaContext instance
54 _config : (config module) : Parameters configuration structure module
56 def __init__(self, context, config, tel):
57 """ Initialize a wfsCompass component for wfs related supervision
60 context : (carmaContext) : CarmaContext instance
62 config : (config module) : Parameters configuration structure module
64 tel : (TelescopeCompass) : A TelescopeCompass instance
75 """ Get an image from the WFS (wfs[0] by default), or from the centroider handling the WFS
76 to get the calibrated image
79 wfs_index : (int) : index of the WFS (or the centroider) to request an image
82 image : (np.ndarray) : WFS image
84 if self.
_config_config.p_wfss[wfs_index].fakecam:
85 return np.array(self.
_wfs_wfs.d_wfs[wfs_index].d_camimg)
87 return np.array(self.
_wfs_wfs.d_wfs[wfs_index].d_binimg)
90 """ Set an image in the WFS (wfs[0] by default)
92 wfs_index : (int) : index of the WFS (or the centroider) to request an image
93 img: (np.ndarray) : Image to set
95 self.
_wfs_wfs.d_wfs[wfs_index].set_binimg(img, img.size)
98 *, weights: np.ndarray =
None) ->
None:
99 """ Set pyramid modulation positions
102 wfs_index : (int) : WFS index
104 cx : (np.ndarray) : X positions of the modulation points [arcsec]
106 cy : (np.ndarray) : Y positions of the modulation points [arcsec]
109 weights : (np.ndarray) : Weights to apply on each modulation point contribution
112 pwfs = self.
_config_config.p_wfss[wfs_index]
113 pwfs.set_pyr_npts(pyr_npts)
120 cx, cy, weights, pyr_npts)
123 """ Set pyramid circular modulation amplitude value - in lambda/D units.
125 Compute new modulation points corresponding to the new amplitude value
127 WARNING : if you are using slopes-based centroider with the PWFS,
128 also update the centroider scale (rtc.set_scale) with the returned
132 wfs_index : (int) : WFS index
134 pyr_mod : (float) : new pyramid modulation amplitude value
137 scale : (float) : scale factor
139 p_wfs = self.
_config_config.p_wfss[wfs_index]
141 cx, cy, scale, pyr_npts = wfs_util.comp_new_pyr_ampl(wfs_index, pyr_mod,
144 p_wfs.set_pyr_ampl(pyr_mod)
147 if (len(p_wfs._halfxy.shape) == 2):
148 print(
"PYR modulation set to: %f L/D using %d points" % (pyr_mod, pyr_npts))
149 elif (len(p_wfs._halfxy.shape) == 3):
150 newhalfxy = np.tile(p_wfs._halfxy[0, :, :], (pyr_npts, 1, 1))
151 print(
"Loading new modulation arrays")
152 self.
_wfs_wfs.d_wfs[wfs_index].set_phalfxy(
153 np.exp(1j * newhalfxy).astype(np.complex64).T)
154 print(
"Done. PYR modulation set to: %f L/D using %d points" % (pyr_mod,
157 raise ValueError(
"Error unknown p_wfs._halfxy shape")
162 *, weights: List =
None, pyr_mod: float = 3.,
163 niters: int =
None) ->
None:
164 """ Sets the Pyramid modulation points with a multiple star system
167 wfs_index : (int) : WFS index
169 coords : (list) : list of couples of length n, coordinates of the n stars in lambda/D
172 weights : (list) : list of weights to apply on each modulation points. Default is None
174 pyr_mod : (float): modulation amplitude of the pyramid in lambda/D. Default is 3
176 niters : (int) : number of iteration. Default is None
179 perim = pyr_mod * 2 * np.pi
180 niters = int((perim // 4 + 1) * 4)
182 scale_circ = self.
_config_config.p_wfss[wfs_index]._pyr_scale_pos * pyr_mod
186 temp_cx.append(scale_circ * \
187 np.sin((np.arange(niters)) * 2. * np.pi / niters) + \
188 k[0] * self.
_config_config.p_wfss[wfs_index]._pyr_scale_pos)
189 temp_cy.append(scale_circ * \
190 np.cos((np.arange(niters)) * 2. * np.pi / niters) + \
191 k[1] * self.
_config_config.p_wfss[wfs_index]._pyr_scale_pos)
192 cx = np.concatenate(np.array(temp_cx))
193 cy = np.concatenate(np.array(temp_cy))
195 if weights
is not None:
199 weights = np.array(w)
203 """ Create disk object by packing PSF in a given radius, using hexagonal packing
204 and set it as modulation pattern
206 There is no modulation
209 wfs_index : (int) : WFS index
211 radius : (float) : radius of the disk object in lambda/D
214 gen_xp, gen_yp = np.array([1,
215 0.]), np.array([np.cos(np.pi / 3),
217 n = 1 + int(1.2 * radius)
219 for k
in range(-n, n):
220 for l
in range(-n, n):
221 coord = k * gen_xp + l * gen_yp
222 if np.sqrt(coord[0]**2 + coord[1]**2) <= radius:
223 mat_circ.append(coord)
224 mat_circ = np.array(mat_circ)
225 cx, cy = mat_circ[:, 0], mat_circ[:, 1]
229 def set_pyr_disk_source(self, wfs_index: int, radius: float, *, density: float = 1.) ->
None:
230 """ Create disk object by packing PSF in a given radius, using square packing
231 and set it as modulation pattern
233 There is no modulation
236 wfs_index : (int) : WFS index
238 radius : (float) : radius of the disk object in lambda/D
241 density : (float) : Spacing between the packed PSF in the disk object, in lambda/D.
244 cx, cy = util.generate_circle(radius, density)
245 cx = cx.flatten() * self.
_config_config.p_wfss[wfs_index]._pyr_scale_pos
246 cy = cy.flatten() * self.
_config_config.p_wfss[wfs_index]._pyr_scale_pos
250 """ Create a square object by packing PSF in a given radius, using square packing
251 and set it as modulation pattern
253 There is no modulation
256 wfs_index : (int) : WFS index
258 radius : (float) : radius of the disk object in lambda/D
261 density : (float) : Spacing between the packed PSF in the disk object, in lambda/D.
264 cx, cy = util.generate_square(radius, density)
265 cx = cx.flatten() * self.
_config_config.p_wfss[wfs_index]._pyr_scale_pos
266 cy = cy.flatten() * self.
_config_config.p_wfss[wfs_index]._pyr_scale_pos
271 additional_psf: int = 0, density: float = 1.) ->
None:
272 """ TODO : DESCRIPTION
275 wfs_index : (int) : WFS index
277 radius : (float) : TODO : DESCRIPTION
280 additional_psf : (int) : TODO : DESCRIPTION
282 density : (float) :TODO : DESCRIPTION
284 cx, cy, weights, _, _ = util.generate_pseudo_source(radius, additional_psf,
286 cx = cx.flatten() * self.
_config_config.p_wfss[wfs_index]._pyr_scale_pos
287 cy = cy.flatten() * self.
_config_config.p_wfss[wfs_index]._pyr_scale_pos
291 """ Set a mask in the Fourier Plane of the given WFS
294 wfs_index : (int) : WFS index
296 new_mask : (ndarray) : mask to set
298 if new_mask.shape != self.
_config_config.p_wfss[wfs_index].get_halfxy().shape:
299 print(
'Error : mask shape should be {}'.format(
300 self.
_config_config.p_wfss[wfs_index].get_halfxy().shape))
302 self.
_wfs_wfs.d_wfs[wfs_index].set_phalfxy(
303 np.exp(1j * np.fft.fftshift(new_mask)).astype(np.complex64).T)
305 def set_noise(self, wfs_index : int, noise: float, *, seed: int = 1234) ->
None:
306 """ Set noise value of WFS wfs_index
309 wfs_index : (int) : WFS index
311 noise : (float) : readout noise value in e-
314 seed : (int) : RNG seed. The seed used will be computed as seed + wfs_index
317 self.
_wfs_wfs.d_wfs[wfs_index].
set_noise(noise, int(seed + wfs_index))
318 print(
"Noise set to: %f on WFS %d" % (noise, wfs_index))
320 def set_gs_mag(self, wfs_index : int, mag : float) ->
None:
321 """ Change the guide star magnitude for the given WFS
324 wfs_index : (int) : WFS index
326 mag : (float) : New magnitude of the guide star
328 wfs = self.
_wfs_wfs.d_wfs[wfs_index]
329 if (self.
_config_config.p_wfss[0].type ==
"pyrhr"):
330 r = wfs.comp_nphot(self.
_config_config.p_loop.ittime,
331 self.
_config_config.p_wfss[wfs_index].optthroughput,
333 self.
_config_config.p_wfss[wfs_index].zerop, mag)
335 r = wfs.comp_nphot(self.
_config_config.p_loop.ittime,
336 self.
_config_config.p_wfss[wfs_index].optthroughput,
337 self.
_config_config.p_tel.diam, self.
_config_config.p_wfss[wfs_index].nxsub,
338 self.
_config_config.p_wfss[wfs_index].zerop, mag)
340 print(
"GS magnitude is now %f on WFS %d" % (mag, wfs_index))
341 self.
_config_config.p_wfss[wfs_index].set_gsmag(mag)
342 self.
_config_config.p_wfss[wfs_index]._nphotons = wfs.nphot
345 """ Computes the image produced by the WFS from its phase screen
348 wfs_index : (int): WFS index
351 noise : (bool) : Flag to enable noise for image computation. Default is True
353 self.
_wfs_wfs.d_wfs[wfs_index].comp_image(noise)
356 """ Reset all the WFS RNG to their original state
358 for wfs_index, p_wfs
in enumerate(self.
_config_config.p_wfss):
359 self.
_wfs_wfs.d_wfs[wfs_index].
set_noise(p_wfs.noise, 1234 + wfs_index)
362 """ Reset the WFS image
365 wfs_index : (int): WFS index. If not provided, will reset all WFS
367 if wfs_index
is not None:
368 self.
_wfs_wfs.d_wfs[wfs_index].d_binimg.reset()
371 for _,swfs
in enumerate(self.
_wfs_wfs.d_wfs):
372 swfs.d_binimg.reset()
375 """ Return the current NCPA phase screen of the WFS path
378 wfs_index : (int) : Index of the WFS
381 ncpa : (np.ndarray) : NCPA phase screen
383 return np.array(self.
_wfs_wfs.d_wfs[wfs_index].d_gs.d_ncpa_phase)
386 """ Return the WFS phase screen of WFS number wfs_index
389 wfs_index : (int) : Index of the WFS
392 phase : (np.ndarray) : WFS phase screen
394 return np.array(self.
_wfs_wfs.d_wfs[wfs_index].d_gs.d_phase)
397 """ Get an high resolution image from the PWFS
400 wfs_index : (int) : Index of the WFS
403 image : (np.ndarray) : PWFS high resolution image
406 return np.array(self.
_wfs_wfs.d_wfs[wfs_index].d_hrimg)
408 def set_ncpa_wfs(self, wfs_index : int, ncpa: np.ndarray) ->
None:
409 """ Set the additional fixed NCPA phase in the WFS path.
410 ncpa must be of the same size of the mpupil support
413 wfs_index : (int) : WFS index
415 ncpa : (ndarray) : NCPA phase screen to set [µm]
417 self.
_wfs_wfs.d_wfs[wfs_index].d_gs.set_ncpa(ncpa)
419 def set_wfs_phase(self, wfs_index : int, phase : np.ndarray) ->
None:
420 """ Set the phase screen seen by the WFS
423 wfs_index : (int) : WFS index
425 phase : (np.ndarray) : phase screen to set
427 self.
_wfs_wfs.d_wfs[wfs_index].d_gs.set_phase(phase)
429 def set_wfs_pupil(self, wfs_index : int, pupil : np.ndarray) ->
None:
430 """ Set the pupil seen by the WFS
431 Other pupils remain unchanged, i.e. DM and target can see an other
432 pupil than the WFS after this call.
433 <pupil> must have the same shape than p_geom._mpupil support
436 wfs_index : (int) : WFS index
438 pupil : (np.ndarray) : new pupil to set
440 old_mpup = self.
_config_config.p_geom._mpupil
441 dimx = old_mpup.shape[0]
442 dimy = old_mpup.shape[1]
443 if ((pupil.shape[0] != dimx)
or (pupil.shape[1] != dimy)):
444 print(
"Error pupil shape on wfs %d must be: (%d,%d)" % (wfs_index, dimx,
447 self.
_wfs_wfs.d_wfs[wfs_index].set_pupil(pupil.copy())
450 """ Returns the psf on the top of the pyramid.
454 wfs_index : (int) : WFS index
457 focal_plane : (np.ndarray) : psf on the top of the pyramid
459 return np.fft.fftshift(np.array(self.
_wfs_wfs.d_wfs[wfs_index].d_pyrfocalplane))
Source handler for compass simulation.
sources
(List) : List of SutraSource instances
WFS handler for compass simulation.
def __init__(self, context, config, tel)
np.ndarray get_wfs_phase(self, int wfs_index)
Return the WFS phase screen of WFS number wfs_index.
None reset_noise(self)
Reset all the WFS RNG to their original state.
np.ndarray get_pyr_focal_plane(self, int wfs_index)
Returns the psf on the top of the pyramid.
None set_pyr_modulation_points(self, int wfs_index, np.ndarray cx, np.ndarray cy, *np.ndarray weights=None)
Set pyramid modulation positions.
float set_pyr_modulation_ampli(self, int wfs_index, float pyr_mod)
Set pyramid circular modulation amplitude value - in lambda/D units.
def set_wfs_image(self, int wfs_index, np.ndarray img)
Set an image in the WFS (wfs[0] by default)
sources
(List) : List of SutraSource instances used for raytracing
None set_pyr_square_source(self, int wfs_index, float radius, *float density=1.)
Create a square object by packing PSF in a given radius, using square packing and set it as modulatio...
None set_pyr_multiple_stars_source(self, int wfs_index, List coords, *List weights=None, float pyr_mod=3., int niters=None)
Sets the Pyramid modulation points with a multiple star system.
np.ndarray get_wfs_image(self, int wfs_index)
Get an image from the WFS (wfs[0] by default), or from the centroider handling the WFS to get the cal...
np.ndarray get_pyrhr_image(self, int wfs_index)
Get an high resolution image from the PWFS.
None set_pyr_disk_source_hexa(self, int wfs_index, float radius)
Create disk object by packing PSF in a given radius, using hexagonal packing and set it as modulation...
None set_wfs_phase(self, int wfs_index, np.ndarray phase)
Set the phase screen seen by the WFS.
None set_wfs_pupil(self, int wfs_index, np.ndarray pupil)
Set the pupil seen by the WFS Other pupils remain unchanged, i.e.
None set_gs_mag(self, int wfs_index, float mag)
Change the guide star magnitude for the given WFS.
None compute_wfs_image(self, int wfs_index, *bool noise=True)
Computes the image produced by the WFS from its phase screen.
None set_pyr_disk_source(self, int wfs_index, float radius, *float density=1.)
Create disk object by packing PSF in a given radius, using square packing and set it as modulation pa...
None set_noise(self, int wfs_index, float noise, *int seed=1234)
Set noise value of WFS wfs_index.
None set_fourier_mask(self, int wfs_index, np.ndarray new_mask)
Set a mask in the Fourier Plane of the given WFS.
None set_pyr_pseudo_source(self, int wfs_index, float radius, *int additional_psf=0, float density=1.)
TODO DESCRIPTION.
def reset_image(self, *int wfs_index=None)
Reset the WFS image.
None set_ncpa_wfs(self, int wfs_index, np.ndarray ncpa)
Set the additional fixed NCPA phase in the WFS path.
np.ndarray get_ncpa_wfs(self, int wfs_index)
Return the current NCPA phase screen of the WFS path.
On the fly modification of the WFS.
Initialization of a Sensors object.
Basic utilities function.