MyNixOS website logo
Description

Automated Cardiac Data Processing via ACF, GA & Tracking Index.

An algorithm developed to efficiently and accurately process complex and variable cardiac data with three key features: 1. employing autocorrelation to identify recurrent heartbeats and use their periods to compute heart rates; 2. incorporating a genetic algorithm framework to minimize data loss due to noise interference and accommodate within-sequence variations; and 3. introducing a tracking index as a moving reference to reduce errors. Lau, Wong, & Gu (2026) <https://ssrn.com/abstract=5153081>.

CardiacDP

CardiacDP (Cardiac Data Processing) can automatically read and collate heart rate data, and compute average heart rate per analysis interval (sequence). The analysis employs the autocorrelation function (ACF) with a genetic algorithm framework to identify periods of repeating waveforms within each sequence. These candidate heart rates of sub-sequences are then evaluated either by the autocorrelation value or a tracking index (TI), and finally weighted as the final output.

Package structure

Installation

install.packages("CardiacDP")

# Or from GitHub
devtools::install_github("Vicellken/CardiacDP")

# Or the source package from GitHub:
# Vector of package names
packages <- c("data.table", "doParallel", "dplyr", "foreach", "ggplot2", "purrr", "RColorBrewer", "stringr")

lapply(packages, function(pkg) {
  if (!require(pkg, character.only = TRUE)) {
    install.packages(pkg)
  }
})

# Install the source package
install.packages("CardiacDP_0.4.2.tar.gz", repos = NULL, type = "source")

Example

This is an example showing the complete analysis pipeline:

library(CardiacDP)

zip_path <- "~/rawfiles.zip" # PATH_TO_ZIP_FILE

# csv_path <- "" # PATH_TO_COLLATED_CSV

# run computeHR() for average heart rate analysis (no files are written by default)
output <- computeHR(
  file_path = csv_path, # collatedata() will automatically run if zip_path is directly provided here
  save_outputs = TRUE,
  output_dir = NULL, # PATH_TO_STORE_OUTPUTS
  verbose = TRUE)

The user can access the output by the channel name. finalsubseq is a list showing the positions and durations of the final periodic sub-sequences determined for each sequence. They are presented as data tables (s = start index of the sub-sequence; e = end index of the sub-sequence; p = which of the initial population the sub-sequence is derived from; and f = duration of the sub-sequence), the rows of which represent separate final sub-sequences.

# positions (in indices) and durations of the final sub-sequences
# NOTE: the results are not included here for simplicity. For more details please refer to Supplementary Information S4 of the publication / User guideline.pdf

# output[["finalsubseq"]][["Channel A"]]

The corresponding candidate heart rates per sub-sequences can be found in candidateHR (ACF = autocorrelation value; lag = time lag; and hr = heart rate).

# candidate heart rates of the final sub-sequences
# NOTE: the results are not included here for simplicity. For more details please refer to Supplementary Information S4 of the publication / User guideline.pdf

# output[["candidateHR"]][["Channel A"]]

The final results after evaluating the candidate heart rates, checking for resolution and weighting for durations can eventually be obtained from results_ACF and results_TI. These results referred to evaluating the candidate heart rates by merely autocorrelation values (i.e. the “ACF + GA” approach in the publication) or the tracking index (i.e. the “ACF + GA +TI” approach in the publication) respectively. Each of them consists of 1) the details of the sub-sequences (subseqHR); 2) the weighted heart rate per sequence (weightedHR); and 3) a plot of weighted heart rate against time (plot).

## results obtained from evaluating the candidate heart rates by autocorrelation values
# output[["results_ACF"]][["Channel A"]]

# results obtained from evaluating the candidate heart rates by the tracking index
# output[["results_TI"]][["Channel A"]]

Interpret results

VariableContent
finalsubseqA list of positions and durations of the final periodic sub-sequences
candidateHRA list of candidate heart rates extracted from ACF for each sub-sequence
results_ACFResults obtained from evaluating the candidate heart rates of each sub-sequence based on autocorrelation values (i.e. following the “ACF + GA” approach as described in the main manuscript). Consisted of three items: 1) subseqHR: a list of sub-sequences and the corresponding heart rates and durations; 2) weightedHR: a list of final heart rates per sequence after weighing; and 3) plot: a plot of final heart rates against time
results_TIResults obtained from evaluating the candidate heart rates of each sub-sequence using a tracking index (i.e. following the “ACF + GA + TI” approach as described in the main manuscript). Consisted of three items: 1) subseqHR: a list of sub-sequences and the corresponding heart rates and durations; 2) weightedHR: a list of final heart rates per sequence after weighing; and 3) plot: a plot of final heart rates against time

