Home > Software engineering >  How to find "waves" in time-series data in R?
How to find "waves" in time-series data in R?

Time:10-16

Good afternoon,

I have a vector of data (force) in which values increase from low values, to a peak value, and then to low values again (repeating this trend twice), then creating two "waves" of data.

This is the code, in which I plot the force vector as a function of time (for a better representation)

force <- c(0,0,0,0,3,4,5,3,0,6,8,9,10,14,21,25,12,10,8,5,0,4,3,4,6,0,3,15,20,24,50,80,150,180,200,250,332,369,470,578,690,540,444,378,299,254,200,130,79,55,29,17,4,5,2,7,8,3,5,7,6,1,2,9,11,20,23,15,4,5,6,8,18,20,29,40,55,69,100,144,189,245,300,415,555,696,500,434,321,279,249,150,130,68,50,43,23,19,4,5,4,5,3,2,0,5,3,4)
time <- seq(from=0, to=length(force)-1, by=1)
plot(time,force, type = "l", lty = 1)

What I would like to do is to cut the vector so as it only contains the two "waves" of data. A "wave" is defined when:

  1. First, data goes above 20
  2. Then, a threshold of 300 is crossed
  3. Finally, data goes below 20 again

So according to these criteria, a wave would be found every time the data goes above 20, crosses a certain threshold, in this case 300 and afterwards goes below 20.

Done manually, the force.cut vector would be the desired result:

force.cut <- c(force[29:52],force[74:97])
time.cut <- seq(from=0, to=length(force.cut)-1, by=1)
plot(time.cut,force.cut, type = "l", lty = 1)

I am almost sure that the findpeaks function from the pracma package should be part of the solution, but I have not found the way to do exactly what I need. I am sure that there should be an easy way to do it, though.

Thank you very much in advance for any help!

CodePudding user response:

A quick try:

force <- c(0,0,0,0,3,4,5,3,0,6,8,9,10,14,21,25,12,10,8,5,0,4,3,4,6,0,3,15,20,24,50,80,150,180,200,250,332,369,470,578,690,540,444,378,299,254,200,130,79,55,29,17,4,5,2,7,8,3,5,7,6,1,2,9,11,20,23,15,4,5,6,8,18,20,29,40,55,69,100,144,189,245,300,415,555,696,500,434,321,279,249,150,130,68,50,43,23,19,4,5,4,5,3,2,0,5,3,4)
time <- seq(from=0, to=length(force)-1, by=1)
plot(time,force, type = "l", lty = 1)


a <- pracma::findpeaks(force, minpeakheight = 301, threshold = 20)
a
#>      [,1] [,2] [,3] [,4]
#> [1,]  690   41   26   53
#> [2,]  696   86   69   99

plot(time, force, xlim =c(a[1,3], a[1,4]), type = "l")

Created on 2022-10-15 with reprex v2.0.2

Regards, Grzegorz

CodePudding user response:

Here's an option using a for loop...


library(pracma)

peaks <- findpeaks(force, threshold = 20, minpeakheight = 300)


peak_period <- colSums(peaks)[4] - colSums(peaks)[3]   nrow(peaks)



peak_vec <- vector(mode = "numeric", length = peak_period)

w_start <- 1

for(i in seq_len(nrow(peaks))){
  
  len_i <- length(peaks[i, 3] : peaks[i, 4])
  w_end <- w_start   len_i-1
  peak_vec[w_start:w_end] <- c(peaks[i, 3]:peaks[i, 4])
  w_start <- len_i   w_start
  
}


plot(1:peak_period, force[peak_vec], type = "l", lty = 1, ylab = "Force", xlab = "Time")

Created on 2022-10-15 with reprex v2.0.2

  • Related