8  Lifetime Features (Fit-Free)

Phasor analysis provides a fast, model-free view of lifetimes by transforming fluorescence decays into phasor coordinates through a Fourier transform. This approach is considered “fit-free” because it does not require iterative curve fitting or predefined decay models—each decay is mapped directly to a point on the phasor plot. It has the nice property that mono-exponential decays fall on the universal semicircle while mixtures lie inside as linear combinations, so clusters reveal distinct species and their fractional contributions. FLIM Playground currently extracts cell-level phasor features: G(1st), S(1st), Tau_phase, Tau_mod, G(2nd), and S(2nd). (Datasets extracted before this feature was renamed use Tau_m, which Data Analysis still recognizes.)

Fit-free features in the final dataset are prefixed by the combination of the feature extractor name (i.e. Lifetime fit free) and the channel name, allowing Data Analysis to group the features. For example, Lifetime fit free_nadh: G(1st) means the \(g\) coordinate for this cell in the NAD(P)H channel.

8.1 Preprocessing

For image inputs, the app sums the pixel decays within each cell ROI labeled by the ROI mask to obtain one cell decay1. For 2D decay inputs, each CSV row already supplies a cell decay, so no mask is needed. Phasor features are calculated from each cell decay.

Two preprocessing steps are then applied, and they are independent of each other:

  • Offset subtraction is applied to every decay curve, regardless of the chosen calibration method. For each cell, the offset is estimated as the mean of the last 10% of the time bins of that cell’s own decay curve, subtracted from the curve, and any resulting negative values are clipped to zero. Note that this per-cell baseline is unrelated to the offset parameter fitted during lifetime fitting.
  • IRF shifting is applied only when the chosen calibration method is IRF shift calibration. The IRF is shifted using the shift values as described in the Shift IRF step. Under fluorescence lifetime standard calibration, no IRF shift is applied.

8.2 Calibration method

In Home → Configuration, choose IRF or Fluorescence Lifetime Standard for Lifetime fit free extraction. This choice determines the reference and the correction applied in Step 2. Both methods use the same offset subtraction for each cell decay.

8.2.1 IRF

Provide an IRF for each channel that uses this method, then complete fit-free IRF calibration. The app shifts the IRF using the selected shift values and calculates its first- and second-harmonic phasors. It divides each cell’s raw phasor by the shifted IRF phasor at the same harmonic.

8.2.2 Fluorescence lifetime standard

Provide a calibration dye with a known lifetime, enter that lifetime in nanoseconds, and set each channel’s standard-file suffix. This method does not apply an IRF shift to the phasor calculation.

The app calculates the standard’s measured phasor separately at each harmonic. PhasorPy’s lifetime.phasor_calibrate uses those measurements and the known lifetime to correct each cell’s phasor at the matching harmonic.

Selecting raw Lifetime fit as well still requires IRF shift calibration for fitting; the standard only calibrates the phasor features.

8.3 Phasor features

The steps below describe default phases, followed by IRF or lifetime-standard calibration and lifetime conversion. FLIM Playground uses this workflow when the supplied time window matches one laser period. Its explicit-phase calculation for other windows is described in the collapsible note at the end.

8.3.1 Step 1: raw phasor coordinates

Default phases

Let \(T\) be the supplied window’s duration in ns and \(K\) its number of bins. PhasorPy’s phasor_from_signal assigns phases \(2\pi hk/K\), where \(h\) is the harmonic and \(k=0,\ldots,K-1\) is the bin index. The raw transform uses bin positions and count; neither duration nor laser_rate is passed to it. The stored bins and photon counts are unchanged.

For bin times \(t_k=kT/K\), these default phases correspond to an analysis frequency of \(1/T\). In the matching-window case described here, that equals the laser frequency (laser_rate, in GHz), which is used in the calibration and lifetime equations below. For a decay \(F_k\):

\[ \begin{aligned} g_{\mathrm{raw}}^{(h)} &= \frac{\sum_{k=0}^{K-1}F_k\cos\!\left(2\pi h k/K\right)} {\sum_{k=0}^{K-1}F_k},\\ s_{\mathrm{raw}}^{(h)} &= \frac{\sum_{k=0}^{K-1}F_k\sin\!\left(2\pi h k/K\right)} {\sum_{k=0}^{K-1}F_k}. \end{aligned} \]

In this default-phase workflow, the app calls phasor_from_signal with harmonic=1 and harmonic=2 for each cell decay to obtain g_raw, s_raw, g_raw_2nd, and s_raw_2nd.

With IRF calibration, it makes the same two calls for the shifted IRF, obtaining g_irf, s_irf, g_irf_2nd, and s_irf_2nd.

With fluorescence lifetime standard calibration, it calculates the reference values separately for each harmonic as shown below. reference_image is the loaded standard decay array, and reference_time_axis is its zero-based time-bin axis (for example, 2 for an array shaped (height, width, time_bins)).

from phasorpy import phasor

ref_mean, ref_real, ref_imag = phasor.phasor_from_signal(
    reference_image, axis=reference_time_axis, harmonic=1,
)
ref_mean_2nd, ref_real_2nd, ref_imag_2nd = phasor.phasor_from_signal(
    reference_image, axis=reference_time_axis, harmonic=2,
)

8.3.2 Step 2: calibrated phasor coordinates

