You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在R中对时间序列执行FFT:拟合谐波、绘图及数据点预测

用FFT实现时间序列波形拟合与预测

嘿,我看你想用FFT来拟合时间序列的波形,还要绘制不同谐波的图像,再预测后续n个数据点——刚好你用的是@catastrophic-failure的代码,我帮你把这个思路补全、解释明白,让你能直接用起来:

完整实现函数

先把补全后的完整代码放出来,这个函数包含了拟合、预测和绘图的功能:

nff = function(y = NULL, n = NULL, up = 10L, plot = TRUE, add = FALSE, main = NULL, ...){
  # 对原始时间序列执行FFT变换
  # 注意:FFT结果第一个元素是直流分量,其余频率分量是对称重复的
  dff = fft(y)
  
  # 原始时间序列的时间点索引
  t = seq(from = 1, to = length(y))
  
  # 构建包含预测点的升采样时间轴:up控制平滑度,n是要预测的点数
  nt = seq(from = 1, to = length(y) + n, length.out = length(y)*up + n*up)
  
  # 处理FFT系数:只保留前半部分(后半部分是共轭对称的)
  len_y = length(y)
  half_len = ceiling(len_y/2)
  
  # 初始化升采样后的FFT系数数组
  dff_up = numeric(length(nt))
  # 复制前半部分的正频率系数
  dff_up[1:half_len] = dff[1:half_len]
  
  # 偶数长度的序列需要单独处理中间的频率分量
  if(len_y %% 2 == 0){
    dff_up[length(nt) - half_len + 2] = dff[half_len + 1]
  }
  
  # 填充后半部分的共轭对称系数
  dff_up[(length(nt) - half_len + 2):length(nt)] = Conj(rev(dff[2:half_len]))
  
  # 逆FFT变换得到拟合/预测序列,取实部并归一化
  y_fit = Re(fft(dff_up, inverse = TRUE)) / length(dff_up)
  
  # 绘制原始数据和拟合曲线
  if(plot){
    if(!add){
      plot(t, y, type = "p", main = ifelse(is.null(main), "FFT拟合与预测结果", main), ...)
    }
    lines(nt, y_fit, col = "red", lwd = 2)
  }
  
  # 返回所有结果供后续分析
  list(original = y, fitted = y_fit, time_original = t, time_fitted = nt, fft_coeff = dff)
}

关键步骤拆解

  • FFT核心变换:fft(y)把时域的时间序列转换成频域的系数,第一个系数是直流分量(信号的平均水平),后面的系数对应不同频率的谐波成分,且正负频率是对称的。
  • 升采样时间轴:nt不仅包含原始数据的时间点,还扩展了n个预测点的时间范围,up参数越大,拟合出来的曲线越平滑,适合观察波形细节。
  • 系数对称处理:因为FFT的结果是对称的,我们只需要保留前半部分的有效系数,再通过共轭对称填充后半部分,这样逆变换后就能得到平滑的拟合波形。
  • 逆FFT还原:逆变换后取实部(因为原始信号是实数),再除以长度做归一化,就能得到和原始信号同尺度的拟合/预测序列。

绘制单个谐波的波形

如果想单独看每个谐波对原始信号的贡献,可以用这个小工具函数:

# 绘制指定次数的谐波波形
plot_single_harmonic = function(y, harmonic_idx){
  len_y = length(y)
  dff = fft(y)
  
  # 初始化系数数组,只保留目标谐波的分量
  dff_single = numeric(len_y)
  dff_single[harmonic_idx + 1] = dff[harmonic_idx + 1]
  
  # 非直流分量需要保留对应的负频率共轭系数
  if(harmonic_idx != 0){
    dff_single[len_y - harmonic_idx + 1] = dff[len_y - harmonic_idx + 1]
  }
  
  # 逆变换得到该谐波的时域波形
  harmonic_wave = Re(fft(dff_single, inverse = TRUE)) / len_y
  t = seq(1, len_y)
  
  # 绘图
  plot(t, harmonic_wave, type = "l", main = paste("第", harmonic_idx, "次谐波"), 
       col = "steelblue", lwd = 2, xlab = "时间点", ylab = "幅值")
}

# 示例:绘制直流分量(0次)、基波(1次)、2次谐波
plot_single_harmonic(y, 0)
plot_single_harmonic(y, 1)
plot_single_harmonic(y, 2)
  • 0次谐波就是信号的平均值,是一条水平线
  • 1次谐波是信号的基波,对应原始信号的基本周期
  • 更高次谐波是叠加在基波上的高频“波纹”,这些谐波组合起来就构成了原始信号的复杂波形

用函数预测n个数据点

调用nff函数时,只需要指定n参数就能得到后续n个点的预测结果:

# 先生成一个测试用的时间序列(带噪声的正弦波)
set.seed(123)
y = sin(seq(1, 20, by = 0.5)) + rnorm(40, 0, 0.1)

# 预测后续10个点,设置up=10保证曲线平滑
result = nff(y, n = 10, up = 10, main = "FFT拟合与10点预测", xlab = "时间点", ylab = "幅值")

# 查看最后10个预测值
tail(result$fitted, 10)

运行后,你会看到黑色散点是原始数据,红色曲线是拟合和预测的结果——红色曲线的后半段就是你要的n个预测点。

内容的提问来源于stack exchange,提问作者m.inam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:58:09