Closed mvandam closed 3 years ago
Thanks @mvandam, I understand the confusion , nBackgroundPhoton
is ill defined , it should be: nBackgroundPhoton is the mean number of background photon per detector pixel and with that definition we got:
nBackgroundPhoton=np.mean(frame)=np.var(frame)
There were two reasons why the background was not working for me. The first is that the background is computed per arcsecond, not per pixel. The second is that the WFS needs to be initialized/calibrated before computing the background. The background should be set in the following way: (this is an NGS tip-tilt sensor)
In [4]: ngswfs_prms = {'N_SIDE_LENSLET':1,'N_PX_LENSLET':NT,'d':D,'DFT_osf':2,'N_PX_IMAGE':ngs_px_image,'BIN_IMAGE':ngs_binning,'N_GS':N_NGS,'readOutNoiseRms':ngs_ ...: readoutnoise,'noiseFactor':ngs_noisefactor,'photoElectronGain':ngs_photoelectrongain, 'exposureTime':exposureTime,'intensityThreshold':0.0} ...: ngswfs = ceo.ShackHartmann(**ngswfs_prms) ...: ...: ~gmt ...: ~ngs ...: gmt.propagate(ngs) ...: ngswfs.calibrate(ngs) ...: ngswfs.camera.nBackgroundPhoton = ngs.nBackgroundPhoton(ngs_sky_magnitude)*ngswfs.pixel_scale_arcsec**2 + ngs_darkcurrent*ngs_binning**2/ngs_photoelectrongain ...: ...
Here is an example that shows that the sky background is not implemented properly in CEO (at least, for Shack-Hartmann WFSs). I will try to fix it at some point.
calculate the background
import warnings warnings.filterwarnings("ignore") import sys import os import ceo import numpy as np import matplotlib.pyplot as plt
pupil_size = 25.5 threshold = 0.01 # subaperture flux threshold vismag = np.array([1000.]) zen = np.array([0.]) azi = np.array([0.]) gmt = ceo.GMT_MX()
N_SIDE_LENSLET = 24 # The linear size of the lenslet array (>=1). N_PX_LENSLET = 30 # The sampling in pixel of one lenslet. d = pupil_size/N_SIDE_LENSLET # The lenslet pitch [m]. DFT_osf = 2 # [2] optional The oversampling factor for the DFT N_PX_IMAGE = 48 # int, optional The sampling in pixel of the imagelet [N_PX_LENSLET] BIN_IMAGE = 6 # optional The binning factor of the imagelet [1] N_GS = 1 # optional The number of guide stars [1] exposureTime = 1. readOutNoiseRms = 0 photoElectronGain = 1 # The photon to electron conversion gain of the camera [1] noiseFactor = 1 fudgeFactor = 0.000550
background photometry
need to understand if this is for binned or unbinned pixels
sky_magnitude = 19
wfs_prms = {'N_SIDE_LENSLET':N_SIDE_LENSLET,'N_PX_LENSLET':N_PX_LENSLET,'d':d,'DFT_osf':DFT_osf,'N_PX_IMAGE':N_PX_IMAGE,'BIN_IMAGE':BIN_IMAGE,'N_GS': N_GS,'readOutNoiseRms':readOutNoiseRms,'noiseFactor':noiseFactor,'photoElectronGain':photoElectronGain, 'exposureTime':exposureTime,'intensityThreshold':-10000.0} wfs = ceo.ShackHartmann(**wfs_prms)
gs = ceo.Source(photometric_band="R+I",zenith=zen,azimuth=azi,magnitude=vismag,rays_box_size=pupil_size,rays_box_sampling=N_SIDE_LENSLET*N_PX_LENSLET+1,rays_origin=[0,0,25])
to do: overwrite the photometry and noise (but ignore for now)
to do: convert geometric to physical optics WFS
~gmt gs.reset() gmt.reset() gmt.propagate(gs) wfs.calibrate(gs,threshold) gs>>(gmt,wfs)
wfs.camera.nBackgroundPhoton = gs.nBackgroundPhoton(sky_magnitude)*fudgeFactor # fudge factor to get the right values
~wfs gs>>(gmt,wfs) +gs +wfs
plt.ion() plt.figure(1) plt.clf() frame = np.array(wfs.camera.ghost_frame[:wfs.N_PX_FRAME,:]) plt.imshow(frame,interpolation='none',cmap='viridis')
print("expected variance", 24.46e9*(pupil_size/N_SIDE_LENSLET)2*2.512*(-sky_magnitude)(wfs.camera.pixelScaleArcsec(gs)2)exposureTimewfs.camera.noiseFactor*2wfs.camera.photoelectron_gain) print("actual variance", np.var(frame))