43 """ RTC handler for compass simulation
46 rtc : (sutraWrap.Rtc) : Sutra rtc instance
48 context : (carmaContext) : CarmaContext instance
50 config : (config module) : Parameters configuration structure module
52 cacao : (bool) : CACAO features enabled in the RTC
54 def __init__(self, context, config, tel, wfs, dms, atm, *, cacao=False):
55 """ Initialize a RtcCompass component for rtc related supervision
58 context : (carmaContext) : CarmaContext instance
60 config : (config module) : Parameters configuration structure module
62 tel : (TelescopeCompass) : A TelescopeCompass instance
64 wfs : (WfsCompass) : A WfsCompass instance
66 dms : (DmCompass) : A DmCompass instance
68 atm : (AtmosCompass) : An AtmosCompass instance
70 cacao : (bool, optional) : If True, enables CACAO features in RTC (Default is False)
71 /!\ Requires OCTOPUS to be installed
77 self.
rtc = rtc_init(self.
context, tel.tel, wfs.wfs, dms.dms, atm.atmos,
81 self.
config.p_dms, cacao=cacao)
84 command: np.ndarray) ->
None:
85 """ Add circular buffer of offset values to integrator (will be applied at the end of next iteration)
88 controller_index : (int) : Controller index
90 name : (str) : Buffer name
92 command : (np.ndarray) : perturbation voltage circular buffer
94 if len(command.shape) == 1:
95 self.
rtc.d_control[controller_index].set_perturb_voltage(name, command, 1)
96 elif len(command.shape) == 2:
97 self.
rtc.d_control[controller_index].set_perturb_voltage(
98 name, command, command.shape[0])
100 raise AttributeError(
"command should be a 1D or 2D array")
102 def get_slopes(self, controller_index: int) -> np.ndarray:
103 """ Return the current slopes vector of the controller_index controller
106 controller_index : (int) : controller index handling the slopes
109 slopes : (np.ndarray) : Current slopes vector containing slopes of all
110 the WFS handled by the specified controller
112 return np.array(self.
rtc.d_control[controller_index].d_centroids)
114 def close_loop(self, controller_index: int=
None) ->
None:
115 """ DM receives controller output + pertuVoltage
118 controller_index: (int, optional): controller index.
119 If None (default), apply on all controllers
121 if controller_index
is None:
122 for controller
in self.
rtc.d_control:
123 controller.set_open_loop(0)
125 self.
rtc.d_control[controller_index].set_open_loop(0)
127 def open_loop(self, controller_index: int=
None, reset=
True) ->
None:
128 """ Integrator computation goes to /dev/null but pertuVoltage still applied
131 controller_index: (int): controller index.
132 If None (default), apply on all controllers
134 reset : (bool, optional) : If True (default), integrator is reset
136 if controller_index
is None:
137 for controller
in self.
rtc.d_control:
138 controller.set_open_loop(1, reset)
140 self.
rtc.d_control[controller_index].set_open_loop(1, reset)
142 def set_ref_slopes(self, ref_slopes: np.ndarray, *, centro_index=
None) ->
None:
143 """ Set given ref slopes in centroider
146 ref_slopes : (ndarray) : Reference slopes vectoronly set the reference slop
148 centro_index : (int, optionnal) : If given, only set the reference slopes vector
149 used by the specified centroider. If None, the reference
150 slopes vector must be a concatenation of all the reference
151 slopes to use for each centroiders handled by the controller
153 if (centro_index
is None):
154 self.
rtc.set_centroids_ref(ref_slopes)
156 self.
rtc.d_centro[centro_index].set_centroids_ref(ref_slopes)
159 """ Get the currently used reference slopes
162 centro_index : (int, optionnal) : If given, only get the reference slopes vector
163 used by the specified centroider. If None, the reference
164 slopes vector returned is a concatenation of all the reference
165 slopes used for by centroiders in the RTC
168 ref_slopes : (np.ndarray) : Reference slopes vector
170 ref_slopes = np.empty(0)
171 if (centro_index
is None):
172 for centro
in self.
rtc.d_centro:
173 ref_slopes = np.append(ref_slopes, np.array(centro.d_centroids_ref))
176 return np.array(self.
rtc.d_centro[centro_index].d_centroids_ref)
178 def set_gain(self, controller_index: int, gain: float) ->
None:
179 """ Set the scalar gain
182 controller_index : (int) : Index of the controller to modify
184 gain : (float) : scalar gain of modal gain to set
186 self.
rtc.d_control[controller_index].
set_gain(gain)
189 """ Return the interaction matrix of the controller
192 controller_index: (int): controller index
195 imat : (np.ndarray) : Interaction matrix currently set in the controller
197 return np.array(self.
rtc.d_control[controller_index].d_imat)
200 """ Return the command matrix of the controller
203 controller_index: (int): controller index
206 cmat : (np.ndarray) : Command matrix currently used by the controller
208 return np.array(self.
rtc.d_control[controller_index].d_cmat)
211 """ Set the command matrix for the controller to use
214 controller_index : (int) : Controller index to modify
216 cmat : (np.ndarray) : command matrix to set
218 self.
rtc.d_control[controller_index].set_cmat(cmat)
221 """ Return sum of intensities in subaps. Size nSubaps, same order as slopes
223 raise NotImplementedError(
"Not implemented")
225 def set_flat(self, centro_index: int, flat: np.ndarray,):
226 """ Load flat field for the given wfs
229 centro_index : (int) : index of the centroider handling the WFS
231 flat : (np.ndarray) : New WFS flat to use
235 def set_dark(self, centro_index: int, dark: np.ndarray):
236 """ Load dark for the given wfs
239 centro_index : (int) : index of the centroider handling the WFS
241 dark : (np.ndarray) : New WFS dark to use
246 """ Compute the slopes handled by a controller, and returns it
249 controller_index : (int) : Controller index that will compute its slopes
252 slopes : (np.ndarray) : Slopes vector
258 """ Reset the perturbation voltage of the controller_index controller
259 (i.e. will remove ALL perturbation voltages.)
260 If you want to reset just one, see the function remove_perturbation_voltage()
263 controller_index : (int) : controller index from where to remove the buffer
265 self.
rtc.d_control[controller_index].reset_perturb_voltage()
268 """ Remove the perturbation voltage called <name>, from the controller number <controller_index>.
269 If you want to remove all of them, see function reset_perturbation_voltage()
272 controller_index : (int) : controller index from where to remove the buffer
274 self.
rtc.d_control[controller_index].remove_perturb_voltage(name)
276 def get_err(self, controller_index: int) -> np.ndarray:
277 """ Get integrator increment from controller_index controller
280 controller_index : (int) : controller index
282 return np.array(self.
rtc.d_control[controller_index].d_err)
285 """ Get voltages vector (i.e. vector sent to the DM) from controller_index controller
288 controller_index : (int) : controller index
291 voltages : (np.ndarray) : current voltages vector
294 return np.array(self.
rtc.d_control[controller_index].d_voltage)
297 """ Set the control law to integrator (controller generic only)
298 v[k] = v[k-1] + g.R.s[k]
301 controller_index: (int): controller index
303 self.
rtc.d_control[controller_index].set_commandlaw(
"integrator")
306 """ Set the control law to 2matrices (controller generic only)
307 v[k] = decayFactor.E.v[k-1] + g.R.s[k]
310 controller_index: (int): controller index
312 self.
rtc.d_control[controller_index].set_commandlaw(
"2matrices")
315 """ Set the control law to 2matrices (controller generic only)
316 v[k] = v[k-1] + E.g.R.s[k]
319 controller_index: (int): controller index
321 self.
rtc.d_control[controller_index].set_commandlaw(
"modal_integrator")
323 def set_decay_factor(self, controller_index: int, decay : np.ndarray) ->
None:
324 """ Set the decay factor used in 2matrices command law (controller generic only)
327 controller_index: (int): controller index
329 decay : (np.ndarray) : decay factor vector
331 self.
rtc.d_control[controller_index].set_decayFactor(decay)
333 def set_E_matrix(self, controller_index: int, e_matrix : np.ndarray) ->
None:
334 """ Set the E matrix used in 2matrices or modal command law (controller generic only)
337 e_matrix : (np.ndarray) : E matrix to set
339 controller_index: (int): controller index
341 self.
rtc.d_control[controller_index].set_matE(e_matrix)
344 """ Reset the reference slopes of each WFS handled by the specified controller
347 controller_index: (int): controller index
349 for centro
in self.
rtc.d_centro:
350 centro.d_centroids_ref.reset()
353 """ Set the threshold value of a thresholded COG
356 centro_index: (int): centroider index
358 thresh: (float): new threshold value
360 self.
rtc.d_centro[centro_index].set_threshold(thresh)
363 """ Get pyramid compute method currently used
366 centro_index: (int): centroider index
369 method : (str) : Pyramid compute method currently used
371 return self.
rtc.d_centro[centro_index].pyr_method
373 def set_pyr_method(self, centro_index: int, pyr_method : int) ->
None:
374 """ Set the pyramid method for slopes computation
377 centro_index : (int) : centroider index
379 pyr_method : (int) : new centroiding method (0: nosinus global
386 print(
"PYR method set to " + self.
rtc.d_centro[centro_index].pyr_method)
389 def set_modal_gains(self, controller_index: int, mgain: np.ndarray) ->
None:
390 """ Sets the modal gain (when using modal integrator control law)
393 controller_index : (int) : Controller index to modify
395 mgain : (np.ndarray) : Modal gains to set
400 """ Returns the modal gains (when using modal integrator control law)
403 controller_index : (int) : Controller index to modify
406 mgain : (np.ndarray) : Modal gains vector currently used
408 return np.array(self.
rtc.d_control[controller_index].d_gain)
411 """ Return the mask of valid pixels used by a maskedpix centroider
414 centro_index : (int): Centroider index. Must be a maskedpix centroider
417 mask : (np.ndarray) : Mask used
419 if (self.
rtc.d_centro[centro_index].type != scons.CentroiderType.MASKEDPIX):
420 raise TypeError(
"Centroider must be a maskedpix one")
422 return np.array(self.
rtc.d_centro[centro_index].d_mask)
424 def get_command(self, controller_index: int) -> np.ndarray:
425 """ Returns the last computed command before conversion to voltages
428 controller_index : (int, optional) : Controller index
431 com : (np.ndarray) : Command vector
433 return np.array(self.
rtc.d_control[controller_index].d_com)
435 def set_command(self, controller_index: int, com : np.ndarray) -> np.ndarray:
436 """ Returns the last computed command before conversion to voltages
439 controller_index : (int, optional) : Controller index
441 com : (np.ndarray) : Command vector to set
443 if(com.size != self.
config.p_controllers[controller_index].nactu):
444 raise ValueError(
"Dimension mismatch")
445 self.
rtc.d_control[controller_index].set_com(com, com.size)
447 def reset_command(self, controller_index: int =
None) ->
None:
448 """ Reset the controller_index Controller command buffer, reset all controllers if controller_index is None
451 controller_index : (int, optional) : Controller index
452 Default is None, i.e. all controllers are reset
454 if (controller_index
is None):
455 for control
in self.
rtc.d_control:
456 control.d_com.reset()
458 self.
rtc.d_control[controller_index].d_com.reset()
461 """ Computes and return the slopes geom from the specified controller
464 controller_index : (int) : controller index
467 slopes_geom : (np.ndarray) : geometrically computed slopes
470 slopes_geom = np.array(self.
rtc.d_control[controller_index].d_centroids)
475 """ Return the pyramid image with only the selected pixels used by the full pixels centroider
478 selected_pix : (np.ndarray) : PWFS image with only selected pixels
480 if (self.
config.p_centroiders[0].type != scons.CentroiderType.MASKEDPIX):
481 raise TypeError(
"Centroider must be maskedPix")
483 carma_centroids = self.
rtc.d_control[0].d_centroids
484 self.
rtc.d_centro[0].fill_selected_pix(carma_centroids)
486 return np.array(self.
rtc.d_centro[0].d_selected_pix)
489 """ Computes and set a new reference slopes for each WFS handled by
490 the specified controller
493 controller_index: (int): controller index
495 print(
"Doing reference slopes...")
496 self.
rtc.do_centroids_ref(controller_index)
497 print(
"Reference slopes done")
499 def do_control(self, controller_index: int, *, sources : SourceCompass =
None, source_index : int = 0, is_wfs_phase : bool =
False) ->
None:
500 """Computes the command from the Wfs slopes
503 controller_index: (int): controller index
505 sources : (SourceCompass, optional) : List of phase screens of a wfs or target sutra object
506 If the controller is a GEO one, specify a SourceCompass instance
507 from WfsCompass or TargetCompass to project the corresponding phase
509 source_index : (int, optional) : Index of the phase screen to consider inside <sources>. Default is 0
511 is_wfs_phase : (bool, optional) : If True, sources[source_index] is a WFS phase screen.
512 Else, it is a Target phase screen (Default)
514 if (self.
rtc.d_control[controller_index].type == scons.ControllerType.GEO):
515 if (sources
is not None):
516 self.
rtc.d_control[controller_index].comp_dphi(sources[source_index],
521 """ Computes the calibrated image from the Wfs image
524 controller_index: (int): controller index
529 """ Computes the centroids from the Wfs image
532 controller_index: (int): controller index
537 """ Computes the centroids geom from the Wfs image
540 controller_index: (int): controller index
544 def apply_control(self, controller_index: int, *, comp_voltage: bool =
True) ->
None:
545 """ Computes the final voltage vector to apply on the DM by taking into account delay and perturbation voltages, and shape the DMs
548 controller_index: (int): controller index
550 comp_voltage: (bool): If True (default), computes the voltage vector from the command one (delay + perturb). Else, directly applies the current voltage vector
554 def do_clipping(self, controller_index: int) ->
None:
555 """ Clip the commands between vmin and vmax values set in the RTC
558 controller_index: (int): controller index
562 def set_scale(self, centroider_index : int, scale : float) ->
None:
563 """ Update the scale factor of the centroider
566 centroider_index : (int) : Index of the centroider to update
568 scale : (float) : scale factor to apply on slopes
573 """ Publish loop data on DDS topics
575 /!\ only with cacao enabled, requires OCTOPUS
578 self.
rtc.rtc.publish()
580 raise AttributeError(
"CACAO must be enabled")