R package to detect premature ventricular complexes (PVCs) in data from a Polar H10 chest-strap heart rate sensor.
We have used the ECGLogger app on an iPhone to extract the Polar H10 data as a CSV file (or really a series of CSV files, in one hour blocks), and the rsleep package to detect "R" peaks in the ECG signal.
You can install the detectPVC package from R-universe.
install.packages("detectPVC", repos="https://kbroman.r-universe.dev")
Alternatively, install it from GitHub. You first need to install the remotes package.
install.packages("remotes")
Then use remotes::install_github():
library(remotes)
install_github("kbroman/detectPVC")
The library comes with a 10-min sample data set, polar_h10.
library(detectPVC)
data(polar_h10)
Convert the included times (which are time stamps from a Polar H10, in 1e-9 seconds) to standard date-time values.
polar_h10$datetime <- convert_timestamp(polar_h10$time)
First detect bad segments in the data, with either wild values or missing data points.
bad_segs <- find_bad_segments(polar_h10$datetime, polar_h10$ecg)
For this example, there is just one bad segment, covering about
7 sec.
You can get the total covered length in seconds with tot_length().
totlength(bad_segs, polar_h10$datetime)
## [1] 6.868205
Use detect_peaks() to detect "R" peaks in the ECG trace.
peaks <- detect_peaks(polar_h10$datetime, polar_h10$ecg, omit_segments=bad_segs)
Plot the first 20 seconds of data, and add points above the peaks. The function
plot_ecg() is a base-graphics-based plotting function with light
gray grid lines.
v <- get_time_interval(polar_h10$datetime, start=polar_h10$datetime[1], length=20)
plot_ecg(polar_h10$datetime[v], polar_h10$ecg[v])
points(polar_h10$datetime[peaks], polar_h10$ecg[peaks], pch=16, col="slateblue")

Use calc_peak_stats() to calculate some statistics about each peak.
peak_stats <- calc_peak_stats(polar_h10$datetime, polar_h10$ecg, peaks)
The simplest rule for classifying PVCs is to take RStime > 50.
The statistic RStime is the time between the R and S peaks in milliseconds.
pvc <- (peak_stats$RStime > 50)
Label the inferred PVCs with pink dots, and the others with green dots.
plot_ecg(polar_h10$datetime[v], polar_h10$ecg[v])
points(polar_h10$datetime[peaks], polar_h10$ecg[peaks], pch=16, col=c("green3", "violetred")[pvc+1])

In this 20 second window, there are 10 PVCs in 29 total beats.
detectPVC is released under the MIT license.