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

R语言实时时间序列数据条件式峰谷信号检测方法优化

带显著性阈值的自适应时序峰谷检测优化方案

针对动态噪声、动态峰宽峰高的时序数据,在原实时峰值检测算法基础上做定向优化,支持自定义幅度阈值过滤微小波动,同时识别显著峰值与谷值。

  • 保留原算法滑动窗口计算局部基线、局部标准差的自适应逻辑,适配背景噪声、峰谷形态动态变化的场景
  • 新增可配置的峰/谷最小幅度参数,自动过滤基线附近不达标的微小震荡
  • 输出结果包含峰谷位置、信号值、相对基线幅度三类信息,可直接用于后续上报逻辑

优化后实现代码

# 优化版带显著性阈值的实时峰谷检测函数
detect_significant_peaks_valleys <- function(
    signal,
    lag = 10,
    threshold = 3,
    influence = 0.2,
    min_peak_amp = 40,  # 可配置:峰值最小显著幅度
    min_valley_amp = 40 # 可配置:谷值最小显著幅度
) {
  # 初始化结果存储向量
  signals <- rep(0, length(signal)) # 0=无异常, 1=峰值, -1=谷值
  filtered_y <- c(signal[1:lag], rep(NA, length(signal)-lag))
  avg_filter <- rep(NA, length(signal))
  std_filter <- rep(NA, length(signal))
  avg_filter[lag] <- mean(signal[1:lag])
  std_filter[lag] <- sd(signal[1:lag])
  
  # 逐点遍历检测
  for (i in (lag+1):length(signal)) {
    local_base <- avg_filter[i-1]
    local_std <- std_filter[i-1]
    # 峰值判定:z分达标 + 幅度超过最小峰值阈值
    if (signal[i] - local_base > threshold * local_std && signal[i] - local_base >= min_peak_amp) {
      signals[i] <- 1
      filtered_y[i] <- influence * signal[i] + (1-influence) * filtered_y[i-1]
    } 
    # 谷值判定:z分达标 + 幅度超过最小谷值阈值
    else if (local_base - signal[i] > threshold * local_std && local_base - signal[i] >= min_valley_amp) {
      signals[i] <- -1
      filtered_y[i] <- influence * signal[i] + (1-influence) * filtered_y[i-1]
    } 
    # 非显著点,纳入基线计算
    else {
      signals[i] <- 0
      filtered_y[i] <- signal[i]
    }
    # 更新滑动窗口的均值、标准差
    avg_filter[i] <- mean(filtered_y[(i-lag+1):i])
    std_filter[i] <- sd(filtered_y[(i-lag+1):i])
  }
  
  # 提取峰谷位置、对应值、相对幅度
  peak_idx <- which(signals == 1)
  valley_idx <- which(signals == -1)
  
  return(list(
    peaks = data.frame(
      index = peak_idx,
      value = signal[peak_idx],
      amp_above_base = signal[peak_idx] - avg_filter[peak_idx-1]
    ),
    valleys = data.frame(
      index = valley_idx,
      value = signal[valley_idx],
      amp_below_base = avg_filter[valley_idx-1] - signal[valley_idx]
    ),
    detection_flag = signals
  ))
}

