API reference#

The package exposes one function and two result types.

fft_cnr.fft_cnr(x, template=None, *, fit_model=None, window='tukey', tukey_alpha=0.25, welch_nperseg=None, welch_noverlap=None, cutoff_guard=(0.05, 0.5), fallback_cut_frac=0.25, roi=None, return_bandpassed_noise=False, estimate_noise_model=False, rng=None)[source]#

Estimate contrast-to-noise ratio from a single 1-D profile using FFT methods.

Uses unitary FFT normalization, Welch PSD estimation with degrees-of-freedom tracking, AIC-based objective cutoff selection, white-noise matched-filter amplitude estimation, and analytical confidence intervals.

Parameters:
  • x (np.ndarray) – Input 1-D signal (e.g., a line profile or spectrum).

  • template (np.ndarray or None) – Expected signal shape for matched-filter amplitude estimation. If None, amplitude is estimated using the method specified by fit_model (default: "peak").

  • fit_model (str or None) – Amplitude estimation method when no template is provided. "peak" (default) applies a spectral low-pass filter and reads the peak from the smoothed signal – robust across arbitrary profile shapes. "generalized_gaussian" fits a 5-parameter generalized Gaussian with a shape exponent that accommodates non-zero excess kurtosis, providing fitted parameters (center, width, shape) in diagnostics. Ignored when template is given.

  • window (str) – Tapering window: "tukey", "hann", or "none".

  • tukey_alpha (float) – Shape parameter for the Tukey window (0 = rectangular, 1 = Hann).

  • welch_nperseg (int or None) – Segment length for Welch PSD estimation. Defaults to max(16, N//8). With 50% overlap this heuristic produces approximately 15 Welch segments at any signal length, giving consistent degrees of freedom for the noise confidence interval. Longer segments reduce the segment count and widen the noise CI substantially without improving CNR accuracy.

  • welch_noverlap (int or None) – Overlap for Welch segments. Defaults to nperseg // 2.

  • cutoff_guard (tuple[float, float]) – Fractional bounds for the AIC knee search range.

  • fallback_cut_frac (float) – Fallback cutoff fraction if AIC selection fails.

  • roi (str, tuple[int, int], or None) – Restrict the estimate to a region of interest. None (default) uses the full profile. A (start, stop) index pair estimates on that slice. "auto" locates the largest feature (peak or dip) and takes a window scaled to its own width (about +/- 2.5 sigma). Windowing removes off-center low-frequency baseline structure that would otherwise be counted as signal; the chosen bounds are reported in diagnostics["roi"]. "auto" locates the largest feature, so when an off-center baseline exceeds the peak of interest, pass explicit bounds instead. The window must span at least 16 points.

  • return_bandpassed_noise (bool) – If True, include the bandpassed noise array in diagnostics.

  • estimate_noise_model (bool) – If True, fit the photon-transfer relation (var = gain * signal + read**2) to the residual, test the fitted gain for significance against a null calibrated through this same pipeline, and attach the result as noise_model. Works with every amplitude method. Adds a Monte Carlo cost of about 200 re-runs of the spectral decomposition.

  • rng (numpy.random.Generator or None) – Random generator for the noise-model null calibration. None (default) uses a fixed seed, so repeated calls on the same input give identical results; pass a Generator for independent draws. Unused unless estimate_noise_model is True.

Returns:

Dataclass containing CNR, amplitude, noise, confidence intervals, and diagnostic information. On the localized-peak methods (peak and generalized_gaussian) the diagnostics carry lowfreq_offpeak_ratio – the RMS of low-frequency structure away from the peak, in units of the noise RMS – and the boolean lowfreq_dominated (true above an off-peak ratio of 2.5). A true flag means smooth baseline or fringe structure dominates the profile, so the reported CNR may reflect baseline power rather than the peak; narrow the estimate with roi. The ratio is NaN on the matched-filter (template) path, where the template defines the signal and the off-peak statistic does not apply.

The localized-peak methods also carry amplitude_sign_ambiguous: true when an opposite-sign excursion at least half the chosen feature’s magnitude rivals it, so the largest-magnitude read could switch features (and flip the amplitude sign) under noise. It is False on the matched-filter path, where the template fixes the feature.

Return type:

CNREstimate

Raises:

ValueError – If the input profile has fewer than 16 points, a region of interest spans fewer than 16 points, or a supplied template is constant after mean-subtraction (the matched filter is then undefined).

class fft_cnr.CNREstimate(cnr, cnr_ci95, amplitude, amplitude_se, noise_rms, noise_ci95, cutoff_index, diagnostics, noise_model=None)[source]#

Result of an FFT-based CNR estimation.

Parameters:
cnr#

Estimated contrast-to-noise ratio.

Type:

float

cnr_ci95#

95% confidence interval on CNR (delta-method approximation).

Type:

tuple[float, float]

amplitude#

Estimated signal amplitude. Signed on the peak and generalized-Gaussian paths: negative for a downward (absorption / dark-contrast) feature. cnr uses its magnitude.

Type:

float

amplitude_se#

Standard error of the amplitude estimate (NaN if unavailable). On the matched-filter and generalized-Gaussian paths this is a derived standard error; on the default peak path it is an uncharacterized proxy (sigma / sqrt(kc_full)) that understates the true scatter, so it feeds cnr_ci95 (where the noise term dominates) but is not exposed through amplitude_snr.

Type:

float

noise_rms#

RMS noise estimated from high-frequency spectral region.

Type:

float

noise_ci95#

95% confidence interval on noise RMS.

Type:

tuple[float, float]

cutoff_index#

Spectral index separating signal from noise.

Type:

int

diagnostics#

Additional diagnostic information.

Type:

dict

noise_model#

Estimated noise structure, or None when no detector has run.

Type:

NoiseModel or None

property amplitude_snr: float#

amplitude over its standard error.

Defined only on the matched-filter (template) path, where the standard error is the whitened estimator’s, so the ratio is the efficient detectability member of the contrast-to-noise-ratio family. It is NaN on every other path: the peak proxy standard error is uncharacterized, and the generalized-Gaussian standard error is denominated in the fit residual rather than the noise spectrum, so neither is the same statistical object and the values are not comparable. Those paths still expose amplitude_se directly for any caller that wants the raw ratio.

Type:

Matched-filter signal-to-noise ratio

class fft_cnr.NoiseModel(read, gain, spectral_exponent, white_floor, signal_dependent, correlated)[source]#

Estimated structure of the noise, beyond a single RMS level.

Characterizes the noise along two orthogonal axes. The real-space axis (read, gain) captures signal-dependent noise via the photon-transfer relation var = gain * signal + read**2 and is populated by the estimate_noise_model detector. The spectral axis (spectral_exponent, white_floor, correlated) names spatially correlated, 1/f-type noise; these fields are reserved and are not populated. Single-frame quantitative correction of correlated noise is unsupported: the low-frequency model error left by an estimated signal shape is indistinguishable from 1/f noise in one frame, so the spectral exponent and white floor cannot be recovered without bias. Use multiple frames, interleaved acquisition, or a reference channel to characterize and correct correlated noise. White, signal-independent noise is the degenerate case of the real-space axis (zero gain).

Real-space numeric fields are NaN and signal_dependent is None until the detector has run, so “not tested” is distinguishable from “tested, not significant”; the spectral-axis fields stay at those sentinels.

Parameters:
read#

Read-noise floor (intercept of the var-vs-signal fit).

Type:

float

gain#

Photon-transfer slope (var-vs-signal).

Type:

float

spectral_exponent#

Reserved (correlated-noise axis); always NaN. Single-frame 1/f correction is unsupported (see the class notes above).

Type:

float

white_floor#

Reserved (correlated-noise axis); always NaN.

Type:

float

signal_dependent#

Whether the gain is significantly above the pipeline null.

Type:

bool or None

correlated#

Reserved flag for a correlated-noise detector; always None (detection deferred, no single-frame correction).

Type:

bool or None

peak_snr(amplitude)[source]#

Peak signal-to-noise ratio under the fitted real-space noise model.

Uses the amplitude magnitude, so a negative (absorption / dark-contrast) amplitude gives the same positive SNR as a peak of equal depth.

Parameters:

amplitude (float)

Return type:

float