feat:增加跌倒时间消抖

fix:修复误触发报警
This commit is contained in:
2026-08-14 16:25:04 +08:00
parent 577eafd0ee
commit 9a4b5cfbeb
+70 -32
View File
@@ -56,14 +56,18 @@ bool g_humiDismissed = false;
uint8_t g_tempAbnCnt = 0; uint8_t g_tempAbnCnt = 0;
uint8_t g_humiAbnCnt = 0; uint8_t g_humiAbnCnt = 0;
uint8_t g_radarTimeoutCnt = 0; uint8_t g_radarTimeoutCnt = 0;
uint8_t g_heartAbnCnt = 0; // 心率异常防抖 uint32_t g_heartAbnMs = 0; // 心率异常持续计时 (ms)
uint8_t g_breathAbnCnt = 0; // 呼吸异常防抖 uint32_t g_heartNormalMs = 0; // 心率正常持续计时 (ms)
uint32_t g_breathAbnMs = 0; // 呼吸异常持续计时 (ms)
uint32_t g_breathNormalMs = 0; // 呼吸正常持续计时 (ms)
uint32_t g_fallDetectMs = 0; // 跌倒检测计时 (ms) uint32_t g_fallDetectMs = 0; // 跌倒检测计时 (ms)
uint32_t g_fallClearMs = 0; // 跌倒清除计时 (ms) uint32_t g_fallClearMs = 0; // 跌倒清除计时 (ms)
bool g_fallDismissed = false; // 已手动解除, 不重复报警 bool g_fallDismissed = false; // 已手动解除, 不重复报警
#define ALARM_HYSTERESIS 3 // 连续3次确认才触发 #define ALARM_HYSTERESIS 3 // 连续3次确认才触发
#define FALL_DETECT_MS 2000 // 跌倒持续2秒才触发 (房顶安装, 过滤坐下) #define FALL_DETECT_MS 10000 // 跌倒持续10秒才触发 (房顶安装, 过滤坐下)
#define FALL_CLEAR_MS 5000 // 跌倒消失5秒后才清除 (防误消) #define FALL_CLEAR_MS 18000 // 跌倒消失18秒后才清除 (防误消)
#define VITAL_DETECT_MS 20000 // 心率/呼吸持续异常20秒才触发
#define VITAL_CLEAR_MS 15000 // 心率/呼吸持续正常15秒才恢复
// ============================================================ // ============================================================
// 时间同步 // 时间同步
@@ -115,8 +119,10 @@ void handleAlarmCommand(const AlarmCommand& cmd) {
g_tempAbnCnt = 0; g_tempAbnCnt = 0;
g_humiAbnCnt = 0; g_humiAbnCnt = 0;
g_radarTimeoutCnt = 0; g_radarTimeoutCnt = 0;
g_heartAbnCnt = 0; g_heartAbnMs = 0;
g_breathAbnCnt = 0; g_heartNormalMs = 0;
g_breathAbnMs = 0;
g_breathNormalMs = 0;
g_fallDetectMs = 0; g_fallDetectMs = 0;
g_fallClearMs = 0; g_fallClearMs = 0;
g_fallDismissed = false; g_fallDismissed = false;
@@ -335,55 +341,85 @@ void checkLocalAlarms(const RadarRawData& radar) {
g_fallClearMs = 0; // 仍在跌倒, 重置消失计时 g_fallClearMs = 0; // 仍在跌倒, 重置消失计时
} }
// ─── ★★★★★ 人身安全: 心率异常 (仅卧室+ABD1, 防抖3次, 30s) ─── // ─── ★★★★★ 人身安全: 心率异常 (仅卧室+ABD1, 持续异常20s触发/正常15s恢复, 30s) ───
#if RADAR_TYPE != RADAR_TYPE_AFD1 #if RADAR_TYPE != RADAR_TYPE_AFD1
if (enVital && millis() > 30000 && humanPresent && radar.vitalValid && radar.heartRate > 0) { if (enVital && millis() > 30000 && humanPresent && radar.vitalValid && radar.heartRate > 0) {
bool heartAbn = (radar.heartRate < HEART_RATE_MIN || radar.heartRate > HEART_RATE_MAX); bool heartAbn = (radar.heartRate < HEART_RATE_MIN || radar.heartRate > HEART_RATE_MAX);
if (heartAbn) { if (heartAbn) {
if (!g_heartDismissed && ++g_heartAbnCnt >= ALARM_HYSTERESIS && !g_localHeartAbnActive) { // 持续异常: 累积时长, 满 VITAL_DETECT_MS 触发
g_localHeartAbnActive = true; if (!g_heartDismissed && !g_localHeartAbnActive) {
char buf[32]; if (g_heartAbnMs == 0) {
snprintf(buf, sizeof(buf), "心率异常: %d bpm", radar.heartRate); g_heartAbnMs = millis();
g_alarm.triggerLocal(AlarmManager::ALARM_HEART_ABNORMAL, buf); } else if (millis() - g_heartAbnMs >= VITAL_DETECT_MS) {
g_localHeartAbnActive = true;
char buf[32];
snprintf(buf, sizeof(buf), "心率异常: %d bpm", radar.heartRate);
g_alarm.triggerLocal(AlarmManager::ALARM_HEART_ABNORMAL, buf);
}
} }
g_heartNormalMs = 0; // 仍异常, 重置正常计时
} else { } else {
g_heartAbnCnt = 0; // 持续正常: 累积时长, 满 VITAL_CLEAR_MS 清除 + 重新武装
g_heartDismissed = false; g_heartAbnMs = 0; // 正常了, 重置异常计时
if (g_localHeartAbnActive) { if (g_heartNormalMs == 0) {
g_localHeartAbnActive = false; g_heartNormalMs = millis();
g_alarm.clearLocal(AlarmManager::ALARM_HEART_ABNORMAL); }
if (millis() - g_heartNormalMs >= VITAL_CLEAR_MS) {
if (g_localHeartAbnActive) {
g_localHeartAbnActive = false;
g_alarm.clearLocal(AlarmManager::ALARM_HEART_ABNORMAL);
}
if (g_heartDismissed) {
g_heartDismissed = false; // 持续正常后重新武装
}
} }
} }
} else if (!humanPresent && g_localHeartAbnActive) { } else if (!humanPresent && g_localHeartAbnActive) {
g_localHeartAbnActive = false; g_localHeartAbnActive = false;
g_heartAbnCnt = 0; g_heartAbnMs = 0;
g_heartNormalMs = 0;
g_heartDismissed = false; g_heartDismissed = false;
g_alarm.clearLocal(AlarmManager::ALARM_HEART_ABNORMAL); g_alarm.clearLocal(AlarmManager::ALARM_HEART_ABNORMAL);
} }
#endif // RADAR_TYPE != AFD1 #endif // RADAR_TYPE != AFD1
// ─── ★★★★★ 人身安全: 呼吸异常 (仅卧室+ABD1, 防抖3次, 30秒后生效) ─── // ─── ★★★★★ 人身安全: 呼吸异常 (仅卧室+ABD1, 持续异常20s触发/正常15s恢复, 30秒后生效) ───
#if RADAR_TYPE != RADAR_TYPE_AFD1 #if RADAR_TYPE != RADAR_TYPE_AFD1
if (enVital && millis() > 30000 && humanPresent && radar.vitalValid && radar.breathRate > 0) { if (enVital && millis() > 30000 && humanPresent && radar.vitalValid && radar.breathRate > 0) {
bool breathAbn = (radar.breathRate < BREATH_RATE_MIN || radar.breathRate > BREATH_RATE_MAX); bool breathAbn = (radar.breathRate < BREATH_RATE_MIN || radar.breathRate > BREATH_RATE_MAX);
if (breathAbn) { if (breathAbn) {
if (!g_breathDismissed && ++g_breathAbnCnt >= ALARM_HYSTERESIS && !g_localBreathAbnActive) { // 持续异常: 累积时长, 满 VITAL_DETECT_MS 触发
g_localBreathAbnActive = true; if (!g_breathDismissed && !g_localBreathAbnActive) {
char buf[32]; if (g_breathAbnMs == 0) {
snprintf(buf, sizeof(buf), "呼吸异常: %d 次/分", radar.breathRate); g_breathAbnMs = millis();
g_alarm.triggerLocal(AlarmManager::ALARM_BREATH_ABNORMAL, buf); } else if (millis() - g_breathAbnMs >= VITAL_DETECT_MS) {
g_localBreathAbnActive = true;
char buf[32];
snprintf(buf, sizeof(buf), "呼吸异常: %d 次/分", radar.breathRate);
g_alarm.triggerLocal(AlarmManager::ALARM_BREATH_ABNORMAL, buf);
}
} }
g_breathNormalMs = 0; // 仍异常, 重置正常计时
} else { } else {
g_breathAbnCnt = 0; // 持续正常: 累积时长, 满 VITAL_CLEAR_MS 清除 + 重新武装
g_breathDismissed = false; g_breathAbnMs = 0; // 正常了, 重置异常计时
if (g_localBreathAbnActive) { if (g_breathNormalMs == 0) {
g_localBreathAbnActive = false; g_breathNormalMs = millis();
g_alarm.clearLocal(AlarmManager::ALARM_BREATH_ABNORMAL); }
if (millis() - g_breathNormalMs >= VITAL_CLEAR_MS) {
if (g_localBreathAbnActive) {
g_localBreathAbnActive = false;
g_alarm.clearLocal(AlarmManager::ALARM_BREATH_ABNORMAL);
}
if (g_breathDismissed) {
g_breathDismissed = false; // 持续正常后重新武装
}
} }
} }
} else if (!humanPresent && g_localBreathAbnActive) { } else if (!humanPresent && g_localBreathAbnActive) {
g_localBreathAbnActive = false; g_localBreathAbnActive = false;
g_breathAbnCnt = 0; g_breathAbnMs = 0;
g_breathNormalMs = 0;
g_breathDismissed = false; g_breathDismissed = false;
g_alarm.clearLocal(AlarmManager::ALARM_BREATH_ABNORMAL); g_alarm.clearLocal(AlarmManager::ALARM_BREATH_ABNORMAL);
} }
@@ -551,8 +587,10 @@ void setup() {
g_localDhtFaultActive = false; g_localDhtFaultActive = false;
g_tempAbnCnt = 0; g_tempAbnCnt = 0;
g_humiAbnCnt = 0; g_humiAbnCnt = 0;
g_heartAbnCnt = 0; g_heartAbnMs = 0;
g_breathAbnCnt = 0; g_heartNormalMs = 0;
g_breathAbnMs = 0;
g_breathNormalMs = 0;
g_radarTimeoutCnt = 0; g_radarTimeoutCnt = 0;
g_fallClearMs = 0; g_fallClearMs = 0;
g_fallDismissed = true; // 抑制重复报警, 等跌倒信号消了再恢复 g_fallDismissed = true; // 抑制重复报警, 等跌倒信号消了再恢复