如何在C++中捕获传感器波形的连续最大/最小峰值?
波形信号峰谷检测的C++实现方案
问题描述
我有一个每周期包含一个最大值和最小值的波形信号,需要在检测到波谷(最小值)时保存该最小峰值,检测到波峰(最大值)时保存该最大峰值,直到下一组峰谷出现。尝试了如下代码但未能成功:
#include <Wire.h> #include <DFRobot_MAX30102.h> DFRobot_MAX30102 particleSensor; int savedRed; bool increase; void setup() { Serial.begin(9600); // Initialize sensor if (particleSensor.begin() == false) { Serial.println("MAX30102 was not found. Please check wiring/power. "); while (1); } particleSensor.sensorConfiguration(0x1F,SAMPLEAVG_4,MODE_MULTILED,SAMPLERATE_400, PULSEWIDTH_411,ADCRANGE_4096); savedRed = particleSensor.getRed(); increase = true; } void loop() { int red = particleSensor.getRed(); red = particleSensor.getRed(); // 重复读取无意义 if (increasing) {} // 变量名错误(定义为increase)+ 多余大括号导致逻辑混乱 if (red < savedRed) { Serial.print(savedRed); increasing = false; } } else if if (red > savedRed) { // 语法错误:else if if 无效 Serial.print(savedRed); increasing = true; } savedRed = red; }
原代码存在以下问题:
- 变量名不一致:定义
increase但使用未声明的increasing - 语法错误:多余大括号、
else if if无效语法 - 逻辑缺陷:仅比较相邻两个采样值,易被传感器噪声干扰,无法准确识别真正的峰谷(短暂波动会被误判为趋势反转)
是否可以用等待局部最小值的状态机来实现?试过if/else循环,但要么无法清除上一个峰值直到出现更小的峰值,要么无法正确保存峰值。
解决方案:状态机实现峰谷检测
状态机非常适合这类需要跟踪状态切换的场景,我们可以定义两个核心状态,结合趋势判断和噪声过滤来准确识别峰谷:
核心思路
- 定义状态:
STATE_WAIT_TROUGH:跟踪下降趋势,寻找波谷(最小值)STATE_WAIT_PEAK:跟踪上升趋势,寻找波峰(最大值)
- 趋势判断:通过连续多个采样点的变化确认趋势,避免单帧噪声干扰
- 峰谷确认:当趋势发生反转且持续达到阈值时,确认峰谷并保存值,切换状态
完整实现代码
#include <Wire.h> #include <DFRobot_MAX30102.h> DFRobot_MAX30102 particleSensor; // 状态枚举定义 typedef enum { STATE_WAIT_TROUGH, // 等待波谷状态 STATE_WAIT_PEAK // 等待波峰状态 } PeakTroughState; PeakTroughState currentState = STATE_WAIT_TROUGH; int currentExtremeValue; // 当前跟踪的极值(波谷/波峰) int previousValue; // 上一次采样值 int trendCounter = 0; // 趋势持续计数器,过滤噪声 const int TREND_THRESHOLD = 3; // 连续N个点趋势一致才确认反转,可根据噪声调整 void setup() { Serial.begin(9600); // 初始化传感器 if (particleSensor.begin() == false) { Serial.println("MAX30102未找到,请检查接线/电源。"); while (1); } particleSensor.sensorConfiguration(0x1F, SAMPLEAVG_4, MODE_MULTILED, SAMPLERATE_400, PULSEWIDTH_411, ADCRANGE_4096); // 初始化采样基准值 previousValue = particleSensor.getRed(); currentExtremeValue = previousValue; } void loop() { int currentValue = particleSensor.getRed(); switch(currentState) { case STATE_WAIT_TROUGH: // 跟踪最小值,判断是否从下降转为上升 if (currentValue < currentExtremeValue) { currentExtremeValue = currentValue; // 更新当前最小值 trendCounter = 0; } else if (currentValue > previousValue) { trendCounter++; // 累计上升趋势计数 // 连续达到阈值,确认波谷 if (trendCounter >= TREND_THRESHOLD) { Serial.print("检测到波谷:"); Serial.println(currentExtremeValue); // 切换到寻找波峰状态 currentState = STATE_WAIT_PEAK; currentExtremeValue = currentValue; trendCounter = 0; } } else { trendCounter = 0; // 趋势未变,重置计数器 } break; case STATE_WAIT_PEAK: // 跟踪最大值,判断是否从上升转为下降 if (currentValue > currentExtremeValue) { currentExtremeValue = currentValue; // 更新当前最大值 trendCounter = 0; } else if (currentValue < previousValue) { trendCounter++; // 累计下降趋势计数 // 连续达到阈值,确认波峰 if (trendCounter >= TREND_THRESHOLD) { Serial.print("检测到波峰:"); Serial.println(currentExtremeValue); // 切换到寻找波谷状态 currentState = STATE_WAIT_TROUGH; currentExtremeValue = currentValue; trendCounter = 0; } } else { trendCounter = 0; } break; } previousValue = currentValue; delay(1); // 可选:添加小延迟避免采样过密 }
代码说明
- 状态切换:通过
switch语句清晰区分波谷/波峰跟踪逻辑,避免if/else嵌套混乱 - 噪声过滤:
TREND_THRESHOLD可根据传感器噪声情况调整,噪声越大阈值可设越高 - 极值跟踪:每个状态下持续更新当前极值,确保捕获到真正的峰谷值
- 闭环检测:确认峰谷后自动切换状态,实现连续的周期峰谷检测
内容的提问来源于stack exchange,提问作者tenebris in kux
相关产品推荐
相关产品推荐

