<commit_before>"""Simulating time series, including oscillations and aperiodic backgrounds."""

import warnings

import numpy as np
import pandas as pd
import scipy as sp
from scipy import signal

from neurodsp import spectral

###################################################################################################
###################################################################################################


def sim_oscillator(n_seconds, fs, freq, rdsym=.5):
    """Simulate an oscillation.

    Parameters
    ----------
    n_seconds : float
        Signal duration, in seconds
    fs : float
        Signal sampling rate, in Hz
    freq : float
        Oscillator frequency
    rdsym : float
        Rise-decay symmetry of the oscillator, as fraction of the period in the rise time
            =0.5 - symmetric (sine wave)
            <0.5 - shorter rise, longer decay
            >0.5 - longer rise, shorter decay

    Returns
    -------
    osc : 1d array
        Oscillating time series
    """

    # Compute number of samples per cycle and number of cycles
    n_samples_cycle = int(np.ceil(fs / freq))
    n_samples = int(fs * n_seconds)
    n_cycles = int(np.ceil(n_seconds * freq))

    # Determine number of samples in rise and decay periods
    rise_samples = int(np.round(n_samples_cycle * rdsym))
    decay_samples = n_samples_cycle - rise_samples

    # Make phase array for a single cycle, then repeat it
    pha_one_cycle = np.hstack([np.linspace(
        0, np.pi, decay_samples + 1), np.linspace(-np.pi, 0, rise_samples + 1)[1:-1]])
    phase_t = np.tile(pha_one_cycle, n_cycles)
    phase_t = phase_t[:n_samples]

    # Transform phase into an oscillator
    osc = np.cos(phase_t)

    return osc


def sim_noisy_oscillator(n_seconds, fs, freq, noise_generator, noise_args, rdsym=.5, ratio_osc_var=1):
    """Simulate an oscillation embedded in background 1/f noise.

    Parameters
    ----------
    n_seconds : float
        Signal duration, in seconds
    fs : float
        Signal sampling rate, in Hz
    freq : float
        Oscillator frequency
    noise_generator: str or numpy.ndarray
        Noise model, can be one of the simulators in neurodsp.sim specificed as a string, or a custom
        numpy.ndarray with the same number of samples as the oscillation (n_seconds*fs).
        Possible models (see respective documentation):
            - 'filtered_powerlaw': sim.sim_filtered_noise()
            - 'powerlaw': sim.sim_variable_powerlaw()
            - 'synaptic' or 'lorentzian': sim.sim_synaptic_noise()
            - 'ou_process': sim.sim_ou_process()
    noise_args: dict('argname':argval, ...)
        Function arguments for the neurodsp.sim noise generaters. See API for arg names.
        NOTE: all args, including optional ones, are required, EXCEPT n_seconds and fs.
    rdsym : float
        Rise-decay symmetry of the oscillator, as fraction of the period in the rise time;
            =0.5 - symmetric (i.e., sine wave, default)
            <0.5 - shorter rise, longer decay
            >0.5 - longer rise, shorter decay
    ratio_osc_var : float
        Ratio of oscillator variance to noise variance
            >1 - oscillator is stronger
            <1 - noise is stronger
            Defaults to 1.

    Returns
    -------
    osc: 1d array
        Oscillator with noise
    """

    # Determine length of signal in samples
    n_samples = int(n_seconds * fs)

    # Generate noise
    noise = _return_noise_sim(n_seconds, fs, noise_generator, noise_args)

    # Generate oscillator
    oscillator = sim_oscillator(n_seconds, fs, freq, rdsym=rdsym)

    # Normalize by variance
    oscillator_var = np.var(oscillator)
    noise_var = np.var(noise)
    noise = np.sqrt(noise**2 * oscillator_var /
                    (noise_var * ratio_osc_var)) * np.sign(noise)

    # Combine oscillator and noise
    osc = oscillator + noise

    return osc


