pyfli.data_cc.irfAligner#

Align decay and IRF cubes with threshold-based rise detection and circular or Fourier shifts.

This module belongs to pyfli.data_cc and is part of PyFLI array preprocessing helpers for normalization, masking, ROI extraction, and IRF alignment. Public API includes classes IRFAligner.

Classes

IRFAligner(decay, irf[, decay_noise_bins, ...])

Run the irfaligner routine.

class IRFAligner(decay, irf, decay_noise_bins=(0, 5), irf_noise_bins=(0, 5), laser_period=12.5, gate_delay=None)[source]#

Bases: object

Run the irfaligner routine. edges per pixel or globally and can shift signals with Fourier or circular methods before fitting.

Parameters:
  • decay (np.ndarray) – Fluorescence decay trace to process.

  • irf (np.ndarray) – Instrument response function aligned with the decay trace.

  • decay_noise_bins (tuple[int, int]) – (start, end) bin range used to estimate the decay noise floor.

  • irf_noise_bins (tuple[int, int]) – (start, end) bin range used to estimate the IRF noise floor.

  • laser_period (float) – Laser repetition period in nanoseconds.

  • gate_delay (float | None) – Time between gate bins in nanoseconds. Defaults to laser_period / num_gates when not given.

estimate_shift(fraction=0.1, manual_correction=0.0)[source]#

Calculates how much the IRF must move to match the decay’s start.

Pixels where either trace has no detectable rise (see _find_rising_point()) get a shift of 0 rather than a spurious value, since there is no meaningful feature to align. manual_correction is subtracted from every pixel’s shift, including those fallback pixels.

Parameters:
Return type:

Any

estimate_shift_debiased(low_fraction=0.02, smooth_window=3, manual_correction=0.0)[source]#

Estimates the per-pixel IRF shift from where each trace departs from background, instead of estimate_shift()’s 10%-of-peak threshold.

decay = irf convolved with the fluorescence decay kernel makes decay’s rising flank intrinsically broader than IRF’s, so a shared peak-relative threshold is crossed later (relative to the true photon arrival time) for decay than for IRF, inflating the shift estimate_shift() returns. Measuring the crossing much closer to the true onset (low_fraction) removes most of that bias — algebraically this is equivalent to subtracting each trace’s own rise-width (10%-of-peak bin minus background-departure bin) from the naive shift, since that width term cancels out.

A low threshold on raw photon-count data fires on background shot noise rather than the real pulse, so each trace is smoothed first with a smooth_window-bin moving average to suppress that before the threshold is applied.

manual_correction is subtracted from every pixel’s shift, including fallback pixels with no detectable rise.

Parameters:
  • low_fraction (float)

  • smooth_window (int)

  • manual_correction (float)

Return type:

Any

estimate_shift_rmse(bin_window=None, left=10, right=7, max_shift=20, fraction=0.1, manual_correction=0.0)[source]#

Refines the per-pixel IRF shift by minimizing RMSE between the decay trace and a candidate-shifted, amplitude-matched IRF within a local comparison window.

If bin_window (start, end) is given, that range is used for every pixel. Otherwise the window is centered per-pixel on the decay’s own rising point (from _find_rising_point()), spanning left bins before it and right bins after, shifted inward at the trace edges rather than wrapped. Integer shifts in [-max_shift, max_shift] are searched and refined to sub-bin precision via a parabolic fit around the best candidate. Pixels with no detectable decay rise fall back to a shift of 0. manual_correction is subtracted from every pixel’s shift, including those fallback pixels.

Parameters:
Return type:

Any

estimate_shift_rmse_pixel(x, y, bin_window=None, left=10, right=7, max_shift=20, fraction=0.1, manual_correction=0.0)[source]#

Runs the estimate_shift_rmse() search for a single pixel (x, y) and returns the full RMSE-vs-shift curve plus the resulting aligned IRF trace — useful to inspect why a particular shift was selected, and how well it lines up with decay, without processing the full cube.

manual_correction is subtracted from the RMSE-refined shift before it is used to build “shifted_irf”, matching estimate_shift_rmse().

Returns:

“shift_candidates” : integer shifts that were tested. “rmse” : RMSE at each candidate shift, same order. “best_shift” : final shift for this pixel (sub-bin refined,

minus manual_correction), matching what estimate_shift_rmse() returns for it.

”window” : (start, end) bin range used for the comparison. “decay_trace” : the pixel’s full decay trace, unmodified. “scaled_irf_trace” : the pixel’s IRF trace, amplitude-matched

to decay via norm_scale(), before any shift.

”shifted_irf””scaled_irf_trace” shifted by “best_shift”

(Fourier/fractional shift, full trace) — plot this against “decay_trace” to see the resulting alignment.

Return type:

dict

Parameters:
apply_fourier_shift(shifts)[source]#

Apply fourier shift.

Parameters:

shifts (np.ndarray) – Per-pixel temporal shifts applied to the IRF cube.

Returns:

Object produced by apply fourier shift.

Return type:

Any

apply_circular_shift(shifts)[source]#

Applies a linear circular shift by rounding fractional shifts to the nearest integer and rolling the array.

Parameters:

shifts (ndarray)

Return type:

ndarray

align(fraction=0.1, method='fourier', manual_correction=0.0)[source]#

Aligns the IRF using the specified method.

Parameters:
Return type:

tuple[Any, …]

align_pixel(x, y, fraction=0.1, method='fourier', manual_correction=0.0)[source]#

Aligns the IRF for a single pixel (x, y) — useful for quick inspection of the alignment at a specific spatial location without processing the full data cube.

Parameters:
Return type:

Any