Source code for stimupy.noises.naturals

import numpy as np

from stimupy.noises import pseudo_white_spectrum
from stimupy.utils import resolution
from stimupy.utils.contrast_conversions import adapt_intensity_range

__all__ = [
    "one_over_f",
    "pink",
    "brown",
]


[docs]def one_over_f( visual_size=None, ppd=None, shape=None, exponent=None, intensity_range=(0, 1), pseudo_noise=False, ): """Draw 1 / (f**exponent) noise texture Parameters ---------- visual_size : Sequence[Number, Number], Number, or None (default) visual size [height, width] of grating, in degrees ppd : Sequence[Number, Number], Number, or None (default) pixels per degree [vertical, horizontal] shape : Sequence[Number, Number], Number, or None (default) shape [height, width] of grating, in pixels exponent exponent used to create 1 / (f**exponent) noise intensity_range : Sequence[Number, Number] minimum and maximum intensity value; default: (0, 1). be aware that not every instance has mean=(max-min)/2. pseudo_noise : bool if True, generate pseudo-random noise with ideal power spectrum. Returns ------- dict[str, Any] dict with the stimulus (key: "img"), and additional keys containing stimulus parameters """ if exponent is None: raise ValueError("one_over_f() missing argument 'exponent' which is not 'None'") # Resolve resolution shape, visual_size, ppd = resolution.resolve(shape=shape, visual_size=visual_size, ppd=ppd) if len(np.unique(ppd)) > 1: raise ValueError("ppd should be equal in x and y direction") # Prepare spatial frequency axes and create bandpass filter: fy = np.fft.fftshift(np.fft.fftfreq(shape[0], d=1.0 / np.unique(ppd))) fx = np.fft.fftshift(np.fft.fftfreq(shape[1], d=1.0 / np.unique(ppd))) Fx, Fy = np.meshgrid(fx, fy) # Create 2d array with 1 / (f**exponent) f = np.sqrt(Fy**2.0 + Fx**2.0) f = f**exponent f[f == 0.0] = 1.0 # Prevent division by zero (DC is zero anyways) if pseudo_noise: # Create white noise with frequency amplitude of 1 everywhere white_noise_fft = pseudo_white_spectrum(shape) else: # Create white noise and fft white_noise = np.random.rand(*shape) * 2.0 - 1.0 white_noise_fft = np.fft.fftshift(np.fft.fft2(white_noise)) # Create 1/f noise: noise_fft = white_noise_fft / f # ifft noise = np.fft.ifft2(np.fft.ifftshift(noise_fft)) noise = np.real(noise) # Adjust intensity range: noise = adapt_intensity_range(noise, intensity_range[0], intensity_range[1]) stim = { "img": noise, "noise_mask": None, "visual_size": visual_size, "ppd": ppd, "shape": shape, "exponent": exponent, "pseudo_noise": pseudo_noise, "intensity_range": [noise.min(), noise.max()], } return stim
[docs]def pink( visual_size=None, ppd=None, shape=None, intensity_range=(0, 1), pseudo_noise=False, ): """Draw pink (1 / f) noise texture Parameters ---------- visual_size : Sequence[Number, Number], Number, or None (default) visual size [height, width] of grating, in degrees ppd : Sequence[Number, Number], Number, or None (default) pixels per degree [vertical, horizontal] shape : Sequence[Number, Number], Number, or None (default) shape [height, width] of grating, in pixels intensity_range : Sequence[Number, Number] minimum and maximum intensity value; default: (0, 1). be aware that not every instance has mean=(max-min)/2. pseudo_noise : bool if True, generate pseudo-random noise with ideal power spectrum Returns ------- A stimulus dictionary with the noise array ['img'] """ stim = one_over_f( visual_size=visual_size, ppd=ppd, exponent=1.0, intensity_range=intensity_range, pseudo_noise=pseudo_noise, ) return stim
[docs]def brown( visual_size=None, ppd=None, shape=None, intensity_range=(0, 1), pseudo_noise=False, ): """Draw brown (1 / (f**2.0)) noise texture Parameters ---------- visual_size : Sequence[Number, Number], Number, or None (default) visual size [height, width] of grating, in degrees ppd : Sequence[Number, Number], Number, or None (default) pixels per degree [vertical, horizontal] shape : Sequence[Number, Number], Number, or None (default) shape [height, width] of grating, in pixels intensity_range : Sequence[Number, Number] minimum and maximum intensity value; default: (0, 1) be aware that not every instance has mean=(max-min)/2. pseudo_noise : bool if True, generate pseudo-random noise with ideal power spectrum Returns ------- A stimulus dictionary with the noise array ['img'] """ stim = one_over_f( visual_size=visual_size, ppd=ppd, exponent=2.0, intensity_range=intensity_range, pseudo_noise=pseudo_noise, ) return stim
def overview(**kwargs): """Generate example stimuli from this module Returns ------- stims : dict dict with all stimuli containing individual stimulus dicts. """ default_params = { "visual_size": 10, "ppd": 10, } default_params.update(kwargs) # fmt: off stimuli = { "naturals_one-over-f": one_over_f(**default_params, exponent=0.5), "naturals_pink": pink(**default_params), "naturals_brown": brown(**default_params), } # fmt: on return stimuli if __name__ == "__main__": from stimupy.utils import plot_stimuli stims = overview() plot_stimuli(stims, mask=False, save=None)