R/wavelet-ECG-annotation.R

# Teresa updated May 18th 2018

#' @importFrom assertthat assert_that
#' @importFrom magrittr %>% subtract add
#' @importFrom purrr as_vector discard partial reduce
#'
library("assertthat")
library("magrittr")
library("purrr")
library("robfilter")
library("signal")


signal_low_pass <-
  function(signal_,
           cutoff = 40,
           filter_order = 5,
           sampling_frequency = 250) {
    lower_limit <- cutoff/(sampling_frequency/2)

    filter_coefficients <-
      signal::butter(filter_order, lower_limit, type = "low")

    filtered_signal <-
      signal::filtfilt(filter_coefficients, signal_)
  }


baseline_wander_removal_median <-
  function(signal_, sampling_frequency) {
    window_size_ <-
      function(fraction_of_frequency) {
        round(fraction_of_frequency * sampling_frequency)
      }

    pluck_median_signal_ <-
      function(filtered_signal) {
        filtered_signal$level$MED
      }

    clean_signal_ <-
      partial(subtract, signal_)

    signal_ %>%
      robfilter::med.filter(window_size_(0.2)) %>%
      pluck_median_signal_() %>%
      robfilter::med.filter(window_size_(0.6)) %>%
      pluck_median_signal_() %>%
      clean_signal_()

  }


convert_unit_to_ms_ <- function(indexes, sampling_frequency = 250) {
  indexes / sampling_frequency * 1000
}


convert_unit_to_sample_ <- function(indexes, sampling_frequency = 250) {
  indexes / 1000 * sampling_frequency
}


#' Detect the locations of P,Q,R,S,T waves in ECG signals
#' Return a list including 9 vectors of indexes for each wave
#' The list includes:
#' Q_peak, R_peak, S_peak,
#' P_onset, P_wave, Type_of_P, T_onset, T_wave, Type_of_T
#'
#' Unit of indexes: ms (millisecond)
#'
#' Type_of_P corresponds to the types of P wave morphology
#' 1 - normal; 2 - inverse; 3 - biphasic +/-; 4 - biphasic -/+; 0 - no type
#'
#' Type_of_T corresponds to the types of T wave morphology
#' 1 - normal; 2 - inverse; 3 - biphasic +/-; 4 - biphasic -/+;
#' 5 - upwards; 6 - downwards
#'
#' @param ecg_signal_ The original ECG signal of a subject
#' @param fs The sampling frequency of ECG signal
#'
#' @export
#'
wavelet_ECG_annotation <- function(ecg_signal_, fs) {

  # preprocessing
  ecg <-
    ecg_signal_ %>%
    baseline_wander_removal_median(fs) %>%
    signal_low_pass(sampling_frequency = fs)

  # wavelet transform
  ecg_list <-
    wavelet_preprocessing(ecg, fs)

  R_detection <-
    wavelet_R_detection(ecg_list$wavelets, ecg_list$thresholds, ecg_list$alignments)

  if(length(R_detection) == 0){
    return(list(
      P_wave = c(),
      Q_peak = c(),
      R_peak = c(),
      S_peak = c(),
      T_wave = c()
    ))
  }else{
    R_peak <- R_detection[!is.na(R_detection)]

    Q_detection <-
      wavelet_Q_detection(R_peak, ecg_list$wavelets, ecg_list$alignments)

    S_detection <-
      wavelet_S_detection(R_peak, ecg_list$wavelets, ecg_list$alignments)

    P_detection <-
      wavelet_P_detection(R_peak, ecg_list$wavelets, ecg_list$alignments)

    T_detection <-
      wavelet_T_detection(R_peak, ecg_list$wavelets, ecg_list$alignments)

    list(
      P_wave = P_detection$P %>%
        convert_unit_to_ms_(),

      P_onset = P_detection$P_onset %>%
        convert_unit_to_ms_(),

      type_of_P = P_detection$type_of_P,

      Q_peak = Q_detection %>%
        convert_unit_to_ms_(),

      R_peak = R_peak %>%
        convert_unit_to_ms_(),

      S_peak = S_detection %>%
        convert_unit_to_ms_(),

      T_wave = T_detection$T_wave %>%
        convert_unit_to_ms_(),

      T_onset = T_detection$T_onset %>%
        convert_unit_to_ms_(),

      type_of_T = T_detection$type_of_T

    )
  }

}
Teresa00/hfmAnnotation documentation built on May 14, 2019, 12:51 a.m.