Exemplo n.º 1
0
def sim_cycle(n_seconds, fs, cycle_type, **cycle_params):
    """Simulate a single cycle of a periodic pattern.

    Parameters
    ----------
    n_seconds : float
        Length of cycle window in seconds.
        This is NOT the period of the cycle, but the length of the returned array of the cycle.
    fs : float
        Sampling frequency of the cycle simulation.
    cycle_type : {'sine', 'asine', 'sawtooth', 'gaussian', 'exp', '2exp'}
        What type of cycle to simulate. Options:

        * sine: a sine wave cycle
        * asine: an asymmetric sine wave
        * sawtooth: a sawtooth wave
        * gaussian: a gaussian cycle
        * exp: a cycle with exponential decay
        * 2exp: a cycle with exponential rise and decay

    **cycle_params
        Keyword arguments for parameters of the cycle, all as float:

        * sine: None
        * asine: `rdsym`, rise-decay symmetry, from 0-1
        * sawtooth: `width`, width of the rising ramp as a proportion of the total cycle
        * gaussian: `std`, standard deviation of the gaussian kernel, in seconds
        * exp: `tau_d`, decay time, in seconds
        * 2exp: `tau_r` & `tau_d` rise time, and decay time, in seconds

    Returns
    -------
    cycle: 1d array
        Simulated cycle.

    Examples
    --------
    Simulate a half second sinusoid, corresponding to a 2 Hz cycle (frequency=1/n_seconds):

    >>> cycle = sim_cycle(n_seconds=0.5, fs=500, cycle_type='sine')

    Simulate a sawtooth cycle, corresponding to a 10 Hz cycle:

    >>> cycle = sim_cycle(n_seconds=0.1, fs=500, cycle_type='sawtooth', width=0.3)

    Notes
    -----
    Any function defined in sim.cycles as `sim_label_cycle(n_seconds, fs, **params)`,
    is accessible by this function. The `cycle_type` input must match the label.
    """

    cycle_func = get_sim_func('sim_' + cycle_type + '_cycle',
                              modules=['cycles'])
    cycle = cycle_func(n_seconds, fs, **cycle_params)

    return cycle
Exemplo n.º 2
0
def sim_combined(n_seconds, fs, simulations, variances=1):
    """Sim multiple component signals and combine them.

    Parameters
    ----------
    n_seconds : float
        Signal duration, in seconds.
    fs : float
        Signal sampling rate, in Hz.
    simulations : dictionary
        A dictionary of simulation functions to run, with their desired parameters.
    variances : list of float or 1
        Specified variance for each component of the signal.

    Returns
    -------
    sig : 1d array
        Simulated combined signal.
    """

    # Check how simulations are specified, in terms of number of parameter sets
    n_sims = sum([1 if isinstance(params, dict) else len(params) \
        for params in simulations.values()])

    # Check that the variance definition matches the number of components specified
    if not (variances == 1 or len(variances) == n_sims):
        raise ValueError('Simulations and proportions lengths do not match.')

    # Collect the sim function to use, and repeat variance if is set to 1
    simulations = {(get_sim_func(name) if isinstance(name, str) else name) : params \
                   for name, params in simulations.items()}
    variances = repeat(variances) if isinstance(variances, int) else variances

    # Simulate each component, specifying the variance for each
    components = []
    for (func, params), variance in zip(simulations.items(), variances):

        # If list, params should be a list of separate parameters for each fucntion call
        if isinstance(params, list):
            components.extend([func(n_seconds, fs, **cur_params, variance=variance) \
                for cur_params in params])

        # Otherwise, params should be a dictionary of parameters for single call
        else:
            components.append(func(n_seconds, fs, **params, variance=variance))

    # Combine total signal across all simulated components
    sig = np.sum(components, axis=0)

    return sig
