Source code for neuralfieldmanifold.simulation.noise
"""White and power-law colored noise generators."""
import numpy as np
from .._validation import positive_integer
[docs]
def white_noise(n_samples, *, seed=0):
"""Return standard-normal samples from NumPy's default generator."""
return np.random.default_rng(seed).normal(
size=positive_integer(n_samples, "n_samples")
)
[docs]
def colored_noise(n_samples, *, exponent=1.0, seed=0, spectrum=None):
"""Generate zero-mean, unit-variance noise with a power-law spectrum.
Parameters
----------
n_samples : int
Number of output samples, at least two.
exponent : float
Spectral exponent; power is proportional to 1/f**exponent.
seed : int
Seed for the NumPy random generator.
spectrum : array_like of complex or None
Optional unweighted Fourier bins, shape (n_samples // 2 + 1,).
When supplied, these replace the random Fourier coefficients.
Returns
-------
ndarray, shape (n_samples,)
Real-valued colored noise.
"""
n_samples = positive_integer(n_samples, "n_samples")
if n_samples < 2 or not np.isfinite(exponent):
raise ValueError("Require n_samples >= 2 and finite exponent")
if spectrum is None:
rng = np.random.default_rng(seed)
size = n_samples // 2 + 1
spectrum = rng.normal(size=size) + 1j * rng.normal(size=size)
spectrum = np.asarray(spectrum)
if spectrum.shape != (n_samples // 2 + 1,) or not np.isfinite(spectrum).all():
raise ValueError("spectrum must have n_samples // 2 + 1 finite complex entries")
frequencies = np.fft.rfftfreq(n_samples)
weights = np.zeros_like(frequencies)
weights[1:] = 1.0 / frequencies[1:] ** (exponent / 2)
x = np.fft.irfft(spectrum * weights, n=n_samples)
return (x - x.mean()) / (x.std() + 1e-12)