eis/eqpalg/utility/fb_state_machine.cpp

227 lines
6.1 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// eqpalg/utility/fb_state_machine.cpp
#include <eqpalg/utility/fb_state_machine.h>
#include <cmath>
#include <cfloat>
#include <string>
// ========== 配置 ==========
void FbStateMachine::configure(bool keepMode, TimeDur timeout) {
keep_mode_ = keepMode;
timeout_ = timeout;
state_ = FbState::Idle;
}
// ========== 每周期状态更新 ==========
FbUpdateResult FbStateMachine::update(bool actTriggered, TimePoint now,
std::map<std::string, double>& mm_vars,
size_t tag_count) {
FbUpdateResult result;
result.funVarsNeedReset = false;
switch (state_) {
case FbState::Idle:
if (actTriggered) {
// → Started快照变量
snapshotActionStart(now, mm_vars, tag_count);
state_ = FbState::Started;
start_time_ = now;
result.state = FbState::Started;
} else {
result.state = FbState::Idle;
result.funVarsNeedReset = true; // 空闲时重置 fun_vars
}
break;
case FbState::Started:
// 更新累积变量(首周期也需要更新)
updateActionVars(now, mm_vars, tag_count);
if (!actTriggered && keep_mode_) {
state_ = FbState::Idle;
result.state = FbState::NotHold;
result.funVarsNeedReset = true;
} else if (isAccumulatorNearOverflow(mm_vars, tag_count)) {
state_ = FbState::Idle;
result.state = FbState::Timeout;
result.funVarsNeedReset = true;
} else {
state_ = FbState::InProgress;
result.state = FbState::Started; // 返回 Started调用方跳过反馈检查
}
break;
case FbState::InProgress:
// 先更新累积变量
updateActionVars(now, mm_vars, tag_count);
if (!actTriggered && keep_mode_) {
state_ = FbState::Idle;
result.state = FbState::NotHold;
result.funVarsNeedReset = true;
} else if (isAccumulatorNearOverflow(mm_vars, tag_count)) {
clearActionAccumulators(mm_vars, tag_count);
state_ = FbState::Idle;
result.state = FbState::Timeout;
result.funVarsNeedReset = true;
} else if (timeout_ != TimeDur(-32768) &&
(now - start_time_) > timeout_) {
clearActionAccumulators(mm_vars, tag_count);
state_ = FbState::Idle;
result.state = FbState::Timeout;
result.funVarsNeedReset = true;
} else {
result.state = FbState::InProgress;
}
break;
// 终端状态 → 下周期自动回 Idle
default:
state_ = FbState::Idle;
result.state = FbState::Idle;
result.funVarsNeedReset = true;
break;
}
return result;
}
// ========== 反馈条件检查 ==========
bool FbStateMachine::checkFeedback(bool fbCondition, TimePoint now,
std::map<std::string, double>& mm_vars) {
if (state_ != FbState::InProgress) {
return false;
}
if (fbCondition) {
recordActionEnd(now, mm_vars);
state_ = FbState::Idle; // 下周期回到 Idle
return true;
}
return false;
}
// ========== 查询 ==========
bool FbStateMachine::isActive() const {
return state_ == FbState::Started || state_ == FbState::InProgress;
}
// ========== 强制重置 ==========
void FbStateMachine::forceReset() {
state_ = FbState::Idle;
start_time_ = TimePoint{};
}
// ========== 内部变量操作 ==========
void FbStateMachine::snapshotActionStart(
TimePoint now,
std::map<std::string, double>& mm_vars,
size_t tag_count) {
mm_vars["stime"] = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch())
.count();
mm_vars["time"] = 0;
for (size_t i = 0; i < tag_count; i++) {
std::string idx = std::to_string(i + 1);
double tag_val = mm_vars["tag" + idx];
double p_val = mm_vars["p" + idx];
// s[n] = tag[n] 在动作开始时刻的快照值
mm_vars["s" + idx] = tag_val;
// 极值初始化为当前值
mm_vars["mx_tag" + idx] = tag_val;
mm_vars["mi_tag" + idx] = tag_val;
// 累积器初始化为 0
mm_vars["mv2_tag" + idx] = 0;
mm_vars["mv2_p" + idx] = 0;
// 上升沿/下降沿初值
mm_vars["up_tag" + idx] = (p_val == 0 && tag_val == 1) ? 1.0 : 0.0;
mm_vars["dw_tag" + idx] = (p_val == 1 && tag_val == 0) ? 1.0 : 0.0;
// 若当前已为 1初始计数为 1
if (tag_val == 1) {
mm_vars["mv2_tag" + idx] = 1;
}
if (p_val == 1) {
mm_vars["mv2_p" + idx] = 1;
}
}
}
void FbStateMachine::updateActionVars(
TimePoint now,
std::map<std::string, double>& mm_vars,
size_t tag_count) {
mm_vars["time"] = mm_vars["now"] - mm_vars["stime"];
for (size_t i = 0; i < tag_count; i++) {
std::string idx = std::to_string(i + 1);
double tag_val = mm_vars["tag" + idx];
double p_val = mm_vars["p" + idx];
// 更新极值
mm_vars["mx_tag" + idx] = std::max(tag_val, mm_vars["mx_tag" + idx]);
mm_vars["mi_tag" + idx] = std::min(tag_val, mm_vars["mi_tag" + idx]);
// 累积 1 的计数
if (tag_val == 1) {
mm_vars["mv2_tag" + idx] += 1;
}
if (p_val == 1) {
mm_vars["mv2_p" + idx] += 1;
}
// 上升沿/下降沿计数
mm_vars["up_tag" + idx] += (p_val == 0 && tag_val == 1) ? 1.0 : 0.0;
mm_vars["dw_tag" + idx] += (p_val == 1 && tag_val == 0) ? 1.0 : 0.0;
}
}
void FbStateMachine::recordActionEnd(
TimePoint now,
std::map<std::string, double>& mm_vars) {
mm_vars["etime"] = mm_vars["now"];
}
void FbStateMachine::clearActionAccumulators(
std::map<std::string, double>& mm_vars,
size_t tag_count) {
for (size_t i = 0; i < tag_count; i++) {
std::string idx = std::to_string(i + 1);
mm_vars["mv2_tag" + idx] = 0;
mm_vars["mv2_p" + idx] = 0;
mm_vars["up_tag" + idx] = 0;
mm_vars["dw_tag" + idx] = 0;
}
}
bool FbStateMachine::isAccumulatorNearOverflow(
const std::map<std::string, double>& mm_vars,
size_t tag_count) const {
for (size_t i = 0; i < tag_count; i++) {
std::string key = "mv2_tag" + std::to_string(i + 1);
auto it = mm_vars.find(key);
if (it != mm_vars.end()) {
if (std::abs(it->second - DBL_MAX) < 2.0) {
return true;
}
}
}
return false;
}