Пример #1
0
def compute_spectrum_wavelet(sig, fs, freqs, avg_type='mean', **kwargs):
    """Estimate the power spectral densitry using wavelets.

    Parameters
    ----------
    sig : 1d or 2d array
        Time series of measurement values.
    fs : float
        Sampling rate, in Hz.
    avg_type : {'mean', 'median'}, optional
        Method to average across the windows.
    **kwargs
        Optional inputs for using wavelets.

    Returns
    -------
    freqs : 1d array
        Array of sample frequencies.
    spectrum : 1d or 2d array
        Power spectral density.
    """

    mwt = morlet_transform(sig, fs, freqs, **kwargs)
    spectrum = get_avg_func(avg_type)(mwt, axis=0)

    return freqs, spectrum
Пример #2
0
def compute_spectrum_wavelet(sig, fs, freqs, avg_type='mean', **kwargs):
    """Compute the power spectral density using wavelets.

    Parameters
    ----------
    sig : 1d or 2d array
        Time series.
    fs : float
        Sampling rate, in Hz.
    freqs : 1d array or list of float
        If array, frequency values to estimate with morlet wavelets.
        If list, define the frequency range, as [freq_start, freq_stop, freq_step].
        The `freq_step` is optional, and defaults to 1. Range is inclusive of `freq_stop` value.
    avg_type : {'mean', 'median'}, optional
        Method to average across the windows.
    **kwargs
        Optional inputs for using wavelets.

    Returns
    -------
    freqs : 1d array
        Frequencies at which the measure was calculated.
    spectrum : 1d or 2d array
        Power spectral density.
    """

    if isinstance(freqs, (tuple, list)):
        freqs = create_freqs(*freqs)

    mwt = compute_wavelet_transform(sig, fs, freqs, **kwargs)
    spectrum = get_avg_func(avg_type)(mwt, axis=0)

    return freqs, spectrum
Пример #3
0
def compute_spectrum_welch(sig,
                           fs,
                           avg_type='mean',
                           window='hann',
                           nperseg=None,
                           noverlap=None,
                           f_range=None,
                           outlier_percent=None):
    """Compute the power spectral density using Welch's method.

    Parameters
    -----------
    sig : 1d or 2d array
        Time series.
    fs : float
        Sampling rate, in Hz.
    avg_type : {'mean', 'median'}, optional
        Method to average across the windows:

        * 'mean' is the same as Welch's method, taking the mean across FFT windows.
        * 'median' uses median across FFT windows instead of the mean, to minimize outlier effect.
    window : str or tuple or array_like, optional, default: 'hann'
        Desired window to use. See scipy.signal.get_window for a list of available windows.
        If array_like, the array will be used as the window and its length must be nperseg.
    nperseg : int, optional
        Length of each segment, in number of samples.
        If None, and window is str or tuple, is set to 1 second of data.
        If None, and window is array_like, is set to the length of the window.
    noverlap : int, optional
        Number of points to overlap between segments.
        If None, noverlap = nperseg // 8.
    f_range : list of [float, float] optional
        Frequency range to sub-select from the power spectrum.
    outlier_percent : float, optional
        The percentage of outlier values to be removed. Must be between 0 and 100.

    Returns
    -------
    freqs : 1d array
        Frequencies at which the measure was calculated.
    spectrum : 1d or 2d array
        Power spectral density.
    """

    # Calculate the short time fourier transform with signal.spectrogram
    nperseg, noverlap = check_spg_settings(fs, window, nperseg, noverlap)
    freqs, _, spg = spectrogram(sig, fs, window, nperseg, noverlap)

    # Throw out outliers if indicated
    if outlier_percent is not None:
        spg = discard_outliers(spg, outlier_percent)

    # Average across windows
    spectrum = get_avg_func(avg_type)(spg, axis=-1)

    # Trim spectrum, if requested
    if f_range:
        freqs, spectrum = trim_spectrum(freqs, spectrum, f_range)

    return freqs, spectrum
