ac_control.c
源文件路径:
logic/ac_control.c所属模块:logic(能量调度核心) 代码行数:1954
1. 文件职责
本文件实现 EMS 的 AC 侧(并网机 / 交流耦合机)功率调度计算:把「运行模式 + 当前 PV / 电池 / 电表 / 逆变侧实时功率」换算成逆变器有功设定值、电池充放电限值和强充使能标志,写入全局结构 g_t_logic_info。它处在数据流的计算末端:上游是 logic/logic.c 的 task_system_logic_control 任务(经 logic_charge_dischg_power_limit() / self_use_funtion() / bat_force_charge() / time_peakshaving_command() 等中间层函数驱动),下游是 midware/inverter/parallel.c(通过 logic_read_ac_total_set_inv_power() 等访问器取走结果,经并机 SCI 下发给从机)和 logic/dispatch.c(Sunspec / 南澳调度路径)。文件内部分为四条相互独立的计算链:AC 总功率控制、AC 三相不平衡控制、削峰填谷、Sunspec 有功控制。全文件被 #ifndef INV_AC_CTRL 之外的整体 #ifdef INV_AC_CTRL(第 21 行 ~ 1951 行)包裹。
2. 关键数据结构与宏
| 名称 | 类型 | 说明 |
|---|---|---|
AC_FORCE_CHG_INV_FLOOR_MARGIN | 宏(= 50) | 强充状态下 AC 有功设定的最低保障余量(W),见 ac_control.c:19、ac_control.c:513 |
INV_AC_CTRL | 条件编译宏 | 来自 midware/inverter/inverter.h,未定义时整个文件除 include 外全部不参与编译 |
SELFUSE_AC_CONTORL_STATE | 枚举 | 总功率控制状态机状态集,详见 ac_control.h 文档;本文件用它做 switch 分派 |
THREE_PHASE_UNBALANCE_AC_CONTORL_STATE | 枚举 | 三相不平衡状态集(总状态 0~5 与单相状态 6~9 混编) |
PEAKSHVING_STATE_E | 枚举(定义于 logic/logic.h:99) | 削峰填谷状态:INITIAL_IDLE=0、NO_INVERTER_POWER_STATE、POWER_REGULATION_STATE |
LOGIC_TABLE_T | 结构体(logic/logic.h:494) | 全局 g_t_logic_info 的类型,本文件所有读写均落在它的 s32_ac_total_set_*、s32_ac_three_phase_set_*、t_logic_control_parameter、t_config_data 字段上 |
LOGIC_CONTROL_PARAMETER_T | 结构体(logic/logic.h:138,#pragma pack(1)) | 逆变器特性 / 规格 / 运行信息 / 调节参数集合,AC 计算的全部输入源;本文件大量读它的 s32_pgrid_metert/a/b/c、s32_pinvt/a/b/c、s32_pbat_inv、s16_ibat_inv、u8_pv_status、u8_bat_status、u8_regulator_speed 等 |
LOGIC_CONFIG_TAB_T | 结构体(logic/logic.h,经 g_t_logic_info.t_config_data) | 系统配置,本文件用到 u8_prepay_meter、GCRatedPower、GCRatePercent、GCOutputMode、GCChargePower |
DEBUG_LOGIC | 宏(= 0,logic/logic.h:17) | 调试打印开关,置 1 时本文件输出大量 printf 轨迹 |
INVERTER_TYPE / INVERTER_MAX / ALPHAESS_TYPE | 宏 | INVERTER_TYPE 当前 = INVERTER_NULL,使第 948、1406 行的 #if 段不参与编译 |
SUB_T10 | 枚举成员(midware/inverter/inverter.h:320) | 并机从机型号 T10,用于把 pbat_inv_offset 从 50 改成 100(该分支同样被 #if 屏蔽) |
GC_CHARGE | 宏(= 1,logic/logic.h:27) | 油机输出模式「充电功率模式」判据 |
3. 函数清单
| 行号 | 函数名 | 作用域 | 说明(一句话) |
|---|---|---|---|
| 62 | ac_control_total_power_limit | 全局 | AC 总功率控制限幅:逆变设定值钳到 [−额定输入, +额定输出],充电/放电限值钳到 [0, 电池允许值] |
| 110 | ac_control_total_power_self_use_calculate | 全局 | 已被 #if 0(103~431 行)整段屏蔽的旧版自发自用计算,含大量 l_u16_test 调试标记;文件里保留但永不编译 |
| 439 | ac_control_total_power_bat_force_charge_control | static | 强充模式核心控制:PV 功率一阶低通滤波 + 滞环判断「充电/馈网」两态,按 u8_regulator_speed 斜坡逼近目标 AC 功率 |
| 562 | ac_control_total_power_bat_force_control | static | 强放 / 无电池模式核心控制:按 max_feedin + pgrid_metert 校正 AC 设定并下限截 0 |
| 599 | ac_control_total_power_bat_force_charge | 全局 | AC 强充入口:充电限值 = 电池充电上限、放电限值 = 0,转调 439 |
| 613 | ac_control_total_power_bat_force_discharge | 全局 | AC 强放入口:充电限值 = 0、放电限值 = 电池放电上限,转调 562 |
| 628 | ac_control_total_power_bat_power_control | 全局 | AC 跟随上位指令的电池功率控制:由 s16_inv_control_power / s16_bat_control_power 直接得到限值 |
| 667 | ac_control_total_power_no_bat_calculate | 全局 | AC 无电池模式:充放电限值清零后转调 562 |
| 683 | ac_control_total_power_gc_chgpower_calculate | 全局 | AC 油机充电功率模式:由 GCRatedPower*GCRatePercent/100 扣掉后备功率得到可用取电功率,取负作为逆变设定 |
| 728 | time_peak_clip_calculate | 全局 | 削峰功率计算:以 s32_set_peak_value 为上限、s32_set_delta_value 为回差给出逆变设定 |
| 749 | time_valley_fill_calculate | 全局 | 填谷功率计算:先把电表功率整体下移 s32_set_valley_value,再跑总功率状态机,并在结果是「PV 追踪馈网」时强制置强充使能 |
| 795 | total_power_control_feedin_track_calculate | static | 「电池满充 + PV 追踪馈网」态计算:max_feedin>100 置强充使能,按 max feedin 修正设定 |
| 831 | total_power_control_bat_open_with_pv_calculate | static | 「有 PV 电池开路」态计算:限值取满,AC 设定按 max_feedin + pgrid_metert 累加 |
| 845 | total_power_control_inv_over_ctrl_calculate | static | 超调控制态:AC 设定直接跟随当前 s32_pinvt,不做调节 |
| 856 | total_power_control_prepay_meter_calculate | static | 南非预付费电表临时防跳闸措施:三段阈值修正 + 强充时禁止取电为负 |
| 904 | prepay_meter_ac_control_state_handle | 全局(头文件未声明) | 预付费电表状态下,依据电池电流/功率是否到顶覆写目标状态为 PV_TRACK_FEEDIN_GRID_STATE 或 GRID_ZERO_WITH_PV_STATE |
| 933 | fsm_total_power_ac_control_state_handle | static | 总功率状态机「纯判断」段:按 PV/电池状态与电表功率决定 nextstate,并插入状态跳变超调态与并机屏蔽 |
| 1015 | fsm_total_power_ac_control | static | 总功率状态机「执行」段:按状态调用对应计算函数,最后无条件跑预付费电表修正 |
| 1055 | ac_control_total_power_self_use_calculate_new | 全局 | 当前生效的 AC 自发自用入口:节拍闸门 → 状态判断 → 状态执行,并置 u8_logic_power_calculation_sync_flag |
| 1123 | three_unbalance_power_inv_single_phase_full_cnt | static | 统计 A/B/C 三相中有几相处于「逆变单相满载」状态,返回 0~3 |
| 1149 | threephase_unbalance_power_state_handle | static | 逐相判定 A/B/C 相状态(买电 / 馈网 / 稳定 / 满载),输出三个单相状态 |
| 1227 | ac_control_three_phase_power_bat_force_control | 全局(头文件未声明) | 三相不平衡强充/强放/无电池的核心控制:按满载相数分配单相 max feedin 或直接跟随电表功率 |
| 1277 | ac_control_three_phase_power_bat_force_charge | 全局 | 三相不平衡强充入口,转调 1227 |
| 1292 | ac_control_three_phase_power_bat_force_discharge | 全局 | 三相不平衡强放入口,转调 1227 |
| 1307 | ac_control_three_phase_power_no_bat_calculate | 全局 | 三相不平衡无电池入口,转调 1227 |
| 1322 | threephase_unbalance_power_grid_track_with_pv_calculate | static | 三相不平衡 + 有 PV:各相按 pgrid_meterX / u8_regulator_speed 斜坡逼近电表归零 |
| 1340 | threephase_unbalance_power_grid_track_without_pv_calculate | static | 三相不平衡 + 无 PV:三相都归零且逆变都很小时把三相设定钉到 10W 并禁止充放电,否则各相斜坡逼近 |
| 1378 | threephase_unbalance_power_pv_track_feedin_grid_calculate | static | 三相不平衡 PV 追踪馈网:按「不满载相数」平摊单相 max feedin,并叠加到三相设定 |
| 1430 | threephase_unbalance_power_bat_open_with_pv_calculate | static | 三相不平衡电池开路:有相在买电时按各相电表功率直接跟随,否则平摊 max feedin 后再叠加各相电表功率 |
| 1475 | threephase_unbalance_power_inv_over_ctrl_calculate | static | 三相不平衡超调态:三相设定直接跟随当前各相逆变功率 |
| 1488 | fsm_threephase_unbalance_power_ac_control_state_handle | static | 三相不平衡状态机「纯判断」段:先算单相状态 → 定总状态 → 打包成 u32 |
| 1546 | fsm_threephase_unbalance_power_ac_control | static | 三相不平衡状态机「执行」段:解包 u32 高位总状态并 switch 分派 |
| 1586 | ac_control_three_phase_power_limit | 全局 | 三相不平衡限幅:三相同时低于最小充电功率时放行到 ±单相额定,否则钳到最小充电功率;上限统一钳到 2× 单相额定 |
| 1631 | ac_control_three_phase_power_self_use_calculate | 全局 | AC 三相不平衡自发自用入口:节拍闸门 → 状态判断 → 状态执行 → 限幅 |
| 1674 | ac_ctrl_time_peak_clip_command | 全局 | 削峰命令入口:带 PEAKSHVING_STATE_E 双状态滞环,调用 time_peak_clip_calculate() 并做「已降到峰值以下」退出判断 |
| 1723 | ac_ctrl_time_valley_fill_command | 全局 | 填谷命令入口:同构的滞环状态机,调用 time_valley_fill_calculate(),退出判据为 AC设定 + 电表 > 100 |
| 1774 | ac_control_Sunspec_unbalance_ctrl | 全局 | Sunspec 有功控制下把 l_add_inv 按「未满载相数」均分给三相,并对馈网侧做 max feedin 限制 |
| 1838 | ac_control_Sunspec_ative_power | 全局 | Sunspec 有功功率控制总入口:参数保护 → 负载/PV 估算 → MPPT 关断与恢复判据 → 斜坡逼近 → 三相不平衡 → 充放电限值写回 |
共 38 个函数定义,其中 1 个(第 110 行)位于 #if 0 内属死代码,实际参与编译 37 个;按作用域统计为 static 17 个、非 static 全局 21 个(其中 2 个全局函数未在头文件声明,属接口泄漏)。
4. 核心逻辑解析
4.1 整体数据流与节拍闸门
所有计算函数开头都有一段一致的节拍闸门(模式统一为):
if (abs(OSTimeGet() - g_t_logic_info.t_logic_control_parameter.u32_calculation_XXX_tick)
< g_t_logic_info.t_logic_control_parameter.u32_calculation_interval)
return;
g_t_logic_info.t_logic_control_parameter.u32_calculation_XXX_tick = OSTimeGet();
- 使用的时间戳字段只有两个:
u32_calculation_ac_total_inv_tick(总功率链)与u32_calculation_ac_three_phase_inv_tick(三相不平衡链)。 - 节拍间隔来自
u32_calculation_interval(按逆变器型号在logic.c里整定的「逆变侧计算间隔」),OSTimeGet()是 uCOS-II 的系统 tick。 - 注意:这两个字段被同一链路上的多个函数共享(总功率链上
ac_control_total_power_bat_force_charge_control、..._bat_force_control、..._bat_power_control、ac_control_total_power_self_use_calculate_new、ac_ctrl_time_peak_clip_command、ac_ctrl_time_valley_fill_command、ac_control_Sunspec_ative_power都用u32_calculation_ac_total_inv_tick),因此同一轮里先跑的函数会「吃掉」这个节拍,后面的直接 return。logic/logic.c:2916-2920在收到POST_PEND_FAST_ENABLE事件时会把这 5 个 tick 字段全部清 0,实现「快调度强制立即计算」。
4.2 总功率控制状态机(自发自用)
判断段 fsm_total_power_ac_control_state_handle()(ac_control.c:933)
输入只有四个量:u8_pv_status、u8_bat_status、s32_pgrid_metert(总电表功率,正为买电)、以及逆变侧电池电流/功率是否到顶。
┌── pv=1,bat=0 ──────────────────────► BAT_OPEN_WITH_PV_STATE
pv_status == TRUE ──┤
│ pgrid < -50(馈网):
│ 到顶(ibat-3 < -chg_cur_lim 或 pbat-50 < -chg_pwr_lim)
│ ├ 是 ──► PV_TRACK_FEEDIN_GRID_STATE
│ └ 否 ──► GRID_TRACK_WITH_PV_STATE
└── pv=1,bat=1 ── pgrid > system_self_consumption
├ 是 ──► GRID_TRACK_WITH_PV_STATE
└ 否 ── 到顶 ? PV_TRACK_FEEDIN_GRID_STATE
: GRID_ZERO_WITH_PV_STATE
pv_status == FALSE ── pgrid < -50 或 pgrid > system_self_consumption
├ 是 ──► GRID_TRACK_WITHOUT_PV_STATE
└ 否 ──► GRID_ZERO_WITHOUT_PV_STATE
其中「到顶」判据把电池充电功率/电流与允许上限比较,并留了 3A / 50W 余量;并机且从机为 SUB_T10 时余量改为 100W,但该分支被 #if ((INVERTER_TYPE == INVERTER_MAX) || (INVERTER_TYPE == ALPHAESS_TYPE))(ac_control.c:948)屏蔽。
判断段末尾有两处关键副作用:
- 调
prepay_meter_ac_control_state_handle(nextstate)(ac_control.c:996):若u8_prepay_meter != TRUE直接返回;否则在-100 < pgrid < 150时按电池到顶与否把状态覆写成PV_TRACK_FEEDIN_GRID_STATE/GRID_ZERO_WITH_PV_STATE。 - 超调滞环(
ac_control.c:999-1006):并机模式(g_t_inv_info.t_config_data.u8_parallel_en == FALSE即非并机)下,只要*prestate != *nextstate,就把*prestate更新为新状态、把*nextstate改成INV_OVER_CTRL_STATE。即「状态每变化一次,先执行一帧超调控制(AC 设定 = 当前实际逆变功率),下一帧才真正进入新状态」。这构成一个两拍的状态迁移。
执行段 fsm_total_power_ac_control()(ac_control.c:1015)
case GRID_TRACK_WITH_PV_STATE:
case GRID_TRACK_WITHOUT_PV_STATE:
case GRID_ZERO_WITH_PV_STATE: → total_power_control_grid_track_calculate();
case PV_TRACK_FEEDIN_GRID_STATE: → total_power_control_feedin_track_calculate();
case GRID_ZERO_WITHOUT_PV_STATE: → total_power_control_grid_zero_without_pv_calculate();
case BAT_OPEN_WITH_PV_STATE: → total_power_control_bat_open_with_pv_calculate();
case INV_OVER_CTRL_STATE: → total_power_control_inv_over_ctrl_calculate();
default: 空
注意前三个状态共用同一个函数 total_power_control_grid_track_calculate(),而该函数不在本文件内,定义在 logic/handle_priority.c:26(声明在 logic/handle_priority.h:31);total_power_control_grid_zero_without_pv_calculate() 同理定义在 logic/handle_priority.c:42。switch 之后,无论什么状态都会再执行一次 total_power_control_prepay_meter_calculate()(ac_control.c:1046)。
入口 ac_control_total_power_self_use_calculate_new()(ac_control.c:1055)
节拍闸门 → 置 u8_logic_power_calculation_sync_flag = TRUE → fsm_total_power_ac_control_state_handle(&s_u32_prestate, &l_u32_nextstate) → fsm_total_power_ac_control(l_u32_nextstate)。s_u32_prestate 是本函数内的 static u32(ac_control.c:1058),因此状态记忆跨调用保持。本函数不自己调 logic_charge_dischg_power_limit(),限幅由上层 logic/logic.c:1866 统一调用。
4.3 AC 三相不平衡控制
单相状态判定 threephase_unbalance_power_state_handle()(ac_control.c:1149)
对 A/B/C 三相各执行同一套判据(用 s32_pgrid_metera/b/c 与 s32_pinva/b/c):
pgrid < -50 → GRID_METER_PHASE_OUTPUT_STATE (该相馈网)
pgrid > system_self_consumption → pinv < (单相额定 - 150) ?
├ 是 → GRID_METER_PHASE_INPUT_STATE (该相买电且还有逆变余量)
└ 否 → INV_PHASE_POWER_FULL_STATE (该相逆变已满)
其他(±50W 内) → GRID_METER_PHASE_ZERO_STATE (该相归零)
总状态判断 + 打包 fsm_threephase_unbalance_power_ac_control_state_handle()(ac_control.c:1488)
- 先算出 3 个单相状态;
- 定总状态:
pv=1,bat=0→UNBALANCE_BAT_OPEN_WITH_PV_STATE;pv=1,bat=1且任一相为GRID_METER_PHASE_INPUT_STATE→UNBALANCE_GRID_TRACK_WITH_PV_STATE;pv=1,bat=1无相买电 → 电池到顶则UNBALANCE_PV_TRACK_FEEDIN_GRID_STATE,否则UNBALANCE_GRID_TRACK_WITH_PV_STATE;pv=0→UNBALANCE_GRID_TRACK_WITHOUT_PV_STATE; - 超调滞环:
*prestate != l_u8_state_t时把l_u8_state_t换成UNBALANCE_INV_OVER_CTRL_STATE(此处没有并机屏蔽,与总功率链不同); - 打包:
nextstate = (state_t << 24) | (state_a << 16) | (state_b << 8) | state_c(ac_control.c:1536)。
执行 fsm_threephase_unbalance_power_ac_control()(ac_control.c:1546):state >> 24 取出总状态并 switch 到 5 个计算函数(无 PV 跟踪 / 有 PV 跟踪 / PV 追踪馈网 / 电池开路 / 超调),UNBALANCE_DEFAULT_STATE 和 default 空处理。
满载相数分配算法
三相不平衡的核心是「max feedin 和电表功率如何摊到三相」。以 threephase_unbalance_power_bat_open_with_pv_calculate()(ac_control.c:1430)为例:
l_u8_power_inv_full_phase_cnt = three_unbalance_power_inv_single_phase_full_cnt(a,b,c);
if (l_u8_power_inv_full_phase_cnt < 3)
l_s32_single_phase_max_feedin_power = s32_max_feedin_power / (3 - full_cnt);
...
if (任一审为 GRID_METER_PHASE_INPUT_STATE)
各相设定 += 各相电表功率;
else {
if (三相设定都 >= 单相额定 && 单相 max feedin > 100) return; // 已满,不再加
各相设定 += 单相 max feedin + 各相电表功率;
}
ac_control_three_phase_power_bat_force_control()(ac_control.c:1227)用的是类似但分子不同的公式:(s32_max_feedin_power + s32_pgrid_metert) / (3 - full_cnt)。
限幅 ac_control_three_phase_power_limit()(ac_control.c:1586)
负下限 = s32_ac_machine_min_charg_power; // 单相最小充电功率
单相额定 = s32_inv_rated_output_power / 3;
if (三相设定都 < 负下限) → 三相各钳到 >= -单相额定 (三相都在取电,允许买电)
else → 三相各钳到 >= 负下限 (任一相在输出,收紧)
三相各钳到 <= 单相额定 * 2
入口 ac_control_three_phase_power_self_use_calculate()(ac_control.c:1631):节拍闸门(u32_calculation_ac_three_phase_inv_tick)→ 状态判断 → 状态执行 → ac_control_three_phase_power_limit()。同样持有自己的 static u32 s_u32_prestate。
4.4 强充 / 强放 / 无电池 / 电池功率控制
- 强充
ac_control_total_power_bat_force_charge()(599)→..._charge_control()(439):先取电池充电限值l_s32_bat_limit_power,非并机时与pvcharger_read_bat_max_charge_power()取小,并机时与parallel_read_system_max_charge_power_limit()取小。PV 功率做一阶低通滤波:filtered = (filtered * 3 + s32_ppv_inv) / 4(ac_control.c:464)。随后用s_u8_feedin_active做 ±100W 滞环:(-pbat_inv + pinvt) > 限值 + 100进馈网态,< 限值 - 100回充电态。- 馈网态:
u8_ac_total_set_bat_forced_charge_en = TRUE;|max_feedin + pgrid_metert| > 100时直接赋值pgrid_metert + max_feedin + pinvt,否则按u8_regulator_speed斜坡累加;最后下限截 0。 - 充电态:强充使能清 0;目标
target = filtered - 电池充电限值,下限target + AC_FORCE_CHG_INV_FLOOR_MARGIN(50);误差inv_err = target - pinvt,若当前设定高于下限或误差为正则按inv_err / u8_regulator_speed累加,最后钳到下限。 - 无 PV 分支:目标为纯电网充电
target = -电池充电限值,按(target - pinvt) / u8_regulator_speed累加。
- 馈网态:
- 强放 / 无电池
..._bat_force_control()(562):不区分 PV 状态,直接按|max_feedin + pgrid_metert| > 100判据赋值或斜坡累加,最后下限截 0。 - 电池功率控制
ac_control_total_power_bat_power_control()(628):s32_ac_total_set_inv_power = abs(s16_inv_control_power);s16_bat_control_power > 0→ 强充使能 + 充电限值 = 该值、放电限值 = 0;否则强充清 0、充电限值 = 0、放电限值 = 该值绝对值。注意 AC 设定取的是abs(),方向信息丢失(PV 侧设定恒为非负)。 - 油机
ac_control_total_power_gc_chgpower_calculate()(683):可用功率 = GCRatedPower * GCRatePercent / 100;若后备功率突增超过可用功率的 1/3,则退化为「只取自耗」;否则扣掉s32_pbackupt,GCOutputMode == GC_CHARGE时再与GCChargePower取小,最后不小于自耗。逆变设定 =-可用功率(负值即取电)。
4.5 削峰填谷
ac_ctrl_time_peak_clip_command()(1674)与 ac_ctrl_time_valley_fill_command()(1723)是同构的双状态滞环机,状态用 PEAKSHVING_STATE_E:
static s8 status = INITIAL_IDLE, old_status = INITIAL_IDLE;
削峰: pgrid < peak_value 且 old_status != POWER_REGULATION_STATE → NO_INVERTER_POWER_STATE
否则 → POWER_REGULATION_STATE
NO_INVERTER_POWER_STATE : 逆变设定 = 0
POWER_REGULATION_STATE : old_status = POWER_REGULATION_STATE
time_peak_clip_calculate();
若 (AC设定 + pgrid) < peak_value → old_status = NO_INVERTER_POWER_STATE, AC设定 = 0
填谷: pgrid > valley_value 且 old_status != POWER_REGULATION_STATE → NO_INVERTER_POWER_STATE
否则 → POWER_REGULATION_STATE
退出判据: (AC设定 + pgrid) > 100
两个入口在闸门通过后都会先把强充使能清 0,并把充放电限值复位为电池允许上限。
底层计算:
time_peak_clip_calculate()(728):pgrid >= peak→AC设定 = pinvt + |pgrid - peak|(补足到刚好不超峰值);pgrid <= peak - delta→AC设定 = pinvt - |pgrid - peak| / speed(回落)。time_valley_fill_calculate()(749):把s32_set_valley_value作为偏移量,就地修改s32_pgrid_metera/b/c(各减offset / u8_inv_phase_num)和s32_pgrid_metert(减offset),并把s32_max_feedin_power强制设为 0;然后跑一遍总功率状态机(fsm_total_power_ac_control_state_handle+fsm_total_power_ac_control),若结果是PV_TRACK_FEEDIN_GRID_STATE则强制置强充使能;最后调logic_charge_dischg_power_limit()做限幅。
4.6 Sunspec / 南澳调度有功控制
ac_control_Sunspec_ative_power(s32 l_s32_ctrl_ac)(1838) 计算步骤:
- 节拍闸门(
u32_calculation_ac_total_inv_tick)。 - 参数保护:
l_s32_ctrl_ac < 0且超充电倍率 → 钳到-sunspec_modbus_max_charge_rat_get();>= 0且超放电倍率 → 钳到sunspec_modbus_max_discharge_rat_get()。 l_s32_pv_power_t = meter_read_actpower(PV_METER, PHASE_T) + s32_ppv_inv;l_s32_set_bat_charge_limit_power = min(sunspec_modbus_chg_get(), s32_bat_charge_power_limit);l_s32_load_power = max(pgrid_metert + pbat_inv + pv_power_t, 0)。- MPPT 关断判据:当调度要充电(
ctrl_ac < 0)且负载 + 最大充电功率 < PV功率 + |ctrl_ac|时,令sunspec_modbus_mppt_over_count_add(),并记录s_s32_max_ctrl_ac = ctrl_ac、s_u32_max_bat_charge_power = 充电限值。计数>= 3时sunspec_modbus_mppt_percentage_set(0)关 PV。 - MPPT 恢复判据:
(s_s32_max_ctrl_ac + 1000) < l_s32_ctrl_ac或充电限值比记录值大 1000 以上时sunspec_modbus_mppt_percentage_set(10000)开 PV。 - 误差
l_s32_diff_tem = ctrl_ac - s32_pinvt;|diff| >= 1000时先除以u8_regulator_speed得到本拍步进。 - 若在馈网且已接近 max feedin(
diff > 0 && pgrid_metert < 0 && max_feedin + pgrid_metert < 100),AC 设定 =pinvt + (max_feedin + pgrid_metert)/speed并下限截 0;否则 AC 设定 =pinvt + diff。 - 调
ac_control_Sunspec_unbalance_ctrl(l_s32_diff_tem)做三相再分配。 logic_charge_dischg_power_limit()限幅。- 把充/放电限值写回
s32_ac_total_set_bat_charge_limit_power/..._discharge_limit_power,同时同步到三相不平衡的对应字段;若 AC 设定 > 0,则总功率与三相不平衡的强充使能都清 0。
ac_control_Sunspec_unbalance_ctrl(s32 l_add_inv)(1774):inverter_get_three_unbalance_mode() == FALSE 直接返回;统计 pinvX < 单相额定 - 100 的相数 l_u8_freed_cnt,为 0 则返回;对每个未满载相:若在馈网且已接近 max feedin,则设定 = 当前相逆变功率 + ((max_feedin + pgrid_metert)/freed_cnt)/speed(下限 0),否则设定 = 当前相逆变功率 + l_add_inv/freed_cnt。
4.7 通信协议帧 / 超时重试
本文件不实现任何通信协议:不组帧、不校验(CRC/和校验)、不重试、不直接收发 UART/CAN/以太网。它只消费已经被其他模块解析好的实时量(meter_read_actpower()、inverter_*、bms_*、sunspec_modbus_*),并产出功率设定值。协议解析在 midware/meter、midware/inverter、midware/interface/modbus 等模块。
4.8 与 uCOS-II 任务的配合
- 本文件不使用任何 uCOS-II API(无
OSSemPend/OSMboxPend/OSTaskCreate),唯一触及的是OSTimeGet()(系统 tick 计数),用于 4.1 的节拍闸门。 - 驱动方是
logic/logic.c:2902的task_system_logic_control任务:它在OSTimeDlyHMSM(0,0,0,280)(280ms)循环里,先判断inverter_get_sys_ctrl_state(),然后按并网/非并网走ongrid_logic_handle()或other_logic_handle();这两个中间层再按u8_sequencecontrol_mode分派到self_use_funtion()/bat_force_charge()/bat_force_discharge()/bat_power_control()/time_peakshaving_command()/ 油机模式等,最终落到本文件的各入口函数。 - 与信号量/消息邮箱的配合:任务开头
OSFlagPend(g_t_fast_dispatch_flag, POST_PEND_FAST_ENABLE, OS_FLAG_WAIT_SET_ALL, 20, &err)等待快调度事件标志;命中时把 5 个 tick 字段清 0(强制立即计算),算完再OSFlagPost(..., POST_LOGIC_CALCULATE_DONE, ...)并OSTimeDlyResume(TASK_INVERTER_PRIO)唤醒逆变器任务。本文件本身不参与事件标志的置位/清位。 - 并发安全:本文件写入的
g_t_logic_info字段是无锁的普通全局变量,与logic.c的 ramp 处理(logic.c:2554-2640会把这些字段再赋一次渐进值)、midware/inverter/parallel.c的读取(logic_read_*)之间没有互斥保护,靠「逻辑任务单点推进 + 逆变任务相对滞后」隐式串行化。
4.9 关键全局变量的读写与触发条件
| 变量 | 读/写 | 触发条件与含义 |
|---|---|---|
g_t_logic_info.s32_ac_total_set_inv_power | 读+写 | 被 9 个函数写;正为逆变输出(放电/馈网)、0 为停止。ac_control_total_power_limit() 只在 logic_charge_dischg_power_limit() 被调用时钳一次 |
g_t_logic_info.s32_ac_total_set_bat_charge_limit_power / ..._discharge_limit_power | 读+写 | 电池充/放电允许上限,各分支按状态赋成「电池允许值」或 0 |
g_t_logic_info.u8_ac_total_set_bat_forced_charge_en | 读+写 | 强充使能:馈网态 / PV_TRACK_FEEDIN_GRID_STATE / bat_control_power>0 时置 TRUE |
g_t_logic_info.s32_ac_three_phase_set_inv_a/b/c_power | 读+写 | 三相不平衡各相有功设定,ac_control_Sunspec_unbalance_ctrl() 里用指针数组 l_s32_set_inv_p[3] 间接写 |
g_t_logic_info.s32_ac_three_phase_set_bat_charge_limit_power / ..._discharge_limit_power / u8_ac_three_phase_set_bat_forced_charge_en | 读+写 | 三相不平衡侧的电池限值与强充使能,与总功率侧并行维护 |
g_t_logic_info.u8_logic_power_calculation_sync_flag | 写 | ac_control_total_power_self_use_calculate_new() 闸门通过后无条件置 TRUE(ac_control.c:1065),供快调度同步判断 |
g_t_logic_info.t_logic_control_parameter.u32_calculation_ac_total_inv_tick / ..._ac_three_phase_inv_tick | 读+写 | 节拍时间戳,见 4.1 |
g_t_logic_info.t_logic_control_parameter.s32_pgrid_metera/b/c / s32_pgrid_metert | 就地修改 | 仅在 time_valley_fill_calculate()(ac_control.c:757-760)中减去填谷偏移量,会改变后续所有模块看到的「电表功率」 |
g_t_logic_info.t_logic_control_parameter.s32_max_feedin_power | 就地修改 | time_valley_fill_calculate() 中强制置 0(ac_control.c:761) |
g_t_logic_info.u16_mppt_percentage | 只读(打印) | 在 #if 0 调试段中引用;实际 MPPT 百分比由 sunspec_modbus_mppt_percentage_set() 维护 |
5. 对外接口
导出的函数与全局变量(供谁调用):
| 导出符号 | 调用方 |
|---|---|
ac_control_total_power_limit() | logic/logic.c:1750 |
ac_control_total_power_bat_force_charge() | logic/logic.c:1768 |
ac_control_total_power_bat_force_discharge() | logic/logic.c:1789 |
ac_control_total_power_bat_power_control() | logic/logic.c:1810 |
ac_control_total_power_no_bat_calculate() | logic/logic.c:2030 |
ac_control_total_power_gc_chgpower_calculate() | logic/logic.c:2103 |
ac_control_total_power_self_use_calculate_new() | logic/logic.c:1862 |
ac_control_three_phase_power_limit() | logic/logic.c:1751 |
ac_control_three_phase_power_bat_force_charge() | logic/logic.c:1769 |
ac_control_three_phase_power_bat_force_discharge() | logic/logic.c:1790 |
ac_control_three_phase_power_no_bat_calculate() | logic/logic.c:2031 |
ac_control_three_phase_power_self_use_calculate() | logic/logic.c:1863 |
ac_control_Sunspec_ative_power() | logic/dispatch.c:1381 |
ac_ctrl_time_peak_clip_command() | logic/logic.c:555 |
ac_ctrl_time_valley_fill_command() | logic/logic.c:564 |
prepay_meter_ac_control_state_handle() | 无外部调用方(仅 ac_control.c:996 内部使用),头文件也未声明 |
ac_control_three_phase_power_bat_force_control() | 无外部调用方(仅 ac_control.c:1283/1298/1313 内部使用),头文件也未声明 |
ac_control_Sunspec_unbalance_ctrl() | 头文件已声明,但外部无调用,仅 ac_control.c:1908 内部使用 |
本文件不定义也不导出任何全局变量(g_t_logic_info / g_t_inv_info 均为外部定义)。
本文件调用的外部函数/变量:
| 名称 | 来源模块 |
|---|---|
g_t_logic_info(LOGIC_TABLE_T) | logic/logic.h:646,定义于 logic/logic.c:36 |
g_t_inv_info.t_config_data.u8_parallel_en | midware/inverter/inverter.h:472 |
total_power_control_grid_track_calculate() | logic/handle_priority.c:26 |
total_power_control_grid_zero_without_pv_calculate() | logic/handle_priority.c:42 |
logic_charge_dischg_power_limit() | logic/logic.c:1742 |
pvcharger_read_bat_max_charge_power() | midware/inverter/pvcharger.h:91 |
parallel_read_system_max_charge_power_limit() | midware/inverter/parallel.h:301 |
inverter_get_three_unbalance_mode() | midware/inverter/inverter.h:2076 |
get_inverter_type() / get_inverter_sub() | midware/inverter/inverter.h:1940 等 |
meter_read_actpower(PV_METER, PHASE_T) | midware/meter/meter.h:471 |
sunspec_modbus_chg_get() / sunspec_modbus_dischg_get() | midware/interface/modbus/sunspec_business.h:21-22 |
sunspec_modbus_max_charge_rat_get() / ..._max_discharge_rat_get() | midware/interface/modbus/sunspec_business.h:30-31 |
sunspec_modbus_mppt_percentage_set() / ..._mppt_over_count_add() / ..._mppt_over_count_get() | midware/interface/modbus/sunspec_business.h:25/28/29 |
OSTimeGet() / abs() / printf() | uCOS-II / C 标准库 / 调试串口 |
6. 依赖关系
依赖(include 与使用时):
- 直接 include(
ac_control.c:12-17):ac_control.h、logic.h、inverter.h、sunspec_business.h、meter.h、handle_priority.h。 - 间接依赖:
chip.h(基础类型、uCOS-II 配置)、bms.h(未 include,本文件未直接调用 BMS 接口)、midware/inverter/pvcharger.h/parallel.h(仅原型可见性依赖inverter.h的包含链)。 - 编译开关依赖:
INV_AC_CTRL(midware/inverter/inverter.h:180)必须定义,否则全文件为空。
被依赖(谁 include / 调用它):
logic/logic.c(include + 13 处调用)logic/dispatch.c(include + 1 处调用)logic/csip_aus.c(仅 include,未调用)
7. 备注与风险点
- 当前构建配置下整个文件几乎不参与编译:
INVERTER_TYPE硬编码为INVERTER_NULL(midware/inverter/inverter.h:172),因此INV_AC_CTRL(inverter.h:180)未定义,ac_control.c:21的#ifdef INV_AC_CTRL把第 21~1951 行全部排除。Keil 工程user/EMS_3_0.uvprojx的<Define>只有USE_STDPERIPH_DRIVER, GD32F407,没有覆盖该宏。本文件的逻辑只在「AC 控机型」的产品配置下才生效,静态审查时容易误判其有效性。
- 两处功能块被
#if ((INVERTER_TYPE == INVERTER_MAX) || (INVERTER_TYPE == ALPHAESS_TYPE))永久屏蔽(ac_control.c:948-953的 T10 并机偏置、ac_control.c:1406-1421的三相设定下限截 0),即使INV_AC_CTRL打开,只要INVERTER_TYPE不是INVERTER_MAX/ALPHAESS_TYPE这两段就是死代码。
three_unbalance_power_inv_single_phase_full_cnt()的名字与注释相反:函数头注释写「三相不平衡单相逆变非满载数量输出」,实际统计的是== INV_PHASE_POWER_FULL_STATE的相数(即满载数量)。调用方全部按「满载数」使用(3 - full_cnt做除数),因此注释错误而未产生 bug,但极易误导后续维护。
threephase_unbalance_power_pv_track_feedin_grid_calculate()(1378)中的l_u8_power_inv_full_phase_cnt是死变量:第 1381 行初始化为 0 后再无赋值,第 1388 行if (l_u8_power_inv_full_phase_cnt < 3)恒真,于是单相 max feedin 恒等于(max_feedin + pgrid_metert)/3。对比..._bat_open_with_pv_calculate()(1430)第 1442 行正确调用了统计函数,可判定此处是漏写,会使「有一相已满载」时仍按 3 相均分,实际下发功率偏小。
ac_control_Sunspec_ative_power()中s_u32_max_bat_charge_power为u32与s32混算(ac_control.c:1850、ac_control.c:1886):l_s32_set_bat_charge_limit_power - s_u32_max_bat_charge_power > 1000,右操作数为无符号,整个表达式按无符号比较。当限值为 0 而记录值为较大正数时,0 - N会回绕成极大无符号数,导致 MPPT 每拍都被重新打开(mppt_percentage_set(10000)),PV 关断保护实际失效。
time_valley_fill_calculate()就地篡改测量量:ac_control.c:757-761直接对s32_pgrid_metera/b/c、s32_pgrid_metert做减法并写回g_t_logic_info,且把s32_max_feedin_power置 0。这些字段是全系统共享的实时测量量(还被net/ems.c上报云端、被midware/meter相关逻辑读取)。本函数每拍按s32_set_valley_value减一次而没有任何恢复动作,若与其它使用同一字段的路径混跑,会出现「电表功率被反复扣减」的累积偏差,属高危副作用。
- 同一节拍时间戳被多条链路复用:
u32_calculation_ac_total_inv_tick被 7 个函数共用(见 4.1)。在填谷模式下time_valley_fill_calculate()会跑一次完整的状态机并消耗该 tick,随后self_use_funtion()里的ac_control_total_power_self_use_calculate_new()在同一轮内必然早退,反之亦然。这使两条链路的实际执行频次互相牵制,行为依赖调用顺序、不易推理。
- 状态机
fsm_total_power_ac_control_state_handle()的超调滞环与并机屏蔽不对称:总功率链有if (g_t_inv_info.t_config_data.u8_parallel_en == FALSE)守卫(ac_control.c:999),三相不平衡链(ac_control.c:1530)没有。并机场景下三相不平衡仍会每拍插入一帧UNBALANCE_INV_OVER_CTRL_STATE,可能造成三相功率在状态切换附近抖动。
prepay_meter_ac_control_state_handle()只在-100 < pgrid < 150区间生效(ac_control.c:912):区间外不覆写状态,直接沿用主状态机结果;函数名与实现职责(「覆写 nextstate」而非「处理状态」)不一致,且头文件未声明,属隐式接口。
- 大量魔法数字:
50/100/150/30/10/3/5/-3(电流余量)/200/1000/10000等阈值遍布全文,只有AC_FORCE_CHG_INV_FLOOR_MARGIN被提为宏;dc_control.c里同类阈值已抽到para_tables[]按机型配置,本文件没有对应机制,机型适配只能改代码。
l_u16_test调试痕迹:ac_control.c:408有l_u16_test = l_u16_test;(自赋值压制未使用告警),#if 0调试段(409-429)与#if(DEBUG_LOGIC)段(如 539-553、585-590)保留了大量printf,其中参数表跨多行、类型与格式串(%d对s32)未做long限定,属跨平台隐患。
- 死代码与注释错位:
ac_control.c:103-431整段#if 0(旧版ac_control_total_power_self_use_calculate)、1089-1115注释掉的ac_control_total_der_default_power_calculat;ac_control.c:1221的函数头注释写的是static void ac_control_three_phase_power_bat_force_charge(void),而实际定义是ac_control_three_phase_power_bat_force_control(且为全局非 static);ac_control.c:898的函数头注释写的是static void fsm_ac_control(u8 state),实际是prepay_meter_ac_control_state_handle;ac_control.c:1580/1625函数头注释把已改成非 static 的函数仍写成static void ...。
ac_control_three_phase_power_limit()的下限判据依赖s32_ac_machine_min_charg_power的符号约定(ac_control.c:1589):该值取自inverter_get_ac_machine_min_charg_power()(logic/logic.c:941)。代码把它同时当作「单相负下限」和「三相同为取电」的门槛值,若逆变器侧上报的是正数(表示充电功率大小而非带符号下限),pgrid < 负下限这一族判据会全部失真,三相限幅退化为「一律钳到正数」,需以机型实现为准。文档无法从本文件单独判定该约定。
fsm_total_power_ac_control_state_handle()的冗余比较:ac_control.c:1354-1355写了(a==b) && (b==c) && (a==c),第三个条件由前两个蕴含,属冗余。
ac_control_Sunspec_unbalance_ctrl()使用l_u8_freed_cnt作除数(ac_control.c:1812、1819):虽在函数开头有l_u8_freed_cnt == 0的早退保护,但该变量在两次遍历之间保持不变,逻辑上是安全的;不过如果后续在循环内修改该计数,就会引入除零风险,属脆弱写法。