def sim_bursty_oscillator(n_seconds, fs, freq, rdsym=.5, prob_enter_burst=.2,
                          prob_leave_burst=.2, cycle_features=None,
                          return_cycle_df=False):
    """Simulate a bursty oscillation.

    Parameters
    ----------
    n_seconds : float
        Simulation time, in seconds
    fs : float
        Sampling rate of simulated signal, in Hz
    freq : float
        Oscillator frequency, in Hz
    rdsym : float
        Rise-decay symmetry of the oscillator, as fraction of the period in the rise time;
            =0.5 - symmetric (sine wave)
            <0.5 - shorter rise, longer decay
            >0.5 - longer rise, shorter decay
    prob_enter_burst : float
        Rrobability of a cycle being oscillating given the last cycle is not oscillating
    prob_leave_burst : float
        Probability of a cycle not being oscillating given the last cycle is oscillating
    cycle_features : dict
        specify the mean and standard deviations
        (within and across bursts) of each cycle's
        amplitude, period, and rise-decay symmetry.
        This can include a complete or incomplete set
        (using defaults) of the following keys:
        amp_mean - mean cycle amplitude
        amp_std - standard deviation of cycle amplitude
        amp_burst_std - std. of mean amplitude for each burst
        period_mean - mean period (computed from `freq`)
        period_std - standard deviation of period (samples)
        period_burst_std - std. of mean period for each burst
        rdsym_mean - mean rise-decay symmetry
        rdsym_std - standard deviation of rdsym
        rdsym_burst_std - std. of mean rdsym for each burst
    return_cycle_df : bool
        if True, return the dataframe that contains the simulation
        parameters for each cycle. This may be useful for computing
        power, for example. Because the power of the oscillator
        should only be considered over the times where there's
        bursts, not when there's nothing.

    Returns
    -------
    sig : 1d array
        bursty oscillator
    df : pd.DataFrame
        cycle-by-cycle properties of the simulated oscillator
    """

    # Define default parameters for cycle features
    mean_period_samples = int(fs / freq)
    cycle_features_use = {'amp_mean': 1, 'amp_burst_std': 0, 'amp_std': 0,
                          'period_mean': mean_period_samples, 'period_burst_std': 0, 'period_std': 0,
                          'rdsym_mean': rdsym, 'rdsym_burst_std': 0, 'rdsym_std': 0}

    # Overwrite default cycle features with those specified
    if cycle_features is not None:
        for k in cycle_features:
            cycle_features_use[k] = cycle_features[k]

    # Determine number of cycles to generate
    n_samples = n_seconds * fs
    n_cycles_overestimate = int(np.ceil(n_samples / mean_period_samples * 2))

    # Simulate if a series of cycles are oscillating or not oscillating
    is_oscillating = [False]
    n_cycles_current = 1
    while n_cycles_current < n_cycles_overestimate:
        rand_num = np.random.rand()
        if is_oscillating[-1]:
            is_oscillating.append(rand_num > prob_leave_burst)
        else:
            is_oscillating.append(rand_num < prob_enter_burst)
        n_cycles_current += 1

    # Determine period, amp, and rdsym for each cycle
    periods = []
    amps = []
    rdsyms = []
    for is_osc in is_oscillating:
        if is_osc is False:
            period = cycle_features_use['period_mean'] + \
                np.random.randn() * cycle_features_use['period_std']
            periods.append(int(period))
            amps.append(np.nan)
            rdsyms.append(np.nan)

            current_burst_period_mean = np.nan<commit_msg>allow noninteger n_seconds and fs in bursty oscillator<commit_after>"""Simulating time series, including oscillations and aperiodic backgrounds."""

import warnings

import numpy as np
import pandas as pd
import scipy as sp
from scipy import signal

from neurodsp import spectral

###################################################################################################
###################################################################################################


def sim_oscillator(n_seconds, fs, freq, rdsym=.5):
    """Simulate an oscillation.

    Parameters
    ----------
    n_seconds : float
        Signal duration, in seconds
    fs : float
        Signal sampling rate, in Hz
    freq : float
        Oscillator frequency
    rdsym : float
        Rise-decay symmetry of the oscillator, as fraction of the period in the rise time
            =0.5 - symmetric (sine wave)
            <0.5 - shorter rise, longer decay
            >0.5 - longer rise, shorter decay

    Returns
    -------
    osc : 1d array
        Oscillating time series
    """

    # Compute number of samples per cycle and number of cycles
    n_samples_cycle = int(np.ceil(fs / freq))
    n_samples = int(fs * n_seconds)
    n_cycles = int(np.ceil(n_seconds * freq))

    # Determine number of samples in rise and decay periods
    rise_samples = int(np.round(n_samples_cycle * rdsym))
    decay_samples = n_samples_cycle - rise_samples

    # Make phase array for a single cycle, then repeat it
    pha_one_cycle = np.hstack([np.linspace(
        0, np.pi, decay_samples + 1), np.linspace(-np.pi, 0, rise_samples + 1)[1:-1]])
    phase_t = np.tile(pha_one_cycle, n_cycles)
    phase_t = phase_t[:n_samples]

    # Transform phase into an oscillator
    osc = np.cos(phase_t)

    return osc


