COMPASS  5.0.0
End-to-end AO simulation tool using GPU acceleration
wfs.py
1 
37 
38 import shesha.config as conf
39 import shesha.constants as scons
40 from shesha.constants import CONST
41 
42 import shesha.util.utilities as util
43 
44 import numpy as np
45 from shesha.sutra_wrap import Sensors, Rtc_FFF as Rtc
46 
47 
48 def comp_new_pyr_ampl(nwfs: int, ampli: float, p_wfss: list,
49  p_tel: conf.Param_tel, npts_force: int = None):
50  """ Set the pyramid modulation amplitude
51 
52  :parameters:
53 
54  nwfs : (int): WFS index
55 
56  ampli : (float) : new amplitude in units of lambda/D
57 
58  p_wfss : (list of Param_wfs) : list of wfs parameters
59 
60  p_tel : (Param_tel) : Telescope parameters
61  """
62 
63  pwfs = p_wfss[nwfs]
64  nFace = pwfs.nPupils
65 
66  if npts_force is None:
67  if ampli == 0.:
68  pyr_npts = 1
69  elif ampli < 2.:
70  pyr_npts = int(np.ceil(int(2 * 2 * np.pi) / nFace) * nFace)
71  else:
72  pyr_npts = int(np.ceil(int(ampli * 2 * np.pi) / nFace) * nFace)
73  else:
74  pyr_npts = npts_force
75 
76  pixsize = pwfs._qpixsize * CONST.ARCSEC2RAD
77  scale_fact = 2 * np.pi / pwfs._Nfft * (
78  pwfs.Lambda * 1e-6 / p_tel.diam) / pixsize * ampli
79  cx = scale_fact * \
80  np.sin((np.arange(pyr_npts, dtype=np.float32)) * 2. * np.pi / pyr_npts)
81  cy = scale_fact * \
82  np.cos((np.arange(pyr_npts, dtype=np.float32)) * 2. * np.pi / pyr_npts)
83 
84  scale = pwfs.Lambda * 1e-6 / p_tel.diam * ampli * 180. / np.pi * 3600.
85 
86  return cx, cy, scale, pyr_npts
87 
88 
89 def noise_cov(nw: int, p_wfs: conf.Param_wfs, p_atmos: conf.Param_atmos,
90  p_tel: conf.Param_tel):
91  """ Compute the diagonal of the noise covariance matrix for a SH WFS (arcsec^2)
92  Photon noise: (pi^2/2)*(1/Nphotons)*(d/r0)^2 / (2*pi*d/lambda)^2
93  Electronic noise: (pi^2/3)*(wfs.noise^2/N^2photons)*wfs.npix^2*(wfs.npix*wfs.pixsize*d/lambda)^2 / (2*pi*d/lambda)^2
94 
95  :parameters:
96 
97  nw: wfs number
98 
99  p_wfs: (Param_wfs) : wfs settings
100 
101  p_atmos: (Param_atmos) : atmos settings
102 
103  p_tel: (Param_tel) : telescope settings
104 
105  :return:
106 
107  cov : (np.ndarray(ndim=1,dtype=np.float64)) : noise covariance diagonal
108  """
109  cov = np.zeros(2 * p_wfs._nvalid)
110  if (p_wfs.noise >= 0):
111  ind = np.where(p_wfs._isvalid.T)
112  flux = p_wfs._fluxPerSub[ind[1], ind[0]]
113  Nph = flux * p_wfs._nphotons
114 
115  r0 = (p_wfs.Lambda / 0.5)**(6.0 / 5.0) * p_atmos.r0
116 
117  sig = (np.pi ** 2 / 2) * (1 / Nph) * \
118  (1. / r0) ** 2 # Photon noise in m^-2
119  # Noise variance in rad^2
120  sig /= (2 * np.pi / (p_wfs.Lambda * 1e-6))**2
121  sig *= CONST.RAD2ARCSEC**2
122 
123  Ns = p_wfs.npix # Number of pixel
124  Nd = (p_wfs.Lambda * 1e-6) * CONST.RAD2ARCSEC / p_wfs.pixsize
125  sigphi = (np.pi ** 2 / 3.0) * (1 / Nph ** 2) * (p_wfs.noise) ** 2 * \
126  Ns ** 2 * (Ns / Nd) ** 2 # Phase variance in m^-2
127  # Noise variance in rad^2
128  sigsh = sigphi / (2 * np.pi / (p_wfs.Lambda * 1e-6))**2
129  sigsh *= CONST.RAD2ARCSEC**2 # Electronic noise variance in arcsec^2
130 
131  cov[:len(sig)] = sig + sigsh
132  cov[len(sig):] = sig + sigsh
133 
134  return cov
135 
136 
137 def comp_new_fstop(wfs: Sensors, n: int, p_wfs: conf.Param_wfs, fssize: float,
138  fstop: bytes):
139  """ Compute a new field stop for pyrhr WFS
140 
141  :parameters:
142 
143  n : (int) : WFS index
144 
145  wfs : (Param_wfs) : WFS parameters
146 
147  fssize : (float) : field stop size [arcsec]
148 
149  fstop : (string) : "square" or "round" (field stop shape)
150  """
151  fsradius_pixels = int(fssize / p_wfs._qpixsize / 2.)
152  if (fstop == scons.FieldStopType.ROUND):
153  p_wfs.fstop = fstop
154  focmask = util.dist(p_wfs._Nfft, xc=p_wfs._Nfft / 2. - 0.5,
155  yc=p_wfs._Nfft / 2. - 0.5) < (fsradius_pixels)
156  # fstop_area = np.pi * (p_wfs.fssize/2.)**2. #UNUSED
157  elif (p_wfs.fstop == scons.FieldStopType.SQUARE):
158  p_wfs.fstop = fstop
159  y, x = np.indices((p_wfs._Nfft, p_wfs._Nfft))
160  x -= (p_wfs._Nfft - 1.) / 2.
161  y -= (p_wfs._Nfft - 1.) / 2.
162  focmask = (np.abs(x) <= (fsradius_pixels)) * \
163  (np.abs(y) <= (fsradius_pixels))
164  # fstop_area = p_wfs.fssize**2. #UNUSED
165  else:
166  msg = "p_wfs " + str(n) + ". fstop must be round or square"
167  raise ValueError(msg)
168 
169  # pyr_focmask = np.roll(focmask,focmask.shape[0]/2,axis=0)
170  # pyr_focmask = np.roll(pyr_focmask,focmask.shape[1]/2,axis=1)
171  pyr_focmask = focmask * 1.0 # np.fft.fftshift(focmask*1.0)
172  p_wfs._submask = np.fft.fftshift(pyr_focmask).astype(np.float32)
173  p_wfs_fssize = fssize
174  wfs.d_wfs[n].set_submask(p_wfs._submask)
shesha.sutra_wrap
Definition: sutra_wrap.py:1
shesha.util.utilities
Basic utilities function.
Definition: utilities.py:1
shesha.constants
Numerical constants for shesha and config enumerations for safe-typing.
Definition: constants.py:1
shesha.config
Parameter classes for COMPASS.
Definition: shesha/shesha/config/__init__.py:1
shesha.ao.wfs.noise_cov
def noise_cov(int nw, conf.Param_wfs p_wfs, conf.Param_atmos p_atmos, conf.Param_tel p_tel)
Compute the diagonal of the noise covariance matrix for a SH WFS (arcsec^2) Photon (pi^2/2)*(1/Nphoto...
Definition: wfs.py:107
shesha.ao.wfs.comp_new_fstop
def comp_new_fstop(Sensors wfs, int n, conf.Param_wfs p_wfs, float fssize, bytes fstop)
Compute a new field stop for pyrhr WFS.
Definition: wfs.py:149
shesha.ao.wfs.comp_new_pyr_ampl
def comp_new_pyr_ampl(int nwfs, float ampli, list p_wfss, conf.Param_tel p_tel, int npts_force=None)
Set the pyramid modulation amplitude.
Definition: wfs.py:60