Source code for neurokit2.ecg.ecg_phase

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

from ..signal import signal_phase
from .ecg_delineate import ecg_delineate
from .ecg_peaks import ecg_peaks


[docs] def ecg_phase(ecg_cleaned, rpeaks=None, delineate_info=None, sampling_rate=None): """**Find the Cardiac Phase** Compute cardiac phase (for both atrial and ventricular), labelled as 1 for systole and 0 for diastole. Parameters ---------- ecg_cleaned : Union[list, np.array, pd.Series] The cleaned ECG channel as returned by ``ecg_clean()``. rpeaks : list or array or DataFrame or Series or dict The samples at which the different ECG peaks occur. If a dict or a DataFrame is passed, it is assumed that these containers were obtained with ``ecg_findpeaks()`` or ``ecg_peaks()``. delineate_info : dict A dictionary containing additional information of ecg delineation and can be obtained with ``ecg_delineate()``. sampling_rate : int The sampling frequency of ``ecg_signal`` (in Hz, i.e., samples/second). Defaults to ``None``. Returns ------- signals : DataFrame A DataFrame of same length as ``ecg_signal`` containing the following columns: * ``"ECG_Phase_Atrial"``: cardiac phase, marked by "1" for systole and "0" for diastole. * ``"ECG_Phase_Completion_Atrial"``: cardiac phase (atrial) completion, expressed in percentage (from 0 to 1), representing the stage of the current cardiac phase. * ``"ECG_Phase_Ventricular"``: cardiac phase, marked by "1" for systole and "0" for diastole. * ``"ECG_Phase_Completion_Ventricular"``: cardiac phase (ventricular) completion, expressed in percentage (from 0 to 1), representing the stage of the current cardiac phase. See Also -------- ecg_clean, ecg_peaks, ecg_delineate, ecg_process, ecg_plot Examples -------- .. ipython:: python import neurokit2 as nk ecg = nk.ecg_simulate(duration=6, sampling_rate=1000) _, rpeaks = nk.ecg_peaks(ecg) signals, waves = nk.ecg_delineate(ecg, rpeaks, sampling_rate=1000) cardiac_phase = nk.ecg_phase(ecg_cleaned=ecg, rpeaks=rpeaks, delineate_info=waves, sampling_rate=1000) @savefig p_ecg_phase.png scale=100% _, ax = plt.subplots(nrows=2) ax[0].plot(nk.rescale(ecg), label="ECG", color="red", alpha=0.3) ax[0].plot(cardiac_phase["ECG_Phase_Atrial"], label="Atrial Phase", color="orange") ax[0].plot(cardiac_phase["ECG_Phase_Completion_Atrial"], label="Atrial Phase Completion", linestyle="dotted") ax[0].legend(loc="upper right") ax[1].plot(nk.rescale(ecg), label="ECG", color="red", alpha=0.3) ax[1].plot(cardiac_phase["ECG_Phase_Ventricular"], label="Ventricular Phase", color="green") ax[1].plot(cardiac_phase["ECG_Phase_Completion_Ventricular"], label="Ventricular Phase Completion", linestyle="dotted") ax[1].legend(loc="upper right") @suppress plt.close() """ # Sanitize inputs if rpeaks is None: if sampling_rate is not None: _, rpeaks = ecg_peaks(ecg_cleaned, sampling_rate=sampling_rate) else: raise ValueError( "R-peaks will be obtained using `nk.ecg_peaks`. Please provide the sampling_rate of ecg_signal." ) # Try retrieving right column if isinstance(rpeaks, dict): rpeaks = rpeaks["ECG_R_Peaks"] if delineate_info is None: __, delineate_info = ecg_delineate(ecg_cleaned, sampling_rate=sampling_rate) # Try retrieving right column if isinstance( delineate_info, dict ): # FIXME: if this evaluates to False, toffsets and ppeaks are not instantiated toffsets = np.full(len(ecg_cleaned), False, dtype=bool) toffsets_idcs = [ int(x) for x in delineate_info["ECG_T_Offsets"] if ~np.isnan(x) ] toffsets[toffsets_idcs] = True ppeaks = np.full(len(ecg_cleaned), False, dtype=bool) ppeaks_idcs = [int(x) for x in delineate_info["ECG_P_Peaks"] if ~np.isnan(x)] ppeaks[ppeaks_idcs] = True # Atrial Phase atrial = np.full(len(ecg_cleaned), np.nan) atrial[rpeaks] = 0.0 atrial[ppeaks] = 1.0 last_element = np.where(~np.isnan(atrial))[0][ -1 ] # Avoid filling beyond the last peak/trough atrial[0:last_element] = ( pd.Series(atrial).ffill().values[0:last_element] ) # Atrial Phase Completion atrial_completion = signal_phase(atrial, method="percent") # Ventricular Phase ventricular = np.full(len(ecg_cleaned), np.nan) ventricular[toffsets] = 0.0 ventricular[rpeaks] = 1.0 last_element = np.where(~np.isnan(ventricular))[0][ -1 ] # Avoid filling beyond the last peak/trough ventricular[0:last_element] = ( pd.Series(ventricular).ffill().values[0:last_element] ) # Ventricular Phase Completion ventricular_comletion = signal_phase(ventricular, method="percent") return pd.DataFrame( { "ECG_Phase_Atrial": atrial, "ECG_Phase_Completion_Atrial": atrial_completion, "ECG_Phase_Ventricular": ventricular, "ECG_Phase_Completion_Ventricular": ventricular_comletion, } )