EMS 知识库
首页 / knowledge/代码解析/logic

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. 函数清单

行号函数名作用域说明(一句话)
62ac_control_total_power_limit全局AC 总功率控制限幅:逆变设定值钳到 [−额定输入, +额定输出],充电/放电限值钳到 [0, 电池允许值]
110ac_control_total_power_self_use_calculate全局已被 #if 0(103~431 行)整段屏蔽的旧版自发自用计算,含大量 l_u16_test 调试标记;文件里保留但永不编译
439ac_control_total_power_bat_force_charge_controlstatic强充模式核心控制:PV 功率一阶低通滤波 + 滞环判断「充电/馈网」两态,按 u8_regulator_speed 斜坡逼近目标 AC 功率
562ac_control_total_power_bat_force_controlstatic强放 / 无电池模式核心控制:按 max_feedin + pgrid_metert 校正 AC 设定并下限截 0
599ac_control_total_power_bat_force_charge全局AC 强充入口:充电限值 = 电池充电上限、放电限值 = 0,转调 439
613ac_control_total_power_bat_force_discharge全局AC 强放入口:充电限值 = 0、放电限值 = 电池放电上限,转调 562
628ac_control_total_power_bat_power_control全局AC 跟随上位指令的电池功率控制:由 s16_inv_control_power / s16_bat_control_power 直接得到限值
667ac_control_total_power_no_bat_calculate全局AC 无电池模式:充放电限值清零后转调 562
683ac_control_total_power_gc_chgpower_calculate全局AC 油机充电功率模式:由 GCRatedPower*GCRatePercent/100 扣掉后备功率得到可用取电功率,取负作为逆变设定
728time_peak_clip_calculate全局削峰功率计算:以 s32_set_peak_value 为上限、s32_set_delta_value 为回差给出逆变设定
749time_valley_fill_calculate全局填谷功率计算:先把电表功率整体下移 s32_set_valley_value,再跑总功率状态机,并在结果是「PV 追踪馈网」时强制置强充使能
795total_power_control_feedin_track_calculatestatic「电池满充 + PV 追踪馈网」态计算:max_feedin>100 置强充使能,按 max feedin 修正设定
831total_power_control_bat_open_with_pv_calculatestatic「有 PV 电池开路」态计算:限值取满,AC 设定按 max_feedin + pgrid_metert 累加
845total_power_control_inv_over_ctrl_calculatestatic超调控制态:AC 设定直接跟随当前 s32_pinvt,不做调节
856total_power_control_prepay_meter_calculatestatic南非预付费电表临时防跳闸措施:三段阈值修正 + 强充时禁止取电为负
904prepay_meter_ac_control_state_handle全局(头文件未声明)预付费电表状态下,依据电池电流/功率是否到顶覆写目标状态为 PV_TRACK_FEEDIN_GRID_STATE 或 GRID_ZERO_WITH_PV_STATE
933fsm_total_power_ac_control_state_handlestatic总功率状态机「纯判断」段:按 PV/电池状态与电表功率决定 nextstate,并插入状态跳变超调态与并机屏蔽
1015fsm_total_power_ac_controlstatic总功率状态机「执行」段:按状态调用对应计算函数,最后无条件跑预付费电表修正
1055ac_control_total_power_self_use_calculate_new全局当前生效的 AC 自发自用入口:节拍闸门 → 状态判断 → 状态执行,并置 u8_logic_power_calculation_sync_flag
1123three_unbalance_power_inv_single_phase_full_cntstatic统计 A/B/C 三相中有几相处于「逆变单相满载」状态,返回 0~3
1149threephase_unbalance_power_state_handlestatic逐相判定 A/B/C 相状态(买电 / 馈网 / 稳定 / 满载),输出三个单相状态
1227ac_control_three_phase_power_bat_force_control全局(头文件未声明)三相不平衡强充/强放/无电池的核心控制:按满载相数分配单相 max feedin 或直接跟随电表功率
1277ac_control_three_phase_power_bat_force_charge全局三相不平衡强充入口,转调 1227
1292ac_control_three_phase_power_bat_force_discharge全局三相不平衡强放入口,转调 1227
1307ac_control_three_phase_power_no_bat_calculate全局三相不平衡无电池入口,转调 1227
1322threephase_unbalance_power_grid_track_with_pv_calculatestatic三相不平衡 + 有 PV:各相按 pgrid_meterX / u8_regulator_speed 斜坡逼近电表归零
1340threephase_unbalance_power_grid_track_without_pv_calculatestatic三相不平衡 + 无 PV:三相都归零且逆变都很小时把三相设定钉到 10W 并禁止充放电,否则各相斜坡逼近
1378threephase_unbalance_power_pv_track_feedin_grid_calculatestatic三相不平衡 PV 追踪馈网:按「不满载相数」平摊单相 max feedin,并叠加到三相设定
1430threephase_unbalance_power_bat_open_with_pv_calculatestatic三相不平衡电池开路:有相在买电时按各相电表功率直接跟随,否则平摊 max feedin 后再叠加各相电表功率
1475threephase_unbalance_power_inv_over_ctrl_calculatestatic三相不平衡超调态:三相设定直接跟随当前各相逆变功率
1488fsm_threephase_unbalance_power_ac_control_state_handlestatic三相不平衡状态机「纯判断」段:先算单相状态 → 定总状态 → 打包成 u32
1546fsm_threephase_unbalance_power_ac_controlstatic三相不平衡状态机「执行」段:解包 u32 高位总状态并 switch 分派
1586ac_control_three_phase_power_limit全局三相不平衡限幅:三相同时低于最小充电功率时放行到 ±单相额定,否则钳到最小充电功率;上限统一钳到 2× 单相额定
1631ac_control_three_phase_power_self_use_calculate全局AC 三相不平衡自发自用入口:节拍闸门 → 状态判断 → 状态执行 → 限幅
1674ac_ctrl_time_peak_clip_command全局削峰命令入口:带 PEAKSHVING_STATE_E 双状态滞环,调用 time_peak_clip_calculate() 并做「已降到峰值以下」退出判断
1723ac_ctrl_time_valley_fill_command全局填谷命令入口:同构的滞环状态机,调用 time_valley_fill_calculate(),退出判据为 AC设定 + 电表 > 100
1774ac_control_Sunspec_unbalance_ctrl全局Sunspec 有功控制下把 l_add_inv 按「未满载相数」均分给三相,并对馈网侧做 max feedin 限制
1838ac_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();

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)屏蔽。

