Source code for neurokit2.rsp.rsp_rate

# -*- coding: utf-8 -*-
import numpy as np

from ..signal import (signal_filter, signal_interpolate, signal_rate,
                      signal_resample)
from .rsp_peaks import rsp_peaks


[docs] def rsp_rate( rsp_cleaned, troughs=None, sampling_rate=1000, window=10, hop_size=1, method="trough", peak_method="khodadad2018", interpolation_method="monotone_cubic", ): """**Find respiration rate** Parameters ---------- rsp_cleaned : Union[list, np.array, pd.Series] The cleaned respiration channel as returned by :func:`.rsp_clean`. troughs : Union[list, np.array, pd.Series, pd.DataFrame] The respiration troughs (inhalation onsets) as returned by :func:`.rsp_peaks`. If None (default), inhalation onsets will be automatically identified from the :func:`.rsp_clean` signal. sampling_rate : int The sampling frequency of :func:`.rsp_cleaned` (in Hz, i.e., samples/second). window : int The duration of the sliding window (in second). Default to 10 seconds. hop_size : int The number of samples between each successive window. Default to 1 sample. method : str Method can either be ``"trough"`` or ``"xcorr"``. In ``"trough"`` method, respiratory rate is calculated from the periods between successive inspirations (i.e., inhalation onsets/ troughs). In ``"xcorr"`` method, cross-correlations between the changes in respiration with a bank of sinusoids of different frequencies are calculated to identify the principal frequency of oscillation. peak_method : str Method to identify successive respiratory inspirations, only relevant if method is ``"trough"``. Can be one of ``"khodadad2018"`` (default) or ``"biosppy"``. interpolation_method : str Method used to interpolate the rate between inhalation onsets. See :func:`.signal_interpolate`. ``"monotone_cubic"`` is chosen as the default interpolation method since it ensures monotone interpolation between data points (i.e., it prevents physiologically implausible "overshoots" or "undershoots" in the y-direction). In contrast, the widely used cubic spline interpolation does not ensure monotonicity. Return ------ rsp_rate : np.ndarray Instantenous respiration rate. Example ------- .. ipython:: python import neurokit2 as nk rsp_signal = nk.data("rsp_1000hz") rsp_cleaned = nk.rsp_clean(rsp_signal, sampling_rate=1000) rsp_rate_onsets = nk.rsp_rate(rsp_cleaned, sampling_rate=1000, method="trough") rsp_rate_xcorr = nk.rsp_rate(rsp_cleaned, sampling_rate=1000, method="xcorr") """ if method.lower() in ["period", "peak", "peaks", "trough", "troughs", "signal_rate"]: if troughs is None: _, troughs = rsp_peaks(rsp_cleaned, sampling_rate=sampling_rate, method=peak_method) rate = signal_rate( troughs["RSP_Troughs"], sampling_rate=sampling_rate, desired_length=len(rsp_cleaned), interpolation_method=interpolation_method, ) elif method.lower() in ["cross-correlation", "xcorr"]: rate = _rsp_rate_xcorr( rsp_cleaned, sampling_rate=sampling_rate, window=window, hop_size=hop_size, interpolation_method=interpolation_method, ) else: raise ValueError( "NeuroKit error: rsp_rate(): 'method' should be" " one of 'trough', or 'cross-correlation'." ) return rate
# ============================================================================= # Cross-correlation method # ============================================================================= def _rsp_rate_xcorr( rsp_cleaned, sampling_rate=1000, window=10, hop_size=1, interpolation_method="monotone_cubic" ): N = len(rsp_cleaned) # Downsample data to 10Hz desired_sampling_rate = 10 rsp = signal_resample( rsp_cleaned, sampling_rate=sampling_rate, desired_sampling_rate=desired_sampling_rate ) # Define paramters window_length = int(desired_sampling_rate * window) rsp_rate = [] for start in np.arange(0, N, hop_size): window_segment = rsp[start : start + window_length] if len(window_segment) < window_length: break # the last frames that are smaller than windlow_length # Calculate the 1-order difference diff = np.ediff1d(window_segment) norm_diff = diff / np.max(diff) # Find xcorr for all frequencies with diff xcorr = [] t = np.linspace(0, window, len(diff)) for frequency in np.arange(5 / 60, 30.25 / 60, 0.25 / 60): # Define the sin waves sin_wave = np.sin(2 * np.pi * frequency * t) # Calculate cross-correlation _xcorr = np.corrcoef(norm_diff, sin_wave)[0, 1] xcorr.append(_xcorr) # Find frequency with the highest xcorr with diff max_frequency_idx = np.argmax(xcorr) max_frequency = np.arange(5 / 60, 30.25 / 60, 0.25 / 60)[max_frequency_idx] # Append max_frequency to rsp_rate - instanteneous rate rsp_rate.append(max_frequency) x = np.arange(len(rsp_rate)) y = rsp_rate rsp_rate = signal_interpolate(x, y, x_new=len(rsp_cleaned), method=interpolation_method) # Smoothing rsp_rate = signal_filter(rsp_rate, highcut=0.1, order=4, sampling_rate=sampling_rate) # Convert to Brpm rsp_rate = np.multiply(rsp_rate, 60) return np.array(rsp_rate)