r - 对 R 中的时间序列执行傅里叶分析

标签 r fft

我想使用 R 对时间序列执行傅立叶变换。我想:

  • 获得 5 次到 18 次谐波的总和
  • 绘制每一波
  • 并输出为 csv 文件。

  • 这是数据的链接:
    Link to Data

    这是我的初始代码。
    dat   <- read.csv("Baguio.csv",header=FALSE)
    y     <- dat$V1
    ssp   <-spectrum(y)
    t     <- 1:73
    per   <- 1/ssp$freq[ssp$spec==max(ssp$spec)]
    reslm <- lm(y ~ sin(2*pi/per*t)+cos(2*pi/per*t))
    rg    <- diff(range(y))
    
    #blue dashed line
    plot(y~t,ylim=c(min(y)-0.1*rg,max(y)+0.1*rg))
    lines(fitted(reslm)~t,col=4,lty=2)
    
    #green line 2nd harmonics
    reslm2 <- lm(y ~ sin(2*pi/per*t)+cos(2*pi/per*t)+sin(4*pi/per*t)+cos(4*pi/per*t))
    lines(fitted(reslm2)~t,col=3)
    

    Sample Output image

    有没有办法简化这段代码?如果我必须达到 18 次谐波,则方程会变得非常长。另外,我仍然不知道如何在这里添加谐波。

    提前谢谢了,

    最佳答案

    一个更简单的解决方案是使用快速傅里叶变换 (fft)

    dat   <- read.csv("Baguio.csv", header=FALSE)
    y     <- dat$V1
    t     <- 1:73
    rg    <- diff(range(y))
    
    nff = function(x = NULL, n = NULL, up = 10L, plot = TRUE, add = FALSE, main = NULL, ...){
      #The direct transformation
      #The first frequency is DC, the rest are duplicated
      dff = fft(x)
      #The time
      t = seq(from = 1, to = length(x))
      #Upsampled time
      nt = seq(from = 1, to = length(x)+1-1/up, by = 1/up)
      #New spectrum
      ndff = array(data = 0, dim = c(length(nt), 1L))
      ndff[1] = dff[1] #Always, it's the DC component
      if(n != 0){
        ndff[2:(n+1)] = dff[2:(n+1)] #The positive frequencies always come first
        #The negative ones are trickier
        ndff[length(ndff):(length(ndff) - n + 1)] = dff[length(x):(length(x) - n + 1)]
      }
      #The inverses
      indff = fft(ndff/73, inverse = TRUE)
      idff = fft(dff/73, inverse = TRUE)
      if(plot){
        if(!add){
          plot(x = t, y = x, pch = 16L, xlab = "Time", ylab = "Measurement",
            main = ifelse(is.null(main), paste(n, "harmonics"), main))
          lines(y = Mod(idff), x = t, col = adjustcolor(1L, alpha = 0.5))
        }
        lines(y = Mod(indff), x = nt, ...)
      }
      ret = data.frame(time = nt, y = Mod(indff))
      return(ret)
    }
    

    然后我们需要调用res ,将时间序列传递为 x ,谐波数为n和上采样(所以我们在原始时间点旁边绘制时间点)为up .
    png("res_18.png")
    res = nff(x = y, n = 18L, up = 100L, col = 2L)
    dev.off()
    

    enter image description here

    要获得 5 次到 18 次谐波的总和,这只是系列之间的差异
    sum5to18 = nff(x = y, n = 18L, up = 10L, plot = FALSE)
    sum5to18$y = sum5to18$y - nff(x = y, n = 4L, up = 10L, plot = FALSE)$y
    png("sum5to18.png")
    plot(sum5to18, pch = 16L, xlab = "Time", ylab = "Measurement", main = "5th to 18th harmonics sum", type = "l", col = 2)
    dev.off()
    

    enter image description here

    添加参数 addcol允许我们用特定颜色绘制多个波
    colors = rainbow(36L, alpha = 0.3)
    nff(x = y, n = 36L, up = 100L, col = colors[1])
    png("all_waves.png")
    for(i in 1:18){
      ad = ifelse(i == 1, FALSE, TRUE)
      nff(x = y, n = i, up = 100L, col = colors[i], add = ad, main = "All waves up to 18th harmonic")
    }
    dev.off()
    

    enter image description here

    Is there a way so extract the data of each series then save as a csv file. So in this example, I should have 18 csv files for the 18 waves.



    我编辑了代码以允许 0 谐波(基本上是平均值),所以现在您将单独的波提取为:
    sep = array(data = NA_real_, dim = c(7300L, 2 + 18), dimnames = list(NULL, c("t", paste0("H", 0:18))))
    sep[,1:2] = as.matrix(nff(x = y, n = 0, up = 100L, plot = FALSE))
    
    for(i in 1:18L){
      sep[,i+2] = nff(x = y, n = i, up = 100L, plot = FALSE)$y - nff(x = y, n = i-1, up = 100L, plot = FALSE)$y
    } 
    

    然后你可以使用 write.table写一个csv文件。

    关于r - 对 R 中的时间序列执行傅里叶分析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41435777/

    相关文章:

    python - 从 MATLAB 到 Python 的二维 FFT

    r - 从日期中提取年份

    r - 使用其他列作为参数在 summary_at() 中起作用

    r - 从 Hmisc 包中的 latex() 创建的表水平左对齐,而不是在 pdf 文档中水平居中

    image - 如何组合一幅图像的相位和不同图像的大小?

    python - 如何让 python 加载一个大(2 小时)wav 文件并将其内容转换为时频数组?

    r - 使用 mlr3-pipelines 在 GraphLearner 中估算数据并编码因子列?

    r - 如何在 Shiny 的应用程序中初始化渲染项目的默认值

    python - 如何找到歌曲的音阶

    matlab - 如何交换两个图像的相位响应?