如何检测离散信号的局部极值并确保极值交替出现?
离散信号交替极值检测解决方案
在处理离散信号的峰/谷检测时,scipy.signal中的argrelmax/argrelmin函数经常会因为信号中的平台段,导致检测出的极值无法满足极小值与极大值交替出现的要求。比如你给出的示例信号[0,1,0,0,1,2,1,0,0,0],直接调用函数只能得到2个极大值和1个极小值,无法形成完整的交替序列。
下面提供几种实用的解决思路:
思路1:预处理消除平台段
离散信号中的平台是破坏极值交替的核心原因之一,给信号添加微小噪声或者做差分处理,能把平台转化为可被极值检测函数识别的微小波动。
示例代码:
from scipy.signal import argrelmax, argrelmin import numpy as np import matplotlib.pyplot as plt y = np.array([0,1,0,0,1,2,1,0,0,0]) # 添加极小随机噪声,避免平台干扰 y_noisy = y + np.random.normal(0, 1e-6, size=y.shape) # 检测极值 local_minima, = argrelmin(y_noisy) local_maxima, = argrelmax(y_noisy) # 合并并排序所有极值点 all_extrema = sorted(np.concatenate([local_minima, local_maxima])) # 可视化 fig, ax = plt.subplots() x = range(len(y)) ax.plot(local_maxima, y[local_maxima], "x", color="orange", label="极大值") ax.plot(local_minima, y[local_minima], "x", color="blue", label="极小值") ax.plot(x, y, label="原始信号") ax.legend() plt.show()
这种方法简单高效,适合对精度要求不高、平台段不复杂的场景。
思路2:自定义遍历检测逻辑
自己实现信号遍历逻辑,严格按照“交替极值”的规则去识别峰谷,能完全控制极值的判定标准,适合复杂平台或特殊规则的场景。
示例代码:
import numpy as np import matplotlib.pyplot as plt def find_alternating_extrema(y): extrema = [] n = len(y) if n < 3: return extrema # 确定第一个有效极值 i = 1 while i < n-1: # 检测严格极大值 if y[i] > y[i-1] and y[i] > y[i+1]: extrema.append(("max", i)) i += 1 break # 检测严格极小值 elif y[i] < y[i-1] and y[i] < y[i+1]: extrema.append(("min", i)) i += 1 break # 处理平台后的趋势变化 elif y[i] == y[i-1] and y[i] != y[i+1]: if y[i+1] > y[i]: extrema.append(("min", i)) else: extrema.append(("max", i)) i += 1 break i += 1 # 按交替规则遍历剩余信号 while i < n-1: last_type = extrema[-1][0] if last_type == "max": # 寻找下一个极小值 while i < n-1: if y[i] < y[i-1] and y[i] < y[i+1]: extrema.append(("min", i)) i += 1 break elif y[i] == y[i-1] and y[i] < y[i+1]: extrema.append(("min", i)) i += 1 break elif y[i] < y[i-1] and y[i] == y[i+1]: extrema.append(("min", i)) i += 1 break i += 1 else: # 寻找下一个极大值 while i < n-1: if y[i] > y[i-1] and y[i] > y[i+1]: extrema.append(("max", i)) i += 1 break elif y[i] == y[i-1] and y[i] > y[i+1]: extrema.append(("max", i)) i += 1 break elif y[i] > y[i-1] and y[i] == y[i+1]: extrema.append(("max", i)) i += 1 break i += 1 return extrema # 测试 y = np.array([0,1,0,0,1,2,1,0,0,0]) extrema = find_alternating_extrema(y) max_indices = [idx for typ, idx in extrema if typ == "max"] min_indices = [idx for typ, idx in extrema if typ == "min"] # 可视化 fig, ax = plt.subplots() x = range(len(y)) ax.plot(max_indices, y[max_indices], "x", color="orange", label="极大值") ax.plot(min_indices, y[min_indices], "x", color="blue", label="极小值") ax.plot(x, y, label="原始信号") ax.legend() plt.show()
这个函数会严格按照交替规则识别极值,处理平台段时会根据后续信号趋势判定极值位置。
思路3:自定义argrelextrema比较器
利用argrelextrema的comparator参数,自定义极值判定规则,把平台段的起点/终点认定为极值,再对结果做交替校验。
示例代码:
from scipy.signal import argrelextrema import numpy as np import matplotlib.pyplot as plt y = np.array([0,1,0,0,1,2,1,0,0,0]) # 自定义极大值比较器:允许平台终点作为极大值 def max_comp(a, b): return a >= b # 自定义极小值比较器:允许平台终点作为极小值 def min_comp(a, b): return a <= b # 检测极值 local_maxima, = argrelextrema(y, max_comp, order=1) local_minima, = argrelextrema(y, min_comp, order=1) # 校验并修正交替顺序 all_extrema = sorted(list(local_maxima) + list(local_minima)) corrected = [] last_type = None for idx in all_extrema: is_max = idx in local_maxima if last_type is None: corrected.append(("max", idx) if is_max else ("min", idx)) last_type = "max" if is_max else "min" else: # 只保留与上一个类型相反的极值 if (last_type == "max" and not is_max) or (last_type == "min" and is_max): corrected.append(("max", idx) if is_max else ("min", idx)) last_type = "max" if is_max else "min" # 提取修正后的索引 max_indices = [idx for typ, idx in corrected if typ == "max"] min_indices = [idx for typ, idx in corrected if typ == "min"] # 可视化 fig, ax = plt.subplots() x = range(len(y)) ax.plot(max_indices, y[max_indices], "x", color="orange", label="极大值") ax.plot(min_indices, y[min_indices], "x", color="blue", label="极小值") ax.plot(x, y, label="原始信号") ax.legend() plt.show()
这种方法兼顾了scipy函数的高效性,同时通过自定义规则和后处理满足交替要求。
内容的提问来源于stack exchange,提问作者Philipp
相关产品推荐
相关产品推荐

