Ejemplo n.º 1
0
def test_compute_irasa(tsig_comb):

    # Estimate periodic and aperiodic components with IRASA
    f_range = [1, 30]
    freqs, psd_ap, psd_pe = compute_irasa(tsig_comb, FS, f_range, noverlap=int(2*FS))

    assert len(freqs) == len(psd_ap) == len(psd_pe)

    # Compute r-squared for the full model, comparing to a standard power spectrum
    _, powers = trim_spectrum(*compute_spectrum(tsig_comb, FS, nperseg=int(4*FS)), f_range)
    r_sq = np.corrcoef(np.array([powers, psd_ap+psd_pe]))[0][1]
    assert r_sq > .95
Ejemplo n.º 2
0
def build_all(sig, fs, n_build=np.inf, sleep=0.05, label='viz', save=False):
    """Build all plots together."""

    size = 750
    step = 2
    start = 2000

    sig_yielder = yield_sig(sig, start=start, size=size, step=step)

    for ind in range(n_build):

        clear_output(wait=True)

        fig, axes = make_axes()

        spect_sig = sig[start + step * ind - 2000:start + step * ind + 2000]
        freqs, powers = trim_spectrum(*compute_spectrum(spect_sig, fs=fs),
                                      [1, 50])

        plot_timeseries(next(sig_yielder), ax=axes[0])
        plot_spectra(freqs, powers, log_freqs=True, ax=axes[1])

        animate_plot(fig, save, ind, label=label, sleep=sleep)
Ejemplo n.º 3
0
def compute_irasa(sig, fs=None, f_range=(1, 30), hset=None, **spectrum_kwargs):
    """Separate the aperiodic and periodic components using the IRASA method.

    Parameters
    ----------
    sig : 1d array
        Time series.
    fs : float
        The sampling frequency of sig.
    f_range : tuple or None
        Frequency range.
    hset : 1d array
        Resampling factors used in IRASA calculation.
        If not provided, defaults to values from 1.1 to 1.9 with an increment of 0.05.
    spectrum_kwargs : dict
        Optional keywords arguments that are passed to `compute_spectrum`.

    Returns
    -------
    freqs : 1d array
        Frequency vector.
    psd_aperiodic : 1d array
        The aperiodic component of the power spectrum.
    psd_periodic : 1d array
        The periodic component of the power spectrum.

    Notes
    -----
    Irregular-Resampling Auto-Spectral Analysis (IRASA) is described in Wen & Liu (2016).
    Briefly, it aims to separate 1/f and periodic components by resampling time series, and
    computing power spectra, effectively averaging away any activity that is frequency specific.

    References
    ----------
    Wen, H., & Liu, Z. (2016). Separating Fractal and Oscillatory Components in the Power Spectrum
    of Neurophysiological Signal. Brain Topography, 29(1), 13–26. DOI: 10.1007/s10548-015-0448-0
    """

    # Check & get the resampling factors, with rounding to avoid floating point precision errors
    hset = np.arange(1.1, 1.95, 0.05) if not hset else hset
    hset = np.round(hset, 4)

    # The `nperseg` input needs to be set to lock in the size of the FFT's
    if 'nperseg' not in spectrum_kwargs:
        spectrum_kwargs['nperseg'] = int(4 * fs)

    # Calculate the original spectrum across the whole signal
    freqs, psd = compute_spectrum(sig, fs, **spectrum_kwargs)

    # Do the IRASA resampling procedure
    psds = np.zeros((len(hset), *psd.shape))
    for ind, h_val in enumerate(hset):

        # Get the up-sampling / down-sampling (h, 1/h) factors as integers
        rat = fractions.Fraction(str(h_val))
        up, dn = rat.numerator, rat.denominator

        # Resample signal
        sig_up = signal.resample_poly(sig, up, dn, axis=-1)
        sig_dn = signal.resample_poly(sig, dn, up, axis=-1)

        # Calculate the power spectrum using the same params as original
        freqs_up, psd_up = compute_spectrum(sig_up, h_val * fs,
                                            **spectrum_kwargs)
        freqs_dn, psd_dn = compute_spectrum(sig_dn, fs / h_val,
                                            **spectrum_kwargs)

        # Geometric mean of h and 1/h
        psds[ind, :] = np.sqrt(psd_up * psd_dn)

    # Now we take the median resampled spectra, as an estimate of the aperiodic component
    psd_aperiodic = np.median(psds, axis=0)

    # Subtract aperiodic from original, to get the periodic component
    psd_periodic = psd - psd_aperiodic

    # Restrict spectrum to requested range
    if f_range:
        psds = np.array([psd_aperiodic, psd_periodic])
        freqs, (psd_aperiodic,
                psd_periodic) = trim_spectrum(freqs, psds, f_range)

    return freqs, psd_aperiodic, psd_periodic
Ejemplo n.º 4
0
# Plot a segment of the extracted time series data
plot_time_series(times, sig)

###################################################################################################
# Calculate Power Spectra
# -----------------------
#
# Next lets check the data in the frequency domain, calculating a power spectrum
# with the median welch's procedure from NeuroDSP.
#

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

