Ejemplo n.º 1
0
def param_sampler(params, probs=None):
    """Makes a generator to sample randomly from possible parameters.

    Parameters
    ----------
    params : list of lists or list of float
        Possible parameter values.
    probs : list of float, optional
        Probabilities with which to sample each parameter option.
        If None, each parameter option is sampled uniformly.

    Yields
    ------
    obj
        A randomly sampled element from params.
    """

    # If input is a list of lists, check each element, and flatten if needed
    if isinstance(params[0], list):
        params = [check_flat(lst) for lst in params]

    # In order to use numpy's choice, with probabilities, choices are made on indices
    # This is because the params can be a messy-sized list, that numpy choice does not like
    inds = np.array(range(len(params)))

    # While loop allows the generator to be called an arbitrary number of times.
    while True:
        yield params[np.random.choice(inds, p=probs)]
Ejemplo n.º 2
0
def param_jitter(params, jitters):
    """Create a generator that adds jitter to parameter definitions.

    Parameters
    ----------
    params : list of lists or list of float
        Possible parameter values.
    jitters : list of lists or list of float
        The scale of the jitter for each parameter.
        Must be the same shape and organization as `params`.

    Yields
    ------
    list of float
        A jittered set of parameters.

    Notes
    -----
    - Jitter is added as random samples from a normal (gaussian) distribution.

        - The jitter specified corresponds to the standard deviation of the normal distribution.
    - For any parameter for which there should be no jitter, set the corresponding value to zero.

    Examples
    --------
    Jitter aperiodic definitions, for offset and exponent, each with the same amount of jitter:

    >>> aps = param_jitter([1, 1], [0.1, 0.1])

    Jitter center frequency of peak definitions, by different amounts for alpha & beta:

    >>> peaks = param_jitter([[10, 1, 1], [20, 1, 1]], [[0.1, 0, 0], [0.5, 0, 0]])
    """

    # Check if inputs are list of lists, and flatten if so
    if isinstance(params[0], list):
        params = check_flat(params)
        jitters = check_flat(jitters)

    # While loop allows the generator to be called an arbitrary number of times
    while True:

        out_params = [None] * len(params)
        for ind, (param, jitter) in enumerate(zip(params, jitters)):
            out_params[ind] = param + np.random.normal(0, jitter)

        yield out_params
Ejemplo n.º 3
0
def gen_power_spectrum(freq_range,
                       aperiodic_params,
                       gauss_params,
                       nlv=0.005,
                       freq_res=0.5):
    """Generate a synthetic power spectrum.

    Parameters
    ----------
    freq_range : list of [float, float]
        Minimum and maximum values of the desired frequency vector.
    aperiodic_params : list of float
        Parameters to create the aperiodic component of a power spectrum. Length of 2 or 3 (see note).
    gauss_params : list of float or list of list of float
        Parameters to create peaks. Total length of n_peaks * 3 (see note).
    nlv : float, optional
        Noise level to add to generated power spectrum. Default: 0.005
    freq_res : float, optional
        Frequency resolution for the synthetic power spectra. Default: 0.5

    Returns
    -------
    freqs : 1d array
        Frequency values, in linear space.
    powers : 1d array
        Power values, in linear space.

    Notes
    -----
    Aperiodic Parameters:
        - The function for the aperiodic process to use is inferred from the provided parameters.
            - If length of 2, the 'fixed' aperiodic mode is used, if length of 3, 'knee' is used.
    Gaussian Parameters:
        - Each gaussian description is a set of three values:
            - mean (Center Frequency), amplitude (Amplitude), and std (Bandwidth)
            - Make sure any center frequencies you request are within the simulated frequency range
        - The total number of parameters that need to be specified is number of peaks * 3
            - These can be specified in as all together in a flat list.
                - For example: [10, 1, 1, 20, 0.5, 1]
            - They can also be grouped into a list of lists
                - For example: [[10, 1, 1], [20, 0.5, 1]]

    Examples
    --------

    Generate a power spectrum with a single

    >>> freqs, psd = gen_power_spectrum([1, 50], [0, 2], [10, 1, 1])

    Generate a power spectrum with alpha and beta peaks

    >>> freqs, psd = gen_power_spectrum([1, 50], [0, 2], [[10, 1, 1], [20, 0.5, 1]])
    """

    freqs = gen_freqs(freq_range, freq_res)
    powers = gen_power_vals(freqs, aperiodic_params, check_flat(gauss_params),
                            nlv)

    return freqs, powers
