/***************************************************************************** * @copyright 2024-202, . POWER SUPPLY CO., LTD. * @file logic_demandctrl.c * @brief xxxx * @author Gary * @date 2024/09/27 * @remark 初修订 *****************************************************************************/ #include "logic_comm.h" // static sliding_window_t g_window; //滑差结构体 void initSlidingWindow(sliding_window_t *window) { window->pccCount = 0; window->pccIndex = 0; window->pccSum = 0; window->loadCount = 0; window->loadIndex = 0; window->loadSum = 0; window->foreCount = 0; window->foreIndex = 0; } int updateSlidingWindow(sliding_window_t *window, double_t pcc, double_t load) { // 如果窗口尚未填满,直接添加数据并更新总和 if (window->pccCount < 450) { window->pccDemand[window->pccCount] = pcc; window->pccSum += pcc; window->pccCount++; window->loadDemand[window->loadCount] = load; window->loadSum += load; window->loadCount++; return 0; } else { // 如果窗口已经填满,移除最早的数据并添加新数据 window->pccSum -= window->pccDemand[window->pccIndex]; window->pccDemand[window->pccIndex] = pcc; window->pccSum += pcc; window->pccIndex = (window->pccIndex + 1) % 450; // 更新索引 window->loadSum -= window->loadDemand[window->loadIndex]; window->loadDemand[window->loadIndex] = load; window->loadSum += load; window->loadIndex = (window->loadIndex + 1) % 450; // 更新索引 return 1; } } int UpdateForeDemand(sliding_window_t *window, double_t fore) { // 如果窗口尚未填满,直接添加数据并更新总和 if (window->foreCount < 15) { window->foreDemand[window->foreCount] = fore; window->foreCount++; return 0; } else { // 如果窗口已经填满,移除最早的数据并添加新数据 window->foreDemand[window->foreIndex] = fore; window->foreIndex = (window->foreIndex + 1) % 15; // 更新索引 return 1; } } // 拟合二次方程 double_t fitQuadraticEquation(double_t *loadDemand) { // 拟合二次方程:y = ax^2 + bx + c double sum_x = 0, sum_x2 = 0, sum_x3 = 0, sum_x4 = 0; double sum_y = 0, sum_xy = 0, sum_x2y = 0; for (int i = 0; i < 15; ++i) { double x = i + 1; // 每分钟对应的时间 double y = loadDemand[i]; // 对应的数据点 sum_x += x; sum_x2 += x * x; sum_x3 += x * x * x; sum_x4 += x * x * x * x; sum_y += y; sum_xy += x * y; sum_x2y += x * x * y; } // 计算二次方程系数 double a = (sum_x2y * sum_x2 - sum_xy * sum_x3) / (sum_x2 * sum_x4 - sum_x3 * sum_x3); double b = (sum_xy - a * sum_x3) / sum_x2; double c = (sum_y - a * sum_x4 - b * sum_x3) / sum_x2; printf("拟合的二次方程为: y = %.2fx^2 + %.2fx + %.2f\n", a, b, c); return a * 15 * 15 + b * 15 + c; } /***************************************************************************** * @brief 获取实际需量 但是不能超过变压器器容量 * @param[in] float_t aimDemand 目标需量 float_t nowDemand 实时电表需量 * float_t maxActivePower 变压器容量 * @return float_t 实际需量 *****************************************************************************/ float_t getActiveDemand(float_t aimDemand, float_t nowDemand, float_t maxActivePower) { return float_min(float_max(aimDemand, nowDemand), maxActivePower); } /***************************************************************************** * @brief 需量超阈值防护判断及处理 * @param[in] protect_demand_t demandParams 运行参数 * @return 参数指针返回 *****************************************************************************/ void logic_protect_demandCtrl(protect_params_t *charge_params) { float_t demand = getActiveDemand(charge_params->aimActiveDemand, charge_params->nowActiveDemand, charge_params->maxActivePower); float_t tmp_active_demand = demand - charge_params->demandCtrlCloseLimt; // 预留 if (tmp_active_demand >= charge_params->totalActivePower) // 关机判断 { float_t load_active_power = charge_params->totalActivePower - charge_params->emsActivePower; // 算出负载功率 tmp_active_demand = demand - charge_params->demandCtrlLowLimt; // 限流值 if (tmp_active_demand >= charge_params->totalActivePower) // 限流判断 { float_t tmp_power = tmp_active_demand - load_active_power - charge_params->demandCtrlLowLimt / 10; if (tmp_power > 0) { charge_params->power = -float_min(abs(charge_params->power), tmp_power); } else { charge_params->power = 0; } if ((uint8_t)getRtdbPointValue(rtdbType, kDev_Type_EMS, 0, kEms_LogicLog_Enable) == 1) { KITLOG(LOG_MODBUS_EN, INFO_EN, "触发需量保护!!! 并网点功率:%.2f kw 目标需量:%.2f kw 实时需量:%.2f kw 新的目标功率:%.2f kw", charge_params->totalActivePower, charge_params->aimActiveDemand, charge_params->nowActiveDemand, charge_params->power); KITLOG(LOG_MODBUS_EN, INFO_EN, "触发需量保护!!! 并网点功率:%.2f kw 目标需量:%.2f kw 实时需量:%.2f kw 新的目标功率:%.2f kw", charge_params->totalActivePower, charge_params->aimActiveDemand, charge_params->nowActiveDemand, charge_params->power); } } else { float_t tmp_power = tmp_active_demand - load_active_power - charge_params->demandCtrlLowLimt / 2; if (tmp_power > 0) { charge_params->power = -float_min(abs(charge_params->power), tmp_power); } else { charge_params->power = 0; } } } else { charge_params->power = 0; if ((uint8_t)getRtdbPointValue(rtdbType, kDev_Type_EMS, 0, kEms_LogicLog_Enable) == 1) { KITLOG(LOG_MODBUS_EN, INFO_EN, "触发需量关机!!! 并网点功率:%.2f kw 目标需量:%.2f kw 实时需量:%.2f kw 新的目标功率:%.2f kw", charge_params->totalActivePower, charge_params->aimActiveDemand, charge_params->nowActiveDemand, charge_params->power); KITLOG(LOG_MODBUS_EN, INFO_EN, "触发需量关机!!! 并网点功率:%.2f kw 目标需量:%.2f kw 实时需量:%.2f kw 新的目标功率:%.2f kw", charge_params->totalActivePower, charge_params->aimActiveDemand, charge_params->nowActiveDemand, charge_params->power); } } }