Automatically saved files

By default, computeHR() does not write any files. If you want CSV/PNG outputs, set save_outputs = TRUE and optionally provide output_dir (if output_dir is NULL, it defaults to tempdir()):

csv_path <- system.file("extdata", "example.csv", package = "CardiacDP")
output <- computeHR(
  file_path = csv_path,
  save_outputs = TRUE,
  output_dir = tempdir()
)

CSV Files

For each channel and method (ACF and TI), the following CSV files are saved:

  • {Channel}_ACF_subseqHR.csv - Details of sub-sequences with heart rates (ACF method)
  • {Channel}_ACF_weightedHR.csv - Weighted heart rates per analysis interval (ACF method)
  • {Channel}_TI_subseqHR.csv - Details of sub-sequences with heart rates (TI method)
  • {Channel}_TI_weightedHR.csv - Weighted heart rates per analysis interval (TI method)

Note: Channel names with spaces (e.g., “Channel A”) are converted to underscores (e.g., “Channel_A”) in filenames.

PNG Files

For each channel and method, heart rate plots are saved:

  • {Channel}_ACF_plot.png - Heart rate plot (ACF method)
  • {Channel}_TI_plot.png - Heart rate plot (TI method)

Column descriptions

weightedHR CSV files contain:

  • ix - Sequence index (1, 2, 3, …)
  • Time_min - Time in minutes (midpoint of analysis interval = (ix - 0.5) × analysis_interval)
  • wACF - Weighted autocorrelation value
  • whr - Weighted heart rate in beats per minute (can be NA)

subseqHR CSV files contain:

  • ix - Sequence index
  • win - Sub-sequence window number within the sequence
  • s, e, p, f - Sub-sequence parameters (start, end, population, fitness)
  • ACF - Autocorrelation value
  • lag - Time lag
  • hr - Heart rate in beats per minute (can be NA)
  • res - Resolution used

Reproducing plots from saved CSV files

The saved CSV files contain all the data needed to reproduce the heart rate plots. Use the weightedHR CSV files for plotting:

library(ggplot2)
library(RColorBrewer)
library(data.table)

# Read the saved weighted heart rate data (example; assumes you ran computeHR(save_outputs=TRUE))
channel <- "Channel A"
data <- fread(paste0(gsub(" ","_",channel),"_TI_weightedHR.csv"))

# Create the plot (matching the package output)
palette <- brewer.pal(n = 11, name = "RdYlBu")
names(palette) <- seq(0, 10, 1) / 10

# analysis interval (by default 1 min)
an_in <- 1

ggplot() +
  geom_point(
    data = data,
    aes(x = ix * an_in, y = whr, fill = factor(floor(wACF * 10) / 10)),
    colour = "black", shape = 21, size = 4, alpha = 0.8
  ) +
  scale_fill_manual(
    name = "ACF", values = palette, na.value = NA,
    na.translate = FALSE, guide = "legend"
  ) +
  scale_y_continuous(
    name = "Heart rate (bpm)",
    breaks = seq(0, ceiling(max(data$whr, na.rm = TRUE) / 50) * 50, 50),
    limits = c(0, ceiling(max(data$whr, na.rm = TRUE) / 50) * 50),
    expand = c(0, 0)
  ) +
  scale_x_continuous(
    name = "Time (min)",
    breaks = seq(0, ceiling(max(data$Time_min, na.rm = TRUE) / 30) * 30, 30),
    limits = c(0, ceiling(max(data$Time_min, na.rm = TRUE) / 30) * 30),
    expand = c(0, 0)
  ) +
  theme_linedraw() +
  theme(
    text = element_text(size = 12, colour = "black"),
    panel.grid.minor = element_blank(),
    panel.border = element_rect(fill = NA, colour = "black", linewidth = 1)
  )

Key columns for plotting:

  • X-axis:ix * an_in - Time in minutes
  • Y-axis:whr - Weighted heart rate (bpm)
  • Fill color:wACF - Weighted autocorrelation value (colored by discrete bins)
Metadata

Version

0.4.2

License

Unknown

Platforms (78)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    uefi
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-freebsd
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64-uefi
  • aarch64-windows
  • aarch64_be-none
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-linux
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-uefi
  • x86_64-windows