Signal-to-noise and exposure time
wcc-etc offers two SNR paths that agree to ~1% for an in-focus point
source, plus their exposure-time inverses.
Image-based SNR (the default)
get_snr() delegates to
get_image_snr(). It renders the PSF on the detector
grid, performs circular-aperture photometry, and returns a dictionary:
r = sim.get_snr(time=60)
r["snr"] # signal-to-noise ratio
r["signal_e"] # source electrons inside the aperture
r["noise_e"] # total noise (electrons)
r["enclosed_fraction"] # PSF fraction inside the aperture
r["r_aper_mas"] # aperture radius (mas)
r["n_pix"] # number of pixels in the aperture
r["n_saturated"] # pixels at/above full well in the per-frame image
r["saturated"] # bool
Important
The return value is a dict — always index ["snr"]. (Earlier versions
returned a Quantity with .value; that is gone.)
Choosing the aperture
Aperture precedence is optimize > r_aper_mas > ee_frac; if none is
given, the Simulation’s stored r_aper_mas is used.
sim.get_snr(60, r_aper_mas=300) # fixed aperture radius (mas)
sim.get_snr(60, ee_frac=0.8) # aperture enclosing 80% of the PSF
sim.get_snr(60, optimize=True) # radius that maximizes SNR
Sweeping time or magnitude
time may be a scalar or an array. get_image_snr additionally accepts
mags to sweep the source brightness off a single cached render (host,
background, dark, and read noise held fixed). time and mags may not
both be arrays.
import numpy as np
sim.get_snr(time=np.array([10, 30, 60, 120]))["snr"] # array of SNR
sim.get_image_snr(time=60, mags=np.arange(16, 24))["snr"] # SNR vs. magnitude
Specifying the PSF and jitter
Pass any PSFSource; override jitter per call:
from wcc_etc import DefocusPSF, DEFOCUS_2WAVE_PATH
sim.get_image_snr(time=60, psf=DefocusPSF(DEFOCUS_2WAVE_PATH))
sim.get_image_snr(time=60, jitter_sigma_mas=15)
See PSFs and image simulation for the PSF models and the npix / oversample grid
parameters.
Exposure time for a target SNR
get_image_exptime_for_snr() inverts the image-based
SNR; get_exptime_for_snr() is the analytic Airy
inverse that pairs with get_snr_airy.
sim.get_image_exptime_for_snr(snr=100) # seconds (PSF-aware)
sim.get_exptime_for_snr(snr=100) # seconds (analytic Airy)
Multiple reads (n_reads)
Detectors that co-add or sample multiple reads per exposure reduce the
effective read noise. All SNR and exposure-time methods accept n_reads;
the default comes from the sensor/meta:
sim.get_snr(60, n_reads=4)
sim.get_image_exptime_for_snr(snr=100, n_reads=4)
The analytic Airy SNR
get_snr_airy() is the original closed-form
Airy-disk approximation. It is retained for cross-checking the image-based
path and emits a DeprecationWarning. To use it quietly:
import warnings
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
snr_airy = sim.get_snr_airy(60)
For an in-focus AiryPSF with the default aperture, the
image-based and analytic results agree to about 1%.