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

如何检测离散信号的局部极值并确保极值交替出现?

离散信号交替极值检测解决方案

在处理离散信号的峰/谷检测时,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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 22:05:29