# 传入示例信号测试
signal <- c(659, 613, 586, 642, 685, 695, 691, 733, 638, 708, 706, 691, 703, 712, 715, 700, 693, 682, 717, 711, 722, 700, 704, 704, 715, 691, 670, 684, 689, 711, 680, 692, 686, 710, 702, 699, 702, 715, 691, 670, 684, 689, 711, 673, 688, 699, 677, 701, 680, 692, 686, 710, 702, 699, 717, 691, 703, 712, 715, 700, 693, 682, 717, 711, 722, 700, 704, 704, 715, 691, 670, 684, 689, 711, 680, 692, 686, 710, 702, 699, 702, 706, 651, 712, 722, 734, 705, 714, 691, 704, 704, 669, 712, 715, 689, 715, 691, 670, 684, 689, 711, 651, 712, 722, 734, 705, 714, 691, 686, 676, 690, 693, 702, 694, 682, 693, 724, 693, 707, 684, 687, 705, 680, 680, 705, 680, 693, 700, 704, 704, 669, 712, 715, 689, 715, 691, 670, 684, 689, 711, 673, 678, 699, 677, 680, 682, 676, 690, 658, 675, 663, 667, 682, 673, 675, 656, 652, 563, 544, 542, 540, 532, 538, 505, 526, 565, 629, 720, 713, 720, 720, 773, 732, 740, 695, 689, 723, 685, 726, 710, 684, 693, 715, 692, 683, 712, 707, 693, 699, 717, 703, 687, 682, 690, 716, 708, 713, 700, 676, 708, 691, 717, 711, 722, 688, 695, 641, 666, 638, 639, 600, 635, 609, 653, 671, 649, 716, 708, 713, 700, 676, 708, 691, 717, 711, 722, 700, 704, 704, 669, 712, 715, 689, 715, 691, 670, 684, 689, 711, 673, 688, 699, 677, 701, 680, 692, 686, 710, 702, 699, 717, 691, 703, 712, 715, 700, 693, 682, 717, 711, 722, 700, 704, 704, 715, 691, 670, 684, 689, 711, 680, 692, 686, 710, 702, 699, 702, 715, 691, 670, 684, 689, 711, 673, 688, 699, 677, 701, 680, 692, 686, 710, 702, 699, 717, 691, 703, 712, 715, 700, 693, 682, 717, 711, 722, 700, 704, 704, 715, 691, 670, 684, 769, 767, 740, 752, 686, 710, 702, 699, 702, 706, 651, 712, 722, 734, 705, 714, 691, 704, 704, 669, 712, 715, 689, 715, 691, 670, 684, 689, 711, 704, 669, 712, 715, 689, 715, 691, 670, 684, 689, 711, 673, 688, 699, 677, 701, 680, 692, 686, 710, 702, 699, 717, 691, 703, 712, 715, 700, 693, 682, 717, 711, 722, 700, 704, 704, 715, 691, 670, 684, 689, 711, 680, 692, 686, 710, 702, 699, 702, 715, 691, 670, 684, 689, 711, 673, 688, 699, 677, 701, 680, 692, 686, 710, 702, 699, 665, 630, 808, 686, 787, 781, 796, 815, 786, 793, 664, 717, 691, 703, 712, 715, 700, 693, 682, 717, 711, 722, 700, 704, 704, 715, 691, 670, 684, 689, 711, 680, 692, 686, 710, 702, 699, 702, 706, 651, 712, 722, 734, 705, 714, 691, 704, 704, 669, 712, 715, 689, 715, 691, 670, 684, 689, 711)

# 运行检测,可根据实际噪声调整幅度阈值过滤小幅波动
result <- detect_significant_peaks_valleys(
  signal = signal,
  lag = 12,
  threshold = 2.8,
  influence = 0.15,
  min_peak_amp = 45,
  min_valley_amp = 45
)

# 查看输出的显著峰值、谷值
print("检测到的显著峰值:")
print(result$peaks)
print("检测到的显著谷值:")
print(result$valleys)

参数说明

  • lag:滑动窗口长度,用于计算局部基线均值与标准差,建议设置为信号中最小峰谷宽度的2~3倍
  • threshold:z-score判定阈值,取值越大对波动的判定越严格,常规场景取2.5~3.5即可
  • influence:已检测到的峰谷对基线计算的影响权重,取值范围01,实时流场景建议取00.3,避免基线被异常峰谷带偏
  • min_peak_amp:峰值最小显著幅度,峰值点高出局部基线的差值低于该值时直接过滤
  • min_valley_amp:谷值最小显著幅度,谷值点低于局部基线的差值低于该值时直接过滤

效果参考

运行代码后将自动过滤参考图中未标注的小幅波动,仅保留红圈标记的显著峰谷:
显著峰谷标注参考图

调参参考

  • 杂峰过多时,适当调高min_peak_amp、min_valley_amp的取值
  • 漏检窄峰时适当减小lag值;宽峰被误拆为多个峰时适当增大lag值
  • 高噪声场景下适当调高threshold取值,减少噪声误判

内容的提问来源于stack exchange,提问作者ramen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 13:30:54