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

如何使用scipy.signal确定信号峰值的上升时间与衰减时间

如何用scipy.signal计算峰值的上升时间与衰减时间

嗨,作为信号处理新手能走到这一步已经很棒啦!你想要获取的上升时间(左宽度点到峰值的距离)和衰减时间(峰值到右宽度点的距离),其实完全可以通过你已经在使用的peak_widths函数的结果直接推导出来,不用额外去折腾一阶矩或者导数(当然如果之后想做更精细的分析,导数方法也可以尝试,先给你最贴合当前工作流的方案)。

直接利用peak_widths的返回值

首先你得知道,peak_widths返回的是一个包含4个元素的元组,其中后两个元素正好是我们需要的宽度点位置:

  • results_full[2]:每个峰值左宽度点的插值位置(因为宽度点可能落在两个采样点之间,所以是浮点数值)
  • results_full[3]:每个峰值右宽度点的插值位置

而你已经得到的peaks数组里是峰值对应的整数采样索引,所以直接做减法就能得到时间差(因为采样间隔是固定的,这里ECG信号的采样率是360Hz,如果你需要转换成实际时间,再除以采样率就行)。

完整示例代码

先补全你之前的代码(记得导入numpy),然后计算并可视化这些时间:

import matplotlib.pyplot as plt
import numpy as np
from scipy.misc import electrocardiogram
from scipy.signal import find_peaks, peak_widths

# 获取ECG信号片段
x = electrocardiogram()[2000:4000]
# 检测峰值
peaks, _ = find_peaks(x, height=0)
# 计算完整的峰值宽度信息(rel_height=1对应峰值底部到顶部的宽度,你也可以调整比如0.5求半高宽)
results_full = peak_widths(x, peaks, rel_height=1)

# 计算上升时间和衰减时间
rise_times = peaks - results_full[2]
decay_times = results_full[3] - peaks

# 可视化展示
plt.plot(x, label='ECG Signal')
plt.plot(peaks, x[peaks], "x", label='Peaks')
# 画出左宽度点和右宽度点
plt.plot(results_full[2], results_full[1], "o", label='Left Width Points')
plt.plot(results_full[3], results_full[1], "o", label='Right Width Points')
plt.plot(np.zeros_like(x), "--", color="gray")

# 标注第一个峰值的上升/衰减时间(示例)
plt.annotate(f"Rise Time: {rise_times[0]:.2f} samples", 
             xy=(results_full[2][0], results_full[1][0]), 
             xytext=(results_full[2][0]-50, results_full[1][0]+0.5),
             arrowprops=dict(arrowstyle='->'))
plt.annotate(f"Decay Time: {decay_times[0]:.2f} samples", 
             xy=(results_full[3][0], results_full[1][0]), 
             xytext=(results_full[3][0]+50, results_full[1][0]+0.5),
             arrowprops=dict(arrowstyle='->'))

plt.legend()
plt.show()

# 打印所有峰值的时间信息
print("上升时间(采样点):", rise_times)
print("衰减时间(采样点):", decay_times)
# 如果要转换成实际时间(ECG采样率360Hz)
sampling_rate = 360
print("上升时间(秒):", rise_times / sampling_rate)
print("衰减时间(秒):", decay_times / sampling_rate)

可选:用导数方法检测上升/下降沿

如果你想更精确地捕捉信号从基线上升到峰值的时间(而不是基于某个相对高度的宽度点),可以通过计算信号的一阶导数来实现:

  1. 用平滑滤波器(比如savgol_filter)预处理信号,减少噪声对导数的影响
  2. 计算一阶导数,找到导数由负变正的点(上升沿起点)和由正变负的点(下降沿终点)
  3. 计算这些点到峰值的距离

示例代码片段:

from scipy.signal import savgol_filter

# 平滑信号并计算导数
smoothed_x = savgol_filter(x, window_length=11, polyorder=2)
dx = np.gradient(smoothed_x)

# 找上升沿:导数从负变正的位置(基线到峰值的起点)
rise_edges = np.where((dx[:-1] < 0) & (dx[1:] > 0))[0]
# 找下降沿:导数从正变负的位置(峰值到基线的终点)
decay_edges = np.where((dx[:-1] > 0) & (dx[1:] < 0))[0]

# 注意:需要把上升/下降沿和对应的峰值匹配,这里简单取最近的点
# (实际应用中可能需要更严谨的匹配逻辑)
for peak in peaks:
    closest_rise = rise_edges[np.argmin(np.abs(rise_edges - peak))]
    closest_decay = decay_edges[np.argmin(np.abs(decay_edges - peak))]
    print(f"峰值{peak}的上升时间:{peak - closest_rise} 采样点")
    print(f"峰值{peak}的衰减时间:{closest_decay - peak} 采样点")

这种方法更贴近“沿”的物理定义,但需要处理噪声和匹配问题,适合对时间精度要求更高的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 08:59:06