如何修改局部极小值检测代码以获取图表8个目标极小值并完成数据切割
问题根源
你当前的代码仅做逐点相邻高低关系判断,没有任何噪声过滤逻辑,会把波形上所有微小毛刺带来的局部低点全部判定为极小值,因此输出了36个冗余结果,完全无法匹配需要的8个带真实波形特征的谷值。
- 原判断逻辑无深度阈值:哪怕相邻波动幅度不足总信号极差的1%,也会被判定为有效谷
- 无谷间距限制:离得极近的连续毛刺会连续输出多个相邻的谷索引
- 原代码存在缩进错误:
if语句和for循环同级,实际运行会报语法错误,无法正常执行循环内的判断逻辑
核心修改逻辑
要精准筛选出8个目标极小值,需在原有逐点检测的基础上加两层过滤,滤除所有伪极小值:
- 深度过滤:给每个原始候选极小值计算对应的谷深度(即谷点比左右两侧相邻最近峰值的高度差),设置最小深度阈值,直接滤除深度过小的噪声毛刺
- 间距过滤:把符合深度要求的候选谷按照深度从大到小排序,优先保留深度更深的真实谷,同时强制两个保留的谷之间满足最小索引间隔,直到刚好筛选出8个有效位置
- 最后将筛选好的谷索引按从小到大排序,作为后续数据切割的锚点
修改后的代码实现
# 可根据实际波形调整的两个核心过滤参数 MIN_VALLEY_DEPTH = 0.05 * (max(y) - min(y)) # 有效谷的最小深度,取整信号极差的5% MIN_VALLEY_DISTANCE = len(y) // 10 # 两个有效谷之间的最小索引间隔 # 第一步:收集所有原始候选极小值(修正原代码的缩进错误) raw_candidates = [] for i in range(1, len(y) - 1): if y[i-1] >= y[i] and y[i] <= y[i+1]: # 计算当前候选点的谷深度 left_peak = max(y[:i]) right_peak = max(y[i:]) valley_depth = min(left_peak - y[i], right_peak - y[i]) raw_candidates.append((i, valley_depth)) # 第二步:分层过滤伪极小值 filtered_candidates = [] # 优先保留深度更大的候选值,因此按深度降序排序 raw_candidates.sort(key=lambda x: -x[1]) for idx, depth in raw_candidates: # 跳过深度不达标的噪声点 if depth < MIN_VALLEY_DEPTH: continue # 跳过和已保留谷距离过近的点 too_close = any(abs(idx - kept_idx) < MIN_VALLEY_DISTANCE for kept_idx, _ in filtered_candidates) if not too_close: filtered_candidates.append((idx, depth)) # 凑够8个目标点就提前停止筛选 if len(filtered_candidates) == 8: break # 最终整理成按x轴顺序排列的极小值索引列表 mini = sorted([idx for idx, depth in filtered_candidates])
基于极小值的数据切割实现
有了按顺序排好的8个极小值索引,直接做数组切片即可完成切割:
- 切割逻辑以极小值为分段边界:从数据起点开始,到第一个谷的位置为第一分段;相邻两个谷的索引之间为中间分段;从最后一个谷的位置到数据终点为收尾分段
- 不需要额外计算分割线坐标,直接用极小值索引作为切片边界即可
cut_segments = [] segment_start = 0 for valley_idx in mini: cut_segments.append(y[segment_start:valley_idx+1]) segment_start = valley_idx cut_segments.append(y[segment_start:])
注:两个过滤参数可根据实际波形微调,如果筛选出的谷位置偏离预期,就适当调高
MIN_VALLEY_DEPTH或MIN_VALLEY_DISTANCE的数值,直到精准匹配到目标的8个谷位置即可。
内容的提问来源于stack exchange,提问作者codexx
相关产品推荐
相关产品推荐

