STEP 5) Fix heart rate frequencies double the real valuestep 1 -- pulse_read()
step 2 -- pulse_split()
step 3 -- pulse_optimize()
step 4 -- pulse_heart()
-->> step 5 -- pulse_doublecheck() <<--
step 6 -- pulse_choose_keep()
Flag (and correct) data points where it is likely that the heart rate frequency computed corresponds to double the actual heart rate frequency due to the algorithm having identified two peaks per heart beat
pulse_doublecheck(heart_rates, flag = 0.9, correct = TRUE)A tibble similar to the one used as input, now augmented with two new columns: d_r and d_f. Values of d_r (ratio) close to 1 are indicative that the value for hz determined by the algorithm should be halved. If correct was set to TRUE, d_f flags data points where hz
HAS BEEN HALVED. If correct was set to FALSE, then d_f flags data points where hz
SHOULD BE HALVED.
the output from pulse_heart()
numerical, decimal from 0 to 1, defaults to 0.9; values of d_r above this number will be flagged as instances where the algorithm resulted in double the real heart rate. Values above 1are meaningless (zero data points will be flagged), and values below ~0.66 are too lax (many data points will be flagged when they shouldn't).
logical, defaults to TRUE; if FALSE, data points with hz values likely double the real value are flagged BUT NOT CORRECTED. If TRUE, hz (as well as data, n, sd and ci) are corrected accordingly. Note that the correction is not reversible!
For many invertebrates, the circulatory system includes more than one contractile chamber, meaning that there are two consecutive movements that may or may not be detected by the PULSE system's IR sensors. Furthermore, when the sensor is attached to the shell of the animal, it remains at a fixed position even as the soft body tissues move below that. As a result, even if one takes explicit care to position the sensor in such a way that only one wave peak is detected for each heart beat cycle, at some point the animal may move and the sensor's field of view may come to encompass both contractile chambers. When that occurs, the shape of the signal detected will include two peaks per heart beat cycle, the relative sizes of which may vary considerably. To be clear, there's nothing wrong with such a signal. However, it creates a problem: the algorithm detects peaks, and therefore, if two peaks are detected for each heart beat, the resulting estimate for the heart beat frequency will show a value twice as much as the real value.
While it is often easy to discern if a PULSE data point has two peaks per heart beat upon visual inspection, to do so automatically is much harder. The strategy employed here relies on analyzing the intervals between consecutive peaks and looking for a regular alternation between longer and shorter intervals, as well as higher and lower peak signal values. If intervals are consistently shorter, then longer, then shorter again, we can assume that the distribution of interval times is bimodal, and that there are always two peaks more closer together separated by a longer interval - a classical two-peaks-per-heart-beat situation. For example, let's say 24 peaks are detected. We can compute the time span between each peak, which will correspond to 23 intervals (measured in seconds). Then, intervals can be classified as being longer or shorter than the preceding interval. Lastly, we divide the number of longer-than-previous intervals by the total number of intervals, deriving the ratio of switching intervals. Similarly, if peak signal values are consistently higher, then lower, then higher again, we can also assume that two different heart movements belonging to the same heartbeat are represented in the data, and a similar algorithm can be followed. The closer the ratio is to 1, the more certain we are that we are facing a situation where the algorithm will result in a heart beat frequency twice the real value. Because the choice of a threshold to flag data points as needing to be halved or not is arbritary, both the flagging and the ratio are provided in the output, thus enabling a reassessment of the resulting classification.
pulse_heart() generates the tibble that is used as input.
pulse_read(), pulse_split(), pulse_optimize(), pulse_heart() and pulse_choose_keep() are the other functions needed for the complete PULSE processing workflow
PULSE() is a wrapper function that executes all the steps needed to process PULSE data at once, including the identification of possible heart rate doublings
## Begin prepare data ----
pulse_data_sub <- pulse_data
pulse_data_sub$data <- pulse_data_sub$data[,1:3]
pulse_data_split <- pulse_split(pulse_data_sub)
pulse_data_split <- pulse_optimize(pulse_data_split, multi = pulse_data$multi)
heart_rates <- pulse_heart(pulse_data_split)
## End prepare data ----
# Correct heartbeat frequency estimates
pulse_doublecheck(heart_rates)
Run the code above in your browser using DataLab