判断段末尾有两处关键副作用:

  1. 调 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。
  2. 超调滞环(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)

  1. 先算出 3 个单相状态;
  2. 定总状态: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;
  3. 超调滞环:*prestate != l_u8_state_t 时把 l_u8_state_t 换成 UNBALANCE_INV_OVER_CTRL_STATE(此处没有并机屏蔽,与总功率链不同);
  4. 打包: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 强充 / 强放 / 无电池 / 电池功率控制

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,并把充放电限值复位为电池允许上限。

底层计算:

4.6 Sunspec / 南澳调度有功控制

ac_control_Sunspec_ative_power(s32 l_s32_ctrl_ac)(1838) 计算步骤:

  1. 节拍闸门(u32_calculation_ac_total_inv_tick)。
  2. 参数保护:l_s32_ctrl_ac < 0 且超充电倍率 → 钳到 -sunspec_modbus_max_charge_rat_get();>= 0 且超放电倍率 → 钳到 sunspec_modbus_max_discharge_rat_get()。
  3. 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)。
  4. 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。
  5. MPPT 恢复判据:(s_s32_max_ctrl_ac + 1000) < l_s32_ctrl_ac 或充电限值比记录值大 1000 以上时 sunspec_modbus_mppt_percentage_set(10000) 开 PV。
  6. 误差 l_s32_diff_tem = ctrl_ac - s32_pinvt;|diff| >= 1000 时先除以 u8_regulator_speed 得到本拍步进。
  7. 若在馈网且已接近 max feedin(diff > 0 && pgrid_metert < 0 && max_feedin + pgrid_metert < 100),AC 设定 = pinvt + (max_feedin + pgrid_metert)/speed 并下限截 0;否则 AC 设定 = pinvt + diff。
  8. 调 ac_control_Sunspec_unbalance_ctrl(l_s32_diff_tem) 做三相再分配。
  9. logic_charge_dischg_power_limit() 限幅。
  10. 把充/放电限值写回 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 任务的配合

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_enmidware/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 / 调用它):

7. 备注与风险点

  1. 当前构建配置下整个文件几乎不参与编译: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 控机型」的产品配置下才生效,静态审查时容易误判其有效性。
  1. 两处功能块被 #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 这两段就是死代码。
  1. three_unbalance_power_inv_single_phase_full_cnt() 的名字与注释相反:函数头注释写「三相不平衡单相逆变非满载数量输出」,实际统计的是 == INV_PHASE_POWER_FULL_STATE 的相数(即满载数量)。调用方全部按「满载数」使用(3 - full_cnt 做除数),因此注释错误而未产生 bug,但极易误导后续维护。
  1. 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 相均分,实际下发功率偏小。
  1. 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 关断保护实际失效。
  1. 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 减一次而没有任何恢复动作,若与其它使用同一字段的路径混跑,会出现「电表功率被反复扣减」的累积偏差,属高危副作用。
  1. 同一节拍时间戳被多条链路复用: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() 在同一轮内必然早退,反之亦然。这使两条链路的实际执行频次互相牵制,行为依赖调用顺序、不易推理。
  1. 状态机 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,可能造成三相功率在状态切换附近抖动。
  1. prepay_meter_ac_control_state_handle() 只在 -100 < pgrid < 150 区间生效(ac_control.c:912):区间外不覆写状态,直接沿用主状态机结果;函数名与实现职责(「覆写 nextstate」而非「处理状态」)不一致,且头文件未声明,属隐式接口。
  1. 大量魔法数字:50/100/150/30/10/3/5/-3(电流余量)/200/1000/10000 等阈值遍布全文,只有 AC_FORCE_CHG_INV_FLOOR_MARGIN 被提为宏;dc_control.c 里同类阈值已抽到 para_tables[] 按机型配置,本文件没有对应机制,机型适配只能改代码。
  1. 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 限定,属跨平台隐患。
  1. 死代码与注释错位:
    • 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 ...。
  1. 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 < 负下限 这一族判据会全部失真,三相限幅退化为「一律钳到正数」,需以机型实现为准。文档无法从本文件单独判定该约定。
  1. fsm_total_power_ac_control_state_handle() 的冗余比较:ac_control.c:1354-1355 写了 (a==b) && (b==c) && (a==c),第三个条件由前两个蕴含,属冗余。
  1. ac_control_Sunspec_unbalance_ctrl() 使用 l_u8_freed_cnt 作除数(ac_control.c:1812、1819):虽在函数开头有 l_u8_freed_cnt == 0 的早退保护,但该变量在两次遍历之间保持不变,逻辑上是安全的;不过如果后续在循环内修改该计数,就会引入除零风险,属脆弱写法。