Пример #4
0
def compute_spectrum_wavelet(sig, fs, freqs, avg_type='mean', **kwargs):
    """Compute the power spectral density using wavelets.

    Parameters
    ----------
    sig : 1d or 2d array
        Time series.
    fs : float
        Sampling rate, in Hz.
    freqs : 1d array or list of float
        If array, frequency values to estimate with morlet wavelets.
        If list, define the frequency range, as [freq_start, freq_stop, freq_step].
        The `freq_step` is optional, and defaults to 1. Range is inclusive of `freq_stop` value.
    avg_type : {'mean', 'median'}, optional
        Method to average across the windows.
    **kwargs
        Optional inputs for using wavelets.

    Returns
    -------
    freqs : 1d array
        Frequencies at which the measure was calculated.
    spectrum : 1d or 2d array
        Power spectral density.

    Examples
    --------
    Compute the power spectrum of a simulated time series using wavelets:

    >>> from neurodsp.sim import sim_combined
    >>> sig = sim_combined(n_seconds=10, fs=500,
    ...                    components={'sim_powerlaw': {}, 'sim_oscillation' : {'freq': 10}})
    >>> freqs, spectrum = compute_spectrum_wavelet(sig, fs=500, freqs=[1, 30])
    """

    if isinstance(freqs, (tuple, list)):
        freqs = create_freqs(*freqs)

    # Compute the wavelet transform
    mwt = compute_wavelet_transform(sig, fs, freqs, **kwargs)

    # Convert the wavelet coefficient outputs to units of power
    mwt_power = abs(mwt)**2

    # Create the power spectrum by averaging across the time dimension
    spectrum = get_avg_func(avg_type)(mwt_power, axis=1)

    return freqs, spectrum
Пример #5
0
def detect_bursts_dual_threshold(sig,
                                 fs,
                                 dual_thresh,
                                 f_range=None,
                                 min_n_cycles=3,
                                 min_burst_duration=None,
                                 avg_type='median',
                                 magnitude_type='amplitude',
                                 **filter_kwargs):
    """Detect bursts in a signal using the dual threshold algorithm.

    Parameters
    ----------
    sig : 1d array
        Time series.
    fs : float
        Sampling rate, in Hz.
    dual_thresh : tuple of (float, float)
        Low and high threshold values for burst detection.
        Units are normalized by the average signal magnitude.
    f_range : tuple of (float, float), optional
        Frequency range, to filter signal to, before running burst detection.
        If f_range is None, then no filtering is applied prior to running burst detection.
    min_n_cycles : float, optional, default: 3
        Minimum burst duration in to keep.
        Only used if `f_range` is defined, and is used as the number of cycles at f_range[0].
    min_burst_duration : float, optional, default: None
        Minimum length of a burst, in seconds. Must be defined if not filtering.
        Only used if `f_range` is not defined, or if `min_n_cycles` is set to None.
    avg_type : {'median', 'mean'}, optional
        Averaging method to use to normalize the magnitude that is used for thresholding.
    magnitude_type : {'amplitude', 'power'}, optional
        Metric of magnitude used for thresholding.
    **filter_kwargs
        Keyword parameters to pass to `filter_signal`.

    Returns
    -------
    is_burst : 1d array
        Boolean indication of where bursts are present in the input signal.
        True indicates that a burst was detected at that sample, otherwise False.

    Notes
    -----
    The dual-threshold burst detection algorithm was originally proposed in [1]_.

    References
    ----------
    .. [1] Feingold, J., Gibson, D. J., DePasquale, B., & Graybiel, A. M. (2015).
           Bursts of beta oscillation differentiate postperformance activity in
           the striatum and motor cortex of monkeys performing movement tasks.
           Proceedings of the National Academy of Sciences, 112(44), 13687–13692.
           DOI: https://doi.org/10.1073/pnas.1517629112

    Examples
    --------
    Detect bursts using the dual threshold algorithm:

    >>> from neurodsp.sim import sim_combined
    >>> sig = sim_combined(n_seconds=10, fs=500,
    ...                    components={'sim_synaptic_current': {},
    ...                                'sim_bursty_oscillation' : {'freq': 10}},
    ...                    component_variances=[0.1, 0.9])
    >>> is_burst = detect_bursts_dual_threshold(sig, fs=500, dual_thresh=(1, 2), f_range=(8, 12))
    """

    if len(dual_thresh) != 2:
        raise ValueError(
            "Invalid number of elements in 'dual_thresh' parameter")

    # Compute amplitude time series
    sig_magnitude = amp_by_time(sig,
                                fs,
                                f_range,
                                remove_edges=False,
                                **filter_kwargs)

    # Set magnitude as power or amplitude: square if power, leave as is if amplitude
    check_param_options(magnitude_type, 'magnitude_type',
                        ['amplitude', 'power'])
    if magnitude_type == 'power':
        sig_magnitude = sig_magnitude**2

    # Calculate normalized magnitude
    sig_magnitude = sig_magnitude / get_avg_func(avg_type)(sig_magnitude)

    # Identify time periods of bursting using the 2 thresholds
    is_burst = _dual_threshold_split(sig_magnitude, dual_thresh[1],
                                     dual_thresh[0])

    # Remove bursts detected that are too short
    # Use a number of cycles defined on the frequency range, if available
    if f_range is not None and min_n_cycles is not None:
        min_burst_samples = int(np.ceil(min_n_cycles * fs / f_range[0]))
    # Otherwise, make sure minimum duration is set, and use that
    else:
        if min_burst_duration is None:
            raise ValueError(
                "Minimum burst duration must be defined if not filtering "
                "and using a number of cycles threshold.")
        min_burst_samples = int(np.ceil(min_burst_duration * fs))

    is_burst = _rmv_short_periods(is_burst, min_burst_samples)

    return is_burst.astype(bool)
