diff --git a/paompy/__pycache__/instrument.cpython-36.pyc b/paompy/__pycache__/instrument.cpython-36.pyc index 60647b04140b2e9681e454842f07a3fa53851a19..915fdb330ce7eaeb4bbba25aedb467e8b5beddc1 100644 Binary files a/paompy/__pycache__/instrument.cpython-36.pyc and b/paompy/__pycache__/instrument.cpython-36.pyc differ diff --git a/paompy/__pycache__/utils.cpython-36.pyc b/paompy/__pycache__/utils.cpython-36.pyc index cf5630f41dc860396ee1340f3c0391cf5401bb68..b49526342a64130321eef33d19fbb9dedd266e10 100644 Binary files a/paompy/__pycache__/utils.cpython-36.pyc and b/paompy/__pycache__/utils.cpython-36.pyc differ diff --git a/paompy/instrument.py b/paompy/instrument.py index 18f721c812493f8707a5d41a177618d21c8e2c9f..d5f280765602f8f5bb7342267eddf9b383ee5ee9 100644 --- a/paompy/instrument.py +++ b/paompy/instrument.py @@ -6,3 +6,130 @@ Created on Mon May 27 17:30:51 2019 @author: rfetick """ +from paompy.utils import circarr, airy, RAD2ARCSEC +from paompy.config import _DEFAULT_RES + +#%% DETECTOR CLASS AND ITS SUBCLASSES + +class Detector(object): + """Represents a detector + + Attributes + ---------- + resolution : float + Pixel scale [meter] + Npix : tuple, list, numpy.ndarray + Number of pixels on X and Y axis + gainADU : float + Detector gain [electron/ADU] + RON : float + Read-Out-Noise [electron] + + """ + + def __init__(self,Npix,resolution=_DEFAULT_RES,gainADU=1.,RON=0.): + self.resolution_pixel = resolution + self.Npix = Npix + self.gainADU = gainADU + self.RON = RON + self.binning = 1 + + def __repr__(self): + s = "PAOMPY Detector\n" + s += "---------------\n" + s += "Pixels : (%u,%u)\n" % (self.Npix[0],self.Npix[1]) + s += "Resolution: %u um\n" % round(self.resolution*1e6) + s += "Binning : %u\n" % self.binning + s += "Gain ADU : %.2f e-/ADU\n" % self.gainADU + s += "RON : %.2f e-" % self.RON + return s + + @property + def resolution(self): + return self.resolution_pixel * self.binning + + +ZIMPOL_DETECTOR = Detector((1024,1024),30*1e-6,gainADU=10.5,RON=20.) + +# Equivalent detector resolution after image reduction pipeline +MUSE_DETECTOR = Detector((200,200),237.14745*1e-6,gainADU=5.,RON=15.) + + + + +#%% INSTRUMENT CLASS AND ITS SUBCLASSES + +class Instrument(object): + """Represents an optical system + + Attributes + ---------- + D : float + Entrance pupil diameter [meter] + detector : Detector + Camera at the focal plane + filters : dict + Dictionary of available filters as tuples (central wvl, width) [meter] + AO_Nact : int + Linear number of actuators + """ + + def __init__(self,D,detector=None,occ=0.): + self.D = D + self.occ = occ # occultation ratio + self.detector = detector + self.filters = {} + self.AO_Nact = 0 + self.focal_length = None + self.name = "" + + def __repr__(self): + s = self.name+" OpticalSystem\n" + s += "-------------------------\n" + s += "Diameter: %.2g m (occ=%u%%)\n" % (self.D,self.occ*100) + s += "AO_Nact : %u\n" % self.AO_Nact + s += "Focal : %s m\n" % str(self.focal_length) + s += "Filters : %u" % len(self.filters) + return s + + @property + def resolution_mas(self): + if self.focal_length is None: + raise ValueError("Cannot compute `resolution_mas` if `focal_length` is not set") + return self.detector.resolution/self.focal_length * RAD2ARCSEC * 1e3 + + def pupil(self,Npix,wvl=None,samp=None): + """Returns the 2D array of the pupil transmission function""" + Dpix = min(Npix)/2 + pup = circarr(Npix) + return (pup < Dpix) * (pup >= Dpix*self.occ) + + def samp(self,wvl): + """Returns sampling value for the given wavelength""" + if self.detector is None: + raise ValueError("Cannot compute sampling if `detector` is not defined") + if self.focal_length is None: + raise ValueError("Cannot compute sampling if `focal_length` is not defined") + return wvl*self.focal_length/(self.detector.resolution*self.D) + + def wvl(self,samp): + """Returns wavelength for the given sampling""" + if self.detector is None: + raise ValueError("Cannot compute wavelength if `detector` is not defined") + if self.focal_length is None: + raise ValueError("Cannot compute wavelength if `focal_length` is not defined") + return samp*(self.detector.resolution*self.D)/self.focal_length + + + def PSFdl(self,Npix,wvl): + """Returns the diffraction limited PSF + + Parameters + ---------- + Npix : tuple, list of 2 elements + Size of the output 2D array + wvl : float + Observation wavelength + """ + return airy(Npix,self.samp(wvl),self.occ) +