#include "mix_cc/ihyper_db.h" #include #include #include #include #include #include #include #include #include #include // 炉辊组算法无需额外的算法初始化步骤 int Roller3::init() { int res = 0; try { res += AlgBase::init(); this->con_monitor_.setThreshold(100); logger_->Debug() << "离群群方式[-2:%;-3:实际值]:" << exp_type_ << std::endl; logger_->Debug() << "res:" << res << std::endl; if (res != 0) { this->exp_is_wrong_ = true; return -1; } if (rule_json_.at("output").contains("error")) { try { error_str_ = rule_json_.at("output").at("error").at("value").get(); } catch (const std::exception &e) { logger_->Error() << "output,error出错:" << e.what() << ",location:" << BOOST_CURRENT_LOCATION << endl; error_message_str_ += "报警内容格式异常!"; return -1; } } res += this->reload_config_data_source(); /*3.数据源*/ res += this->first_fill_mm_vars(); /*4.数据项*/ res += init_X_exp(); rule_stat_.unit = unit_; print_load_content(); for (auto tagid : tag_seq_) { state_info_map_[tagid] = HoldState::StateInfo(); } } catch (const std::exception &e) { std::throw_with_nested( mix_cc::Exception(-1, "load error", BOOST_CURRENT_LOCATION)); } if (res == 0) { this->exp_is_wrong_ = false; } return res; } Roller3::Roller3(const string &name, const mix_cc::json &rule_json, const string &ruleId, size_t exp_type) : ExpBase(name, rule_json, ruleId, exp_type) { logger_.reset( new LOG("Roller3_" + std::to_string(exp_type) + ":" + rule_name_, AUTO_CATCH_PID)); } Roller3::~Roller3() { // AlgBase::~AlgBase(); } AlarmInfo Roller3::mon_proc() { if ((bool)exp_act_->evaluate() == false) { logger_->Debug() << "前提条件不满足!" << std::endl; return AlarmInfo{}; } /*最新数据*/ for (int i = 0; i < value_num_; i++) { values_[i] = std::fabs(mm_vars["tag" + std::to_string(tag_seq_[i])]); if (values_[i] == 0) { is_zero_list_[i] = 1; } else { is_zero_list_[i] = 0; } } /*中位数*/ median_ = calculateMedian(values_); /*允许偏差*/ double deviationMax = std::fabs(median_ * limit_error_ * 0.01); double deviationWarn = std::fabs(median_ * limit_warn_ * 0.01); if (exp_type_ == ExpType::OuterAct) { deviationMax = limit_error_; deviationWarn = limit_warn_; } /*数据偏差*/ for (int j = 0; j < value_num_; j++) { deviations_[j] = std::fabs(values_[j] - median_); if (is_zero_list_[j] == 1) { deviations_[j] = 0; } } /*找最大偏差*/ auto maxIndexValue = findMaxWithIndex(deviations_); limit_down_ = median_ - deviationWarn; limit_up_ = median_ + deviationWarn; rule_stat_.limit_down = get_up_down(limit_down_, 0); rule_stat_.limit_up = get_up_down(limit_up_, 1); // rule_stat_.current_value = // mm_vars["tag" + std::to_string(maxIndexValue.first + 1)]; rule_stat_.current_value = std::fabs(mm_vars["tag" + std::to_string(maxIndexValue.first + 1)]); /*无持续时间要求*/ if (hold_time_ <= this->delay_time_) { /*报警检查*/ if (ExpBase::detect_up_down(rule_stat_.current_value)) { std::string msg = ""; msg = error_str_ + "," + SingletonTemplate::GetInstance()( m_tags[maxIndexValue.first]) + ":" + DAA::double2str( std::fabs( mm_vars["tag" + std::to_string(maxIndexValue.first + 1)]), 3) + unit_ + ",合理区间:[" + DAA::double2strLimit(rule_stat_.limit_down, 3) + "," + DAA::double2strLimit(rule_stat_.limit_up, 3) + "]" + unit_; auto alarm_time = get_alarm_time(); print_exp_vars(); logger_->Debug() << " median_:" << median_ << ",maxIndexValue:[" << maxIndexValue.first << "," << maxIndexValue.second << "]," << msg << endl; if (maxIndexValue.second > deviationMax) { return utility::build_alarm_info("ERROR", rule_id_, rule_name_, "EXP16", msg, alarm_time); } return utility::build_alarm_info("WARN", rule_id_, rule_name_, "EXP16", msg, alarm_time); } } else { std::string msg = ""; msg = error_str_; HoldState::AlarmType alarm_type = HoldState::AlarmType::Warn; /*持续时间检测*/ for (int i = 0; i < value_num_; i++) { int tagid = tag_seq_[i]; double n_value = values_[i]; HoldState::AlarmState up_down = Roller3::detect_up_down(n_value); HoldState::StateInfo &n_state_info = state_info_map_[tagid]; std::string tag_name; int idx = tag_seq_[i] - 1; if (idx >= 0 && idx < m_tags.size()) { tag_name = SingletonTemplate::GetInstance()(m_tags[idx]); } HoldState::AlarmType n_alarm_type = deviations_[i] > deviationMax ? HoldState::AlarmType::Error : HoldState::AlarmType::Warn; if (is_zero_list_[i] != 1 && up_down != HoldState::AlarmState::None) { if (up_down == n_state_info.last_alarm_tate) { n_state_info.alarm_type = n_alarm_type == HoldState::AlarmType::Warn ? n_alarm_type : n_state_info.alarm_type; if ((now_time_ - n_state_info.last_start_time) > hold_time_) { /*报警*/ msg = msg + "," + tag_name + ":" + DAA::double2str(std::fabs(n_value), 3) + unit_; alarm_type = n_state_info.alarm_type; n_state_info.last_start_time = now_time_; n_state_info.alarm_type = HoldState::AlarmType::Error; } } else { n_state_info.last_start_time = now_time_; } } n_state_info.last_alarm_tate = up_down; } if (!msg.empty()) { auto alarm_time = get_alarm_time(); print_exp_vars(); logger_->Debug() << " median_:" << median_ << ",maxIndexValue:[" << maxIndexValue.first << "," << maxIndexValue.second << "]," << msg << endl; if (alarm_type == HoldState::AlarmType::Error) { return utility::build_alarm_info("ERROR", rule_id_, rule_name_, "EXP16", msg, alarm_time); } return utility::build_alarm_info("WARN", rule_id_, rule_name_, "EXP16", msg, alarm_time); } } return AlarmInfo{}; } std::vector Roller3::exec_task(mix_cc::time_range_t time_range) { std::vector result; for (auto now_time = time_range.get_left(); now_time <= time_range.get_right(); now_time += delay_time_) { this->now_time_ = now_time; auto rr1 = this->exec_mon(); result.push_back(rr1); } return result; } void Roller3::print_load_content() { logger_->Debug() << "limit_error_:" << limit_error_ << ",exp_str_:" << exp_str_ << ",tags_exp_:" << tags_exp_ << std::endl; logger_->Debug() << "limit_error_:" << limit_error_ << ",limit_warn_:" << limit_warn_ << ",单位unit_:" << unit_ << ",detect_mode_:" << detect_mode_ << ",hold_time:" << hold_time_.count() << "ms" << std::endl; } int Roller3::init_X_exp() { int res = 0; if (rule_json_.at("function").contains("pre_exp")) { string tmp_exp = rule_json_.at("function").at("pre_exp").at("value").get(); exp_str_ = get_macro_replaced_exp(tmp_exp); res += init_hold_exp_str(exp_str_); auto fun_res = fun_vars_.add_exp_str(exp_str_, &mm_vars); res += fun_res.first ? 0 : -1; exp_str_ = fun_res.second; feedback_mode_ = false; auto messy_code = exp_messy_code_check(exp_str_); if (messy_code == -1) { this->error_code_list_.push_back( {ErrorType::EnCodeError, ErrorLocation::ActExp}); res += messy_code; } } if (rule_json_.at("function").contains("input")) { tags_exp_ = rule_json_.at("function").at("input").at("value").get(); auto tag_seq = extractTagNumbers(tags_exp_); if (tag_seq.empty()) { return -1; } std::sort(tag_seq.begin(), tag_seq.end()); tag_seq_ = tag_seq; if (rule_json_.at("function") .at("input") .at("param") .contains("limit_error")) { limit_error_ = std::stod(rule_json_.at("function") .at("input") .at("param") .at("limit_error") .at("value") .get()); } if (rule_json_.at("function") .at("input") .at("param") .contains("limit_warn")) { limit_warn_ = std::stod(rule_json_.at("function") .at("input") .at("param") .at("limit_warn") .at("value") .get()); } if (rule_json_.at("function").at("input").at("param").contains("unit")) { unit_ = rule_json_.at("function") .at("input") .at("param") .at("unit") .at("value") .get(); } if (rule_json_.at("function") .at("input") .at("param") .contains("detect_mode")) { detect_mode_ = std::stoi(rule_json_.at("function") .at("input") .at("param") .at("detect_mode") .at("value") .get()); } if (rule_json_.at("function") .at("input") .at("param") .contains("hold_time")) { hold_time_ = milliseconds(std::stoi(rule_json_.at("function") .at("input") .at("param") .at("hold_time") .at("value") .get())); } } value_num_ = tag_seq_.size(); if (exp_act_ == nullptr && exp_str_ != "") { try { exp_act_ = std::make_unique(exp_str_, &mm_vars); logger_->Debug() << "exp_act:" << exp_str_ << "=" << exp_act_->evaluate() << endl; } catch (const std::exception &e) { logger_->Error() << "exp_act:" << exp_str_ << "计算出错:" << e.what() << ",location:" << BOOST_CURRENT_LOCATION << endl; this->error_code_list_.push_back( {ErrorType::CalError, ErrorLocation::ActExp}); return -1; } } if (exp_result_ == nullptr && tags_exp_ != "") { try { exp_result_ = std::make_unique(tags_exp_, &mm_vars); logger_->Debug() << "tags_exp_:" << tags_exp_ << "=" << exp_result_->evaluate() << endl; } catch (const std::exception &e) { logger_->Error() << "tags_exp_:" << tags_exp_ << "计算出错:" << e.what() << ",location:" << BOOST_CURRENT_LOCATION << endl; this->error_code_list_.push_back( {ErrorType::CalError, ErrorLocation::ActExp}); return -1; } } deviations_.resize(value_num_, 0); values_.resize(value_num_, 0); is_zero_list_.resize(value_num_, 0); return res; } vector Roller3::extractTagNumbers(const string &expr) { vector result; const string tagPrefix = "tag"; // 定义要查找的前缀 size_t pos = 0; // 当前查找位置 while (pos < expr.size()) { // 查找下一个 "tag" 的出现位置 size_t found = expr.find(tagPrefix, pos); if (found == string::npos) { break; // 没有更多 "tag",退出循环 } // 计算数字部分的起始位置(在 "tag" 之后) size_t numStart = found + tagPrefix.size(); size_t numEnd = numStart; // 提取连续的数字字符序列(直到遇到非数字字符,如 '+' 或字符串结尾) while (numEnd < expr.size() && isdigit(expr[numEnd])) { numEnd++; } // 如果存在数字序列,则转换为整数并添加到结果中 if (numEnd > numStart) { string numStr = expr.substr(numStart, numEnd - numStart); try { int num = stoi(numStr); // 将字符串转换为整数[7](@ref) result.push_back(num); } catch (const invalid_argument &e) { // 处理无效数字字符串(例如非数字内容),根据需求可忽略或记录错误 // 这里选择跳过无效转换,继续处理后续部分 } catch (const out_of_range &e) { // 处理数字超出 int 范围的情况,同样跳过 } } // 更新查找位置到当前数字序列的末尾,继续搜索 pos = numEnd; } return result; } double Roller3::calculateMedian( std::vector data) { // 传值以创建副本,不改变原向量 if (data.empty()) return 0.0; size_t size = data.size(); std::sort(data.begin(), data.end()); // 排序 if (size % 2 == 0) { // 偶数个元素,取中间两个数的平均值 return (data[size / 2 - 1] + data[size / 2]) / 2.0; } else { // 奇数个元素,取中间的数 return data[size / 2]; } } // 函数返回一个pair,first是下标,second是最大值 std::pair Roller3::findMaxWithIndex(const std::vector &vec) { // 检查vector是否为空 if (vec.empty()) { return std::make_pair(-1, 0.0); // 返回无效值 } // 使用max_element找到最大元素的迭代器[1,2,5](@ref) auto max_iter = std::max_element(vec.begin(), vec.end()); // 计算下标序号[1,6,8](@ref) int index = std::distance(vec.begin(), max_iter); // 获取最大值 double max_value = *max_iter; return std::make_pair(index, max_value); } double Roller3::get_up_down(const double &value, bool is_up) { switch (this->detect_mode_) { case DetectMode::Default: return value; break; case DetectMode::OnlyLeft: return is_up ? 32767 : value; break; case DetectMode::OnlyRight: return is_up ? value : -32768; break; default: return value; break; } return value; } HoldState::AlarmState Roller3::detect_up_down(const double &value) { switch (this->detect_mode_) { case DetectMode::Default: { if (value < this->limit_down_) { return HoldState::AlarmState::DownLower; } else if (value > limit_up_) { return HoldState::AlarmState::UpHigher; } else { return HoldState::AlarmState::None; } } break; case DetectMode::OnlyLeft: return value < limit_down_ ? HoldState::AlarmState::DownLower : HoldState::AlarmState::None; break; case DetectMode::OnlyRight: return value > limit_up_ ? HoldState::AlarmState::UpHigher : HoldState::AlarmState::None; break; default: return HoldState::AlarmState::None; break; } return HoldState::AlarmState::None; }