Ejemplo n.º 4
0
def param_sampler(params, probs=None):
    """Create a generator to sample randomly from possible parameters.

    Parameters
    ----------
    params : list of lists or list of float
        Possible parameter values.
    probs : list of float, optional
        Probabilities with which to sample each parameter option.
        If None, each parameter option is sampled uniformly.

    Yields
    ------
    list of float
        A randomly sampled set of parameters.

    Examples
    --------
    Sample from aperiodic definitions with high and low exponents, with 50% probability of each:

    >>> aps = param_sampler([[1, 1], [2, 1]], probs=[0.5, 0.5])

    Sample from peak definitions of alpha or alpha & beta, with 75% change of sampling just alpha:

    >>> peaks = param_sampler([[10, 1, 1], [[10, 1, 1], [20, 0.5, 1]]], probs=[0.75, 0.25])
    """

    # If input is a list of lists, check each element, and flatten if needed
    if isinstance(params[0], list):
        params = [check_flat(lst) for lst in params]

    # In order to use numpy's choice, with probabilities, choices are made on indices
    # This is because the params can be a messy-sized list, that numpy choice does not like
    inds = np.array(range(len(params)))

    # Check that length of options is same as length of probs, if provided
    if np.any(probs):
        if len(inds) != len(probs):
            raise ValueError(
                "The number of options must match the number of probabilities."
            )

    # While loop allows the generator to be called an arbitrary number of times
    while True:
        yield params[np.random.choice(inds, p=probs)]
Ejemplo n.º 5
0
def collect_sim_params(aperiodic_params, periodic_params, nlv):
    """Collect simulation parameters into a SimParams object.

    Parameters
    ----------
    aperiodic_params : list of float
        Parameters of the aperiodic component of the power spectrum.
    periodic_params : list of float or list of list of float
        Parameters of the periodic component of the power spectrum.
    nlv : float
        Noise level of the power spectrum.

    Returns
    -------
    SimParams
        Object containing the simulation parameters.
    """

    return SimParams(aperiodic_params.copy(),
                     sorted(group_three(check_flat(periodic_params))), nlv)
