diff --git a/biosppy/features/time.py b/biosppy/features/time.py index c4798402..90db07a8 100644 --- a/biosppy/features/time.py +++ b/biosppy/features/time.py @@ -22,29 +22,29 @@ def time(signal=None, sampling_rate=1000., include_diff=True): """Compute various time metrics describing the signal. - Parameters - ---------- - signal : array - Input signal. - sampling_rate : int, float, optional - Sampling Rate (Hz). - include_diff : bool, optional - Whether to include the features of the signal's differences (first, second and absolute). - - Returns - ------- - feats : ReturnTuple object - Time features of the signal. - - Notes - ----- - Besides the features directly extracted in this function, it also calls: - - biosppy.signals.tools.signal_stats - - biosppy.stats.quartiles - - biosppy.stats.histogram - - biosppy.features.time.hjorth_features - - """ + Parameters + ---------- + signal : array + Input signal. + sampling_rate : int, float, optional + Sampling Rate (Hz). + include_diff : bool, optional + Whether to include the features of the signal's differences (first, second and absolute). + + Returns + ------- + feats : ReturnTuple object + Time features of the signal. + + Notes + ----- + Besides the features directly extracted in this function, it also calls: + - biosppy.signals.tools.signal_stats + - biosppy.stats.quartiles + - biosppy.stats.histogram + - biosppy.features.time.hjorth_features + + """ # check inputs if signal is None: diff --git a/biosppy/quality.py b/biosppy/quality.py index 034de597..dbd06c4f 100644 --- a/biosppy/quality.py +++ b/biosppy/quality.py @@ -24,24 +24,24 @@ def quality_eda(x=None, methods=['bottcher'], sampling_rate=None, verbose=1): """Compute the quality index for one EDA segment. - Parameters - ---------- - x : array - Input signal to test. - methods : list - Method to assess quality. One or more of the following: 'bottcher'. - sampling_rate : int - Sampling frequency (Hz). - verbose : int - If 1, a commentary is printed regarding the quality of the signal and details of the function. Default is 1. - - Returns - ------- - args : tuple - Tuple containing the quality index for each method. - names : tuple - Tuple containing the name of each method. - """ + Parameters + ---------- + x : array + Input signal to test. + methods : list + Method to assess quality. One or more of the following: 'bottcher'. + sampling_rate : int + Sampling frequency (Hz). + verbose : int + If 1, a commentary is printed regarding the quality of the signal and details of the function. Default is 1. + + Returns + ------- + args : tuple + Tuple containing the quality index for each method. + names : tuple + Tuple containing the name of each method. + """ # check inputs if x is None: raise TypeError("Please specify the input signal.") @@ -71,7 +71,6 @@ def quality_ecg(segment, methods=['Level3'], sampling_rate=None, fisher=True, f_thr=0.01, threshold=0.9, bit=0, nseg=1024, num_spectrum=[5, 20], dem_spectrum=None, mode_fsqi='simple', verbose=1): - """Compute the quality index for one ECG segment. Parameters @@ -130,10 +129,8 @@ def quality_ecg(segment, methods=['Level3'], sampling_rate=None, def ecg_sqi_level3(segment, sampling_rate, threshold, bit): - """Compute the quality index for one ECG segment. The segment should have 10 seconds. - Parameters ---------- segment : array @@ -223,24 +220,27 @@ def eda_sqi_bottcher(x=None, sampling_rate=None, verbose=1): # -> Timeline def cSQI(rpeaks=None, verbose=1): - """For the ECG signal - Calculate the Coefficient of Variation of RR Intervals (cSQI). + """For the ECG signal, calculate the Coefficient of Variation of RR Intervals (cSQI). + Parameters ---------- rpeaks : array-like Array containing R-peak locations. Should be filtered? How many seconds are adequate? verbose : int If 1, a commentary is printed regarding the quality of the signal and details of the function. Default is 1. + Returns ------- cSQI : float Coefficient of Variation of RR Intervals. cSQI - best near 0 + References ---------- .. [Zhao18] Zhao, Z., & Zhang, Y. (2018). SQI quality evaluation mechanism of single-lead ECG signal based on simple heuristic fusion and fuzzy comprehensive evaluation. Frontiers in Physiology, 9, 727. """ + if rpeaks is None: raise TypeError("Please specify the R-peak locations.") @@ -269,6 +269,7 @@ def cSQI(rpeaks=None, verbose=1): def hosSQI(signal=None, quantitative=False, verbose=1): """For the ECG signal. Calculate the Higher-order-statistics-SQI (hosSQI). + Parameters ---------- signal : array-like diff --git a/biosppy/signals/bvp.py b/biosppy/signals/bvp.py index 4290290c..1fadc971 100644 --- a/biosppy/signals/bvp.py +++ b/biosppy/signals/bvp.py @@ -31,6 +31,7 @@ def bvp(signal=None, sampling_rate=1000., path=None, show=True): """Process a raw BVP signal and extract relevant signal features using default parameters. + Parameters ---------- signal : array @@ -41,6 +42,7 @@ def bvp(signal=None, sampling_rate=1000., path=None, show=True): If provided, the plot will be saved to the specified file. show : bool, optional If True, show a summary plot. + Returns ------- ts : array diff --git a/biosppy/signals/ecg.py b/biosppy/signals/ecg.py index 2bece3ab..6043a01b 100644 --- a/biosppy/signals/ecg.py +++ b/biosppy/signals/ecg.py @@ -1482,7 +1482,7 @@ def Pan_Tompkins_Plus_Plus_segmenter(signal=None, sampling_rate=1000.0): Sampling frequency (Hz). Returns - ---------- + ------- qrs_i_raw: array R-peak location indices. @@ -1964,17 +1964,17 @@ def find_artifacts(peaks, sampling_rate): Parameters ---------- - peaks: array - Vector containing indices of detected peaks (R waves locations) - sampling_rate : float - ECG sampling frequency, in Hz. + peaks: array + Vector containing indices of detected peaks (R waves locations) + sampling_rate : float + ECG sampling frequency, in Hz. Returns ------- - artifacts: dictionary - Struct containing indices of detected artifacts. - subspaces: dictionary - Subspaces containing rr, drrs, mrrs, s12, s22, c1, c2 used to classify artifacts. + artifacts: dictionary + Struct containing indices of detected artifacts. + subspaces: dictionary + Subspaces containing rr, drrs, mrrs, s12, s22, c1, c2 used to classify artifacts. """ c1 = 0.13 c2 = 0.17 @@ -2097,17 +2097,17 @@ def estimate_th(x, alpha, ww): Parameters ---------- - x: array - Vector containing drrs or mrrs. - alpha : float - Empirically obtaind constant used in threshold calculation. - ww: int - Window width in ms. + x: array + Vector containing drrs or mrrs. + alpha : float + Empirically obtaind constant used in threshold calculation. + ww: int + Window width in ms. Returns ------- - th: float - Threshold. + th: float + Threshold. """ x_abs = np.abs(x) @@ -2125,15 +2125,15 @@ def correct_extra(extra_indices, peaks): Parameters ---------- - extra_indices: array - Vector containing indices of extra beats. - peaks : array - Vector containing indices of detected peaks (R waves locations). + extra_indices: array + Vector containing indices of extra beats. + peaks : array + Vector containing indices of detected peaks (R waves locations). Returns ------- - corrected_peaks: array - Vector containing indices of corrected peaks. + corrected_peaks: array + Vector containing indices of corrected peaks. """ corrected_peaks = peaks.copy() corrected_peaks = np.delete(corrected_peaks, extra_indices) @@ -2145,15 +2145,15 @@ def correct_misaligned(misaligned_indices, peaks): Parameters ---------- - misaligned_indices: array - Vector containing indices of misaligned beats. - peaks : array - Vector containing indices of detected peaks (R waves locations). + misaligned_indices: array + Vector containing indices of misaligned beats. + peaks : array + Vector containing indices of detected peaks (R waves locations). Returns ------- - corrected_peaks: array - Vector containing indices of corrected peaks. + corrected_peaks: array + Vector containing indices of corrected peaks. """ corrected_peaks = np.array(peaks.copy()) @@ -2181,15 +2181,15 @@ def correct_missed(missed_indices, peaks): Parameters ---------- - missed_indices: array - Vector containing indices of missed beats. - peaks : array - Vector containing indices of detected peaks (R waves locations). + missed_indices: array + Vector containing indices of missed beats. + peaks : array + Vector containing indices of detected peaks (R waves locations). Returns ------- - corrected_peaks: array - Vector containing indices of corrected peaks. + corrected_peaks: array + Vector containing indices of corrected peaks. """ corrected_peaks = peaks.copy() missed_indices = np.array(missed_indices) @@ -2214,17 +2214,17 @@ def update_indices(source_indices, update_indices, update): Parameters ---------- - source_indices: array - Vector containing original indices. - update_indices : array - Vector containing update_indices. - update: int - Update index + source_indices: array + Vector containing original indices. + update_indices : array + Vector containing update_indices. + update: int + Update index Returns ------- - list(np.unique(update_indices)): array - Vector containing unique updated indices. + list(np.unique(update_indices)): array + Vector containing unique updated indices. """ if not update_indices: return update_indices @@ -2245,8 +2245,8 @@ def correct_artifacts(artifacts, peaks): Returns ------- - peaks: array - Vector containing indices of corrected R peaks. + peaks: array + Vector containing indices of corrected R peaks. """ extra_indices = artifacts["extra"] missed_indices = artifacts["missed"] @@ -2278,14 +2278,14 @@ def plot_artifacts(artifacts, subspaces): Parameters ---------- - artifacts: dictionary - Struct containing indices of detected artifacts. - subspaces: dictionary - Subspaces containing rr, drrs, mrrs, s12, s22, c1, c2 used to classify artifacts. + artifacts: dictionary + Struct containing indices of detected artifacts. + subspaces: dictionary + Subspaces containing rr, drrs, mrrs, s12, s22, c1, c2 used to classify artifacts. Returns ------- - None + None """ ectopic_indices = artifacts["ectopic"] missed_indices = artifacts["missed"] @@ -2373,21 +2373,21 @@ def fixpeaks(peaks, sampling_rate=1000, iterative=True, show=False): Parameters ---------- - peaks: array - Vector containing indices of detected peaks (R waves locations) - sampling_rate : int, float, optional - ECG sampling frequency, in Hz. - iterative: boolean, optional - Repeatedly apply the artifact correction (default = true). - show: boolean, optional - Visualize artifacts and artifact thresholds (default = false). + peaks: array + Vector containing indices of detected peaks (R waves locations) + sampling_rate : int, float, optional + ECG sampling frequency, in Hz. + iterative: boolean, optional + Repeatedly apply the artifact correction (default = true). + show: boolean, optional + Visualize artifacts and artifact thresholds (default = false). Returns ------- - artifacts: dictionary - Struct containing indices of detected artifacts. - peaks_clean: array - Vector of corrected peak values (indices) + artifacts: dictionary + Struct containing indices of detected artifacts. + peaks_clean: array + Vector of corrected peak values (indices) References ---------- @@ -2429,10 +2429,10 @@ def getQPositions(ecg_proc=None, show=False): Parameters ---------- - signal : object - object return by the function ecg. + ecg_proc : object + object return by the function ecg. show : bool, optional - If True, show a plot of the Q Positions on every signal sample/template. + If True, show a plot of the Q Positions on every signal sample/template. Returns ------- @@ -2519,10 +2519,10 @@ def getSPositions(ecg_proc=None, show=False): Parameters ---------- - signal : object - object return by the function ecg. + ecg_proc : object + object return by the function ecg. show : bool, optional - If True, show a plot of the S Positions on every signal sample/template. + If True, show a plot of the S Positions on every signal sample/template. Returns ------- @@ -2610,19 +2610,19 @@ def getPPositions(ecg_proc=None, show=False): Parameters ---------- - signal : object - object return by the function ecg. + ecg_proc : object + object return by the function ecg. show : bool, optional - If True, show a plot of the P Positions on every signal sample/template. + If True, show a plot of the P Positions on every signal sample/template. Returns ------- P_positions : array - Array with all P positions on the signal + Array with all P positions on the signal P_start_ positions : array - Array with all P start positions on the signal + Array with all P start positions on the signal P_end_ positions : array - Array with all P end positions on the signal + Array with all P end positions on the signal """ templates_ts = ecg_proc["templates_ts"] @@ -2734,10 +2734,10 @@ def getTPositions(ecg_proc=None, show=False): Parameters ---------- - signal : object - object return by the function ecg. + ecg_proc : object + object return by the function ecg. show : bool, optional - If True, show a plot of the T Positions on every signal sample/template. + If True, show a plot of the T Positions on every signal sample/template. Returns ------- @@ -3029,8 +3029,6 @@ def power_in_range(f_range, f, Pxx_den): def ZZ2018( signal, detector_1, detector_2, fs=1000, search_window=100, nseg=1024, mode="simple" ): - import numpy as np - """ Signal quality estimator. Designed for signal with a lenght of 10 seconds. Follows the approach by Zhao *et la.* [Zhao18]_. @@ -3062,6 +3060,7 @@ def ZZ2018( SQI quality evaluation mechanism of single-lead ECG signal based on simple heuristic fusion and fuzzy comprehensive evaluation. Frontiers in Physiology, 9, 727. """ + import numpy as np if len(detector_1) == 0 or len(detector_2) == 0: return "Unacceptable" diff --git a/biosppy/signals/eda.py b/biosppy/signals/eda.py index c73ad44a..258bbac3 100644 --- a/biosppy/signals/eda.py +++ b/biosppy/signals/eda.py @@ -316,8 +316,7 @@ def cvx_decomposition(signal=None, sampling_rate=1000.0, tau0=2., tau1=0.7, Processing" IEEE Transactions on Biomedical Engineering, 2015. This function is used under the terms of the GNU General Public License - v3.0 (GPLv3). You should comply with the GPLv3 if you use this code (see - 'License' section below). + v3.0 (GPLv3). You should comply with the GPLv3 if you use this code. Copyright (C) 2014-2015 Luca Citi, Alberto Greco @@ -339,9 +338,9 @@ def cvx_decomposition(signal=None, sampling_rate=1000.0, tau0=2., tau1=0.7, Penalization for the tonic spline coefficients solver : ndarray Sparse QP solver to be used, see cvxopt.solvers.qp - options : dict + options : dict solver options, see: http://cvxopt.org/userguide/coneprog.html#algorithm-parameters - + Returns ------- edr : array @@ -356,31 +355,29 @@ def cvx_decomposition(signal=None, sampling_rate=1000.0, tau0=2., tau1=0.7, Offset and slope of the linear drift term res : array Model residuals - obj : array + obj : array Value of objective function being minimized (eq 15 of paper) - + References ---------- .. [cvxEDA] A Greco, G Valenza, A Lanata, EP Scilingo, and L Citi "cvxEDA: a Convex Optimization Approach to Electrodermal Activity Processing" IEEE Transactions on Biomedical Engineering, 2015. DOI: 10.1109/TBME.2015.2474131 - + .. [Figner2011] Figner, Bernd & Murphy, Ryan. (2011). Using skin conductance in judgment and decision making research. A Handbook of Process Tracing Methods for Decision Research. - License - ------- - The cvxEDA function is distributed under the GNU General Public License - v3.0 (GPLv3). For details, please see the full license text at: + Notes + ----- + **License notice:** The cvxEDA function is distributed under the GNU + General Public License v3.0 (GPLv3). For details, see https://www.gnu.org/licenses/gpl-3.0.en.html This code is provided as-is, without any warranty or support from the original authors. - Notes - ----- Changes from original code: - 'y' -> 'signal' - 'delta' -> 1. / 'sampling_rate' diff --git a/biosppy/signals/eeg.py b/biosppy/signals/eeg.py index dda9e741..089632af 100644 --- a/biosppy/signals/eeg.py +++ b/biosppy/signals/eeg.py @@ -218,11 +218,12 @@ def get_power_features(signal=None, sampling_rate=1000.0, size=0.25, overlap=0.5 Computes the average signal power, with overlapping windows, in typical EEG frequency bands: - * Theta: from 4 to 8 Hz, - * Lower Alpha: from 8 to 10 Hz, - * Higher Alpha: from 10 to 13 Hz, - * Beta: from 13 to 25 Hz, - * Gamma: from 25 to 40 Hz. + + - Theta: from 4 to 8 Hz, + - Lower Alpha: from 8 to 10 Hz, + - Higher Alpha: from 10 to 13 Hz, + - Beta: from 13 to 25 Hz, + - Gamma: from 25 to 40 Hz. Parameters ---------- diff --git a/biosppy/signals/egm.py b/biosppy/signals/egm.py index 9a8d0a1f..5e69bc92 100644 --- a/biosppy/signals/egm.py +++ b/biosppy/signals/egm.py @@ -47,7 +47,7 @@ def egm(signal=None, sampling_rate=1000., type = 'bipolar', rhythm = None, woi=N If True, show a summary plot. Returns - ---------- + ------- ts : array Signal time axis reference (seconds). filtered : array @@ -238,7 +238,7 @@ def get_woi(signal, woi_from, woi_to, reference=None): """ Extracts a window of interest (WOI) from the EGM signal. - Parameters: + Parameters ---------- signal : array An array with the EGM signal. @@ -249,8 +249,8 @@ def get_woi(signal, woi_from, woi_to, reference=None): reference : int, optional Reference sample index for the window of interest. If provided, the window will be centered around this reference. - Returns: - ---------- + Returns + ------- egm_woi : array The EGM signal cropped to the window of interest. """ @@ -270,7 +270,7 @@ def nleo_lat(signal=None, sampling_rate=1000., woi = None, reference = None, plo """ Calculate the NLEO (Non-Linear Energy Operator) and activation times from EGM signals. - Parameters: + Parameters ---------- egm : np.ndarray An array with the EGM signal. @@ -283,8 +283,8 @@ def nleo_lat(signal=None, sampling_rate=1000., woi = None, reference = None, plo plot : bool, optional If True, plots the EGM signal with activation time marked. - Returns: - ---------- + Returns + ------- nleo : np.ndarray The NLEO of the EGM signal. nleo_filt : np.ndarray @@ -305,7 +305,7 @@ def nleo(signal=None, sampling_rate=1000., woi = None, reference = None, thresho """ Calculate activation time based on the NLEO (Non-Linear Energy Operator) method. - Parameters: + Parameters ---------- signal : array An array with the EGM signal. @@ -318,8 +318,8 @@ def nleo(signal=None, sampling_rate=1000., woi = None, reference = None, thresho plot : bool, optional If True, plots the EGM signal with activation time marked. - Returns: - ---------- + Returns + ------- nleo : array The NLEO of the EGM signal. nleo_filt : array @@ -409,7 +409,7 @@ def dvdt_lat(signal=None, sampling_rate=1000., woi = None, reference = None, plo """ Calculate activation time based on maximum negative dv/dt from EGM signal. - Parameters: + Parameters ---------- signal : array An array with the EGM signal. @@ -422,8 +422,8 @@ def dvdt_lat(signal=None, sampling_rate=1000., woi = None, reference = None, plo plot : bool, optional If True, plots the EGM signal with activation time marked. - Returns: - ---------- + Returns + ------- lat_index : int Index corresponding to the activation time of the EGM signal. lat : float @@ -463,7 +463,7 @@ def max_lat(signal=None, sampling_rate=1000., woi = None, reference = None, plot """ Calculate activation time based on maximum amplitude from EGM signal. - Parameters: + Parameters ---------- signal : array An array with the EGM signal. @@ -476,8 +476,8 @@ def max_lat(signal=None, sampling_rate=1000., woi = None, reference = None, plot plot : bool, optional If True, plots the EGM signal with activation time marked. - Returns: - ---------- + Returns + ------- lat_index : int Index corresponding to the activation time of the EGM signal. lat : float @@ -512,7 +512,7 @@ def min_lat(signal=None, sampling_rate=1000., woi = None, reference = None, plot """ Calculate activation time based on minimum amplitude from EGM signal. - Parameters: + Parameters ---------- signal : array An array with the EGM signal. @@ -525,8 +525,8 @@ def min_lat(signal=None, sampling_rate=1000., woi = None, reference = None, plot plot : bool, optional If True, plots the EGM signal with activation time marked. - Returns: - ---------- + Returns + ------- lat_index : int Index corresponding to the activation time of the EGM signal. lat : float @@ -561,7 +561,7 @@ def get_activation_times(signals=None, sampling_rate=1000., woi=None, reference= """ Calculate activation times for multiple EGM signals. - Parameters: + Parameters ---------- signals : array A 2D array where each row is an EGM signal. @@ -572,7 +572,8 @@ def get_activation_times(signals=None, sampling_rate=1000., woi=None, reference= reference : int, optional Reference sample index for the window of interest. If provided, the window will be centered around this reference. - Returns: + Returns + ------- lat_indexes : int Indexes corresponding to the activation times of each EGM signal. lats : float @@ -605,7 +606,7 @@ def compare_activation_times(signal=None, sampling_rate=1000., woi=None, referen """ Compare activation times calculated by different methods for a single EGM signal. - Parameters: + Parameters ---------- signal : array An array with the EGM signal. @@ -618,8 +619,8 @@ def compare_activation_times(signal=None, sampling_rate=1000., woi=None, referen plot : bool, optional If True, plots the EGM signal with activation times marked. - Returns: - ---------- + Returns + ------- lat_index_nleo : int Index corresponding to the activation time from NLEO method. lat_index_dvdt : int @@ -667,7 +668,7 @@ def get_voltage(signal=None, woi=None, reference=None): """ Get the maximum voltage of the EGM signal. - Parameters: + Parameters ---------- signal : array An array with the EGM signal. @@ -676,8 +677,8 @@ def get_voltage(signal=None, woi=None, reference=None): reference : int, optional Reference sample index for the window of interest. If provided, the window will be centered around this reference. - Returns: - ---------- + Returns + ------- voltage : float The maximum voltage of the EGM signal. """ @@ -700,7 +701,7 @@ def get_voltages(signals=None, woi=None, reference=None): """ Get the maximum voltages for multiple EGM signals. - Parameters: + Parameters ---------- signals : array A 2D array where each row is an EGM signal. @@ -709,8 +710,8 @@ def get_voltages(signals=None, woi=None, reference=None): reference : int, optional Reference sample index for the window of interest. If provided, the window will be centered around this reference. - Returns: - ---------- + Returns + ------- voltages : array An array of maximum voltages for each EGM signal. """ @@ -729,7 +730,7 @@ def dominant_frequency(signal=None, sampling_rate=1000., plot=False): """ Get the dominant frequency of the EGM signal. - Parameters: + Parameters ---------- signal : array An array with the EGM signal. @@ -738,8 +739,8 @@ def dominant_frequency(signal=None, sampling_rate=1000., plot=False): plot : bool, optional If True, plots the power spectral density of the EGM signal. - Returns: - ---------- + Returns + ------- dominant_freq : float The dominant frequency of the EGM signal in Hz. fft_freqs : array @@ -803,7 +804,7 @@ def shannon_entropy(signal=None, sampling_rate=1000., plot=False): """ Calculate Shannon entropy of the EGM signal. - Parameters: + Parameters ---------- signal : array An array with the EGM signal. @@ -812,8 +813,8 @@ def shannon_entropy(signal=None, sampling_rate=1000., plot=False): plot : bool, optional If True, plots the histogram of the EGM signal voltages. - Returns: - ---------- + Returns + ------- shannon_entropy : float Shannon entropy of the EGM signal. """ @@ -843,15 +844,15 @@ def organization_index(signal=None, sampling_rate=1000.): """ Calculate organization index of the EGM signal. - Parameters: + Parameters ---------- signal : array An array with the EGM signal. sampling_rate : int, float, optional Sampling frequency (Hz) of the EGM signal (default is 1000 Hz). - Returns: - ---------- + Returns + ------- organization_index : float Organization index of the EGM signal. """ @@ -891,15 +892,15 @@ def regularity_index(signal=None, sampling_rate=1000.): """ Calculate regularity index of the EGM signal. - Parameters: + Parameters ---------- signal : array An array with the EGM signal. sampling_rate : int, float, optional Sampling frequency (Hz) of the EGM signal (default is 1000 Hz). - Returns: - ---------- + Returns + ------- regularity_index : float Regularity index of the EGM signal. """ diff --git a/biosppy/signals/ppg.py b/biosppy/signals/ppg.py index 33f276fc..63e0902b 100644 --- a/biosppy/signals/ppg.py +++ b/biosppy/signals/ppg.py @@ -147,7 +147,7 @@ def find_onsets_elgendi2013(signal=None, sampling_rate=1000., peakwindow=0.111, Avoids false positives Returns - ---------- + ------- onsets : array Indices of PPG pulse onsets. params : dict @@ -156,18 +156,19 @@ def find_onsets_elgendi2013(signal=None, sampling_rate=1000., peakwindow=0.111, References ---------- - - Elgendi M, Norton I, Brearley M, Abbott D, Schuurmans D (2013) Systolic Peak Detection in - Acceleration Photoplethysmograms Measured from Emergency Responders in Tropical Conditions. - PLoS ONE 8(10): e76585. doi:10.1371/journal.pone.0076585. - + .. [Elgendi2013] Elgendi M, Norton I, Brearley M, Abbott D, Schuurmans D. + Systolic Peak Detection in Acceleration Photoplethysmograms Measured + from Emergency Responders in Tropical Conditions. PLoS ONE, + 8(10):e76585, 2013. doi:10.1371/journal.pone.0076585. + Notes - --------------------- - Optimal ranges for signal filtering (from Elgendi et al. 2013): - "Optimization of the beat detector’s spectral window for the lower frequency resulted in a + ----- + Optimal ranges for signal filtering (from [Elgendi2013]_): + "Optimization of the beat detector’s spectral window for the lower frequency resulted in a value within 0.5– 1 Hz with the higher frequency within 7–15 Hz" All the number references below between curly brackets {...} by the code refer to the line numbers of - code in "Table 2 Algorithm IV: DETECTOR (PPG signal, F1, F2, W1, W2, b)" from Elgendi et al. 2013 for a + code in "Table 2 Algorithm IV: DETECTOR (PPG signal, F1, F2, W1, W2, b)" from [Elgendi2013]_ for a better comparison of the algorithm """ @@ -283,7 +284,7 @@ def find_onsets_kavsaoglu2016( Maximum value accepted as valid BPM. Returns - ---------- + ------- onsets : array Indices of PPG pulse onsets. window_marks : array @@ -294,13 +295,14 @@ def find_onsets_kavsaoglu2016( References ---------- - - Kavsaoğlu, Ahmet & Polat, Kemal & Bozkurt, Mehmet. (2016). An innovative peak detection algorithm for - photoplethysmography signals: An adaptive segmentation method. TURKISH JOURNAL OF ELECTRICAL ENGINEERING - & COMPUTER SCIENCES. 24. 1782-1796. 10.3906/elk-1310-177. + .. [Kavsaoglu2016] Kavsaoglu A, Polat K, Bozkurt M. An innovative peak + detection algorithm for photoplethysmography signals: an adaptive + segmentation method. Turkish Journal of Electrical Engineering and + Computer Sciences, 24:1782-1796, 2016. doi:10.3906/elk-1310-177. Notes - --------------------- - This algorithm is an adaption of the one described on Kavsaoğlu et al. (2016). + ----- + This algorithm is an adaptation of the one described in [Kavsaoglu2016]_. This version takes into account a minimum delay between peaks and builds upon the adaptive segmentation by using a low-pass filter for BPM changes. This way, even if the algorithm wrongly detects a peak, the BPM value will stay relatively constant so the next pulse can be correctly segmented. diff --git a/biosppy/storage.py b/biosppy/storage.py index c9141be5..ffbc09cd 100644 --- a/biosppy/storage.py +++ b/biosppy/storage.py @@ -1291,7 +1291,7 @@ def _read_ecg_files(ECG_file): Path to the ECG_Export.txt file. Returns - ---------- + ------- channel_names : list List of channel names. reference_channel : str @@ -1347,7 +1347,7 @@ def _find_file(directory, start_str=None, end_str=None): String that the file should end with. Returns - ---------- + ------- str Path to the found file, or None if no file is found. """ @@ -1378,7 +1378,7 @@ def _find_all_files(directory, start_str=None, end_str=None): String that the file should end with. Returns - ---------- + ------- list of str List of paths to the found files, or an empty list if no file is found. """ diff --git a/biosppy/synthesizers/ecg.py b/biosppy/synthesizers/ecg.py index 47592711..42cb2613 100644 --- a/biosppy/synthesizers/ecg.py +++ b/biosppy/synthesizers/ecg.py @@ -30,12 +30,14 @@ def B(l, Kb): Follows the approach by Dolinský, Andráš, Michaeli and Grimaldi [Model03]_. If the parameter introduced doesn't make sense in this context, an error will raise. + Parameters ---------- l : float Inverse of the sampling rate. Kb : int B segment width (miliseconds). + Returns ------- B_segment : array @@ -61,6 +63,7 @@ def P(i, Ap, Kp): Follows the approach by Dolinský, Andráš, Michaeli and Grimaldi [Model03]_. If the parameters introduced don't make sense in this context, an error will raise. + Parameters ---------- i : int @@ -69,6 +72,7 @@ def P(i, Ap, Kp): P wave amplitude (milivolts). Kp : int P wave width (miliseconds). + Returns ------- P_wave : array @@ -97,12 +101,14 @@ def Pq(l, Kpq): Follows the approach by Dolinský, Andráš, Michaeli and Grimaldi [Model03]_. If the parameters introduced don't make sense in this context, an error will raise. + Parameters ---------- l : float Inverse of the sampling rate. Kpq : int PQ segment width (miliseconds). + Returns ------- PQ_segment : array @@ -128,6 +134,7 @@ def Q1(i, Aq, Kq1): Follows the approach by Dolinský, Andráš, Michaeli and Grimaldi [Model03]_. If the parameters introduced don't make sense in this context, an error will raise. + Parameters ---------- i : int @@ -136,6 +143,7 @@ def Q1(i, Aq, Kq1): Q wave amplitude (milivolts). Kq1 : int First 5/6 of the Q wave width (miliseconds). + Returns ------- Q1_wave : array @@ -164,6 +172,7 @@ def Q2(i, Aq, Kq2): Follows the approach by Dolinský, Andráš, Michaeli and Grimaldi [Model03]_. If the parameters introduced don't make sense in this context, an error will raise. + Parameters ---------- i : int @@ -200,6 +209,7 @@ def R(i, Ar, Kr): Follows the approach by Dolinský, Andráš, Michaeli and Grimaldi [Model03]_. If the parameters introduced don't make sense in this context, an error will raise. + Parameters ---------- i : int @@ -208,6 +218,7 @@ def R(i, Ar, Kr): R wave amplitude (milivolts). Kr : int R wave width (miliseconds). + Returns ------- R_wave : array @@ -236,6 +247,7 @@ def S(i, As, Ks, Kcs, k=0): Follows the approach by Dolinský, Andráš, Michaeli and Grimaldi [Model03]_. If the parameters introduced don't make sense in this context, an error will raise. + Parameters ---------- i : int @@ -247,6 +259,7 @@ def S(i, As, Ks, Kcs, k=0): Kcs : int Parameter which allows slight adjustment of S wave shape by cutting away a portion at the end. k : int, optional + Returns ------- S : array @@ -296,6 +309,7 @@ def St(i, As, Ks, Kcs, sm, Kst, k=0): Follows the approach by Dolinský, Andráš, Michaeli and Grimaldi [Model03]_. If the parameters introduced don't make sense in this context, an error will raise. + Parameters ---------- i : int @@ -311,6 +325,7 @@ def St(i, As, Ks, Kcs, sm, Kst, k=0): Kst : int ST segment width (miliseconds). k : int, optional + Returns ------- ST : array @@ -344,6 +359,7 @@ def T(i, As, Ks, Kcs, sm, Kst, At, Kt, k=0): Follows the approach by Dolinský, Andráš, Michaeli and Grimaldi [Model03]_. If the parameters introduced don't make sense in this context, an error will raise. + Parameters ---------- i : int @@ -363,6 +379,7 @@ def T(i, As, Ks, Kcs, sm, Kst, At, Kt, k=0): Kt : int T wave width (miliseconds). k : int, optional + Returns ------- T : array @@ -404,6 +421,7 @@ def I(i, As, Ks, Kcs, sm, Kst, At, Kt, si, Ki): Follows the approach by Dolinský, Andráš, Michaeli and Grimaldi [Model03]_. If the parameters introduced don't make sense in this context, an error will raise. + Parameters ---------- i : int @@ -426,6 +444,7 @@ def I(i, As, Ks, Kcs, sm, Kst, At, Kt, si, Ki): Parameter for setting the transition slope between T wave and isoelectric line. Ki : int I segment width (miliseconds). + Returns ------- I_segment : array @@ -527,29 +546,35 @@ def ecg( Input parameters of the function - Example - ------- - sampling_rate = 10000 - beats = 3 - noise_amplitude = 0.05 - - ECGtotal = np.array([]) - for i in range(beats): - ECGwave, _, _ = ecg(sampling_rate=sampling_rate, var=0.1) - ECGtotal = np.concatenate((ECGtotal, ECGwave)) - t = np.arange(0, len(ECGtotal)) / sampling_rate - - # add powerline noise (50 Hz) - noise = noise_amplitude * np.sin(50 * (2 * pi) * t) - ECGtotal += noise - - plt.plot(t, ECGtotal) - plt.xlabel("Time (ms)") - plt.ylabel("Amplitude (mV)") - plt.grid() - plt.title("ECG") - - plt.show() + Examples + -------- + .. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + from biosppy.synthesizers import ecg as ecg_syn + + sampling_rate = 10000 + beats = 3 + noise_amplitude = 0.05 + + ecg_total = np.array([]) + for _ in range(beats): + ecg_wave, _, _ = ecg_syn.ecg(sampling_rate=sampling_rate, var=0.1) + ecg_total = np.concatenate((ecg_total, ecg_wave)) + + t = np.arange(0, len(ecg_total)) / sampling_rate + + # Add powerline noise (50 Hz). + noise = noise_amplitude * np.sin(50 * (2 * np.pi) * t) + ecg_total += noise + + plt.plot(t, ecg_total) + plt.xlabel("Time (s)") + plt.ylabel("Amplitude (mV)") + plt.title("Synthetic ECG") + plt.grid(True) + plt.show() References ---------- diff --git a/biosppy/synthesizers/emg.py b/biosppy/synthesizers/emg.py index 31bc500e..10900cb1 100644 --- a/biosppy/synthesizers/emg.py +++ b/biosppy/synthesizers/emg.py @@ -67,7 +67,7 @@ def synth_uniform(duration=10, Seed for the random number generator. Returns - ---------- + ------- emg : array Vector containing the EMG signal. t : array @@ -76,36 +76,36 @@ def synth_uniform(duration=10, Input parameters of the function, clean EMG and noise signals, and SNR Examples - ---------- - sampling_rate = 1000 - duration = 10 - noise_amplitude = 0.05 - bursts = 7 - burst_duration = [0.5,1,0.5,0.6,1,0.5,0.5] - burst_location = [0.1,2.5,4,5.5,7,8.5,9.4] - amplitude_mult = [1,1,0.5,1.5,1,0.75,1] - emg_synth, t, params = synth_uniform(duration=duration, sampling_rate=sampling_rate, noise=noise_amplitude, - burst_number=bursts, burst_duration=burst_duration, burst_location=burst_location, - amplitude_mult=amplitude_mult) - - # Get muscle activity state - activity = params["activity"] - - plt.plot(t,emg_synth,label="EMG") - plt.plot(t,activity,label="Muscle activity") - plt.xlabel("Time (s)") - plt.ylabel("Amplitude (mV)") - plt.grid() - plt.title("EMG") - plt.legend() - - plt.show() + -------- + .. code-block:: python + + sampling_rate = 1000 + duration = 10 + noise_amplitude = 0.05 + bursts = 7 + burst_duration = [0.5,1,0.5,0.6,1,0.5,0.5] + burst_location = [0.1,2.5,4,5.5,7,8.5,9.4] + amplitude_mult = [1,1,0.5,1.5,1,0.75,1] + emg_synth, t, params = synth_uniform(duration=duration, sampling_rate=sampling_rate, noise=noise_amplitude, + burst_number=bursts, burst_duration=burst_duration, burst_location=burst_location, + amplitude_mult=amplitude_mult) + + # Get muscle activity state + activity = params["activity"] + + plt.plot(t,emg_synth,label="EMG") + plt.plot(t,activity,label="Muscle activity") + plt.xlabel("Time (s)") + plt.ylabel("Amplitude (mV)") + plt.grid() + plt.title("EMG") + plt.legend() + + plt.show() References - ----------- - .. [ModelEMG1] Joanna DIONG, - "PYTHON: ANALYSING EMG SIGNALS", - https://scientificallysound.org/2016/08/11/python-analysing-emg-signals-part-1/ + ---------- + .. [ModelEMG1] Joanna DIONG, "PYTHON: ANALYSING EMG SIGNALS", https://scientificallysound.org/2016/08/11/python-analysing-emg-signals-part-1/ """ # Seed the random generator for reproducible results # If seed is an integer, use the legacy RandomState class @@ -319,7 +319,7 @@ def _truncated_gaussian_window(sigma, The truncated Gaussian window. References - ----------- + ---------- .. [ModelEMG] Marco GHISLIERI, Giacinto Luigi CERONE, Marco KNAFLITZ & Valentina AGOSTINI "LONG SHORT-TERM MEMORY (LSTM) RECURRENT NEURAL NETWORK FOR MUSCLE ACTIVITY DETECTION" Journal of NeuroEngineering and Rehabilitation, Vol. 18, No. 1, 2021, 3–4 @@ -388,7 +388,7 @@ def synth_gaussian(duration=10, Seed for the random number generator. Returns - ---------- + ------- emg : array Vector containing the EMG signal. t : array @@ -397,35 +397,37 @@ def synth_gaussian(duration=10, Input parameters of the function, clean EMG and noise signals, and SNR Examples - ---------- - sampling_rate = 1000 - duration = 10 - SNR = 30 - sigma = 0.2 - alpha = 1.25 - bursts = 4 - burst_location = [2,4,6,8] - output = synth_gaussian(duration=duration, sampling_rate=sampling_rate, SNR=SNR, - sigma=sigma, alpha=alpha, burst_number=bursts, burst_location=burst_location, - random_state=0) - emg_synth, t, params = output["emg"], output["t"], output["params"] - - # Get muscle activity state - activity = params["activity"] - - plt.figure() - plt.plot(t,emg_synth,label="EMG") - plt.plot(t,activity,label="Muscle activity") - plt.xlabel("Time (s)") - plt.ylabel("Amplitude (mV)") - plt.grid() - plt.title("EMG") - plt.legend() - - plt.show() + -------- + .. code-block:: python + + sampling_rate = 1000 + duration = 10 + SNR = 30 + sigma = 0.2 + alpha = 1.25 + bursts = 4 + burst_location = [2,4,6,8] + output = synth_gaussian(duration=duration, sampling_rate=sampling_rate, SNR=SNR, + sigma=sigma, alpha=alpha, burst_number=bursts, burst_location=burst_location, + random_state=0) + emg_synth, t, params = output["emg"], output["t"], output["params"] + + # Get muscle activity state + activity = params["activity"] + + plt.figure() + plt.plot(t,emg_synth,label="EMG") + plt.plot(t,activity,label="Muscle activity") + plt.xlabel("Time (s)") + plt.ylabel("Amplitude (mV)") + plt.grid() + plt.title("EMG") + plt.legend() + + plt.show() References - ----------- + ---------- .. [ModelEMG2] Marco GHISLIERI, Giacinto Luigi CERONE, Marco KNAFLITZ & Valentina AGOSTINI "LONG SHORT-TERM MEMORY (LSTM) RECURRENT NEURAL NETWORK FOR MUSCLE ACTIVITY DETECTION" Journal of NeuroEngineering and Rehabilitation, Vol. 18, No. 1, 2021, 3–4 diff --git a/docs/_static/custom.css b/docs/_static/custom.css new file mode 100644 index 00000000..ce3f2713 --- /dev/null +++ b/docs/_static/custom.css @@ -0,0 +1,30 @@ +/* Code snippet readability tweaks for Furo. */ +:root { + --color-code-background: #f5f7fb; + --color-code-foreground: #1f2937; +} + +body[data-theme="dark"] { + --color-code-background: #111827; + --color-code-foreground: #e5e7eb; +} + +@media (prefers-color-scheme: dark) { + body:not([data-theme="light"]) { + --color-code-background: #111827; + --color-code-foreground: #e5e7eb; + } +} + +/* Make blocks a bit cleaner and easier to scan. */ +div.highlight pre, +pre { + border: 1px solid var(--color-background-border); + border-radius: 10px; + line-height: 1.45; +} + +code { + font-size: 0.92em; +} + diff --git a/docs/_static/logo_dark.png b/docs/_static/logo_dark.png new file mode 100644 index 00000000..52d7a03c Binary files /dev/null and b/docs/_static/logo_dark.png differ diff --git a/docs/_static/logo_light.png b/docs/_static/logo_light.png new file mode 100644 index 00000000..4b49e6c6 Binary files /dev/null and b/docs/_static/logo_light.png differ diff --git a/docs/api/biosppy.biometrics.rst b/docs/api/biosppy.biometrics.rst new file mode 100644 index 00000000..e87a1fea --- /dev/null +++ b/docs/api/biosppy.biometrics.rst @@ -0,0 +1,52 @@ +biosppy.biometrics +================== + +.. automodule:: biosppy.biometrics + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + assess_classification + assess_runs + combination + cross_validation + get_auth_rates + get_id_rates + get_subject_results + majority_rule + + + + + + .. rubric:: Classes + + .. autosummary:: + + BaseClassifier + KNN + SVM + + + + + + .. rubric:: Exceptions + + .. autosummary:: + + CombinationError + SubjectError + UntrainedError + + + + + diff --git a/docs/api/biosppy.clustering.rst b/docs/api/biosppy.clustering.rst new file mode 100644 index 00000000..d072eb0d --- /dev/null +++ b/docs/api/biosppy.clustering.rst @@ -0,0 +1,40 @@ +biosppy.clustering +================== + +.. automodule:: biosppy.clustering + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + centroid_templates + coassoc_partition + consensus + consensus_kmeans + create_coassoc + create_ensemble + dbscan + hierarchical + kmeans + mdist_templates + outliers_dbscan + outliers_dmean + + + + + + + + + + + + + diff --git a/docs/api/biosppy.metrics.rst b/docs/api/biosppy.metrics.rst new file mode 100644 index 00000000..6664d482 --- /dev/null +++ b/docs/api/biosppy.metrics.rst @@ -0,0 +1,32 @@ +biosppy.metrics +=============== + +.. automodule:: biosppy.metrics + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + cdist + pcosine + pdist + squareform + + + + + + + + + + + + + diff --git a/docs/api/biosppy.plotting.rst b/docs/api/biosppy.plotting.rst new file mode 100644 index 00000000..cb2397e4 --- /dev/null +++ b/docs/api/biosppy.plotting.rst @@ -0,0 +1,51 @@ +biosppy.plotting +================ + +.. automodule:: biosppy.plotting + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + color_palette + plot_abp + plot_acc + plot_bcg + plot_biometrics + plot_bvp + plot_clustering + plot_ecg + plot_eda + plot_eeg + plot_egm + plot_emg + plot_filter + plot_hrv + plot_hrv_fbands + plot_hrv_hist + plot_pcg + plot_poincare + plot_ppg + plot_resp + plot_rri + plot_signal + plot_spectrum + + + + + + + + + + + + + diff --git a/docs/api/biosppy.quality.rst b/docs/api/biosppy.quality.rst new file mode 100644 index 00000000..e05d3d1e --- /dev/null +++ b/docs/api/biosppy.quality.rst @@ -0,0 +1,34 @@ +biosppy.quality +=============== + +.. automodule:: biosppy.quality + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + cSQI + ecg_sqi_level3 + eda_sqi_bottcher + hosSQI + quality_ecg + quality_eda + + + + + + + + + + + + + diff --git a/docs/api/biosppy.stats.rst b/docs/api/biosppy.stats.rst new file mode 100644 index 00000000..4790165c --- /dev/null +++ b/docs/api/biosppy.stats.rst @@ -0,0 +1,35 @@ +biosppy.stats +============= + +.. automodule:: biosppy.stats + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + diff_stats + histogram + linear_regression + paired_test + pearson_correlation + quartiles + unpaired_test + + + + + + + + + + + + + diff --git a/docs/api/biosppy.storage.rst b/docs/api/biosppy.storage.rst new file mode 100644 index 00000000..e3648970 --- /dev/null +++ b/docs/api/biosppy.storage.rst @@ -0,0 +1,48 @@ +biosppy.storage +=============== + +.. automodule:: biosppy.storage + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + alloc_h5 + deserialize + dumpJSON + loadJSON + load_carto_study + load_edf + load_h5 + load_txt + pack_zip + serialize + store_h5 + store_txt + unpack_zip + zip_write + + + + + + .. rubric:: Classes + + .. autosummary:: + + HDF + + + + + + + + + diff --git a/docs/api/biosppy.timing.rst b/docs/api/biosppy.timing.rst new file mode 100644 index 00000000..24430049 --- /dev/null +++ b/docs/api/biosppy.timing.rst @@ -0,0 +1,32 @@ +biosppy.timing +============== + +.. automodule:: biosppy.timing + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + clear + clear_all + tac + tic + + + + + + + + + + + + + diff --git a/docs/api/biosppy.utils.rst b/docs/api/biosppy.utils.rst new file mode 100644 index 00000000..b03f9bc6 --- /dev/null +++ b/docs/api/biosppy.utils.rst @@ -0,0 +1,41 @@ +biosppy.utils +============= + +.. automodule:: biosppy.utils + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + fileparts + fullfile + highestAveragesAllocator + normpath + random_fraction + remainderAllocator + walktree + + + + + + .. rubric:: Classes + + .. autosummary:: + + ReturnTuple + + + + + + + + + diff --git a/docs/api/features/biosppy.features.cepstral.rst b/docs/api/features/biosppy.features.cepstral.rst new file mode 100644 index 00000000..d81ced67 --- /dev/null +++ b/docs/api/features/biosppy.features.cepstral.rst @@ -0,0 +1,32 @@ +biosppy.features.cepstral +========================= + +.. automodule:: biosppy.features.cepstral + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + cepstral + freq_to_mel + mel_to_freq + mfcc + + + + + + + + + + + + + diff --git a/docs/api/features/biosppy.features.frequency.rst b/docs/api/features/biosppy.features.frequency.rst new file mode 100644 index 00000000..9afb6438 --- /dev/null +++ b/docs/api/features/biosppy.features.frequency.rst @@ -0,0 +1,31 @@ +biosppy.features.frequency +========================== + +.. automodule:: biosppy.features.frequency + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + compute_fbands + frequency + spectral_features + + + + + + + + + + + + + diff --git a/docs/api/features/biosppy.features.phase_space.rst b/docs/api/features/biosppy.features.phase_space.rst new file mode 100644 index 00000000..5409a934 --- /dev/null +++ b/docs/api/features/biosppy.features.phase_space.rst @@ -0,0 +1,31 @@ +biosppy.features.phase\_space +============================= + +.. automodule:: biosppy.features.phase_space + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + compute_recurrence_plot + phase_space + recurrence_plot_features + + + + + + + + + + + + + diff --git a/docs/api/features/biosppy.features.time.rst b/docs/api/features/biosppy.features.time.rst new file mode 100644 index 00000000..58385dea --- /dev/null +++ b/docs/api/features/biosppy.features.time.rst @@ -0,0 +1,30 @@ +biosppy.features.time +===================== + +.. automodule:: biosppy.features.time + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + hjorth_features + time + + + + + + + + + + + + + diff --git a/docs/api/features/biosppy.features.time_freq.rst b/docs/api/features/biosppy.features.time_freq.rst new file mode 100644 index 00000000..e1c0b77c --- /dev/null +++ b/docs/api/features/biosppy.features.time_freq.rst @@ -0,0 +1,30 @@ +biosppy.features.time\_freq +=========================== + +.. automodule:: biosppy.features.time_freq + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + compute_wavelet + time_freq + + + + + + + + + + + + + diff --git a/docs/api/inter_plotting/biosppy.inter_plotting.acc.rst b/docs/api/inter_plotting/biosppy.inter_plotting.acc.rst new file mode 100644 index 00000000..23e9d782 --- /dev/null +++ b/docs/api/inter_plotting/biosppy.inter_plotting.acc.rst @@ -0,0 +1,29 @@ +biosppy.inter\_plotting.acc +=========================== + +.. automodule:: biosppy.inter_plotting.acc + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + plot_acc + + + + + + + + + + + + + diff --git a/docs/api/inter_plotting/biosppy.inter_plotting.ecg.rst b/docs/api/inter_plotting/biosppy.inter_plotting.ecg.rst new file mode 100644 index 00000000..a5e3b4e3 --- /dev/null +++ b/docs/api/inter_plotting/biosppy.inter_plotting.ecg.rst @@ -0,0 +1,29 @@ +biosppy.inter\_plotting.ecg +=========================== + +.. automodule:: biosppy.inter_plotting.ecg + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + plot_ecg + + + + + + + + + + + + + diff --git a/docs/api/ml/biosppy.ml.ecg_ml.rst b/docs/api/ml/biosppy.ml.ecg_ml.rst new file mode 100644 index 00000000..06f959c0 --- /dev/null +++ b/docs/api/ml/biosppy.ml.ecg_ml.rst @@ -0,0 +1,29 @@ +biosppy.ml.ecg\_ml +================== + +.. automodule:: biosppy.ml.ecg_ml + + + + + + + + + + + + .. rubric:: Classes + + .. autosummary:: + + AFibDetection + + + + + + + + + diff --git a/docs/api/ml/biosppy.ml.utils_ml.rst b/docs/api/ml/biosppy.ml.utils_ml.rst new file mode 100644 index 00000000..ed34cfb2 --- /dev/null +++ b/docs/api/ml/biosppy.ml.utils_ml.rst @@ -0,0 +1,29 @@ +biosppy.ml.utils\_ml +==================== + +.. automodule:: biosppy.ml.utils_ml + + + + + + + + + + + + .. rubric:: Classes + + .. autosummary:: + + KerasClassifier + + + + + + + + + diff --git a/docs/api/signals/biosppy.signals.abp.rst b/docs/api/signals/biosppy.signals.abp.rst new file mode 100644 index 00000000..088a5912 --- /dev/null +++ b/docs/api/signals/biosppy.signals.abp.rst @@ -0,0 +1,30 @@ +biosppy.signals.abp +=================== + +.. automodule:: biosppy.signals.abp + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + abp + find_onsets_zong2003 + + + + + + + + + + + + + diff --git a/docs/api/signals/biosppy.signals.acc.rst b/docs/api/signals/biosppy.signals.acc.rst new file mode 100644 index 00000000..a47c7337 --- /dev/null +++ b/docs/api/signals/biosppy.signals.acc.rst @@ -0,0 +1,32 @@ +biosppy.signals.acc +=================== + +.. automodule:: biosppy.signals.acc + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + acc + activity_index + frequency_domain_feature_extractor + time_domain_feature_extractor + + + + + + + + + + + + + diff --git a/docs/api/signals/biosppy.signals.bvp.rst b/docs/api/signals/biosppy.signals.bvp.rst new file mode 100644 index 00000000..0df31ad4 --- /dev/null +++ b/docs/api/signals/biosppy.signals.bvp.rst @@ -0,0 +1,29 @@ +biosppy.signals.bvp +=================== + +.. automodule:: biosppy.signals.bvp + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + bvp + + + + + + + + + + + + + diff --git a/docs/api/signals/biosppy.signals.ecg.rst b/docs/api/signals/biosppy.signals.ecg.rst new file mode 100644 index 00000000..95b1fa68 --- /dev/null +++ b/docs/api/signals/biosppy.signals.ecg.rst @@ -0,0 +1,59 @@ +biosppy.signals.ecg +=================== + +.. automodule:: biosppy.signals.ecg + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + ASI_segmenter + Pan_Tompkins_Plus_Plus_segmenter + ZZ2018 + bSQI + call_segmenter + christov_segmenter + compare_segmentation + correct_artifacts + correct_extra + correct_misaligned + correct_missed + correct_rpeaks + ecg + engzee_segmenter + estimate_th + extract_heartbeats + fSQI + find_artifacts + fixpeaks + gamboa_segmenter + getPPositions + getQPositions + getSPositions + getTPositions + hamilton_segmenter + kSQI + pSQI + plot_artifacts + sSQI + ssf_segmenter + update_indices + + + + + + + + + + + + + diff --git a/docs/api/signals/biosppy.signals.eda.rst b/docs/api/signals/biosppy.signals.eda.rst new file mode 100644 index 00000000..29cb4174 --- /dev/null +++ b/docs/api/signals/biosppy.signals.eda.rst @@ -0,0 +1,36 @@ +biosppy.signals.eda +=================== + +.. automodule:: biosppy.signals.eda + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + basic_scr + biosppy_decomposition + cvx_decomposition + eda + eda_events + emotiphai_eda + kbk_scr + rec_times + + + + + + + + + + + + + diff --git a/docs/api/signals/biosppy.signals.eeg.rst b/docs/api/signals/biosppy.signals.eeg.rst new file mode 100644 index 00000000..461d9687 --- /dev/null +++ b/docs/api/signals/biosppy.signals.eeg.rst @@ -0,0 +1,32 @@ +biosppy.signals.eeg +=================== + +.. automodule:: biosppy.signals.eeg + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + car_reference + eeg + get_plf_features + get_power_features + + + + + + + + + + + + + diff --git a/docs/api/signals/biosppy.signals.egm.rst b/docs/api/signals/biosppy.signals.egm.rst new file mode 100644 index 00000000..1983485c --- /dev/null +++ b/docs/api/signals/biosppy.signals.egm.rst @@ -0,0 +1,44 @@ +biosppy.signals.egm +=================== + +.. automodule:: biosppy.signals.egm + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + call_lat_method + compare_activation_times + dominant_frequency + dvdt_lat + egm + get_activation_times + get_voltage + get_voltages + get_woi + max_lat + min_lat + nleo + nleo_lat + organization_index + regularity_index + shannon_entropy + + + + + + + + + + + + + diff --git a/docs/api/signals/biosppy.signals.emg.rst b/docs/api/signals/biosppy.signals.emg.rst new file mode 100644 index 00000000..51187843 --- /dev/null +++ b/docs/api/signals/biosppy.signals.emg.rst @@ -0,0 +1,37 @@ +biosppy.signals.emg +=================== + +.. automodule:: biosppy.signals.emg + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + abbink_onset_detector + bonato_onset_detector + emg + find_onsets + hodges_bui_onset_detector + lidierth_onset_detector + londral_onset_detector + silva_onset_detector + solnik_onset_detector + + + + + + + + + + + + + diff --git a/docs/api/signals/biosppy.signals.hrv.rst b/docs/api/signals/biosppy.signals.hrv.rst new file mode 100644 index 00000000..853ab942 --- /dev/null +++ b/docs/api/signals/biosppy.signals.hrv.rst @@ -0,0 +1,41 @@ +biosppy.signals.hrv +=================== + +.. automodule:: biosppy.signals.hrv + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + approximate_entropy + compute_fbands + compute_geometrical + compute_poincare + compute_rri + detrend_window + hrv + hrv_frequencydomain + hrv_nonlinear + hrv_timedomain + rri_correction + rri_filter + sample_entropy + + + + + + + + + + + + + diff --git a/docs/api/signals/biosppy.signals.pcg.rst b/docs/api/signals/biosppy.signals.pcg.rst new file mode 100644 index 00000000..77ee6889 --- /dev/null +++ b/docs/api/signals/biosppy.signals.pcg.rst @@ -0,0 +1,34 @@ +biosppy.signals.pcg +=================== + +.. automodule:: biosppy.signals.pcg + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + ecg_based_segmentation + find_peaks + get_avg_heart_rate + homomorphic_filter + identify_heart_sounds + pcg + + + + + + + + + + + + + diff --git a/docs/api/signals/biosppy.signals.ppg.rst b/docs/api/signals/biosppy.signals.ppg.rst new file mode 100644 index 00000000..1d82487c --- /dev/null +++ b/docs/api/signals/biosppy.signals.ppg.rst @@ -0,0 +1,32 @@ +biosppy.signals.ppg +=================== + +.. automodule:: biosppy.signals.ppg + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + find_onsets_elgendi2013 + find_onsets_kavsaoglu2016 + ppg + ppg_segmentation + + + + + + + + + + + + + diff --git a/docs/api/signals/biosppy.signals.resp.rst b/docs/api/signals/biosppy.signals.resp.rst new file mode 100644 index 00000000..fbfcf827 --- /dev/null +++ b/docs/api/signals/biosppy.signals.resp.rst @@ -0,0 +1,29 @@ +biosppy.signals.resp +==================== + +.. automodule:: biosppy.signals.resp + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + resp + + + + + + + + + + + + + diff --git a/docs/api/signals/biosppy.signals.tools.rst b/docs/api/signals/biosppy.signals.tools.rst new file mode 100644 index 00000000..cb3c78bb --- /dev/null +++ b/docs/api/signals/biosppy.signals.tools.rst @@ -0,0 +1,60 @@ +biosppy.signals.tools +===================== + +.. automodule:: biosppy.signals.tools + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + analytic_signal + band_power + detrend_smoothness_priors + distance_profile + filter_signal + find_extrema + find_intersection + finite_difference + get_filter + get_heart_rate + mean_waves + median_waves + normalize + pearson_correlation + phase_locking + power_spectrum + resample_signal + rms_error + signal_cross_join + signal_self_join + signal_stats + smoother + synchronize + welch_spectrum + windower + zero_cross + + + + + + .. rubric:: Classes + + .. autosummary:: + + OnlineFilter + + + + + + + + + diff --git a/docs/api/spatial/biosppy.spatial.eam.rst b/docs/api/spatial/biosppy.spatial.eam.rst new file mode 100644 index 00000000..61321f2f --- /dev/null +++ b/docs/api/spatial/biosppy.spatial.eam.rst @@ -0,0 +1,31 @@ +biosppy.spatial.eam +=================== + +.. automodule:: biosppy.spatial.eam + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + cv_triangulation + interpolator + plot_geometry + + + + + + + + + + + + + diff --git a/docs/api/synthesizers/biosppy.synthesizers.ecg.rst b/docs/api/synthesizers/biosppy.synthesizers.ecg.rst new file mode 100644 index 00000000..185e781f --- /dev/null +++ b/docs/api/synthesizers/biosppy.synthesizers.ecg.rst @@ -0,0 +1,39 @@ +biosppy.synthesizers.ecg +======================== + +.. automodule:: biosppy.synthesizers.ecg + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + B + I + P + Pq + Q1 + Q2 + R + S + St + T + ecg + + + + + + + + + + + + + diff --git a/docs/api/synthesizers/biosppy.synthesizers.emg.rst b/docs/api/synthesizers/biosppy.synthesizers.emg.rst new file mode 100644 index 00000000..4a8d8303 --- /dev/null +++ b/docs/api/synthesizers/biosppy.synthesizers.emg.rst @@ -0,0 +1,30 @@ +biosppy.synthesizers.emg +======================== + +.. automodule:: biosppy.synthesizers.emg + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + synth_gaussian + synth_uniform + + + + + + + + + + + + + diff --git a/docs/biosignals/acc.rst b/docs/biosignals/acc.rst new file mode 100644 index 00000000..7257ee16 --- /dev/null +++ b/docs/biosignals/acc.rst @@ -0,0 +1,51 @@ +Accelerometer (ACC) +=================== + +Accelerometer (ACC) signals capture body movement and orientation from linear +acceleration measured along one or more axes. In biosignal workflows, ACC is +commonly used to quantify physical activity, estimate posture transitions, and +provide motion context for other modalities such as ECG or PPG. + +API quick links: :py:mod:`biosppy.signals.acc` | :py:func:`biosppy.signals.acc.acc` + +.. image:: ../images/plots/acc.png + :align: center + :width: 100% + :alt: Example ACC signal plot. + +Quick Usage with :py:func:`biosppy.signals.acc.acc` +--------------------------------------------------- + +.. code-block:: python + + import numpy as np + from biosppy.signals import acc + + # Load a sample ACC recording (one or multiple axes). + signal = np.loadtxt("examples/acc.txt") + + # sampling_rate is in Hz; show=False avoids opening the plot window. + out = acc.acc(signal=signal, sampling_rate=100.0, show=False) + + # ReturnTuple behaves like a tuple + dict-style keys. + print(out.keys()) + +**Inputs** + +- ``signal``: ACC samples (typically N x channels). +- ``sampling_rate``: acquisition frequency in Hz. +- ``units`` / ``path`` / ``show``: optional metadata, output path, and plotting control. + +**Outputs** + +- A ``ReturnTuple`` with processed ACC information (timestamps, filtered views, + and activity-related descriptors). +- Use ``out.keys()`` to inspect all available outputs in your installed version. + + +Example of ACC summary plot: + +.. image:: ../images/plots/acc_summary.png + :align: center + :width: 100% + :alt: Example ACC signal summary plot. \ No newline at end of file diff --git a/docs/biosignals/ecg.rst b/docs/biosignals/ecg.rst new file mode 100644 index 00000000..bed5ba4b --- /dev/null +++ b/docs/biosignals/ecg.rst @@ -0,0 +1,46 @@ +Electrocardiogram (ECG) +======================= + +Electrocardiogram (ECG/EKG) signals describe the electrical activity of the +heart and are widely used to characterize cardiac rhythm and morphology. ECG +processing pipelines typically include filtering, heartbeat detection, and heart +rate estimation as foundational analysis steps. + +API quick links: :py:mod:`biosppy.signals.ecg` | :py:func:`biosppy.signals.ecg.ecg` + +.. image:: ../images/plots/ecg.png + :align: center + :width: 100% + :alt: Example ECG signal plot. + +Quick Usage with :py:func:`biosppy.signals.ecg.ecg` +--------------------------------------------------- + +.. code-block:: python + + import numpy as np + from biosppy.signals import ecg + + signal = np.loadtxt("examples/ecg.txt") + + out = ecg.ecg(signal=signal, sampling_rate=1000.0, show=False) + print(out.keys()) + +**Inputs** + +- ``signal``: raw ECG samples. +- ``sampling_rate``: acquisition frequency in Hz. +- ``units`` / ``path`` / ``show``: optional label, save path, and plotting control. + +**Outputs** + +- A ``ReturnTuple`` with processed ECG information, including time axis, + filtered signal, detected R-peaks, and instantaneous heart-rate related outputs. +- Use ``out.keys()`` to inspect the complete output set. + +Example of ECG summary plot: + +.. image:: ../images/plots/ecg_summary.png + :align: center + :width: 100% + :alt: Example ECG signal summary plot. \ No newline at end of file diff --git a/docs/biosignals/eda.rst b/docs/biosignals/eda.rst new file mode 100644 index 00000000..9f2e2eb5 --- /dev/null +++ b/docs/biosignals/eda.rst @@ -0,0 +1,46 @@ +Electrodermal Activity (EDA) +============================ + +Electrodermal Activity (EDA) signals reflect variations in skin conductance and +are strongly associated with sympathetic nervous system activation. EDA is +frequently used in stress and arousal studies by separating tonic and phasic +components of the skin response. + +API quick links: :py:mod:`biosppy.signals.eda` | :py:func:`biosppy.signals.eda.eda` + +.. image:: ../images/plots/eda.png + :align: center + :width: 100% + :alt: Example EDA signal plot. + +Quick Usage with :py:func:`biosppy.signals.eda.eda` +--------------------------------------------------- + +.. code-block:: python + + import numpy as np + from biosppy.signals import eda + + signal = np.loadtxt("examples/eda.txt") + + out = eda.eda(signal=signal, sampling_rate=1000.0, show=False) + print(out.keys()) + +**Inputs** + +- ``signal``: raw EDA/skin conductance signal. +- ``sampling_rate``: acquisition frequency in Hz. +- ``min_amplitude`` / ``size``: optional parameters for SCR-related detection. + +**Outputs** + +- A ``ReturnTuple`` with EDA processing results such as filtered signal, + onsets/peaks, and amplitude-related descriptors. +- Use ``out.keys()`` to inspect all returned fields. + +Example of EDA summary plot: + +.. image:: ../images/plots/eda_summary.png + :align: center + :width: 100% + :alt: Example EDA signal summary plot. diff --git a/docs/biosignals/eeg.rst b/docs/biosignals/eeg.rst new file mode 100644 index 00000000..959c6eea --- /dev/null +++ b/docs/biosignals/eeg.rst @@ -0,0 +1,46 @@ +Electroencephalogram (EEG) +========================== + +Electroencephalogram (EEG) signals measure electrical brain activity using +scalp electrodes and enable time-domain and frequency-domain analysis of neural +dynamics. EEG processing is commonly used for cognitive state assessment, +sleep staging, and event-related studies. + +API quick links: :py:mod:`biosppy.signals.eeg` | :py:func:`biosppy.signals.eeg.eeg` + +.. image:: ../images/plots/eeg_ec.png + :align: center + :width: 100% + :alt: Example EEG signal plot with eyes closed. + +.. image:: ../images/plots/eeg_eo.png + :align: center + :width: 100% + :alt: Example EEG signal plot with eyes open. + + +Quick Usage with :py:func:`biosppy.signals.eeg.eeg` +--------------------------------------------------- + +.. code-block:: python + + import numpy as np + from biosppy.signals import eeg + + # EEG processing expects channels in columns for multichannel data. + signal = np.loadtxt("examples/eeg_ec.txt") + + out = eeg.eeg(signal=signal, sampling_rate=1000.0, show=False) + print(out.keys()) + +**Inputs** + +- ``signal``: EEG samples (N x channels). +- ``sampling_rate``: acquisition frequency in Hz. +- ``labels``: optional channel labels for readable plots/results. + +**Outputs** + +- A ``ReturnTuple`` with EEG processing results such as filtered signals and + derived channel-wise descriptors. +- Use ``out.keys()`` to inspect all outputs. diff --git a/docs/biosignals/egm.rst b/docs/biosignals/egm.rst new file mode 100644 index 00000000..78f06be8 --- /dev/null +++ b/docs/biosignals/egm.rst @@ -0,0 +1,45 @@ +Electrogram (EGM) +================= + +Electrogram (EGM) signals are intracardiac electrical recordings acquired by +catheters or implanted leads, offering localized information about atrial or +ventricular activation. EGM analysis is useful in electrophysiology workflows, +including rhythm characterization and arrhythmia assessment. + +API quick links: :py:mod:`biosppy.signals.egm` | :py:func:`biosppy.signals.egm.egm` + +.. image:: ../images/plots/egm.png + :align: center + :width: 100% + :alt: Example bipolar EGM signal in sinus rhythm. + +Quick Usage with :py:func:`biosppy.signals.egm.egm` +--------------------------------------------------- + +.. code-block:: python + + import numpy as np + from biosppy.signals import egm + + signal = np.loadtxt("examples/egm_bipolar_sinus.txt") + + out = egm.egm( + signal=signal, + sampling_rate=1000.0, + type="bipolar", + show=False, + ) + print(out.keys()) + +**Inputs** + +- ``signal``: intracardiac EGM waveform. +- ``sampling_rate``: acquisition frequency in Hz. +- ``type`` / ``rhythm`` / ``method`` / ``threshold``: options controlling + morphology and event-detection behavior. + +**Outputs** + +- A ``ReturnTuple`` with filtered EGM signals and arrhythmia/event-related + descriptors according to the chosen method. +- Use ``out.keys()`` to inspect exact return fields. diff --git a/docs/biosignals/emg.rst b/docs/biosignals/emg.rst new file mode 100644 index 00000000..9721030a --- /dev/null +++ b/docs/biosignals/emg.rst @@ -0,0 +1,47 @@ +Electromyogram (EMG) +==================== + +Electromyogram (EMG) signals measure muscle electrical activity and are often +analyzed to detect activation bursts, fatigue patterns, and neuromuscular +control behavior. Surface EMG enables non-invasive acquisition and supports +applications in rehabilitation, sports, and human-computer interaction. + +API quick links: :py:mod:`biosppy.signals.emg` | :py:func:`biosppy.signals.emg.emg` + +.. image:: ../images/plots/emg.png + :align: center + :width: 100% + :alt: Example EMG signal plot. + + +Quick Usage with :py:func:`biosppy.signals.emg.emg` +--------------------------------------------------- + +.. code-block:: python + + import numpy as np + from biosppy.signals import emg + + signal = np.loadtxt("examples/emg.txt") + + out = emg.emg(signal=signal, sampling_rate=1000.0, show=False) + print(out.keys()) + +**Inputs** + +- ``signal``: raw EMG samples. +- ``sampling_rate``: acquisition frequency in Hz. +- ``units`` / ``path`` / ``show``: optional units label, output path, and plotting flag. + +**Outputs** + +- A ``ReturnTuple`` with processed EMG outputs, usually including filtered signal + and event markers (for example activation/onset-related information). +- Use ``out.keys()`` to inspect the exact outputs. + +Example of EMG summary plot: + +.. image:: ../images/plots/emg_summary.png + :align: center + :width: 100% + :alt: Example ACC signal summary plot. \ No newline at end of file diff --git a/docs/biosignals/index.rst b/docs/biosignals/index.rst new file mode 100644 index 00000000..fb413438 --- /dev/null +++ b/docs/biosignals/index.rst @@ -0,0 +1,65 @@ +Biosignals +========== + +`BioSPPy` includes processing pipelines for several biosignal types, +combining common preprocessing steps with feature extraction and visualization. +The pages below give a quick overview of each signal type and show a representative +example plot from the project dataset. + +.. toctree:: + :maxdepth: 1 + + acc + ecg + eda + eeg + egm + emg + pcg + ppg + resp + rri + +++++++++++++++++++++ +What are Biosignals? +++++++++++++++++++++ + +Biosignals, in the most general sense, are measurements of physical properties +of biological systems. These include the measurement of properties at the +cellular level, such as concentrations of molecules, membrane potentials, and +DNA assays. On a higher level, for a group of specialized cells (i.e. an organ) +we are able to measure properties such as cell counts and histology, organ +secretions, and electrical activity (the electrical system of the heart, for +instance). Finally, for complex biological systems like the human being, +biosignals also include blood and urine test measurements, core body +temperature, motion tracking signals, and imaging techniques such as CAT and MRI +scans. However, the term biosignal is most often applied to bioelectrical, +time-varying signals, such as the electrocardiogram. + +The task of obtaining biosignals of good quality is time-consuming, +and typically requires the use of costly hardware. Access to these instruments +is, therefore, usually restricted to research institutes, medical centers, +and hospitals. However, recent projects like `BITalino `__ +or `OpenBCI `__ have lowered the entry barriers of biosignal +acquisition, fostering the Do-It-Yourself and Maker communities to develop +physiological computing applications. You can find a list of biosignal +platform `here `__. + +The following sub-sections briefly describe the biosignals +covered by `biosppy`. + + ++++++++++++++++ +Quick API links ++++++++++++++++ + +- ACC: :py:mod:`biosppy.signals.acc` +- ECG: :py:mod:`biosppy.signals.ecg` +- EDA: :py:mod:`biosppy.signals.eda` +- EEG: :py:mod:`biosppy.signals.eeg` +- EGM: :py:mod:`biosppy.signals.egm` +- EMG: :py:mod:`biosppy.signals.emg` +- PCG: :py:mod:`biosppy.signals.pcg` +- PPG: :py:mod:`biosppy.signals.ppg` +- RESP: :py:mod:`biosppy.signals.resp` +- RRI/HRV: :py:mod:`biosppy.signals.hrv` diff --git a/docs/biosignals/pcg.rst b/docs/biosignals/pcg.rst new file mode 100644 index 00000000..96123706 --- /dev/null +++ b/docs/biosignals/pcg.rst @@ -0,0 +1,46 @@ +Phonocardiogram (PCG) +===================== + +Phonocardiogram (PCG) signals capture acoustic information from heart sounds, +including S1 and S2 components and their temporal structure. PCG analysis can +complement electrical measurements and help characterize mechanical aspects of +cardiac function. + +API quick links: :py:mod:`biosppy.signals.pcg` | :py:func:`biosppy.signals.pcg.pcg` + +.. image:: ../images/plots/pcg.png + :align: center + :width: 100% + :alt: Example PCG signal plot. + +Quick Usage with :py:func:`biosppy.signals.pcg.pcg` +--------------------------------------------------- + +.. code-block:: python + + import numpy as np + from biosppy.signals import pcg + + signal = np.loadtxt("examples/pcg.txt") + + out = pcg.pcg(signal=signal, sampling_rate=1000.0, show=False) + print(out.keys()) + +**Inputs** + +- ``signal``: raw phonocardiogram waveform. +- ``sampling_rate``: acquisition frequency in Hz. +- ``units`` / ``path`` / ``show``: optional metadata, save path, and plotting flag. + +**Outputs** + +- A ``ReturnTuple`` with processed PCG outputs, including filtered signal, + heart-sound markers, and heart-rate related descriptors. +- Use ``out.keys()`` to inspect all available fields. + +Example of PCD summary plot: + +.. image:: ../images/plots/pcg_summary.png + :align: center + :width: 100% + :alt: Example PCG signal summary plot. diff --git a/docs/biosignals/ppg.rst b/docs/biosignals/ppg.rst new file mode 100644 index 00000000..dce73013 --- /dev/null +++ b/docs/biosignals/ppg.rst @@ -0,0 +1,46 @@ +Photoplethysmogram (PPG) +======================== + +Photoplethysmogram (PPG) signals are optical measurements of peripheral blood +volume changes and are widely used in wearable health monitoring. PPG supports +pulse detection, heart rate estimation, and variability analysis with low-cost +sensor setups. + +API quick links: :py:mod:`biosppy.signals.ppg` | :py:func:`biosppy.signals.ppg.ppg` + +.. image:: ../images/plots/ppg.png + :align: center + :width: 100% + :alt: Example PPG signal plot. + +Quick Usage with :py:func:`biosppy.signals.ppg.ppg` +--------------------------------------------------- + +.. code-block:: python + + import numpy as np + from biosppy.signals import ppg + + signal = np.loadtxt("examples/ppg.txt") + + out = ppg.ppg(signal=signal, sampling_rate=1000.0, show=False) + print(out.keys()) + +**Inputs** + +- ``signal``: raw PPG samples. +- ``sampling_rate``: acquisition frequency in Hz. +- ``units`` / ``show``: optional units label and plotting control. + +**Outputs** + +- A ``ReturnTuple`` with processed PPG outputs, usually including filtered + signal, pulse onsets/peaks, and heart-rate related descriptors. +- Use ``out.keys()`` to inspect returned values. + +Example of PPG summary plot: + +.. image:: ../images/plots/ppg_summary.png + :align: center + :width: 100% + :alt: Example PPG signal summary plot. diff --git a/docs/biosignals/resp.rst b/docs/biosignals/resp.rst new file mode 100644 index 00000000..6da6a9b1 --- /dev/null +++ b/docs/biosignals/resp.rst @@ -0,0 +1,47 @@ +Respiration (RESP) +================== + +Respiration (RESP) signals describe breathing dynamics over time and provide +useful information about respiratory rate, cycle morphology, and ventilatory +patterns. They are frequently analyzed alongside cardiovascular signals to +capture cardiorespiratory interactions. + +API quick links: :py:mod:`biosppy.signals.resp` | :py:func:`biosppy.signals.resp.resp` + +.. image:: ../images/plots/resp.png + :align: center + :width: 100% + :alt: Example respiration signal plot. + + +Quick Usage with :py:func:`biosppy.signals.resp.resp` +----------------------------------------------------- + +.. code-block:: python + + import numpy as np + from biosppy.signals import resp + + signal = np.loadtxt("examples/resp.txt") + + out = resp.resp(signal=signal, sampling_rate=1000.0, show=False) + print(out.keys()) + +**Inputs** + +- ``signal``: raw respiration waveform. +- ``sampling_rate``: acquisition frequency in Hz. +- ``units`` / ``path`` / ``show``: optional metadata and plotting options. + +**Outputs** + +- A ``ReturnTuple`` with processed respiration outputs, including timestamps, + filtered signal, respiratory cycle markers, and rate-related information. +- Use ``out.keys()`` to inspect exact output names. + +Example of RESP summary plot: + +.. image:: ../images/plots/resp_summary.png + :align: center + :width: 100% + :alt: Example RESP signal summary plot. diff --git a/docs/biosignals/rri.rst b/docs/biosignals/rri.rst new file mode 100644 index 00000000..569f46d5 --- /dev/null +++ b/docs/biosignals/rri.rst @@ -0,0 +1,48 @@ +R-R Intervals (RRI) / HRV +========================= + +R-R interval (RRI) signals represent the beat-to-beat timing series extracted +from cardiac peaks and are the core input for heart rate variability (HRV) +analysis. RRI processing helps quantify autonomic modulation through temporal +and spectral descriptors. + +API quick links: :py:mod:`biosppy.signals.hrv` | :py:func:`biosppy.signals.hrv.hrv` + +.. image:: ../images/plots/rri.png + :align: center + :width: 100% + :alt: Example RRI signal plot. + +Quick Usage with :py:func:`biosppy.signals.hrv.hrv` +--------------------------------------------------- + +.. code-block:: python + + import numpy as np + from biosppy.signals import hrv + + # RRI in milliseconds. + rri = np.loadtxt("examples/rri.txt") + + out = hrv.hrv(rri=rri, sampling_rate=1000.0, show=False) + print(out.keys()) + +**Inputs** + +- ``rri``: beat-to-beat intervals (ms), or alternatively ``rpeaks`` with + ``sampling_rate`` to derive RRI internally. +- ``rri_min`` / ``rri_max``: optional physiological bounds for artifact control. +- ``parameters``: which HRV feature families to compute. + +**Outputs** + +- A ``ReturnTuple`` with HRV results (time-domain, frequency-domain, and + non-linear descriptors, depending on selected parameters). +- Use ``out.keys()`` to inspect all computed metrics. + +Example of HRV summary plot: + +.. image:: ../images/plots/hrv_summary.png + :align: center + :width: 100% + :alt: Example HRV summary plot. diff --git a/docs/biosppy.features.rst b/docs/biosppy.features.rst index 441b4b46..9cb72267 100644 --- a/docs/biosppy.features.rst +++ b/docs/biosppy.features.rst @@ -7,30 +7,11 @@ This sub-package provides methods to extract common features from physiological Modules ------- -.. contents:: - :local: - -.. automodule:: biosppy.features.cepstral - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.features.frequency - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.features.phase_space - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.features.time - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.features.time_freq - :members: - :undoc-members: - :show-inheritance: \ No newline at end of file +.. autosummary:: + :toctree: api/features + + biosppy.features.cepstral + biosppy.features.frequency + biosppy.features.phase_space + biosppy.features.time + biosppy.features.time_freq diff --git a/docs/biosppy.inter_plotting.rst b/docs/biosppy.inter_plotting.rst index c84e3c6e..b5880b0e 100644 --- a/docs/biosppy.inter_plotting.rst +++ b/docs/biosppy.inter_plotting.rst @@ -1,20 +1,13 @@ biosppy.inter_plotting -=============== +====================== This sub-package provides support for interactive plots that allow manual annotation of physiological signals. Modules ------- -.. contents:: - :local: +.. autosummary:: + :toctree: api/inter_plotting -.. automodule:: biosppy.inter_plotting.acc - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.inter_plotting.ecg - :members: - :undoc-members: - :show-inheritance: \ No newline at end of file + biosppy.inter_plotting.acc + biosppy.inter_plotting.ecg diff --git a/docs/biosppy.ml.rst b/docs/biosppy.ml.rst new file mode 100644 index 00000000..1a6d35fb --- /dev/null +++ b/docs/biosppy.ml.rst @@ -0,0 +1,15 @@ +biosppy.ml +========== + +This sub-package provides optional machine-learning models and utilities for +biosignal analysis. + +Modules +------- + +.. autosummary:: + :toctree: api/ml + + biosppy.ml.ecg_ml + biosppy.ml.utils_ml + diff --git a/docs/biosppy.rst b/docs/biosppy.rst index 44c9f4e9..d1566af5 100644 --- a/docs/biosppy.rst +++ b/docs/biosppy.rst @@ -13,54 +13,21 @@ Packages biosppy.features biosppy.synthesizers biosppy.inter_plotting + biosppy.spatial + biosppy.ml Modules ------- -.. contents:: - :local: - -.. automodule:: biosppy.biometrics - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.clustering - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.metrics - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.plotting - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.quality - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.stats - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.storage - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.timing - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.utils - :members: - :undoc-members: - :show-inheritance: +.. autosummary:: + :toctree: api + + biosppy.biometrics + biosppy.clustering + biosppy.metrics + biosppy.plotting + biosppy.quality + biosppy.stats + biosppy.storage + biosppy.timing + biosppy.utils diff --git a/docs/biosppy.signals.rst b/docs/biosppy.signals.rst index 39c5c80e..753ded39 100644 --- a/docs/biosppy.signals.rst +++ b/docs/biosppy.signals.rst @@ -7,65 +7,19 @@ This sub-package provides methods to process common physiological signals Modules ------- -.. contents:: - :local: - -.. automodule:: biosppy.signals.abp - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.signals.acc - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.signals.bvp - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.signals.ecg - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.signals.eda - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.signals.eeg - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.signals.emg - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.signals.hrv - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.signals.pcg - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.signals.ppg - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.signals.resp - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.signals.tools - :members: - :undoc-members: - :show-inheritance: +.. autosummary:: + :toctree: api/signals + + biosppy.signals.abp + biosppy.signals.acc + biosppy.signals.bvp + biosppy.signals.ecg + biosppy.signals.eda + biosppy.signals.eeg + biosppy.signals.egm + biosppy.signals.emg + biosppy.signals.hrv + biosppy.signals.pcg + biosppy.signals.ppg + biosppy.signals.resp + biosppy.signals.tools diff --git a/docs/biosppy.spatial.rst b/docs/biosppy.spatial.rst new file mode 100644 index 00000000..1d2b5507 --- /dev/null +++ b/docs/biosppy.spatial.rst @@ -0,0 +1,14 @@ +biosppy.spatial +=============== + +This sub-package provides methods for spatial analysis and visualization of +biosignal-derived maps. + +Modules +------- + +.. autosummary:: + :toctree: api/spatial + + biosppy.spatial.eam + diff --git a/docs/biosppy.synthesizers.rst b/docs/biosppy.synthesizers.rst index 66eb5c0f..67f2edfc 100644 --- a/docs/biosppy.synthesizers.rst +++ b/docs/biosppy.synthesizers.rst @@ -1,5 +1,5 @@ biosppy.synthesizers -=============== +==================== This sub-package provides methods to generate artificial (synthesised) physiological signals. (biosignals). @@ -7,15 +7,8 @@ This sub-package provides methods to generate artificial (synthesised) physiolog Modules ------- -.. contents:: - :local: +.. autosummary:: + :toctree: api/synthesizers -.. automodule:: biosppy.synthesizers.ecg - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: biosppy.synthesizers.emg - :members: - :undoc-members: - :show-inheritance: \ No newline at end of file + biosppy.synthesizers.ecg + biosppy.synthesizers.emg diff --git a/docs/conf.py b/docs/conf.py index b44485d8..f729abce 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -30,7 +30,7 @@ def __getattr__(cls, name): return Mock() -MOCK_MODULES = ['numpy', 'scipy', 'matplotlib', 'matplotlib.pyplot','matplotlib.lines', +MOCK_MODULES = ['numpy', 'scipy', 'scipy.fft', 'matplotlib', 'matplotlib.pyplot', 'matplotlib.colors', 'matplotlib.lines', 'matplotlib.patches','matplotlib.backends.backend_tkagg', 'scipy.signal', 'scipy.interpolate', 'scipy.optimize', 'scipy.stats', 'scipy.cluster', 'scipy.cluster.hierarchy', @@ -38,7 +38,8 @@ def __getattr__(cls, name): 'scipy.spatial.distance', 'sklearn', 'sklearn.cluster', 'sklearn.model_selection', 'sklearn.externals', 'matplotlib.gridspec', 'h5py', 'shortuuid', 'bidict', 'svm', - 'sksvm','pywt','joblib','scipy.linalg','scipy.integrate','scipy.ndimage','peakutils'] + 'sksvm','pywt','joblib','scipy.linalg','scipy.integrate','scipy.ndimage','peakutils', + 'pyvista', 'tensorflow', 'tensorflow.keras'] sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES) @@ -57,12 +58,23 @@ def __getattr__(cls, name): # ones. extensions = [ 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', 'sphinx.ext.coverage', 'sphinx.ext.viewcode', 'sphinx.ext.napoleon', 'sphinx.ext.imgmath', + 'sphinx_copybutton', ] +autosummary_generate = True + +# Make autosummary-generated module pages render full API details for members. +autodoc_default_options = { + 'members': True, + 'undoc-members': True, + 'show-inheritance': True, +} + # Napoleon settings napoleon_use_rtype = False @@ -138,8 +150,9 @@ def __getattr__(cls, name): # output. They are ignored by default. #show_authors = False -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +# Syntax highlighting styles (light and dark mode). +pygments_style = 'friendly' +pygments_dark_style = 'monokai' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] @@ -153,15 +166,13 @@ def __getattr__(cls, name): # -- Options for HTML output ---------------------------------------------- -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'sphinx_rtd_theme' +# The theme to use for HTML and HTML Help pages. +html_theme = 'furo' -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. +# Furo supports separate logos for light/dark mode. html_theme_options = { - 'logo_only': True, + 'light_logo': 'logo_light.png', + 'dark_logo': 'logo_dark.png', } # Add any paths that contain custom themes here, relative to this directory. @@ -174,9 +185,8 @@ def __getattr__(cls, name): # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -html_logo = "logo/logo_inverted_no_tag.png" +# Keep theme-aware logos only (configured via html_theme_options above). +html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 @@ -186,7 +196,8 @@ def __getattr__(cls, name): # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -# html_static_path = ['_static'] +html_static_path = ['_static'] +html_css_files = ['custom.css'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied diff --git a/docs/contribute.rst b/docs/contribute.rst new file mode 100644 index 00000000..2357a993 --- /dev/null +++ b/docs/contribute.rst @@ -0,0 +1,89 @@ +Contributing to BioSPPy +======================= + +Thank you for helping improve ``BioSPPy``. This page summarizes the contribution +workflow in a simple, practical format. + +Before You Start +---------------- + +- You need a `GitHub account `_. +- Contributions are made through your fork of + `scientisst/BioSPPy `_. + +Quick Workflow +-------------- + +1. **Fork the repository** on GitHub. +2. **Clone your fork** locally. +3. **Create a branch** for your work. +4. **Install dependencies** and make your changes. +5. **Commit and push** your branch. +6. **Open a Pull Request** to ``scientisst/BioSPPy:main``. + +Setup Commands +-------------- + +.. code-block:: bash + + git clone https://github.com/yourusername/biosppy.git + cd biosppy + git checkout -b your-feature-name + pip install -r requirements.txt + +You can also clone using GitHub Desktop if you prefer a GUI workflow. + +Making Good Changes +------------------- + +- Keep commits small and focused (one logical change per commit). +- Write clear commit messages. +- Follow existing project conventions. +- Update docstrings and docs when behavior changes. + +Example commit: + +.. code-block:: bash + + git add . + git commit -m "Improve ECG peak detection edge-case handling" + +Code Style +---------- + +- Follow `PEP 8 `_. +- Use ``snake_case`` for variables and functions. +- Prefer clear, well-structured code over clever shortcuts. +- Use docstrings in + `numpydoc format `_. +- Avoid adding new dependencies unless they are necessary. + +Open a Pull Request +------------------- + +After committing locally, push your branch: + +.. code-block:: bash + + git push origin your-feature-name + +Then open a Pull Request from your fork to ``scientisst/BioSPPy`` ``main``. + +When writing your PR: + +- Use a clear title. +- Explain *what* changed and *why*. +- Mention any important trade-offs or limitations. + +If your fork is behind, sync it with upstream before opening the PR: +`Syncing a fork `_. + +Need Help? +---------- + +- Open an issue: + `github.com/scientisst/BioSPPy/issues/new `_ +- Contact maintainers: `developer@scientisst.com `_ + +Thanks again for contributing. + diff --git a/docs/gettingstarted.rst b/docs/gettingstarted.rst new file mode 100644 index 00000000..adfa4a30 --- /dev/null +++ b/docs/gettingstarted.rst @@ -0,0 +1,198 @@ +Getting Started +=============== + +``BioSPPy`` is organized around a simple idea: start with ready-to-use +processing pipelines for common biosignals, and then drill down into more +specialized modules as your analysis grows. + +This page gives a quick mental model of the package and then walks through a +complete ECG example using the sample data included in the repository. + +How ``BioSPPy`` is organized +---------------------------- + +Most users begin in one of these places: + +* :doc:`biosppy.signals` contains signal-specific pipelines such as + :py:func:`biosppy.signals.ecg.ecg`, :py:func:`biosppy.signals.eda.eda`, and + :py:func:`biosppy.signals.ppg.ppg`. These are the highest-level entry points + and are usually the best place to start. +* :py:mod:`biosppy.signals.tools` provides lower-level reusable operations such + as filtering, smoothing, and heart-rate estimation. +* :py:mod:`biosppy.storage` handles loading and saving data. In this tutorial we + will use :py:func:`biosppy.storage.load_txt` to read an example ECG file. +* :py:mod:`biosppy.plotting` and :doc:`biosppy.inter_plotting` generate the + summary figures produced by the processing pipelines. +* :doc:`biosppy.features` provides feature extraction methods in time, + frequency, cepstral, time-frequency, and phase-space domains. +* :py:mod:`biosppy.quality` contains signal quality assessment utilities. +* :doc:`biosppy.synthesizers` contains synthetic signal generators useful for + simulation and testing. + +Across the package, many functions return a +:py:class:`biosppy.utils.ReturnTuple`. This behaves like a regular tuple, but it +also lets you access results by name. See :doc:`returntuple` for details. + +A typical workflow looks like this: + +1. Load a signal with :py:mod:`biosppy.storage` or your own I/O code. +2. Process it with a signal-specific function from :doc:`biosppy.signals`. +3. Inspect the named outputs from the returned + :py:class:`biosppy.utils.ReturnTuple`. +4. Plot, save, or pass those outputs into downstream analysis. + +ECG example +----------- + +The repository includes example signals in the ``examples/`` folder (available +`on GitHub `__). We +will use ``examples/ecg.txt`` to demonstrate the workflow. + +Step 1: load and inspect the raw ECG signal +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The example below loads the ECG recording, reads its metadata, builds a time +axis, and plots the raw waveform. + +.. code-block:: python + + import matplotlib.pyplot as plt + import numpy as np + + from biosppy import storage + + data_path = "examples/ecg.txt" + signal, metadata = storage.load_txt(data_path) + + sampling_rate = metadata["sampling_rate"] + n_samples = len(signal) + duration = (n_samples - 1) / sampling_rate + ts = np.linspace(0, duration, n_samples, endpoint=False) + + plt.figure(figsize=(10, 4)) + plt.plot(ts, signal, lw=1.5) + plt.xlabel("Time (s)") + plt.ylabel("Amplitude") + plt.title("Raw ECG signal") + plt.grid(True) + plt.tight_layout() + plt.show() + +This should produce a plot similar to the one shown below. + +.. image:: images/ECG_raw.png + :align: center + :width: 100% + :alt: Example of a raw ECG signal. + +For this example, the metadata indicates a sampling rate of 1000 Hz. The raw +signal is already usable, but you can still see typical acquisition artifacts +such as baseline offset and high-frequency interference. + +Step 2: run the ECG processing pipeline +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Now process the same signal with :py:func:`biosppy.signals.ecg.ecg`: + +.. code-block:: python + + from biosppy.signals import ecg + + out = ecg.ecg(signal=signal, sampling_rate=sampling_rate, show=True) + +This single call performs the standard high-level ECG workflow: + +* bandpass filtering, +* DC offset removal, +* R-peak detection, +* heartbeat template extraction, and +* instantaneous heart-rate estimation. + +With ``show=True``, ``BioSPPy`` also generates a summary plot like the one +below. + +.. image:: images/ECG_processed.png + :align: center + :width: 100% + :alt: Example of processed ECG signal. + +Step 3: inspect the outputs +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ECG pipeline returns a :py:class:`biosppy.utils.ReturnTuple` with named +results: + +.. code-block:: python + + print(out.keys()) + +Typical keys include: + +* ``ts``: time axis for the filtered ECG signal; +* ``filtered``: filtered ECG waveform; +* ``rpeaks``: indices of detected R-peaks; +* ``templates_ts`` and ``templates``: extracted heartbeat templates; +* ``heart_rate_ts`` and ``heart_rate``: timestamps and instantaneous heart rate + in beats per minute. + +You can access values either by position or by name: + +.. code-block:: python + + ts = out[0] + filtered = out["filtered"] + rpeaks = out["rpeaks"] + heart_rate = out["heart_rate"] + +Named access is usually more convenient when exploring a pipeline +interactively. + +Step 4: reuse the extracted results +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Once you have the outputs, you can build custom plots or downstream analysis. +For example, this snippet overlays the detected R-peaks on top of the filtered +signal: + +.. code-block:: python + + plt.figure(figsize=(10, 4)) + plt.plot(out["ts"], out["filtered"], label="Filtered ECG", lw=1.5) + plt.plot( + out["ts"][out["rpeaks"]], + out["filtered"][out["rpeaks"]], + "ro", + label="R-peaks", + markersize=4, + ) + plt.xlabel("Time (s)") + plt.ylabel("Amplitude") + plt.legend() + plt.grid(True) + plt.tight_layout() + plt.show() + +If you want to save the standard ECG summary figure instead of displaying it, +pass a file path: + +.. code-block:: python + + out = ecg.ecg( + signal=signal, + sampling_rate=sampling_rate, + path="ecg_summary.png", + show=True, + ) + +Where to go next +---------------- + +* For signal-specific documentation, continue to :doc:`biosignals/index`. +* For the complete API, see :doc:`biosppy`. +* For the ``ReturnTuple`` container used throughout the project, see + :doc:`returntuple`. + +Once you are comfortable with the ECG example, the same pattern applies to +other supported biosignals: load a recording, call the corresponding pipeline +from :doc:`biosppy.signals`, and inspect the named outputs. + diff --git a/docs/howtocite.rst b/docs/howtocite.rst new file mode 100644 index 00000000..1a624de9 --- /dev/null +++ b/docs/howtocite.rst @@ -0,0 +1,25 @@ +Citing +====== + + +Please use the following if you need to cite BioSPPy: + +P. Bota, R. Silva, C. Carreiras, A. Fred, and H. P. da Silva, "BioSPPy: A Python toolbox for physiological signal processing," SoftwareX, vol. 26, pp. 101712, 2024, doi: 10.1016/j.softx.2024.101712. + +.. code-block:: text + + @article{biosppy, + title = {BioSPPy: A Python toolbox for physiological signal processing}, + author = {Patrícia Bota and Rafael Silva and Carlos Carreiras and Ana Fred and Hugo Plácido {da Silva}}, + journal = {SoftwareX}, + volume = {26}, + pages = {101712}, + year = {2024}, + issn = {2352-7110}, + doi = {https://doi.org/10.1016/j.softx.2024.101712}, + url = {https://www.sciencedirect.com/science/article/pii/S2352711024000839}, + } + +However, if you want to cite a specific version of BioSPPy, you can use Zenodo's reference: + +| **Zenodo DOI**: `10.5281/zenodo.17551774 `_ \ No newline at end of file diff --git a/docs/images/ECG_processed.png b/docs/images/ECG_processed.png new file mode 100644 index 00000000..b070a4e8 Binary files /dev/null and b/docs/images/ECG_processed.png differ diff --git a/docs/images/ECG_raw.png b/docs/images/ECG_raw.png index e99eb841..b88fed9d 100644 Binary files a/docs/images/ECG_raw.png and b/docs/images/ECG_raw.png differ diff --git a/docs/images/ECG_summary.png b/docs/images/ECG_summary.png deleted file mode 100644 index 70a1ed95..00000000 Binary files a/docs/images/ECG_summary.png and /dev/null differ diff --git a/docs/images/biosppy_stats-dark.svg b/docs/images/biosppy_stats-dark.svg new file mode 100644 index 00000000..4d82336a --- /dev/null +++ b/docs/images/biosppy_stats-dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/docs/images/biosppy_stats.svg b/docs/images/biosppy_stats.svg new file mode 100644 index 00000000..6632216c --- /dev/null +++ b/docs/images/biosppy_stats.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/docs/images/plots/acc.png b/docs/images/plots/acc.png new file mode 100644 index 00000000..54e42956 Binary files /dev/null and b/docs/images/plots/acc.png differ diff --git a/docs/images/plots/acc_summary.png b/docs/images/plots/acc_summary.png new file mode 100644 index 00000000..8a3bcc8d Binary files /dev/null and b/docs/images/plots/acc_summary.png differ diff --git a/docs/images/plots/ecg.png b/docs/images/plots/ecg.png new file mode 100644 index 00000000..96153d07 Binary files /dev/null and b/docs/images/plots/ecg.png differ diff --git a/docs/images/plots/ecg_summary.png b/docs/images/plots/ecg_summary.png new file mode 100644 index 00000000..724d6e93 Binary files /dev/null and b/docs/images/plots/ecg_summary.png differ diff --git a/docs/images/plots/eda.png b/docs/images/plots/eda.png new file mode 100644 index 00000000..60e782fd Binary files /dev/null and b/docs/images/plots/eda.png differ diff --git a/docs/images/plots/eda_summary.png b/docs/images/plots/eda_summary.png new file mode 100644 index 00000000..23d85ac4 Binary files /dev/null and b/docs/images/plots/eda_summary.png differ diff --git a/docs/images/plots/eeg_ec.png b/docs/images/plots/eeg_ec.png new file mode 100644 index 00000000..e7fe7b3f Binary files /dev/null and b/docs/images/plots/eeg_ec.png differ diff --git a/docs/images/plots/eeg_eo.png b/docs/images/plots/eeg_eo.png new file mode 100644 index 00000000..976084cd Binary files /dev/null and b/docs/images/plots/eeg_eo.png differ diff --git a/docs/images/plots/egm.png b/docs/images/plots/egm.png new file mode 100644 index 00000000..02f80fed Binary files /dev/null and b/docs/images/plots/egm.png differ diff --git a/docs/images/plots/emg.png b/docs/images/plots/emg.png new file mode 100644 index 00000000..20551734 Binary files /dev/null and b/docs/images/plots/emg.png differ diff --git a/docs/images/plots/emg_summary.png b/docs/images/plots/emg_summary.png new file mode 100644 index 00000000..8568a64e Binary files /dev/null and b/docs/images/plots/emg_summary.png differ diff --git a/docs/images/plots/hrv_summary.png b/docs/images/plots/hrv_summary.png new file mode 100644 index 00000000..109695f7 Binary files /dev/null and b/docs/images/plots/hrv_summary.png differ diff --git a/docs/images/plots/pcg.png b/docs/images/plots/pcg.png new file mode 100644 index 00000000..7ba0761e Binary files /dev/null and b/docs/images/plots/pcg.png differ diff --git a/docs/images/plots/pcg_summary.png b/docs/images/plots/pcg_summary.png new file mode 100644 index 00000000..1efd6f12 Binary files /dev/null and b/docs/images/plots/pcg_summary.png differ diff --git a/docs/images/plots/ppg.png b/docs/images/plots/ppg.png new file mode 100644 index 00000000..3a11426c Binary files /dev/null and b/docs/images/plots/ppg.png differ diff --git a/docs/images/plots/ppg_summary.png b/docs/images/plots/ppg_summary.png new file mode 100644 index 00000000..fad2f659 Binary files /dev/null and b/docs/images/plots/ppg_summary.png differ diff --git a/docs/images/plots/resp.png b/docs/images/plots/resp.png new file mode 100644 index 00000000..b432b51c Binary files /dev/null and b/docs/images/plots/resp.png differ diff --git a/docs/images/plots/resp_summary.png b/docs/images/plots/resp_summary.png new file mode 100644 index 00000000..b9e5f11f Binary files /dev/null and b/docs/images/plots/resp_summary.png differ diff --git a/docs/images/plots/rri.png b/docs/images/plots/rri.png new file mode 100644 index 00000000..f3c8583e Binary files /dev/null and b/docs/images/plots/rri.png differ diff --git a/docs/index.rst b/docs/index.rst index af2359bd..79dadce9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,55 +1,132 @@ Welcome to ``BioSPPy`` ====================== -.. image:: logo/logo.png +.. image:: _static/logo_light.png :align: center :alt: I know you're listening! + :class: only-light + +.. image:: _static/logo_dark.png + :align: center + :alt: I know you're listening! + :class: only-dark + +| +.. image:: images/biosppy_stats.svg + :align: left + :alt: BioSPPy stats + :class: only-light + +.. image:: images/biosppy_stats-dark.svg + :align: left + :alt: BioSPPy stats + :class: only-dark + +| +| +| ``BioSPPy`` is a toolbox for biosignal processing written in Python. -The toolbox bundles together various signal processing and pattern -recognition methods geared torwards the analysis of biosignals. +The toolbox bundles together signal processing, visualization, feature +extraction, quality assessment, synthesis, and pattern recognition methods +geared towards the analysis of physiological signals. + +Whether you are exploring a single ECG recording, prototyping a signal quality +pipeline, extracting domain-specific features, or benchmarking biosignal +algorithms, ``BioSPPy`` provides both ready-to-use high-level workflows and the +lower-level building blocks behind them. Highlights: -- Support for various biosignals: PPG, ECG, EDA, EEG, EMG, Respiration -- Signal analysis primitives: filtering, frequency analysis -- Clustering -- Biometrics +- Turnkey signal-processing pipelines for common biosignals +- Signal analysis primitives such as filtering, smoothing, spectral analysis, + segmentation, and heart-rate estimation +- Feature extraction in time, frequency, cepstral, time-frequency, and + non-linear / phase-space domains +- Signal quality assessment utilities +- Synthetic signal generators for simulation and testing +- Interactive and publication-style plotting utilities +- Clustering and biometrics tools for downstream analysis + +Supported biosignals +-------------------- + +``BioSPPy`` includes support for a broad range of physiological signals, +including: + +- ACC (Accelerometry) +- ABP (Arterial Blood Pressure) +- BVP (Blood Volume Pulse) +- ECG (Electrocardiography) +- EDA (Electrodermal Activity) +- EEG (Electroencephalography) +- EGM (Electrogram) +- EMG (Electromyography) +- PCG (Phonocardiography) +- PPG (Photoplethysmography) +- Respiration +- RRI / HRV (RR intervals and heart-rate variability analysis) + +For signal-specific overviews and examples, see :doc:`biosignals/index`. + +Main modules at a glance +------------------------ + +- :doc:`gettingstarted` for the package overview and first ECG walkthrough +- :doc:`biosignals/index` for biosignal-specific pages and examples +- :doc:`ml/index` for optional machine-learning models and usage examples +- :doc:`biosppy` for the complete API reference +- :doc:`returntuple` for the named return container used across the package +- :doc:`biosppy.features` for feature extraction modules +- :doc:`biosppy.synthesizers` for synthetic biosignal generation Contents: .. toctree:: :maxdepth: 1 - tutorial + gettingstarted + returntuple + biosignals/index + ml/index biosppy + contribute + howtocite Installation ------------ Installation can be easily done with ``pip``: -.. code:: bash +.. code:: console $ pip install biosppy -Simple Example --------------- +Quick ECG example +----------------- -The code below loads an ECG signal from the ``examples`` folder, filters -it, performs R-peak detection, and computes the instantaneous heart -rate. +The code below loads an ECG signal from the ``examples`` folder, processes it, +detects R-peaks, and computes the instantaneous heart rate. .. code:: python - import numpy as np + from biosppy import storage from biosppy.signals import ecg # load raw ECG signal - signal = np.loadtxt('./examples/ecg.txt') + signal, metadata = storage.load_txt('./examples/ecg.txt') # process it and plot - out = ecg.ecg(signal=signal, sampling_rate=1000., show=True) + out = ecg.ecg(signal=signal, sampling_rate=metadata['sampling_rate'], show=True) + +This high-level pipeline returns a :py:class:`biosppy.utils.ReturnTuple` +containing named outputs such as the filtered signal, detected R-peaks, +heartbeat templates, and instantaneous heart rate. + +.. image:: images/plots/ecg_summary.png + :align: center + :width: 100% + :alt: Example of ECG summary. Index ----- diff --git a/docs/ml/index.rst b/docs/ml/index.rst new file mode 100644 index 00000000..7bffc01d --- /dev/null +++ b/docs/ml/index.rst @@ -0,0 +1,61 @@ +Machine Learning +================ + +The ``biosppy.ml`` package is an optional extension for machine-learning +workflows on biosignals. The first available model is +:py:class:`biosppy.ml.ecg_ml.AFibDetection`, a pre-trained bidirectional LSTM +that detects atrial fibrillation (AFib) from RR interval sequences. + +Installation +------------ + +Install the optional dependencies with: + +.. code-block:: bash + + pip install biosppy[ml] + +Package structure +----------------- + +- ``biosppy.ml.utils_ml``: base utilities for Keras-based classifiers. +- ``biosppy.ml.ecg_ml``: ECG-related ML models, including AFib detection. +- ``biosppy/ml/_models``: packaged pre-trained model files and metadata. + +Model architecture +------------------ + +:py:class:`biosppy.ml.utils_ml.KerasClassifier` is the base class used by ML +models. It validates model files, loads model metadata from JSON, and provides +shared prediction/preprocessing behavior. + +:py:class:`biosppy.ml.ecg_ml.AFibDetection` extends this base class and uses a +windowed RR-interval pipeline: + +1. Segment the RR sequence into windows (default ``win_len=20``, ``step=1``). +2. Reshape to ``(n_windows, win_len, 1)``. +3. Run the BiLSTM model to obtain one probability per window. +4. Return ``True`` if any probability exceeds the configured threshold. + +Quick example +------------- + +.. code-block:: python + + from biosppy import storage + from biosppy.ml.ecg_ml import AFibDetection + + # RR intervals in ms + rri, _ = storage.load_txt('examples/rri.txt') + + model = AFibDetection() + afib = model.predict(rri) + print(f"AFib detected: {afib}") + +API links +--------- + +- :doc:`../biosppy.ml` +- :py:mod:`biosppy.ml.ecg_ml` +- :py:mod:`biosppy.ml.utils_ml` + diff --git a/docs/requirements.txt b/docs/requirements.txt index 6aa4424f..9a8ac4a1 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,5 +1,6 @@ sphinx==6.2.1 -sphinx-rtd-theme==1.2.2 +furo==2024.8.6 +sphinx-copybutton==0.5.2 pillow==10.3.0 mock==1.0.1 commonmark==0.9.1 diff --git a/docs/returntuple.rst b/docs/returntuple.rst new file mode 100644 index 00000000..bb6f04a1 --- /dev/null +++ b/docs/returntuple.rst @@ -0,0 +1,188 @@ +ReturnTuple Object +================== + +Before we dig into the core aspects of the package, you will quickly notice +that many of the methods and functions defined here return a custom object +class. This return class is defined in :py:class:`biosppy.utils.ReturnTuple`. +The goal of this return class is to strengthen the semantic relationship +between a function's output variables, their names, and what is described in +the documentation. Consider the following function definition: + + +.. code:: python + + def compute(a, b): + """Simultaneously compute the sum, subtraction, multiplication and + division between two integers. + + Args: + a (int): First input integer. + b (int): Second input integer. + + Returns: + (tuple): containing: + sum (int): Sum (a + b). + sub (int): Subtraction (a - b). + mult (int): Multiplication (a * b). + div (int): Integer division (a / b). + + """ + + if b == 0: + raise ValueError("Input 'b' cannot be zero.") + + v1 = a + b + v2 = a - b + v3 = a * b + v4 = a / b + + return v1, v2, v3, v4 + +Note that Python doesn't actually support returning multiple objects. In this +case, the ``return`` statement packs the objects into a tuple. + +.. code:: python + + >>> out = compute(4, 50) + >>> type(out) + + >>> print out + (54, -46, 200, 0) + +This is pretty straightforward, yet it shows one disadvantage of the native +Python return pattern: the semantics of the output elements (i.e. what each +variable actually represents) are only implicitly defined with the ordering +of the docstring. If there isn't a dosctring available (yikes!), the only way +to figure out the meaning of the output is by analyzing the code itself. + +This is not necessarily a bad thing. One should always try to understand, +at least in broad terms, how any given function works. However, the initial +steps of the data analysis process encompass a lot of experimentation and +interactive exploration of the data. This is important in order to have an +initial sense of the quality of the data and what information we may be able to +extract. In this case, the user typically already knows what a function does, +but it is cumbersome to remember by heart the order of the outputs, without +having to constantly check out the documentation. + +For instance, does the `numpy.histogram +`__ +function first return the edges or the values of the histogram? Maybe it's the +edges first, which correspond to the x axis. Oops, it's actually the other way +around... + +In this case, it could be useful to have an explicit reference directly in the +return object to what each variable represents. Returning to the example above, +we would like to have something like: + +.. code:: python + + >>> out = compute(4, 50) + >>> print out + (sum=54, sub=-46, mult=200, div=0) + +This is exactly what :py:class:`biosppy.utils.ReturnTuple` accomplishes. +Rewriting the `compute` function to work with `ReturnTuple` is simple. Just +construct the return object with a tuple of strings with names for each output +variable: + +.. code:: python + + from biosppy import utils + + def compute_new(a, b): + """Simultaneously compute the sum, subtraction, multiplication and + division between two integers. + + Args: + a (int): First input integer. + b (int): Second input integer. + + Returns: + (ReturnTuple): containing: + sum (int): Sum (a + b). + sub (int): Subtraction (a - b). + mult (int): Multiplication (a * b). + div (int): Integer division (a / b). + + """ + + if b == 0: + raise ValueError("Input 'b' cannot be zero.") + + v1 = a + b + v2 = a - b + v3 = a * b + v4 = a / b + + # build the return object + output = utils.ReturnTuple((v1, v2, v3, v4), ('sum', 'sub', 'mult', 'div')) + + return output + +The output now becomes: + +.. code:: python + + >>> out = compute_new(4, 50) + >>> print out + ReturnTuple(sum=54, sub=-46, mult=200, div=0) + +It allows to access a specific variable by key, like a dictionary: + +.. code:: python + + >>> out['sum'] + 54 + +And to list all the available keys: + +.. code:: python + + >>> out.keys() + ['sum', 'sub', 'mult', 'div'] + +It is also possible to convert the object to a more traditional dictionary, +specifically an `OrderedDict `__: + +.. code:: python + + >>> d = out.as_dict() + >>> print d + OrderedDict([('sum', 54), ('sub', -46), ('mult', 200), ('div', 0)]) + +Dictionary-like unpacking is supported: + +.. code:: python + + >>> some_function(**out) + +`ReturnTuple` is heavily inspired by `namedtuple `__, +but without the dynamic class generation at object creation. It is a subclass +of `tuple`, therefore it maintains compatibility with the native return pattern. +It is still possible to unpack the variables in the usual way: + +.. code:: python + + >>> a, b, c, d = compute_new(4, 50) + >>> print a, b, c, d + 54 -46 200 0 + +The behavior is slightly different when only one variable is returned. In this +case it is necessary to explicitly unpack a one-element tuple: + +.. code:: python + + from biosppy import utils + + def foo(): + """Returns 'bar'.""" + + out = 'bar' + + return utils.ReturnTuple((out, ), ('out', )) + +.. code:: python + + >>> out, = foo() + >>> print out + 'bar' diff --git a/docs/tutorial.rst b/docs/tutorial.rst deleted file mode 100644 index 2d42f8d7..00000000 --- a/docs/tutorial.rst +++ /dev/null @@ -1,389 +0,0 @@ -======== -Tutorial -======== - -In this tutorial we will describe how `biosppy` enables the development of -Pattern Recognition and Machine Learning workflows for the analysis of -biosignals. The major goal of this package is to make these tools easily -available to anyone wishing to start playing around with biosignal data, -regardless of their level of knowledge in the field of Data Science. Throughout -this tutorial we will discuss the major features of `biosppy` and introduce the -terminology used by the package. - -What are Biosignals? -==================== - -Biosignals, in the most general sense, are measurements of physical properties -of biological systems. These include the measurement of properties at the -cellular level, such as concentrations of molecules, membrane potentials, and -DNA assays. On a higher level, for a group of specialized cells (i.e. an organ) -we are able to measure properties such as cell counts and histology, organ -secretions, and electrical activity (the electrical system of the heart, for -instance). Finally, for complex biological systems like the human being, -biosignals also include blood and urine test measurements, core body -temperature, motion tracking signals, and imaging techniques such as CAT and MRI -scans. However, the term biosignal is most often applied to bioelectrical, -time-varying signals, such as the electrocardiogram. - -The task of obtaining biosignals of good quality is time-consuming, -and typically requires the use of costly hardware. Access to these instruments -is, therefore, usually restricted to research institutes, medical centers, -and hospitals. However, recent projects like `BITalino `__ -or `OpenBCI `__ have lowered the entry barriers of biosignal -acquisition, fostering the Do-It-Yourself and Maker communities to develop -physiological computing applications. You can find a list of biosignal -platform `here `__. - - - - - -The following sub-sections briefly describe the biosignals -covered by `biosppy`. - -Blood Volume Pulse ------------------- - -Photoplethysmogram (PPG) signals is an optical technique used to detect blood volume changes -within the microvascular bed of your tissue. A PPG wave is made of a pulsatile physiological -measurement taken at the skin surface. The baseline is made of a superimposed varying baseline -with various lower frequency componenets attributed to respiration, thermoregulation, and -sympathetic nervous system activity. Due to it's low cost and simplicity it can be found within -personal devices such as Smart Watches, Phones, and handheld heart rate monitors. - -Electrocardiogram ------------------ - -Electrocardiogrm (ECG/EKG) signals are a measure of the electrical heartbeat of the heart. -Each heartbeat an electrical impulse travels through the heart, causing your heart to -pump blood from the heart throughout your body. Often times upto twelve non-invasive -electrodes are attached to your chest and limbs. They record the electrical signals that -result in a heartbeat and output them onto ECG charts either on paper or on a computer. -ECG/EKG signals can be processed in time and frequency domains. A healthy adult ECG/EKG is -often predictable while adults with heart problems are often unpredictable. - -Electrodermal Activity ----------------------- - -Electrodermal Activity (EDA) signals are measures of the electrical characteristics of the skin -using methods such as skin potential (SP), skin conductance response (SCR), skin potential response (SPR). -Training in EDA allows the patient to become more aware of stress. It is not commonly used -and, when used, it is often in conjunction with other forms of biofeedback. Because EDA -measures only skin changes, it does not provide feedback about more complex physiological -reactions. When used for treatment, it tends to be as a monitoring system for unresolved -issues in psychotherapy or for general stress. - -Electroencephalogram --------------------- - -Electroencephalogram (EEG) signals are measures of electrical activity in the brain using -electrodes attached to the scalp. Generally the process used to get an EEG is non-invasive. -An EEG measures voltage fluctuations resulting from ionic currents within nuerons, which can -be recorded over a period of time thus allowing for analysis within the time domain. -The recording is obtained by placing electrodes on the scalp with a conductive gel, -usually after preparing the scalp area by light abrasion to reduce impedance due to dead skin cells. - - -Electromyogram --------------- - -Electromyogram (EMG) signals are a measure of the electrical activity of -muscles. There are two types of sensors that can be used to record this -electrical activity, in particular surface EMG (sEMG), measured by non-invasive -electrodes, and intramuscular EMG. Out of the two, sEMG allows for non-invasive -electrodes to be applied at the body surface, that measure muscle activity. -In sEMG, contact with the skin can be done with standard pre-gelled electrodes, -dry Ag/AgCl electrodes or conductive textiles. Normally, there are three -electrodes in an sEMG interface: two electrodes work on bipolar differential -measurement and the other one is attached to a neutral zone, to serve as the -reference point. After being recorded, this signal can be processed in time, -frequency and time-frequency domains. In an EMG signal, when the muscle is in -a relaxed state, this corresponds to the baseline activity. The bursts of -activity match the muscular activations and have a random shape, meaning that -a raw recording of contractions cannot be exactly reproduced. The onset of an -event corresponds to the beginning of the burst. - -Respiration ------------ - -Respiration (Resp) signals are... - - -What is Pattern Recognition? -============================ - -Pattern Recognition is an automated analytical recognition of patterns and -regularities within a piece of data. Often time stastical fields such as -Machine Learning rely on pattern recognition to find similarities within -data in order to predict future data. - -A Note on Return Objects -======================== - -Before we dig into the core aspects of the package, you will quickly notice -that many of the methods and functions defined here return a custom object -class. This return class is defined in :py:class:`biosppy.utils.ReturnTuple`. -The goal of this return class is to strengthen the semantic relationship -between a function's output variables, their names, and what is described in -the documentation. Consider the following function definition: - -.. code:: python - - def compute(a, b): - """Simultaneously compute the sum, subtraction, multiplication and - division between two integers. - - Args: - a (int): First input integer. - b (int): Second input integer. - - Returns: - (tuple): containing: - sum (int): Sum (a + b). - sub (int): Subtraction (a - b). - mult (int): Multiplication (a * b). - div (int): Integer division (a / b). - - """ - - if b == 0: - raise ValueError("Input 'b' cannot be zero.") - - v1 = a + b - v2 = a - b - v3 = a * b - v4 = a / b - - return v1, v2, v3, v4 - -Note that Python doesn't actually support returning multiple objects. In this -case, the ``return`` statement packs the objects into a tuple. - -.. code:: python - - >>> out = compute(4, 50) - >>> type(out) - - >>> print out - (54, -46, 200, 0) - -This is pretty straightforward, yet it shows one disadvantage of the native -Python return pattern: the semantics of the output elements (i.e. what each -variable actually represents) are only implicitly defined with the ordering -of the docstring. If there isn't a dosctring available (yikes!), the only way -to figure out the meaning of the output is by analyzing the code itself. - -This is not necessarily a bad thing. One should always try to understand, -at least in broad terms, how any given function works. However, the initial -steps of the data analysis process encompass a lot of experimentation and -interactive exploration of the data. This is important in order to have an -initial sense of the quality of the data and what information we may be able to -extract. In this case, the user typically already knows what a function does, -but it is cumbersome to remember by heart the order of the outputs, without -having to constantly check out the documentation. - -For instance, does the `numpy.histogram -`__ -function first return the edges or the values of the histogram? Maybe it's the -edges first, which correspond to the x axis. Oops, it's actually the other way -around... - -In this case, it could be useful to have an explicit reference directly in the -return object to what each variable represents. Returning to the example above, -we would like to have something like: - -.. code:: python - - >>> out = compute(4, 50) - >>> print out - (sum=54, sub=-46, mult=200, div=0) - -This is exactly what :py:class:`biosppy.utils.ReturnTuple` accomplishes. -Rewriting the `compute` function to work with `ReturnTuple` is simple. Just -construct the return object with a tuple of strings with names for each output -variable: - -.. code:: python - - from biosppy import utils - - def compute_new(a, b): - """Simultaneously compute the sum, subtraction, multiplication and - division between two integers. - - Args: - a (int): First input integer. - b (int): Second input integer. - - Returns: - (ReturnTuple): containing: - sum (int): Sum (a + b). - sub (int): Subtraction (a - b). - mult (int): Multiplication (a * b). - div (int): Integer division (a / b). - - """ - - if b == 0: - raise ValueError("Input 'b' cannot be zero.") - - v1 = a + b - v2 = a - b - v3 = a * b - v4 = a / b - - # build the return object - output = utils.ReturnTuple((v1, v2, v3, v4), ('sum', 'sub', 'mult', 'div')) - - return output - -The output now becomes: - -.. code:: python - - >>> out = compute_new(4, 50) - >>> print out - ReturnTuple(sum=54, sub=-46, mult=200, div=0) - -It allows to access a specific variable by key, like a dictionary: - -.. code:: python - - >>> out['sum'] - 54 - -And to list all the available keys: - -.. code:: python - - >>> out.keys() - ['sum', 'sub', 'mult', 'div'] - -It is also possible to convert the object to a more traditional dictionary, -specifically an `OrderedDict `__: - -.. code:: python - - >>> d = out.as_dict() - >>> print d - OrderedDict([('sum', 54), ('sub', -46), ('mult', 200), ('div', 0)]) - -Dictionary-like unpacking is supported: - -.. code:: python - - >>> some_function(**out) - -`ReturnTuple` is heavily inspired by `namedtuple `__, -but without the dynamic class generation at object creation. It is a subclass -of `tuple`, therefore it maintains compatibility with the native return pattern. -It is still possible to unpack the variables in the usual way: - -.. code:: python - - >>> a, b, c, d = compute_new(4, 50) - >>> print a, b, c, d - 54 -46 200 0 - -The behavior is slightly different when only one variable is returned. In this -case it is necessary to explicitly unpack a one-element tuple: - -.. code:: python - - from biosppy import utils - - def foo(): - """Returns 'bar'.""" - - out = 'bar' - - return utils.ReturnTuple((out, ), ('out', )) - -.. code:: python - - >>> out, = foo() - >>> print out - 'bar' - -A First Approach -================ - -One of the major goals of `biosppy` is to provide an easy starting point into -the world of biosignal processing. For that reason, we provide simple turnkey -solutions for each of the supported biosignal types. These functions implement -typical methods to filter, transform, and extract signal features. Let's see -how this works for the example of the ECG signal. - -The GitHub repository includes a few example signals (see -`here `__). To load -and plot the raw ECG signal follow: - -.. code:: python - - >>> import numpy as np - >>> import pylab as pl - >>> from biosppy import storage - >>> - >>> signal, mdata = storage.load_txt('.../examples/ecg.txt') - >>> Fs = mdata['sampling_rate'] - >>> N = len(signal) # number of samples - >>> T = (N - 1) / Fs # duration - >>> ts = np.linspace(0, T, N, endpoint=False) # relative timestamps - >>> pl.plot(ts, signal, lw=2) - >>> pl.grid() - >>> pl.show() - -This should produce a similar output to the one shown below. - -.. image:: images/ECG_raw.png - :align: center - :width: 80% - :alt: Example of a raw ECG signal. - -This signal is a Lead I ECG signal acquired at 1000 Hz, with a resolution of 12 -bit. Although of good quality, it exhibits powerline noise interference, has a -DC offset resulting from the acquisition device, and we can also observe the -influence of breathing in the variability of R-peak amplitudes. - -We can minimize the effects of these artifacts and extract a bunch of features -with the :py:class:`biosppy.signals.ecg.ecg` function: - -.. code:: python - - >>> from biosppy.signals import ecg - >>> out = ecg.ecg(signal=signal, sampling_rate=Fs, show=True) - -It should produce a plot like the one below. - -.. image:: images/ECG_summary.png - :align: center - :width: 80% - :alt: Example of processed ECG signal. - - - - -Signal Processing -================= - -To do.. - -Clustering -========== - -To do.. - -Biometrics -========== - -To do.. - -What's Next? -============ - -To do.. - -References -========== - -To do.