Exemplo n.º 3
0
def sim_combined(n_seconds, fs, components, component_variances=1):
    """Simulate a signal by combining multiple component signals.

    Parameters
    ----------
    n_seconds : float
        Simulation time, in seconds.
    fs : float
        Signal sampling rate, in Hz.
    components : dictionary
        A dictionary of simulation functions to run, with their desired parameters.
    component_variances : list of float or 1, optional, default: 1
        Variance to simulate with for each component of the signal.
        If 1, each component signal is simulated with unit variance.

    Returns
    -------
    sig : 1d array
        Simulated combined signal.

    Examples
    --------
    Simulate a combined signal with an aperiodic and periodic component:

    >>> sim_components = {'sim_powerlaw': {'exponent' : -2}, 'sim_oscillation': {'freq' : 10}}
    >>> sig = sim_combined(n_seconds=1, fs=500, components=sim_components)

    Simulate a combined signal with multiple periodic components:

    >>> sim_components = {'sim_powerlaw': {'exponent' : -2},
    ...                   'sim_oscillation': [{'freq' : 10}, {'freq' : 20}]}
    >>> sig = sim_combined(n_seconds=1, fs=500, components=sim_components)

    Simulate a combined signal with unequal variance for the different components:

    >>> sig = sim_combined(n_seconds=1, fs=500,
    ...                    components={'sim_powerlaw': {}, 'sim_oscillation': {'freq' : 10}},
    ...                    component_variances=[0.25, 0.75])
    """

    # Check how simulation components are specified, in terms of number of parameter sets
    n_sims = sum([1 if isinstance(params, dict) else len(params) \
        for params in components.values()])

    # Check that the variance definition matches the number of components specified
    if not (component_variances == 1 or len(component_variances) == n_sims):
        raise ValueError(
            'Signal components and variances lengths do not match.')

    # Collect the sim function to use, and repeat variance if is single number
    components = {(get_sim_func(name) if isinstance(name, str) else name) : params \
                   for name, params in components.items()}
    variances = repeat(component_variances) if isinstance(component_variances, (int, float)) \
        else iter(component_variances)

    # Simulate each component of the signal
    sig_components = []
    for func, params in components.items():

        # If list, params should be a list of separate parameters for each function call
        if isinstance(params, list):
            sig_components.extend([
                func(n_seconds=n_seconds,
                     fs=fs,
                     **cur_params,
                     variance=next(variances)) for cur_params in params
            ])

        # Otherwise, params should be a dictionary of parameters for single call
        else:
            sig_components.append(
                func(n_seconds=n_seconds,
                     fs=fs,
                     **params,
                     variance=next(variances)))

    # Combine total signal across all simulated components
    sig = np.sum(sig_components, axis=0)

    return sig
Exemplo n.º 4
0
def sim_cycle(n_seconds, fs, cycle_type, phase=0, **cycle_params):
    """Simulate a single cycle of a periodic pattern.

    Parameters
    ----------
    n_seconds : float
        Length of cycle window in seconds.
        This is NOT the period of the cycle, but the length of the returned array of the cycle.
    fs : float
        Sampling frequency of the cycle simulation.
    cycle_type : str or callable
        What type of cycle to simulate. String label options include:

        * sine: a sine wave cycle
        * asine: an asymmetric sine cycle
        * sawtooth: a sawtooth cycle
        * gaussian: a gaussian cycle
        * skewed_gaussian: a skewed gaussian cycle
        * exp: a cycle with exponential decay
        * 2exp: a cycle with exponential rise and decay
        * exp_cos: an exponential cosine cycle
        * asym_harmonic: an asymmetric cycle made as a sum of harmonics
        * ap: an action potential

    phase : float or {'min', 'max'}, optional, default: 0
        If non-zero, applies a phase shift by rotating the cycle.
        If a float, the shift is defined as a relative proportion of cycle, between [0, 1].
        If 'min' or 'max', the cycle is shifted to start at it's minima or maxima.
    **cycle_params
        Keyword arguments for parameters of the cycle, all as float:

        * sine: None
        * asine: `rdsym`, rise-decay symmetry, from 0-1
        * sawtooth: `width`, width of the rising ramp as a proportion of the total cycle
        * gaussian: `std`, standard deviation of the gaussian kernel, in seconds
        * skewed_gaussian: `center`, `std`, `alpha`, `height`
        * exp: `tau_d`, decay time, in seconds
        * 2exp: `tau_r` & `tau_d` rise time, and decay time, in seconds
        * exp_cos: `exp`, `scale`, `shift`
        * asym_harmonic: `phi`, the phase at each harmonic and `n_harmonics`
        * ap: `centers`, `stds`, `alphas`, `heights`

    Returns
    -------
    cycle : 1d array
        Simulated cycle.

    Examples
    --------
    Simulate a half second sinusoid, corresponding to a 2 Hz cycle (frequency=1/n_seconds):

    >>> cycle = sim_cycle(n_seconds=0.5, fs=500, cycle_type='sine')

    Simulate a sawtooth cycle, corresponding to a 10 Hz cycle:

    >>> cycle = sim_cycle(n_seconds=0.1, fs=500, cycle_type='sawtooth', width=0.3)

    Notes
    -----
    Any function defined in sim.cycles as `sim_label_cycle(n_seconds, fs, **params)`,
    is accessible by this function. The `cycle_type` input must match the label.
    """

    if isinstance(cycle_type, str):
        cycle_func = get_sim_func('sim_' + cycle_type + '_cycle',
                                  modules=['cycles'])
    else:
        cycle_func = cycle_type

    cycle = cycle_func(n_seconds, fs, **cycle_params)
    cycle = phase_shift_cycle(cycle, phase)

    return cycle