braintools.analysis.stats.phase_randomize#
- braintools.analysis.stats.phase_randomize(key, x, axis=0, same_phases=False)#
Randomise the Fourier phases of a real signal, keeping its power spectrum.
The signal is transformed with a real FFT along
axis, every Fourier coefficient is multiplied by \(e^{i\phi_f}\) with \(\phi_f \sim U(0, 2\pi)\), and the result is transformed back [1]. Because only the non-negative frequencies are randomised and the inverse real FFT restores Hermitian symmetry, the output is real and has exactly the amplitude spectrum \(|X_f|\) (hence the power spectrum and autocorrelation) of the input, while any nonlinear or phase structure is destroyed. The DC term and, for even lengths, the Nyquist term keep phase 0, so they stay real and unchanged.With
same_phases=Trueall channels share one set of random phases, which also preserves the cross-spectra and hence the (circular) cross-correlations between channels [2]. Statistics recomputed on many randomised copies give the null distribution of a significance test (the copies are called surrogate data in the literature).- Parameters:
- Returns:
Randomised signal with the shape, dtype and unit of
x.- Return type:
- Raises:
TypeError – If
xis complex oraxisis not an integer.ValueError – If
xis 0-d oraxisis out of bounds.
See also
jitter_spikesRandomised copies of spike trains.
bootstrap_ciBootstrap confidence intervals.
Notes
Works under
jax.jitandjax.vmap(vmap over keys for many copies) and is differentiable with respect tox(the map is linear inxfor a fixed key).References
Examples
>>> import jax >>> import jax.numpy as jnp >>> from braintools.analysis.stats import phase_randomize >>> x = jax.random.normal(jax.random.key(0), (256, 3)) >>> y = phase_randomize(jax.random.key(1), x) >>> y.shape (256, 3) >>> power = lambda s: jnp.abs(jnp.fft.rfft(s, axis=0)) >>> bool(jnp.allclose(power(x), power(y), atol=1e-3)) True >>> bool(jnp.allclose(x, y)) False