{ "cells": [ { "cell_type": "markdown", "id": "cell-0", "metadata": {}, "source": [ "# Respiratory Analysis\n", "\n", "This notebook demonstrates respiratory rate estimation using multiple methods and sleep apnea event detection from ECG and PPG signals using vitalDSP." ] }, { "cell_type": "markdown", "id": "cell-1", "metadata": {}, "source": [ "## Setup" ] }, { "cell_type": "code", "execution_count": null, "id": "cell-2", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import plotly.io as pio\n", "pio.renderers.default = \"sphinx_gallery\"\n", "from plotly import graph_objects as go\n", "from vitalDSP.notebooks import load_sample_ecg_small, load_sample_ppg, plot_trace\n", "\n", "fs = 128\n", "signal_col, date_col = load_sample_ecg_small()\n", "signal_col = np.array(signal_col)\n", "\n", "ppg_col, ppg_date = load_sample_ppg()\n", "ppg_col = np.array(ppg_col)\n", "\n", "print(f\"ECG signal: {len(signal_col)} samples at {fs} Hz\")" ] }, { "cell_type": "markdown", "id": "cell-3", "metadata": {}, "source": [ "## FFT-Based Respiratory Rate Estimation" ] }, { "cell_type": "code", "execution_count": null, "id": "cell-4", "metadata": {}, "outputs": [], "source": [ "from vitalDSP.respiratory_analysis.estimate_rr import fft_based_rr, peak_detection_rr, frequency_domain_rr\n", "\n", "# FFT method — finds dominant frequency in the respiratory band (0.1-0.5 Hz)\n", "rr_fft = fft_based_rr(signal_col, sampling_rate=fs)\n", "print(f\"Respiratory Rate (FFT) : {rr_fft:.2f} breaths/min\")" ] }, { "cell_type": "markdown", "id": "cell-5", "metadata": {}, "source": [ "## Peak Detection Respiratory Rate" ] }, { "cell_type": "code", "execution_count": null, "id": "cell-6", "metadata": {}, "outputs": [], "source": [ "rr_peaks = peak_detection_rr(signal_col, sampling_rate=fs, min_peak_distance=1.5)\n", "print(f\"Respiratory Rate (Peak Detect): {rr_peaks:.2f} breaths/min\")" ] }, { "cell_type": "markdown", "id": "cell-7", "metadata": {}, "source": [ "## Frequency Domain Respiratory Rate" ] }, { "cell_type": "code", "execution_count": null, "id": "cell-8", "metadata": {}, "outputs": [], "source": [ "rr_freq = frequency_domain_rr(signal_col, sampling_rate=fs)\n", "print(f\"Respiratory Rate (Freq Domain): {rr_freq:.2f} breaths/min\")" ] }, { "cell_type": "markdown", "id": "cell-9", "metadata": {}, "source": [ "## Ensemble Respiratory Rate Estimation" ] }, { "cell_type": "code", "execution_count": null, "id": "cell-10", "metadata": {}, "outputs": [], "source": [ "from vitalDSP.respiratory_analysis.respiratory_analysis import RespiratoryAnalysis\n", "\n", "ra = RespiratoryAnalysis(signal_col, fs=fs)\n", "\n", "# Single method\n", "rr_single = ra.compute_respiratory_rate(method='fft')\n", "print(f\"Single Method (FFT): {rr_single:.2f} breaths/min\")\n", "\n", "# Ensemble: weighted combination of multiple methods\n", "ensemble_result = ra.compute_respiratory_rate_ensemble()\n", "\n", "print(\"\\nEnsemble Respiratory Rate Estimation:\")\n", "print(f\" Rate : {ensemble_result['respiratory_rate']:.2f} breaths/min\")\n", "print(f\" Confidence : {ensemble_result['confidence']:.3f}\")\n", "print(f\" Quality : {ensemble_result['quality']}\")" ] }, { "cell_type": "markdown", "id": "cell-11", "metadata": {}, "source": [ "## Visualizing the Respiratory Band" ] }, { "cell_type": "code", "execution_count": null, "id": "cell-12", "metadata": {}, "outputs": [], "source": [ "from vitalDSP.filtering.signal_filtering import SignalFiltering\n\n# Isolate the respiratory frequency band (0.1-0.5 Hz)\nsf = SignalFiltering(signal_col)\nresp_band = sf.bandpass(0.1, 0.5, fs, order=4)\n\nt = np.arange(len(signal_col)) / fs\nfig = go.Figure()\nfig.add_trace(go.Scatter(x=t, y=signal_col, mode='lines', name='ECG Signal', opacity=0.4))\nfig.add_trace(go.Scatter(x=t, y=resp_band, mode='lines', name='Respiratory Band (0.1-0.5 Hz)'))\nfig.update_layout(\n title='Respiratory Modulation in ECG Signal',\n xaxis_title='Time (s)', yaxis_title='Amplitude'\n)\nfig.show()" ] }, { "cell_type": "markdown", "id": "cell-13", "metadata": {}, "source": [ "## PPG Respiratory Rate" ] }, { "cell_type": "code", "execution_count": null, "id": "cell-14", "metadata": {}, "outputs": [], "source": [ "ra_ppg = RespiratoryAnalysis(ppg_col, fs=fs)\n", "rr_ppg = ra_ppg.compute_respiratory_rate(method='fft')\n", "rr_ppg_ensemble = ra_ppg.compute_respiratory_rate_ensemble()\n", "\n", "print(f\"PPG Respiratory Rate (FFT) : {rr_ppg:.2f} breaths/min\")\n", "print(f\"PPG Respiratory Rate (Ensemble) : {rr_ppg_ensemble['respiratory_rate']:.2f} breaths/min\")\n", "print(f\"PPG Ensemble Confidence : {rr_ppg_ensemble['confidence']:.3f}\")" ] }, { "cell_type": "markdown", "id": "cell-15", "metadata": {}, "source": [ "## Sleep Apnea Detection" ] }, { "cell_type": "code", "execution_count": null, "id": "cell-16", "metadata": {}, "outputs": [], "source": [ "from vitalDSP.respiratory_analysis.sleep_apnea_detection.pause_detection import detect_apnea_pauses\n", "from vitalDSP.respiratory_analysis.sleep_apnea_detection.amplitude_threshold import detect_apnea_amplitude\n", "\n", "# Detect apnea pauses (cessation of respiratory activity)\n", "pause_events = detect_apnea_pauses(signal_col, sampling_rate=fs, min_pause_duration=10)\n", "print(f\"Apnea pauses detected : {len(pause_events)}\")\n", "\n", "# Detect apnea by amplitude threshold (signal amplitude drops below threshold)\n", "threshold = np.std(signal_col) * 0.3\n", "amplitude_events = detect_apnea_amplitude(signal_col, sampling_rate=fs, threshold=threshold, min_duration=10)\n", "print(f\"Amplitude-based events detected: {len(amplitude_events)}\")\n", "\n", "# Visualize detected events\n", "fig = go.Figure()\n", "t = np.arange(len(signal_col)) / fs\n", "fig.add_trace(go.Scatter(x=t, y=signal_col, mode='lines', name='Signal', opacity=0.6))\n", "for start, end in pause_events[:5]: # show first 5 events\n", " fig.add_vrect(x0=start/fs, x1=end/fs, fillcolor='red', opacity=0.2, layer='below', line_width=0)\n", "fig.update_layout(\n", " title='Sleep Apnea Pause Detection (red = apnea event)',\n", " xaxis_title='Time (s)', yaxis_title='Amplitude'\n", ")\n", "fig.show()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.9.0" } }, "nbformat": 4, "nbformat_minor": 5 }