2 ROKET (erROr breaKdown Estimation Tool)
4 Computes the error breakdown during a COMPASS simulation
5 and saves it in a HDF5 file
6 Error contributors are bandwidth, tomography, noise, aliasing,
7 WFS non linearity, filtered modes and fitting
8 Saved file contained temporal buffers of those contributors
22 import matplotlib.pyplot
as pl
26 from scipy.sparse
import csr_matrix
32 Inherits from CompassSupervisor
35 def __init__(self, str=None, N_preloop=1000, gamma=1.):
37 Initializes an instance of Roket class
40 str: (str): (optional) path to a parameter file
41 N_preloop: (int): (optional) number of iterations before starting error breakdown estimation
42 gamma: (float): (optional) centroid gain
50 Initializes the COMPASS simulation and the ROKET buffers
56 self.
nactus = self.get_command(0).size
58 self.
com = np.zeros((self.
n, self.
nactus), dtype=np.float32)
69 self.
fit = np.zeros(self.
n)
75 self.
config.p_loop.set_niter(self.
n)
76 self.
IFpzt = self.get_influ_basis_sparse(1)
77 self.
TT = self.get_tt_influ_basis(1)
79 self.Btt, self.
P = compute_btt(self.
IFpzt.T, self.
TT)
80 tmp = self.Btt.dot(self.Btt.T)
81 self._sim.rtc.d_control[1].load_Btt(tmp[:-2, :-2], tmp[-2:, -2:])
82 compute_cmat_with_Btt(self._sim.rtc, self.Btt, self.
nfiltered)
83 self.
cmat = self.get_command_matrix(0)
84 self.
D = self.get_interaction_matrix(0)
86 self.
gRD = np.identity(
88 shape[0]) - self.
config.p_controllers[0].gain * self.
gamma * self.
RD
92 def next(self, **kwargs):
95 Iterates the AO loop, with optional parameters
97 :param move_atmos (bool): move the atmosphere for this iteration, default: True
98 :param nControl (int): Controller number to use, default 0 (single control configurations)
99 :param tar_trace (None or list[int]): list of targets to trace. None equivalent to all.
100 :param wfs_trace (None or list[int]): list of WFS to trace. None equivalent to all.
101 :param apply_control (bool): (optional) if True (default), apply control on DMs
103 self._sim.
next(apply_control=
False)
105 self._sim.applyControl(0)
108 def loop(self, monitoring_freq=100, **kwargs):
110 Performs the AO loop for n iterations
113 monitoring_freq: (int): (optional) Loop monitoring frequency [frames] in the terminal
115 print(
"-----------------------------------------------------------------")
116 print(
"iter# | SE SR | LE SR | FIT SR | PH SR | ETR (s) | Framerate (Hz)")
117 print(
"-----------------------------------------------------------------")
119 for i
in range(self.
n):
121 if ((i + 1) % monitoring_freq == 0):
122 framerate = (i + 1) / (time.time() - t0)
123 self._sim.comp_tar_image(0)
124 self._sim.compStrehl(0)
125 strehltmp = self.get_strehl(0)
126 etr = (self.
n - i) / framerate
127 print(
"%d \t %.2f \t %.2f\t %.2f \t %.2f \t %.1f \t %.1f" %
128 (i + 1, strehltmp[0], strehltmp[1], np.exp(-strehltmp[2]),
129 np.exp(-strehltmp[3]), etr, framerate))
132 print(
" loop execution time:", t1 - t0,
" (", self.
n,
"iterations), ",
133 (t1 - t0) / self.
n,
"(mean) ", self.
n / (t1 - t0),
"Hz")
136 SRs = self.get_strehl(0)
142 Compute the error breakdown of the AO simulation. Returns the error commands of
143 each contributors. Suppose no delay (for now) and only 2 controllers : the main one, controller #0, (specified on the parameter file)
144 and the geometric one, controller #1 (automatically added if roket is asked in the parameter file)
145 Commands are computed by applying the loop filter on various kind of commands : (see schema_simulation_budget_erreur_v2)
147 - Ageom : Aliasing contribution on WFS direction
148 Obtained by computing commands from DM orthogonal phase (projection + slopes_geom)
150 - B : Projection on the target direction
151 Obtained as the commmands output of the geometric controller
154 Obtained by computing commands from DM parallel phase (RD*B)
156 - E : Wavefront + aliasing + ech/trunc + tomo
157 Obtained by performing the AO loop iteration without noise on the WFS
159 - F : Wavefront + aliasing + tomo
160 Obtained by performing the AO loop iteration without noise on the WFS and using phase deriving slopes
164 Note : rtc.get_err returns to -CMAT.slopes
166 g = self.
config.p_controllers[0].gain
167 Dcom = self.get_command(0)
168 Derr = self.get_err(0)
170 tarphase = self.get_tar_phase(0)
176 if (self.
config.p_wfss[0].type == scons.WFSType.SH):
177 ideal_img = np.array(self._sim.wfs.d_wfs[0].d_binimg_notnoisy)
178 binimg = np.array(self._sim.wfs.d_wfs[0].d_binimg)
179 if (self.
config.p_centroiders[0].type == scons.CentroiderType.TCOG
181 invalidpix = np.where(binimg <= self.
config.p_centroiders[0].thresh)
182 ideal_img[invalidpix] = 0
183 self.set_centroider_threshold(0, -1e16)
184 self._sim.wfs.d_wfs[0].set_binimg(ideal_img, ideal_img.size)
185 elif (self.
config.p_wfss[0].type == scons.centroiderType.PYRHR):
186 ideal_pyrimg = np.array(self._sim.wfs.d_wfs[0].d_binimg_notnoisy)
187 self._sim.wfs.d_wfs[0].set_binimg(ideal_pyrimg, ideal_pyrimg.size)
189 self._sim.doCentroids(0)
190 if (self.
config.p_centroiders[0].type == scons.CentroiderType.TCOG):
191 self.set_centroider_threshold(0, config.p_centroiders[0].thresh)
193 self._sim.do_control(0)
195 E_meas = self.get_slopes(0)
203 self._sim.doCentroidsGeom(0)
204 self._sim.do_control(0)
206 F_meas = self.get_slopes(0)
217 self._sim.do_control(1, 0, wfs_direction=
True)
218 self._sim.applyControl(1)
219 for w
in range(len(self.
config.p_wfss)):
220 self._sim.raytrace_wfs(w,
"dm", rst=
False)
222 wfs.sensors_compimg(0)
223 if(config.p_wfss[0].type == scons.WFSType.SH):
224 ideal_img = wfs.get_binimgNotNoisy(0)
225 binimg = wfs.get_binimg(0)
226 if(config.p_centroiders[0].type == scons.CentroiderType.TCOG): # Select the same pixels with or without noise
227 invalidpix = np.where(binimg <= config.p_centroiders[0].thresh)
228 ideal_img[self.iter_numbernvalidpix] = 0
229 rtc.setthresh(0,-1e16)
230 wfs.set_binimg(0,ideal_img)
231 elif(config.p_wfss[0].type == scons.centroiderType.PYRHR):
232 ideal_pyrimg = wfs.get_binimg_notnoisy(0)
233 wfs.set_pyrimg(0,ideal_pyrimg)
235 self._sim.doCentroidsGeom(0)
236 self._sim.do_control(0)
237 Ageom = self.get_err(0)
247 self._sim.raytraceTar(0,
"atmos")
248 self._sim.do_control(1, 0, wfs_direction=
False)
249 B = self.get_command(1)
254 self._sim.applyControl(1)
255 self._sim.raytraceTar(0,
"dm", rst=
False)
257 self._sim.comp_tar_image(0, compLE=
False)
258 self._sim.compStrehl(0)
261 self.
psf_ortho += self.get_tar_image(0,
'se')
266 modes = self.
P.dot(B)
267 modes_filt = modes.copy() * 0.
285 for w
in range(len(self.
config.p_wfss)):
286 self._sim.raytrace_wfs(w,
"atmos")
288 self._sim.do_control(1, 0, wfs_direction=
True)
289 G = self.get_command(1)
290 modes = self.
P.dot(G)
300 self._sim.tar.d_targets[0].set_phase(tarphase)
301 self._sim.rtc.d_control[0].set_com(Dcom, Dcom.size)
305 Saves all the ROKET buffers + simuation parameters in a HDF5 file
308 savename: (str): name of the output file
310 tmp = (self.
config.p_geom._ipupil.shape[0] -
311 (self.
config.p_dms[0]._n2 - self.
config.p_dms[0]._n1 + 1)) // 2
312 tmp_e0 = self.
config.p_geom._ipupil.shape[0] - tmp
313 tmp_e1 = self.
config.p_geom._ipupil.shape[1] - tmp
314 pup = self.
config.p_geom._ipupil[tmp:tmp_e0, tmp:tmp_e1]
315 indx_pup = np.where(pup.flatten() > 0)[0].astype(np.int32)
316 dm_dim = self.
config.p_dms[0]._n2 - self.
config.p_dms[0]._n1 + 1
318 psf = self.get_tar_image(0,
"le")
320 fname = os.getenv(
"DATA_GUARDIAN") + savename
371 self.
config.p_dms[0]._xpos,
373 self.
config.p_dms[0]._ypos,
375 self.get_command_matrix(0),
377 self.get_interaction_matrix(0),
389 h5u.save_h5(fname,
"psf", self.
config, psf)
390 for k
in list(pdict.keys()):
391 h5u.save_hdf5(fname, k, pdict[k])
395 Computes covariance matrix and correlation matrix between all the contributors
397 self.
cov = np.zeros((6, 6))
398 self.
cor = np.zeros((6, 6))
407 for i
in range(self.
cov.shape[0]):
408 for j
in range(self.
cov.shape[1]):
410 tmpi = self.
P.dot(bufdict[str(i)])
411 tmpj = self.
P.dot(bufdict[str(j)])
412 self.
cov[i, j] = np.sum(
413 np.mean(tmpi * tmpj, axis=1) -
414 np.mean(tmpi, axis=1) * np.mean(tmpj, axis=1))
416 self.
cov[i, j] = self.
cov[j, i]
418 s = np.reshape(np.diag(self.
cov), (self.
cov.shape[0], 1))
421 self.
cor[ok] = self.
cov[ok] / np.sqrt(sst[ok])
429 if __name__ ==
"__main__":
430 if (len(sys.argv) < 2):
431 error =
'command line should be at least:"python -i test.py parameters_filename"\n with "parameters_filename" the path to the parameters file'
432 raise Exception(error)
435 param_file = sys.argv[1]
437 if (len(sys.argv) > 2):
438 savename = sys.argv[2]
440 savename =
"roket_default.h5"
445 roket.save_in_hdf5(savename)