# Calculate the power spectrum, using a median welch & extract a frequency range of interest
freqs, powers = compute_spectrum(sig, fs, method='welch', avg_type='median')
freqs, powers = trim_spectrum(freqs, powers, [3, 30])

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

# Check where the peak power is
peak_cf = freqs[np.argmax(powers)]
print(peak_cf)

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

# Plot the power spectra, and note the peak power
plot_power_spectra(freqs, powers)
plt.plot(freqs[np.argmax(powers)], np.max(powers), '.r', ms=12)

###################################################################################################
# Look for Bursts
Ejemplo n.º 5
0
def compute_irasa(sig,
                  fs,
                  f_range=None,
                  hset=None,
                  thresh=None,
                  **spectrum_kwargs):
    """Separate aperiodic and periodic components using IRASA.

    Parameters
    ----------
    sig : 1d array
        Time series.
    fs : float
        The sampling frequency of sig.
    f_range : tuple, optional
        Frequency range to restrict the analysis to.
    hset : 1d array, optional
        Resampling factors used in IRASA calculation.
        If not provided, defaults to values from 1.1 to 1.9 with an increment of 0.05.
    thresh : float, optional
        A relative threshold to apply when separating out periodic components.
        The threshold is defined in terms of standard deviations of the original spectrum.
    spectrum_kwargs : dict
        Optional keywords arguments that are passed to `compute_spectrum`.

    Returns
    -------
    freqs : 1d array
        Frequency vector.
    psd_aperiodic : 1d array
        The aperiodic component of the power spectrum.
    psd_periodic : 1d array
        The periodic component of the power spectrum.

    Notes
    -----
    Irregular-Resampling Auto-Spectral Analysis (IRASA) is an algorithm ([1]_) that aims to
    separate 1/f and periodic components by resampling time series and computing power spectra,
    averaging away any activity that is frequency specific to isolate the aperiodic component.

    References
    ----------
    .. [1] Wen, H., & Liu, Z. (2016). Separating Fractal and Oscillatory Components in
           the Power Spectrum of Neurophysiological Signal. Brain Topography, 29(1), 13–26.
           DOI: https://doi.org/10.1007/s10548-015-0448-0
    """

    # Check & get the resampling factors, with rounding to avoid floating point precision errors
    hset = np.arange(1.1, 1.95, 0.05) if hset is None else hset
    hset = np.round(hset, 4)

    # The `nperseg` input needs to be set to lock in the size of the FFT's
    if 'nperseg' not in spectrum_kwargs:
        spectrum_kwargs['nperseg'] = int(4 * fs)

    # Calculate the original spectrum across the whole signal
    freqs, psd = compute_spectrum(sig, fs, **spectrum_kwargs)

    # Do the IRASA resampling procedure
    psds = np.zeros((len(hset), *psd.shape))
    for ind, h_val in enumerate(hset):

        # Get the up-sampling / down-sampling (h, 1/h) factors as integers
        rat = fractions.Fraction(str(h_val))
        up, dn = rat.numerator, rat.denominator

        # Resample signal
        sig_up = signal.resample_poly(sig, up, dn, axis=-1)
        sig_dn = signal.resample_poly(sig, dn, up, axis=-1)

        # Calculate the power spectrum, using the same params as original
        freqs_up, psd_up = compute_spectrum(sig_up, h_val * fs,
                                            **spectrum_kwargs)
        freqs_dn, psd_dn = compute_spectrum(sig_dn, fs / h_val,
                                            **spectrum_kwargs)

        # Calculate the geometric mean of h and 1/h
        psds[ind, :] = np.sqrt(psd_up * psd_dn)

    # Take the median resampled spectra, as an estimate of the aperiodic component
    psd_aperiodic = np.median(psds, axis=0)

    # Subtract aperiodic from original, to get the periodic component
    psd_periodic = psd - psd_aperiodic

    # Apply a relative threshold for tuning which activity is labeled as periodic
    if thresh is not None:
        sub_thresh = np.where(
            psd_periodic - psd_aperiodic < thresh * np.std(psd))[0]
        psd_periodic[sub_thresh] = 0
        psd_aperiodic[sub_thresh] = psd[sub_thresh]

    # Restrict spectrum to requested range
    if f_range:
        psds = np.array([psd_aperiodic, psd_periodic])
        freqs, (psd_aperiodic,
                psd_periodic) = trim_spectrum(freqs, psds, f_range)

    return freqs, psd_aperiodic, psd_periodic
Ejemplo n.º 6
0
    }
}

# Define the frequency range of interest for the analysis
f_range = (1, 40)

# Create the simulate time series
sig = sim_combined(n_seconds, fs, components)

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

# Compute the power spectrum of the simulated signal
freqs, psd = compute_spectrum(sig, fs, nperseg=4 * fs)

# Trim the power spectrum to the frequency range of interest
freqs, psd = trim_spectrum(freqs, psd, f_range)

# Plot the computed power spectrum
plot_power_spectra(freqs, psd, title="Original Spectrum")

###################################################################################################
#
# In the above spectrum, we can see a pattern of power across all frequencies, which reflects
# the 1/f activity, as well as a peak at 10 Hz, which represents the simulated oscillation.
#

###################################################################################################
# IRASA
# -----
#
# In the analysis of neural data, we may want to separate aperiodic and periodic components