Apply the selected calibration using the reference phasor at the matching harmonic.

IRF calibration

FLIM Playground divides each raw cell phasor by the shifted IRF phasor at the same harmonic to obtain g, s, g_2nd, and s_2nd:

from phasorpy import phasor
g, s = phasor.phasor_divide(g_raw, s_raw, g_irf, s_irf)
g_2nd, s_2nd = phasor.phasor_divide(
    g_raw_2nd, s_raw_2nd, g_irf_2nd, s_irf_2nd
)

Fluorescence lifetime standard calibration

FLIM Playground uses the known lifetime and the standard’s measured reference values for each harmonic calculated in Step 1:

from phasorpy import lifetime

g, s = lifetime.phasor_calibrate(
    g_raw, s_raw, ref_mean, ref_real, ref_imag,
    frequency=laser_rate * 1000,
    lifetime=reference_dye_lifetime,
)
g_2nd, s_2nd = lifetime.phasor_calibrate(
    g_raw_2nd, s_raw_2nd,
    ref_mean_2nd, ref_real_2nd, ref_imag_2nd,
    frequency=laser_rate * 1000,
    lifetime=reference_dye_lifetime,
    harmonic=2,
)

The laser rate is entered in MHz in Numerical source settings or Configuration, then stored internally as laser_rate in GHz. PhasorPy expects MHz, so both calls multiply the stored value by 1000: an entered 80 MHz is stored as 0.08 GHz and passed to PhasorPy as 80 MHz. The reference_dye_lifetime remains in nanoseconds. Using harmonic=2 calibrates the second-harmonic coordinates at twice the laser frequency.

8.3.3 Step 3: phasor-derived lifetime

Tau_phase and Tau_mod are calculated using the first harmonic’s phasor coordinates g and s.

import numpy as np
w = 2 * np.pi * laser_rate
phi = np.arctan2(s, g) 
mod = np.sqrt(g**2 + s**2)
tau_phase = 1/w * np.tan(phi)
tau_mod = 1/w * np.sqrt(1/mod**2 - 1)

\[ \phi = \operatorname{atan2}(s,\,g), \mathrm{mod} = \sqrt{g^{2}+s^{2}}, \tau_{\phi} = \frac{\tan \phi}{\omega}, \tau_{\mathrm{mod}} = \frac{1}{\omega}\sqrt{\frac{1}{\mathrm{mod}^{2}}-1} \]

Because \(\omega\) is derived from the laser rate in GHz, Tau_phase and Tau_mod are expressed in nanoseconds. Note that this differs from the Lifetime fit extractor, whose lifetime columns are exported in picoseconds.

FLIM Playground uses explicit phases when the supplied time window differs from one laser period by more than a small rounding tolerance. It then calculates phasors at the laser frequency, using both duration and laser_rate to place each bin within the laser cycle. A shortened acquisition window or a small difference caused by PTU bin rounding can select this branch; it is not a test for whether the acquisition was complete.

For example, a 10 ns window with a 12.5 ns laser period covers 80% of a laser cycle. Let \(f\) be laser_rate, \(P=1/f\) the laser period, and \(T\) the supplied window’s duration. The bin times are \(t_k=kT/K\), with first-harmonic phases \(\phi_k=2\pi t_k/P=2\pi f t_k\). At harmonic \(h\):

\[ \begin{aligned} g_{\mathrm{raw}}^{(h)} &= \frac{\sum_{k=0}^{K-1} F_k \cos(h\phi_k)} {\sum_{k=0}^{K-1} F_k},\\ s_{\mathrm{raw}}^{(h)} &= \frac{\sum_{k=0}^{K-1} F_k \sin(h\phi_k)} {\sum_{k=0}^{K-1} F_k}. \end{aligned} \]

For cell decays and the shifted IRF, the app evaluates these sums directly. For a fluorescence lifetime standard, it supplies the same phases through PhasorPy’s sample_phase argument. The standard must have the same bin count and spacing as the sample:

import numpy as np
from phasorpy import phasor

time_bins = reference_image.shape[reference_time_axis]
time_axis = np.arange(time_bins) * (duration / time_bins)  # ns
phi = 2 * np.pi * laser_rate * time_axis

ref_mean, ref_real, ref_imag = phasor.phasor_from_signal(
    reference_image, axis=reference_time_axis,
    sample_phase=phi, harmonic=1, use_fft=False,
)
ref_mean_2nd, ref_real_2nd, ref_imag_2nd = phasor.phasor_from_signal(
    reference_image, axis=reference_time_axis,
    sample_phase=2 * phi, harmonic=1, use_fft=False,
)

Use harmonic=1 and use_fft=False with sample_phase. The doubled phases select the second harmonic; harmonic=2 with sample_phase would raise an error. The resulting coordinates enter the calibration and lifetime calculations in Steps 2 and 3.

Explicit phases preserve bin timing but do not recover missing fluorescence. For a substantially truncated window, the usual calibration and lifetime equations can remain biased; a standard measured over the same window does not generally remove that bias.

1.
Samimi, K. et al. Segmentation-guided photon pooling enables robust single cell analysis and fast fluorescence lifetime imaging microscopy. bioRxiv https://doi.org/10.1101/2025.09.30.679660 (2025) doi:10.1101/2025.09.30.679660.