Пример #6
0
def detect_bursts_dual_threshold(sig,
                                 fs,
                                 dual_thresh,
                                 f_range=None,
                                 min_n_cycles=3,
                                 min_burst_duration=None,
                                 avg_type='median',
                                 magnitude_type='amplitude',
                                 **filter_kwargs):
    """Detect bursts in a signal using the dual threshold algorithm.

    Parameters
    ----------
    sig : 1d array
        Time series.
    fs : float
        Sampling rate, in Hz.
    dual_thresh : tuple of (float, float)
        Low and high threshold values for burst detection.
        Units are normalized by the average signal magnitude.
    f_range : tuple of (float, float), optional
        Frequency range, to filter signal to, before running burst detection.
        If f_range is None, then no filtering is applied prior to running burst detection.
    min_n_cycles : float, optional, default=3
        Minimum burst duration in to keep.
        Only used if `f_range` is defined, and is used as the number of cycles at f_range[0].
    min_burst_duration : float, optional, default=None
        Minimum length of a burst, in seconds. Must be defined if not filtering.
        Only used if `f_range` is not defined, or if `min_n_cycles` is set to None.
    avg_type : {'median', 'mean'}, optional
        Averaging method to use to normalize the magnitude that is used for thresholding.
    magnitude_type : {'amplitude', 'power'}, optional
        Metric of magnitude used for thresholding.
    **filter_kwargs
        Keyword parameters to pass to `filter_signal`.

    Returns
    -------
    is_burst : 1d array
        Boolean indication of where bursts are present in the input signal.
        True indicates that a burst was detected at that sample, otherwise False.
    """

    if len(dual_thresh) != 2:
        raise ValueError(
            "Invalid number of elements in 'dual_thresh' parameter")

    # Compute amplitude time series
    sig_magnitude = amp_by_time(sig,
                                fs,
                                f_range,
                                remove_edges=False,
                                **filter_kwargs)

    # Set magnitude as power or amplitude: square if power, leave as is if amplitude
    if magnitude_type not in ['amplitude', 'power']:
        raise ValueError("Invalid input for 'magnitude_type'")
    if magnitude_type == 'power':
        sig_magnitude = sig_magnitude**2

    # Calculate normalized magnitude
    sig_magnitude = sig_magnitude / get_avg_func(avg_type)(sig_magnitude)

    # Identify time periods of bursting using the 2 thresholds
    is_burst = _dual_threshold_split(sig_magnitude, dual_thresh[1],
                                     dual_thresh[0])

    # Remove bursts detected that are too short
    # Use a number of cycles defined on the frequency range, if available
    if f_range and min_n_cycles:
        min_burst_samples = int(np.ceil(min_n_cycles * fs / f_range[0]))
    # Otherwise, make sure minimum duration is set, and use that
    else:
        if min_burst_duration is None:
            raise ValueError(
                "Minimum burst duration must be defined if not filtering"
                "and using a number of cycles threshold.")
        min_burst_samples = int(np.ceil(min_burst_duration * fs))

    is_burst = _rmv_short_periods(is_burst, min_burst_samples)

    return is_burst.astype(bool)
