Skip to main content

cells.spike_triggered_population_coupling

cells.spike_triggered_population_coupling(
    spike_times,
    spike_clusters,
    cluster_ids,
    lateral_um,
    axial_um,
    radius_um,
    lags=0.08,
    binsize=BINSIZE,
    lowpass_hz=20.0,
)

Population coupling of each cluster to its local, spatially-restricted population, as defined in Bimbard, Harris & Carandini, “Invariant activity sequences across the mouse brain” (bioRxiv 2025.12.20.695676), Methods section “Population coupling”, itself an extension of Okun et al. 2015 (Nature 521, 511-515).

For cluster i, let :math:g_i(t) be the mean, across every other cluster within radius_um of it on the probe, of the mean-centred binned firing:

.. math::

g_i(t) = \frac{1}{N_i - 1}\sum_{j \in \mathrm{neighbours}(i)} (f_j(t) - \mu_j)

The coupling at lag :math:\tau is then the spike-triggered average of :math:g_i, i.e. the (normalised) cross-correlation of cluster i’s spike train with :math:g_i:

.. math::

c_{i,\tau} = 100 \times \frac{1}{\lVert f_i \rVert}
    \int f_i(t - \tau)\, g_i(t)\, dt

where :math:\lVert f_i \rVert is the number of spikes fired by cluster i. The result is expressed as a percentage and, by construction, is uncorrelated with a neuron’s own firing rate.

Parameters

Name Type Description Default
spike_times array_like Spike times (s), one entry per spike. required
spike_clusters array_like Cluster id of each spike (same length as spike_times); values are looked up in cluster_ids, so ids need not be contiguous or start at 0. required
cluster_ids array_like Cluster ids to compute the coupling for, and from which each cluster’s local population is built; defines the row order of the outputs and must align with lateral_um, axial_um. required
lateral_um array_like Cluster coordinates on the probe, one entry per entry of cluster_ids, in micrometres (the lateral_um / axial_um columns of :class:ModelClusters). required
axial_um array_like Cluster coordinates on the probe, one entry per entry of cluster_ids, in micrometres (the lateral_um / axial_um columns of :class:ModelClusters). required
radius_um float Inclusion radius for a cluster’s local population, in micrometres. A cluster with no other cluster within radius_um gets an all-nan coupling row. required
lags float or (float, float) Symmetric half-window (single float) or explicit (lag_min, lag_max) window of lags, in seconds, over which the coupling is returned. Default 0.08, i.e. [-80, 80] ms, as in Bimbard et al. 2025 (“we computed coupling within a [-80, 80] ms window”). 0.08
binsize float Bin size (s) used to bin the spike trains before cross-correlating. Default 1 ms, as in Bimbard et al. 2025. BINSIZE
lowpass_hz float or None Cutoff (Hz) of the zero-phase, 3rd-order Butterworth low-pass filter applied to each coupling curve (“low-passed filtered the coupling with a 20 Hz cutoff”). None disables filtering. Default 20.0. 20.0

Returns

Name Type Description
iblutil.util.Bunch stpc : numpy.ndarray (n_clusters, n_lags) Population coupling, in %, one row per entry of cluster_ids. tscale : numpy.ndarray (n_lags,) Lag axis (s) matching axis 1 of stpc. coupling_strength : numpy.ndarray (n_clusters,) Coupling at zero lag, stpc[:, tscale == 0]. coupling_delay : numpy.ndarray (n_clusters,) Centre of mass of the (filtered) coupling curve, in seconds, per the literal Methods definition (no absolute value). For a cluster whose coupling is weak and noisy enough that the curve’s signed sum is close to zero, this ratio can be ill-conditioned and land outside the lags window; such rows are more reliably screened out by coupling_strength than trusted for their delay. firing_rate : numpy.ndarray (n_clusters,) Mean firing rate (Hz) of each cluster over [spike_times.min(), spike_times.max()]. n_neighbours : numpy.ndarray (n_clusters,) Number of other clusters within radius_um, i.e. :math:N_i - 1.

Notes

Memory and compute scale with n_clusters ** 2 * n_bins (the local-population sum) and n_clusters * n_bins (the batched FFT cross-correlation), where n_bins = duration / binsize. For very long recordings, pre-restrict spike_times / spike_clusters to the epoch of interest (e.g. spontaneous-activity periods, as in Bimbard et al. 2025) before calling this function.