phase_locking_value

phase_locking_value#

class braintools.metric.phase_locking_value(spike_matrix, reference_freq, dt=None)#

Calculate phase-locking value (PLV) for spike synchronization.

The PLV measures the consistency of phase relationships between spike trains and a reference oscillation, indicating rhythmic synchronization.

For each spike, the phase relative to the reference oscillation is computed, and the PLV is the magnitude of the mean resultant vector:

\[PLV = \left|\frac{1}{N}\sum_{k=1}^{N} e^{i\phi_k}\right|\]

where \(\phi_k\) is the phase of the k-th spike.

Parameters:
  • spike_matrix (Array | ndarray | bool | number | bool | int | float | complex | Quantity) – Spike matrix with shape (n_time_steps, n_neurons).

  • reference_freq (float) – Reference frequency for phase computation (in Hz).

  • dt (float | Quantity) – Time step between successive samples. If None, uses the brainstate default. A plain float is assumed to be in seconds (so that it is consistent with reference_freq in Hz); a brainunit.Quantity is converted to seconds.

Returns:

Phase-locking values for each neuron. Shape (n_neurons,). Values range from 0 (no phase locking) to 1 (perfect phase locking).

Return type:

jnp.ndarray

Notes

This computes the vector strength (Rayleigh resultant length) of each neuron’s spikes relative to an external reference oscillation of frequency reference_freq. It is therefore a spike–field locking measure, not the Lachaux et al. (1999) pairwise PLV between two continuous signals.

Vector strength is biased upward for small spike counts: a neuron with a single spike trivially yields PLV = 1, and a handful of spikes can give a large value by chance. Interpret values with caution when spike counts are low, and consider a Rayleigh-style bias correction or a minimum-spike threshold.

This function runs on host (concrete) arrays (Python loop over neurons, boolean-mask indexing), so it is not jit/vmap/grad-compatible.

References

Examples

>>> import jax.numpy as jnp
>>> import braintools
>>> n_time, n_neurons = 1000, 5
>>> spikes = jnp.zeros((n_time, n_neurons))
>>> freq, dt = 10.0, 0.001  # 10 Hz reference, 1 ms step
>>> # Place one spike per 10 Hz cycle for neuron 0 (strong locking).
>>> idx = (jnp.arange(10) / freq / dt).astype(int)
>>> spikes = spikes.at[idx, 0].set(1.0)
>>> plv = braintools.metric.phase_locking_value(spikes, freq, dt)
>>> plv.shape
(5,)