Пример #7
0
def detect_bursts_dual_threshold(sig,
                                 fs,
                                 f_range,
                                 dual_thresh,
                                 min_cycles=3,
                                 avg_type='median',
                                 magnitude_type='amplitude',
                                 **filter_kwargs):
    """Detect bursts in a neural signal using the dual threshold algorithm.

    Parameters
    ----------
    sig : 1d array
        Voltage time series.
    fs : float
        Sampling rate, in Hz.
    f_range : tuple of (float, float)
        Frequency range, in Hz, for narrowband signal of interest.
    dual_thresh : tuple of (float, float)
        Low and high threshold values for burst detection.
        Units are normalized by the average signal magnitude.
    min_cycles : float, optional, default=3
        Minimum burst duration in terms of number of cycles of f_range[0].
    avg_type : {'median', 'mean'}, optional
        Averaging method to use to normalize the magnitude that is used for thresholding.
    magnitude_type : {'amplitude', 'power'}, optional
        Metric of magnitude used for thresholding.
    **filter_kwargs
        Keyword parameters to pass to `filter_signal`.

    Returns
    -------
    is_burst : 1d array
        Boolean indication of where bursts are present in the input signal.
        True indicates that a burst was detected at that sample, otherwise False.
    """

    if len(dual_thresh) != 2:
        raise ValueError(
            "Invalid number of elements in 'dual_thresh' parameter")

    # Compute amplitude time series
    sig_magnitude = amp_by_time(sig,
                                fs,
                                f_range,
                                remove_edges=False,
                                **filter_kwargs)

    # Set magnitude as power or amplitude: square if power, leave as is if amplitude
    if magnitude_type not in ['amplitude', 'power']:
        raise ValueError("Invalid input for 'magnitude_type'")
    if magnitude_type == 'power':
        sig_magnitude = sig_magnitude**2

    # Calculate normalized magnitude
    sig_magnitude = sig_magnitude / get_avg_func(avg_type)(sig_magnitude)

    # Identify time periods of bursting using the 2 thresholds
    is_burst = _dual_threshold_split(sig_magnitude, dual_thresh[1],
                                     dual_thresh[0])

    # Remove bursts detected that are too short
    min_period_length = int(np.ceil(min_cycles * fs / f_range[0]))
    is_burst = _rmv_short_periods(is_burst, min_period_length)

    return is_burst.astype(bool)
Пример #8
0
def compute_spectrum_welch(sig, fs, avg_type='mean', window='hann',
                           nperseg=None, noverlap=None,
                           f_range=None, outlier_percent=None):
    """Compute the power spectral density using Welch's method.

    Parameters
    ----------
    sig : 1d or 2d array
        Time series.
    fs : float
        Sampling rate, in Hz.
    avg_type : {'mean', 'median'}, optional
        Method to average across the windows:

        * 'mean' is the same as Welch's method, taking the mean across FFT windows.
        * 'median' uses median across FFT windows instead of the mean, to minimize outlier effects.
    window : str or tuple or array_like, optional, default: 'hann'
        Desired window to use. See scipy.signal.get_window for a list of available windows.
        If array_like, the array will be used as the window and its length must be nperseg.
    nperseg : int, optional
        Length of each segment, in number of samples.
        If None, and window is str or tuple, is set to 1 second of data.
        If None, and window is array_like, is set to the length of the window.
    noverlap : int, optional
        Number of points to overlap between segments.
        If None, noverlap = nperseg // 8.
    f_range : list of [float, float], optional
        Frequency range to sub-select from the power spectrum.
    outlier_percent : float, optional
        The percentage of outlier values to be removed. Must be between 0 and 100.

    Returns
    -------
    freqs : 1d array
        Frequencies at which the measure was calculated.
    spectrum : 1d or 2d array
        Power spectral density.

    Notes
    -----
    - Welch's method ([1]_) computes a power spectra by averaging over windowed FFTs.

    References
    ----------
    .. [1] Welch, P. (1967). The use of fast Fourier transform for the estimation of power
           spectra: A method based on time averaging over short, modified periodograms.
           IEEE Transactions on Audio and Electroacoustics, 15(2), 70–73.
           DOI: https://doi.org/10.1109/TAU.1967.1161901

    Examples
    --------
    Compute the power spectrum of a simulated time series using Welch's method:

    >>> from neurodsp.sim import sim_combined
    >>> sig = sim_combined(n_seconds=10, fs=500,
    ...                    components={'sim_powerlaw': {}, 'sim_oscillation': {'freq': 10}})
    >>> freqs, spec = compute_spectrum_welch(sig, fs=500)
    """

    # Calculate the short time Fourier transform with signal.spectrogram
    nperseg, noverlap = check_spg_settings(fs, window, nperseg, noverlap)
    freqs, _, spg = spectrogram(sig, fs, window, nperseg, noverlap)

    # Throw out outliers if indicated
    if outlier_percent is not None:
        spg = discard_outliers(spg, outlier_percent)

    # Average across windows
    spectrum = get_avg_func(avg_type)(spg, axis=-1)

    # Trim spectrum, if requested
    if f_range:
        freqs, spectrum = trim_spectrum(freqs, spectrum, f_range)

    return freqs, spectrum