The noise model

Every error bar lazuli_exo reports traces back to one array per planet: depth_err_1transit(λ), the single-transit transit-depth uncertainty computed offline with slicersim for the Lazuli IFS.

What observe() does with it

Two operations, both simple and both worth knowing exactly:

  1. Bin the native noise channels onto the requested constant-R grid (edges snapped to whole detector pixels, see Spectra and scenarios), in inverse variance:

    \[\sigma_\mathrm{bin} = \left( \sum_{i \in \mathrm{bin}} \sigma_i^{-2} \right)^{-1/2}\]
  2. Scale by the number of transits:

    \[\sigma_\mathrm{depth} = \sigma_\mathrm{bin} / \sqrt{N_\mathrm{transits}}\]

That is the entire noise model at runtime. The binned model depth is untouched by n_transits. obs.plot_noise() draws the result against wavelength.

Warning

The \(1/\sqrt{N}\) scaling has no floor. There is no per-transit systematics term and no red noise, so the predicted precision improves without limit as transits accumulate. Any “number of transits needed” computed from these outputs is a lower bound, optimistic by an amount this model cannot tell you.

The two resolution limits

Both are set by the part of the band where the dispersion makes the pixels coarsest in resolving power, which for the shipped tables is near 1.0 µm, not by the median.

The instrument resolving power is 2.3 pixels per resolution element (RESOLUTION_PX): R ≈ 369 at 0.40 µm, a minimum of R ≈ 101 near 1.02 µm, and R ≈ 165 at 1.69 µm. Above the minimum, observe() and simulate() still run but warn: bins narrower than a resolution element are correlated by the line-spread function, so the error bars are no longer independent.

UserWarning: requested R=150 exceeds the instrument resolving power
(R_instr = 101-369 over the binned range); bins narrower than a
resolution element are correlated by the LSF

The native channel sampling is the hard ceiling: one pixel per bin, R ≈ 231 at its minimum (848 at 0.40 µm). Above it the request raises:

ValueError: requested R exceeds the native noise sampling (bins narrower
than one channel; R_px >= 231)

Both numbers are on every observation and in the tables:

obs.meta["instrument_response"]["R_instr_min"]     # ~101
from lazuli_exo import tables, binning
wl, err, meta = tables.load_noise(tables.resolve_tables_dir(None), "WASP-39 b")
binning.R_instr(wl).min()                            # ~101, the warning threshold
(wl[:-1] / np.diff(wl)).min()                        # ~231, the hard ceiling

What the tables assume

The assumptions are recorded in meta["noise"] on every observation:

instrument

The instrument configuration used, e.g. lazuli_cbe.

norm_band / J_mag / mag_ab / vega_ab_offset

The band the source was normalized in, the archive (Vega) magnitude and its AB equivalent, which is what slicersim actually normalizes to.

default_nmd / nmd_used

The MACC readout configuration: the default, and what was actually used after tuning to remove point-source saturation.

t14_s / t_obs_s / tframe_s / n_reset_frames

Transit duration and the native integration time (including the reset frame overhead), in seconds. These also set the light-curve window and cadence.

package_version / git_commit / slicersim_version / *_sha256

Provenance: the code and the input files the table was generated from.

assumption

A plain-text statement of the depth-uncertainty model: equal out-of-transit baseline; SNR ~ sqrt(t); readout tuned per-target to remove point-source saturation before reading SNR.

fully_desaturated / nsaturated_detpx

Whether the detector ramp could be fully de-saturated, and how many pixels remained saturated if not.

Equal out-of-transit baseline

The depth uncertainty combines an in-transit and an out-of-transit measurement,

\[\sigma_\mathrm{depth} = \sqrt{ \mathrm{SNR}_\mathrm{in}^{-2} + \mathrm{SNR}_\mathrm{out}^{-2} }\]

with the two exposures assumed equal. This is neither optimized nor constrained by a telescope-time budget. It is also the assumption that lets the light-curve module derive its per-point scatter from the band depth precision. See Transit light curves.

Bright hosts: unvalidated uncertainties

Danger

For HD 189733 b, slicersim’s detector ramp could not be fully de-saturated even at the minimal MACC configuration (2 groups × 1 frame; 324 pixels remain saturated at the last read). Saturation can bias extraction weights, nonlinearity, and wavelength dependence in either direction, so its uncertainties are unvalidated. Treat its forecasts as indicative only until an unsaturated readout strategy or an injection/recovery validation exists. HAT-P-11 b and HD 209458 b were on this list before the 2026-10-11 table regeneration and now desaturate. HD 189733 b stays in the tables on purpose: it is the brightest host in the sample and the warning travels with every result.

Rather than silently ignoring this, observe() raises a UserWarning:

obs = lazuli_exo.observe("HD 189733 b")
# UserWarning: HD 189733 b: noise table was generated with residual
# detector saturation (324 px); its uncertainties are unvalidated —
# do not use for quantitative forecasts

To find the affected targets programmatically, check the flag rather than hard-coding the name:

flagged = [p for p in lazuli_exo.list_planets()
           if tables.load_noise(tdir, p)[2].get("fully_desaturated") is False]