Ejemplo n.º 6
0
def gen_power_spectrum(freq_range,
                       aperiodic_params,
                       periodic_params,
                       nlv=0.005,
                       freq_res=0.5,
                       f_rotation=None,
                       return_params=False):
    """Generate a simulated power spectrum.

    Parameters
    ----------
    freq_range : list of [float, float]
        Frequency range to simulate power spectrum across, as [f_low, f_high], inclusive.
    aperiodic_params : list of float
        Parameters to create the aperiodic component of a power spectrum.
        Length should be 2 or 3 (see note).
    periodic_params : list of float or list of list of float
        Parameters to create the periodic component of a power spectrum.
        Total length of n_peaks * 3 (see note).
    nlv : float, optional, default: 0.005
        Noise level to add to generated power spectrum.
    freq_res : float, optional, default: 0.5
        Frequency resolution for the simulated power spectrum.
    f_rotation : float, optional
        Frequency value, in Hz, to rotate around.
        Should only be set if spectrum is to be rotated.
    return_params : bool, optional, default: False
        Whether to return the parameters for the simulated spectrum.

    Returns
    -------
    freqs : 1d array
        Frequency values, in linear spacing.
    powers : 1d array
        Power values, in linear spacing.
    sim_params : SimParams
        Definition of parameters used to create the spectrum.
        Only returned if `return_params` is True.

    Notes
    -----
    Aperiodic Parameters:

    - The function for the aperiodic process to use is inferred from the provided parameters.
    - If length of 2, the 'fixed' aperiodic mode is used, if length of 3, 'knee' is used.

    Periodic Parameters:

    - The periodic component is comprised of a set of 'peaks', each of which is described as:

      * Mean (Center Frequency), height (Power), and standard deviation (Bandwidth).
      * Make sure any center frequencies you request are within the simulated frequency range.

    - The total number of parameters that need to be specified is number of peaks * 3

      * These can be specified in as all together in a flat list (ex: [10, 1, 1, 20, 0.5, 1])
      * They can also be grouped into a list of lists (ex: [[10, 1, 1], [20, 0.5, 1]])

    Rotating Power Spectra:

    - You can optionally specify a rotation frequency, such that power spectra will be
      simulated and rotated around that point to the specified aperiodic exponent.

      * This can be used so that any power spectra simulated with the same 'f_rotation'
        will relate to each other by having the specified rotation point.

    - Note that rotating power spectra changes the offset.

      * If you specify an offset value to simulate as well as 'f_rotation', the returned
        spectrum will NOT have the requested offset. It instead will have the offset
        value required to create the requested aperiodic exponent with the requested
        rotation point.
      * If you return SimParams, the recorded offset will be the calculated offset
        of the data post rotation, and not the entered value.

    - You cannot rotate power spectra simulated with a knee.

      * The procedure we use to rotate does not support spectra with a knee, and so
        setting 'f_rotation' with a knee will lead to an error.

    Examples
    --------
    Generate a power spectrum with a single peak, at 10 Hz:

    >>> freqs, powers = gen_power_spectrum([1, 50], [0, 2], [10, 0.5, 1])

    Generate a power spectrum with alpha and beta peaks:

    >>> freqs, powers = gen_power_spectrum([1, 50], [0, 2], [[10, 0.5, 1], [20, 0.5, 1]])

    Generate a power spectrum, that was rotated around a particular frequency point:

    >>> freqs, powers = gen_power_spectrum([1, 50], [None, 2], [10, 0.5, 1], f_rotation=15)
    """

    freqs = gen_freqs(freq_range, freq_res)

    if f_rotation:

        powers = gen_rotated_power_vals(freqs, aperiodic_params,
                                        check_flat(periodic_params), nlv,
                                        f_rotation)

        # The rotation changes the offset, so recalculate it's value & update params
        new_offset = compute_rotation_offset(aperiodic_params[1], f_rotation)
        aperiodic_params = [new_offset, aperiodic_params[1]]

    else:

        powers = gen_power_vals(freqs, aperiodic_params,
                                check_flat(periodic_params), nlv)

    if return_params:
        sim_params = collect_sim_params(aperiodic_params, periodic_params, nlv)
        return freqs, powers, sim_params
    else:
        return freqs, powers
