
Event Detection  R Peaks (ECG) 
Tags  detect☁ecg☁rpeaks 
One of the distinctive characteristics of the electrocardiographic (ECG) signals is their periodicity, something that is not common in physiological terms.
Due to this characteristic, the study of cardiac cycle variability (heart rate variability) defines an important segment of ECG analysis.
However, heart rate variability analysis is dependent of the detection of ECG R peaks, which is the main topic of the present Jupyter Notebook . This task can be achieved by applying the PanTompkins algorithm, translated to Python paradigm by Raja Selvaraj
1  Importation of the needed packages and definition of auxiliary functions
# biosignalsnotebooks python package
import biosignalsnotebooks as bsnb
# Scientific packages
from numpy import linspace, diff, zeros_like, arange, array
2  Load of acquired ECG data
# Load of data
data, header = bsnb.load_signal("ecg_4000_Hz", get_header=True)
3  Identification of the device macaddress and the channel used during acquisition
channel = list(data.keys())[0]
4  Storage of sampling rate and acquired data inside variables
# Sampling rate.
sr = header["sampling rate"]
# Signal Samples.
signal = data[channel]
4.1  A timeaxis should be generated in order to a more intuitive interpretation of the final results
time = bsnb.generate_time(signal)
5  Simplification of ECG signal (isolation of abrupt transitions)
5.1  Step 1 of PanTompkins Algorithm  ECG Filtering (Bandpass between 5 and 15 Hz)
# Step 1 of PanTompkins Algorithm
filtered_signal = bsnb.detect._ecg_band_pass_filter(signal, sr)
5.2  Step 2 of PanTompkins Algorithm  ECG Differentiation
# Step 2 of PanTompkins Algorithm
differentiated_signal = diff(filtered_signal)
5.3  Step 3 of PanTompkins Algorithm  ECG Rectification
# Step 3 of PanTompkins Algorithm
squared_signal = differentiated_signal * differentiated_signal
5.4  Step 4 of PanTompkins Algorithm  ECG Integration (
Moving window integration
)
5.4.1  Definition of the samples number inside the moving average window
nbr_sampls_int_wind = int(0.080 * sr)
5.4.2  Initialisation of the variable that will contain the integrated signal samples
integrated_signal = zeros_like(squared_signal)
5.4.3  Determination of a cumulative version of "squared_signal"
In the cumulative version of the signal under analysis, his sample value $i$ will be sum of all values included between entry 0 and entry $i$ of the studied signal (in our case "squared_signals").cumulative_sum = squared_signal.cumsum()
5.4.4  Estimation of the area/integral below the curve that defines the "squared_signal"
Implicitly, with the current procedure, "squared_signal" is divided into multiple rectangles with fixed width (equal 1 sample) and height determined by the sample value under analysis .integrated_signal[nbr_sampls_int_wind:] = (cumulative_sum[nbr_sampls_int_wind:] 
cumulative_sum[:nbr_sampls_int_wind]) / nbr_sampls_int_wind
integrated_signal[:nbr_sampls_int_wind] = cumulative_sum[:nbr_sampls_int_wind] / arange(1, nbr_sampls_int_wind + 1)