Detector models#

optixstuff ships two concrete detector implementations and three noise-generator primitives. This page explains when to reach for each.

The two detectors#

IdealDetector#

from optixstuff import IdealDetector

detector = IdealDetector(
    pixel_scale_arcsec=0.01,         # arcsec/pixel
    shape=(512, 512),         # detector grid
    quantum_efficiency=1.0,   # constant QE (default)
    dark_current_rate_e_per_s=0.0,    # no dark current
    read_noise_e=0.0, # no read noise
    clock_induced_charge_rate_e_per_frame=0.0,             # no clock-induced charge
)

Use for: broadband imaging studies where wavelength-dependent QE variation and detector noise contributions are negligible. Sandbox / debugging / first-pass forward modeling.

All noise sources default to zero – IdealDetector models a pure photon counter.

Detector#

from optixstuff import Detector

detector = Detector(
    pixel_scale_arcsec=0.01,
    shape=(512, 512),
    quantum_efficiency=0.9,
    dark_current_rate_e_per_s=1e-4,       # e/s/pixel
    read_noise_e=3.0,     # e RMS per read
    clock_induced_charge_rate_e_per_frame=1e-3,                # e per frame per pixel
    frame_time_s=300.0,             # seconds per readout frame
    read_time_s=0.05,
    dqe=0.0,                      # detector quantum efficiency factor
)

Use for: realistic noise budgets, mission yield calculations, end-to-end performance simulations.

Detector uses all of its noise-source fields. Dark current and CIC enter as Poisson processes; read noise is Gaussian. Compose with the detector’s readout method or with the standalone noise primitives (below).

Same schema, different behavior#

IdealDetector and Detector accept the same field signature. The difference is in the methods: IdealDetector uses constant QE (ignores wavelength) and skips noise contributions when rates are zero. Detector uses every field and returns the full physical noise budget. Use Detector whenever you want realistic noise.

The noise primitives#

Three standalone functions for direct noise simulation:

from optixstuff import (
    dark_current,
    clock_induced_charge,
    read_noise,
)

# Dark current: Poisson with mean = rate * exposure_time_s
dark_e = dark_current(
    dark_current_rate_e_per_s=1e-4,    # e/s/pixel
    exposure_time_s=3600.0,      # seconds
    shape=(512, 512),
    prng_key=jax.random.PRNGKey(0),
)

# Clock-induced charge: Poisson per-frame, scaled by num_frames
cic_e = clock_induced_charge(
    clock_induced_charge_rate_e_per_frame=1e-3,             # e/frame/pixel
    num_frames=12.0,
    shape=(512, 512),
    prng_key=jax.random.PRNGKey(1),
)

# Read noise: Gaussian per-frame, RMS-summed across frames
read_e = read_noise(
    read_noise_e=3.0,            # e RMS per read
    num_frames=12.0,
    shape=(512, 512),
    prng_key=jax.random.PRNGKey(2),
)

These are noise contributions (additive to a source readout), not full readouts. Each returns the per-pixel noise electrons for one exposure, ready to be summed into a complete frame alongside the source-readout contributions from coronagraphoto.

Composing a realistic frame#

import jax
from optixstuff import dark_current, clock_induced_charge, read_noise
from coronagraphoto import star_readout, planet_readout

keys = jax.random.split(jax.random.PRNGKey(0), 6)

# Sources (Poisson realisations of the count rates)
star_e   = star_readout(star, optical_path, keys[0], ...)
planet_e = planet_readout(planet, optical_path, keys[1], ...)

# Detector noise contributions
shape = optical_path.detector.shape
dark_e = dark_current(
    optical_path.detector.dark_current_rate_e_per_s,
    exposure_time_s,
    shape,
    keys[2],
)
cic_e = clock_induced_charge(
    optical_path.detector.clock_induced_charge_rate_e_per_frame,
    num_frames,
    shape,
    keys[3],
)
read_e = read_noise(
    optical_path.detector.read_noise_e,
    num_frames,
    shape,
    keys[4],
)

# Compose
frame = star_e + planet_e + dark_e + cic_e + read_e

For most use cases the detector’s high-level readout method handles this composition for you; the primitives are exposed for advanced use (custom noise budgets, sensitivity studies, partial-noise traces).

See also#

  • Architecture – where detectors fit in the optixstuff abstraction hierarchy