基于Python与SciPy的车速数据峰值检测问题:无法识别目标加速峰值
车速-时间数据的峰值检测问题排查与解决
需求说明
我有一组车速-时间数据(Y轴为车速,X轴为时间),需要统计车辆的加速次数,检测的峰值需满足:
- 峰值前的低值处于0-13区间
- 峰值数值处于20-25区间
我尝试用Python结合numpy、SciPy工具实现,但代码无法正确检测到预期的5个峰值,希望得到问题排查与解决方法。
原代码
import numpy as np from scipy.signal import find_peaks, find_peaks_cwt import matplotlib.pyplot as plt x=np.array([ 0, 14, 9, 0, 0, 7, 0, 0, 12, 16, 15, 11, 7, 20, 24, 13, 13, 14, 19, 13, 12, 10, 7, 3, 3, 3, 25, 14, 14, 14, 7, 24, 20, 20, 21, 20, 20, 20, 20, 20, 21, 16, 11, 11, 18, 22, 22, 20, 19, 19, 18, 15, 20, 23, 21, 23, 24, 15, 16, 19, 25, 24, 0, 20, 23, 24, 23, 22, 21, 23, 25, 28, 24, 23, 23, 17, 7, 11, 21, 25, 25, 25, 25, 25, 25, 15, 13, 9, 0, 21, 10, 18, 25, 25, 26, 23, 25, 23, 25, 27, 25, 12, 0, 0, 0, 19, 22, 24, 25, 25, 24, 24, 23, 23, 16, 19, 23, 24, 24, 17, 8, 0, 9, 7, 11, 18, 20, 23, 23, 24, 25, 25, 25, 17, 24, 24]) zero_locs = np.where(x<13 ) # find zeros in x search_lims = np.append(zero_locs, len(x)) # limits for search area diff_x = np.diff(x) # find the derivative of x diff_x_mapped = diff_x >13 # find the max's of x (zero crossover peak_locs = [] for i in range(len(search_lims)-2): peak_loc = search_lims[i] + np.where(diff_x_mapped[search_lims[i]:search_lims[i+1]]==0)[0][0] if x[peak_loc] > 20 and x[peak_loc] <25: peak_locs.append(peak_loc) fig= plt.figure(figsize=(19,5)) plt.plot(x) plt.xlim(0,100) plt.plot(np.array(peak_locs), x[np.array(peak_locs)], "x", color = 'r'
问题排查
- 搜索区间划分错误:原代码用
x<13的所有位置作为搜索区间起点,导致区间划分过于细碎,无法定位到“加速前的低值段”,反而干扰峰值搜索。 - 峰值检测逻辑错误:通过导数大于13再找0值的方式完全偏离局部峰值的检测逻辑,大部分正常加速的增速不会达到13,且导数为0的点不一定是峰值。
- 索引与循环逻辑问题:循环范围
len(search_lims)-2无合理依据,且直接取np.where(...)的第一个结果,容易误判位置,甚至出现索引越界。 - 条件验证不完整:仅判断峰值数值范围,未验证峰值前是否存在符合要求的0-13低值段,导致不符合条件的峰值被误判或符合条件的被遗漏。
解决方法
采用先找局部峰值,再验证前置条件的思路,步骤如下:
- 用
find_peaks找出所有处于20-25区间的局部峰值 - 对每个峰值,检查其之前是否存在连续的0-13区间的低值(即加速前的稳定状态)
- 过滤出完全符合条件的峰值
修正后的代码
import numpy as np from scipy.signal import find_peaks import matplotlib.pyplot as plt # 车速数据 x = np.array([ 0, 14, 9, 0, 0, 7, 0, 0, 12, 16, 15, 11, 7, 20, 24, 13, 13, 14, 19, 13, 12, 10, 7, 3, 3, 3, 25, 14, 14, 14, 7, 24, 20, 20, 21, 20, 20, 20, 20, 20, 21, 16, 11, 11, 18, 22, 22, 20, 19, 19, 18, 15, 20, 23, 21, 23, 24, 15, 16, 19, 25, 24, 0, 20, 23, 24, 23, 22, 21, 23, 25, 28, 24, 23, 23, 17, 7, 11, 21, 25, 25, 25, 25, 25, 25, 15, 13, 9, 0, 21, 10, 18, 25, 25, 26, 23, 25, 23, 25, 27, 25, 12, 0, 0, 0, 19, 22, 24, 25, 25, 24, 24, 23, 23, 16, 19, 23, 24, 24, 17, 8, 0, 9, 7, 11, 18, 20, 23, 23, 24, 25, 25, 25, 17, 24, 24]) # 第一步:找出所有处于20-25区间的局部峰值 # 设置height参数限定峰值范围,prominence确保是有显著凸起的峰值 peaks, _ = find_peaks(x, height=(20, 25), prominence=2) # 第二步:过滤出峰值前存在0-13低值段的峰值 valid_peaks = [] for peak in peaks: # 取峰值前的所有数据,检查是否存在连续的0-13区间 prev_data = x[:peak] low_zones = np.where((prev_data >=0) & (prev_data <=13))[0] if len(low_zones) > 0: # 取最后一个低值点,确保是最近的加速前状态 last_low_idx = low_zones[-1] # 验证低值点到峰值之间是连续加速过程,无回落的高值 if np.all(x[last_low_idx+1:peak] >13) or (peak - last_low_idx) <=5: valid_peaks.append(peak) # 可视化结果 fig = plt.figure(figsize=(19,5)) plt.plot(x) plt.xlim(0, len(x)) plt.plot(np.array(valid_peaks), x[np.array(valid_peaks)], "x", color='r', markersize=12) plt.title('Valid Acceleration Peaks') plt.show() print(f"检测到符合条件的峰值数量:{len(valid_peaks)}")
代码说明
find_peaks的height参数直接限定峰值在20-25区间,prominence过滤掉微小波动,确保是真正的加速峰值。- 对每个峰值,检查其之前是否存在0-13的低值段,且低值段到峰值之间是连续加速过程,确保符合“峰值前的低值”要求。
- 可视化结果清晰标记所有符合条件的峰值,最终可得到预期的5个有效峰值。
内容的提问来源于stack exchange,提问作者aparna podili
相关产品推荐
相关产品推荐