Ejemplo n.º 7
0
def gen_group_power_spectra(n_spectra,
                            freq_range,
                            aperiodic_params,
                            periodic_params,
                            nlvs=0.005,
                            freq_res=0.5,
                            f_rotation=None,
                            return_params=False):
    """Generate a group of simulated power spectra.

    Parameters
    ----------
    n_spectra : int
        The number of power spectra to generate.
    freq_range : list of [float, float]
        Frequency range to simulate power spectra across, as [f_low, f_high], inclusive.
    aperiodic_params : list of float or generator
        Parameters for the aperiodic component of the power spectra.
    periodic_params : list of float or generator
        Parameters for the periodic component of the power spectra.
        Length of n_peaks * 3.
    nlvs : float or list of float or generator, optional, default: 0.005
        Noise level to add to generated power spectrum.
    freq_res : float, optional, default: 0.5
        Frequency resolution for the simulated power spectra.
    f_rotation : float, optional
        Frequency value, in Hz, to rotate around.
        Should only be set if spectra are to be rotated.
    return_params : bool, optional, default: False
        Whether to return the parameters for the simulated spectra.

    Returns
    -------
    freqs : 1d array
        Frequency values, in linear spacing.
    powers : 2d array
        Matrix of power values, in linear spacing, as [n_power_spectra, n_freqs].
    sim_params : list of SimParams
        Definitions of parameters used for each spectrum. Has length of n_spectra.
        Only returned if `return_params` is True.

    Notes
    -----
    Parameters options can be:

    - A single set of parameters.
      If so, these same parameters are used for all spectra.
    - A list of parameters whose length is n_spectra.
      If so, each successive parameter set is such for each successive spectrum.
    - A generator object that returns parameters for a power spectrum.
      If so, each spectrum has parameters sampled from the generator.

    Aperiodic Parameters:

    - The function for the aperiodic process to use is inferred from the provided parameters.
    - If length of 2, the 'fixed' aperiodic mode is used, if length of 3, 'knee' is used.

    Periodic Parameters:

    - The periodic component is comprised of a set of 'peaks', each of which is described as:

      * Mean (Center Frequency), height (Power), and standard deviation (Bandwidth).
      * Make sure any center frequencies you request are within the simulated frequency range.

    Rotating Power Spectra:

    - You can optionally specify a rotation frequency, such that power spectra will be
      simulated and rotated around that point to the specified aperiodic exponent.

      * This can be used so that any power spectra simulated with the same 'f_rotation'
        will relate to each other by having the specified rotation point.

    - Note that rotating power spectra changes the offset.

      * If you specify an offset value to simulate as well as 'f_rotation', the returned
        spectrum will NOT have the requested offset. It instead will have the offset
        value required to create the requested aperiodic exponent with the requested
        rotation point.
      * If you return SimParams, the recorded offset will be the calculated offset
        of the data post rotation, and not the entered value.

    - You cannot rotate power spectra simulated with a knee.

      * The procedure we use to rotate does not support spectra with a knee, and so
        setting 'f_rotation' with a knee will lead to an error.

    Examples
    --------
    Generate 2 power spectra using the same parameters:

    >>> freqs, powers = gen_group_power_spectra(2, [1, 50], [0, 2], [10, 0.5, 1])

    Generate 10 power spectra, randomly sampling possible parameters:

    >>> from fooof.sim.params import param_sampler
    >>> ap_opts = param_sampler([[0, 1.0], [0, 1.5], [0, 2]])
    >>> pe_opts = param_sampler([[], [10, 0.5, 1], [10, 0.5, 1, 20, 0.25, 1]])
    >>> freqs, powers = gen_group_power_spectra(10, [1, 50], ap_opts, pe_opts)

    Generate 5 power spectra, rotated around 20 Hz:

    >>> ap_params = [[None, 1], [None, 1.25], [None, 1.5], [None, 1.75], [None, 2]]
    >>> pe_params = [10, 0.5, 1]
    >>> freqs, powers = gen_group_power_spectra(5, [1, 50], ap_params, pe_params, f_rotation=20)

    Generate power spectra stepping across exponent values, and return parameter values:

    >>> from fooof.sim.params import Stepper, param_iter
    >>> ap_params = param_iter([0, Stepper(1, 2, 0.25)])
    >>> pe_params = [10, 0.5, 1]
    >>> freqs, powers, sps = gen_group_power_spectra(5, [1, 50], ap_params, pe_params,
    ...                                              return_params=True)
    """

    # Initialize things
    freqs = gen_freqs(freq_range, freq_res)
    powers = np.zeros([n_spectra, len(freqs)])
    sim_params = [None] * n_spectra

    # Check if inputs are generators, if not, make them into repeat generators
    ap_params = check_iter(aperiodic_params, n_spectra)
    pe_params = check_iter(periodic_params, n_spectra)
    nlvs = check_iter(nlvs, n_spectra)
    f_rots = check_iter(f_rotation, n_spectra)

    # Simulate power spectra
    for ind, ap, pe, nlv, f_rot in zip(range(n_spectra), ap_params, pe_params,
                                       nlvs, f_rots):

        if f_rotation:
            powers[ind, :] = gen_rotated_power_vals(freqs, ap, check_flat(pe),
                                                    nlv, f_rot)
            aperiodic_params = [compute_rotation_offset(ap[1], f_rot), ap[1]]

        else:
            powers[ind, :] = gen_power_vals(freqs, ap, check_flat(pe), nlv)

        sim_params[ind] = collect_sim_params(ap, pe, nlv)

    if return_params:
        return freqs, powers, sim_params
    else:
        return freqs, powers