def sim_noisy_oscillator(n_seconds, fs, freq, noise_generator, noise_args, rdsym=.5, ratio_osc_var=1):
    """Simulate an oscillation embedded in background 1/f noise.

    Parameters
    ----------
    n_seconds : float
        Signal duration, in seconds
    fs : float
        Signal sampling rate, in Hz
    freq : float
        Oscillator frequency
    noise_generator: str or numpy.ndarray
        Noise model, can be one of the simulators in neurodsp.sim specificed as a string, or a custom
        numpy.ndarray with the same number of samples as the oscillation (n_seconds*fs).
        Possible models (see respective documentation):
            - 'filtered_powerlaw': sim.sim_filtered_noise()
            - 'powerlaw': sim.sim_variable_powerlaw()
            - 'synaptic' or 'lorentzian': sim.sim_synaptic_noise()
            - 'ou_process': sim.sim_ou_process()
    noise_args: dict('argname':argval, ...)
        Function arguments for the neurodsp.sim noise generaters. See API for arg names.
        NOTE: all args, including optional ones, are required, EXCEPT n_seconds and fs.
    rdsym : float
        Rise-decay symmetry of the oscillator, as fraction of the period in the rise time;
            =0.5 - symmetric (i.e., sine wave, default)
            <0.5 - shorter rise, longer decay
            >0.5 - longer rise, shorter decay
    ratio_osc_var : float
        Ratio of oscillator variance to noise variance
            >1 - oscillator is stronger
            <1 - noise is stronger
            Defaults to 1.

    Returns
    -------
    osc: 1d array
        Oscillator with noise
    """

    # Determine length of signal in samples
    n_samples = int(n_seconds * fs)

    # Generate noise
    noise = _return_noise_sim(n_seconds, fs, noise_generator, noise_args)

    # Generate oscillator
    oscillator = sim_oscillator(n_seconds, fs, freq, rdsym=rdsym)

    # Normalize by variance
    oscillator_var = np.var(oscillator)
    noise_var = np.var(noise)
    noise = np.sqrt(noise**2 * oscillator_var /
                    (noise_var * ratio_osc_var)) * np.sign(noise)

    # Combine oscillator and noise
    osc = oscillator + noise

    return osc


def sim_bursty_oscillator(n_seconds, fs, freq, rdsym=.5, prob_enter_burst=.2,
                          prob_leave_burst=.2, cycle_features=None,
                          return_cycle_df=False):
    """Simulate a bursty oscillation.

    Parameters
    ----------
    n_seconds : float
        Simulation time, in seconds
    fs : float
        Sampling rate of simulated signal, in Hz
    freq : float
        Oscillator frequency, in Hz
    rdsym : float
        Rise-decay symmetry of the oscillator, as fraction of the period in the rise time;
            =0.5 - symmetric (sine wave)
            <0.5 - shorter rise, longer decay
            >0.5 - longer rise, shorter decay
    prob_enter_burst : float
        Rrobability of a cycle being oscillating given the last cycle is not oscillating
    prob_leave_burst : float
        Probability of a cycle not being oscillating given the last cycle is oscillating
    cycle_features : dict
        specify the mean and standard deviations
        (within and across bursts) of each cycle's
        amplitude, period, and rise-decay symmetry.
        This can include a complete or incomplete set
        (using defaults) of the following keys:
        amp_mean - mean cycle amplitude
        amp_std - standard deviation of cycle amplitude
        amp_burst_std - std. of mean amplitude for each burst
        period_mean - mean period (computed from `freq`)
        period_std - standard deviation of period (samples)
        period_burst_std - std. of mean period for each burst
        rdsym_mean - mean rise-decay symmetry
        rdsym_std - standard deviation of rdsym
        rdsym_burst_std - std. of mean rdsym for each burst
    return_cycle_df : bool
        if True, return the dataframe that contains the simulation
        parameters for each cycle. This may be useful for computing
        power, for example. Because the power of the oscillator
        should only be considered over the times where there's
        bursts, not when there's nothing.

    Returns
    -------
    sig : 1d array
        bursty oscillator
    df : pd.DataFrame
        cycle-by-cycle properties of the simulated oscillator
    """

    # Define default parameters for cycle features
    mean_period_samples = int(fs / freq)
    cycle_features_use = {'amp_mean': 1, 'amp_burst_std': 0, 'amp_std': 0,
                          'period_mean': mean_period_samples, 'period_burst_std': 0, 'period_std': 0,
                          'rdsym_mean': rdsym, 'rdsym_burst_std': 0, 'rdsym_std': 0}

    # Overwrite default cycle features with those specified
    if cycle_features is not None:
        for k in cycle_features:
            cycle_features_use[k] = cycle_features[k]

    # Determine number of cycles to generate
    n_samples = int(n_seconds * fs)
    n_cycles_overestimate = int(np.ceil(n_samples / mean_period_samples * 2))

    # Simulate if a series of cycles are oscillating or not oscillating
    is_oscillating = [False]
    n_cycles_current = 1
    while n_cycles_current < n_cycles_overestimate:
        rand_num = np.random.rand()
        if is_oscillating[-1]:
            is_oscillating.append(rand_num > prob_leave_burst)
        else:
            is_oscillating.append(rand_num < prob_enter_burst)
        n_cycles_current += 1

    # Determine period, amp, and rdsym for each cycle
    periods = []
    amps = []
    rdsyms = []
    for is_osc in is_oscillating:
        if is_osc is False:
            period = cycle_features_use['period_mean'] + \
                np.random.randn() * cycle_features_use['period_std']
            periods.append(int(period))
            amps.append(np.nan)
            rdsyms.append(np.nan)

            current_burst_period_mean = np.nan
{'fraction_non_alphanumeric': 0.09850552306692657, 'fraction_numerical': 0.006367771280051982, 'mean_word_length': 2.4617633828160144, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1303626', 'n_tokens_mistral': 4554, 'n_tokens_neox': 4248, 'n_words': 1466}