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

dc_control.c

源文件路径:logic/dc_control.c 所属模块:logic(能量调度核心) 代码行数:2033

1. 文件职责

本文件实现 EMS 的 DC 侧(直流耦合机 / 储能一体机)功率调度计算:把当前电表功率、PV 功率、电池实时功率、逆变器各相输出与电池允许充放电上限,换算成「逆变器 DC 侧有功设定」「电池功率设定」「并网点功率设定」,写入全局结构 g_t_logic_info。它处在数据流的计算末端,上游由 logic/logic.c:2902 的 task_system_logic_control 任务经 logic_charge_dischg_power_limit() / self_use_funtion() / bat_force_charge() / bat_force_discharge() / bat_power_control() / time_peakshaving_command() 等中间层函数驱动,下游由 logic/logic.c 的 logic_read_dc_total_set_*() 访问器与 midware/inverter/parallel.c(并机 SCI 下发)取走结果。文件分两条独立链路:DC 总功率控制与 DC 三相不平衡控制,另含油机充电模式与削峰填谷。除第 19 行的全局变量外,全部代码被 #ifdef INV_DC_CTRL(第 31 行 ~ 2031 行)包裹。

2. 关键数据结构与宏

名称类型说明
g_u8_dc_disturbance_count全局变量(u8,dc_control.c:19)DC 扰动计数,0~10 饱和。定义在 #ifdef 之外,因此任何配置下都参与编译;被 midware/inverter/inverter.c:41 以 extern 引用,用于生成「多次限制无效」的位掩码判据(inverter.c:2755-2762)
INV_DC_CTRL条件编译宏来自 midware/inverter/inverter.h:176,未定义时第 31~2031 行全部不参与编译
LOGIC_CONTROL_SPECIAL_HANDLE_T结构体(logic/logic.h:240)按逆变器型号整定的调节步长表,字段:u8_speed_para1、u8_speed_para2、u8_speed_test_11、u8_speed_test_13、u8_speed_test_3112、u8_speed_test_3121_1、u8_speed_test_3121_2、u8_speed_min_der_ac_power
para_tables[]全局数组(logic/logic.c:52,长度 LOGIC_CTROL_SPECIAL_MAX_COUNT)索引为 g_t_logic_info.t_logic_control_parameter.u8_inv_type;下标 0 是通用值(speed_para1/2 = 0、test 值 50/50/30/30/30),下标 1 是 SNJ_M5 特殊值(speed_para1=1、test 值 30/30/5/2/5);u8_inv_type 由 inverter_get_special_control_inv_type()(midware/inverter/inverter.c:7985)决定,返回值只有 NOT_SPECIAL_HANDLE(0) 或 SNJ_M5_SPECIAL_HANDLE(1)
LOGIC_CTROL_SPECIAL_MAX_COUNT宏(= 2,logic/logic.h:32)para_tables[] 的长度
LOGIC_TABLE_T结构体(logic/logic.h:494)全局 g_t_logic_info 的类型;本文件写它的 s32_dc_total_set_bat_power / s32_dc_total_set_inv_power / s32_dc_total_set_grid_power(总功率侧)与 s32_dc_three_phase_set_bat_power / s32_dc_three_phase_set_inv_a/b/c_power(三相不平衡侧)
LOGIC_CONTROL_PARAMETER_T结构体(logic/logic.h:138,#pragma pack(1))全部输入源:s32_pgrid_metert/a/b/c、s32_pinvt/a/b/c、s32_pbat_inv、s16_ibat_inv、s32_bat_total_power、s32_ppv_inv、s32_pbackupt、u8_pv_status、u8_bat_status、u8_regulator_speed、u8_inv_phase_num、s32_max_feedin_power、s32_bat_charge_power_limit、s32_bat_dischg_power_limit、s32_inv_rated_output_power、s32_inv_power_fine_tuning_range、s32_bat_power_fine_tuning_range、s32_system_self_consumption、s32_system_control_accuracy、u8_disturbance_flag、u16_dc_disturbance_count、5 个 u32_calculation_*_tick
PEAKSHVING_STATE_E枚举(logic/logic.h:99)削峰填谷状态:INITIAL_IDLE=0、NO_INVERTER_POWER_STATE(=1)、POWER_REGULATION_STATE(=2)
LOGIC_CONFIG_TAB_T结构体(g_t_logic_info.t_config_data)本文件用到 GCRatedPower、GCRatePercent、GCOutputMode、GCChargePower
GC_CHARGE宏(= 1,logic/logic.h:27)油机输出模式「充电功率模式」判据
FORCE_BAT_FEEDIN_MODE枚举成员(logic/logic.h:56)u8_sequencecontrol_mode 的一种,强制电池馈网;本文件用它决定 max feedin 是否包含电池充电功率
PV_METER / PHASE_T枚举成员(midware/meter/meter.h:166、177)仅在 DEBUG_LOGIC 打印段里使用
DEBUG_LOGIC宏(= 0,logic/logic.h:17)调试打印开关

3. 函数清单

行号函数名作用域说明(一句话)
39dc_control_total_power_limit全局DC 总功率限幅:电池功率按符号钳到 ±允许充放电上限,逆变/并网设定钳到 [0, 逆变额定输出]
83dc_control_total_power_bat_force_charge全局DC 强充:电池设定 = −充电上限,逆变设定按 pgrid_metert + max_feedin + pinvt 给(上限截额定、下限截 0),并网设定 = 逆变设定 − 后备功率
120dc_control_total_power_bat_force_discharge全局DC 强放:电池设定 = 放电上限(或逆变额定),逆变/并网设定同上
170dc_control_total_power_bat_power_control全局DC 电池功率控制:逆变设定 = −s16_bat_control_power,并网设定 = 逆变设定 − 后备功率
183dc_control_total_power_self_use_calculate全局DC 自发自用主算法:按电表三区间(馈网 / 买电 / 稳定)调节电池功率,含扰动计数与「多次无效即加速回退」机制
479dc_control_total_power_no_bat_calculate全局DC 无电池:电池设定置 0,`max_feedin + pgrid_metert> 50` 时按电表修正逆变与并网设定
504dc_control_total_power_gc_chgpower_calculate全局DC 油机充电模式:在「油机可用功率 − 后备功率」的额度内调节电池充电,输出逆变设定恒为 0
750dc_control_three_phase_power_limit全局DC 三相不均衡限幅:电池功率按符号钳位,三相逆变设定统一钳到 [10, 逆变额定/相数]
818dc_control_three_phase_power_bat_force_charge全局DC 三相强充:电池设定 = −充电上限,三相设定 = 逆变额定/相数
839dc_control_three_phase_power_bat_force_discharge全局DC 三相强放:电池设定 = 放电上限;get_maxfeedin_priority_flag() 为真时三相按「各相电表 + maxfeedin/相数 + 各相逆变功率」给,否则给满
877dc_control_three_phase_power_bat_power_control全局DC 三相电池功率控制:电池设定 = −s16_bat_control_power,三相设定 = `s16_inv_control_power/ 相数`
892dc_control_three_phase_power_self_use_calculate全局DC 三相不均衡自发自用主算法(本文件最大函数,1832−892 = 940 行):A/B/C 三相各跑一套相同的扰动状态逻辑,最后统一校准与限幅
1832dc_control_three_phase_power_no_bat_calculate全局DC 三相无电池:三相设定按 各相电表 + maxfeedin/3 + 各相逆变功率 给(`和> 50` 时),电池设定置 0
1869dc_time_valley_fill_calculate全局DC 填谷:以 s32_set_valley_value 为目标做三状态滞环,按 error / u8_regulator_speed 斜坡调整电池功率并限幅
1951dc_ctrl_time_valley_fill_command全局DC 填谷命令入口:dc_time_valley_fill_calculate() + dc_control_total_power_limit()
1963dc_time_peak_clip_calculate全局DC 削峰:以 s32_set_peak_value 为上限、s32_set_delta_value 为回差给出电池与逆变设定
1987dc_ctrl_time_peak_clip_command全局DC 削峰命令入口:带 PEAKSHVING_STATE_E 双状态滞环,先限幅再计算,并做「已降到峰值以下」退出判断

共 17 个函数定义,与 logic/dc_control.h 的 17 条原型一一对应;其中 static 函数 0 个——所有内部实现都被写成全局可见。

4. 核心逻辑解析

4.1 节拍闸门与时间戳共享

除 dc_control_total_power_bat_power_control()(170)与 dc_time_peak_clip_calculate()(1963)外,所有计算函数都带同一段闸门:

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();

时间戳只有两个:

因此同一轮内先执行的函数会消耗该 tick,后续同链路的函数直接 return。logic/logic.c:2916-2920 在快调度事件 POST_PEND_FAST_ENABLE 到来时会把 u32_calculation_dc_total_inv_tick / u32_calculation_dc_total_bat_tick / u32_calculation_dc_three_phase_inv_tick 三者清 0,强制本轮立即计算。

dc_control_total_power_gc_chgpower_calculate()(504)的闸门被注释掉(dc_control.c:515-520),因此该函数每次被调用都完整执行一遍。

4.2 DC 自发自用主算法(dc_control_total_power_self_use_calculate,183)

这是本文件最核心的算法,输入取局部快照后按电表功率分三个区间。

前置计算

dc_ctrol_para_tables = &para_tables[g_t_logic_info.t_logic_control_parameter.u8_inv_type];

// max feedin 的等效值(含电池充电功率)
if (u8_sequencecontrol_mode == FORCE_BAT_FEEDIN_MODE)
    l_s32_max_feed_power = s32_max_feedin_power;                        // 强制电池馈网时不再叠加
else
    l_s32_max_feed_power = s32_max_feedin_power
        + (bat_charge_limit + bat_total_power
           - (bat_total_power < 0 ? para->u8_speed_para1 : para->u8_speed_para2)
             * abs(bat_total_power / 60));                              // 按电池功率大小做速率补偿

区间一:馈网(l_s32_meter_power_t < -50),前置 l_u8_dc_disturbance_flag = FALSE,再分三支:

  1. bat_charge_power_limit == 0(电池已满):若 |max_feed + meter| > para->u8_speed_test_11,把逆变设定直接设为 meter + max_feed + pinvt 以限制馈网;电池设定:bat_total_power > 60 时取 (0 − bat_total_power),否则固定 15W,且 bms_read_relay_status() == 1 时改为 50W。
  2. set_bat_power > -bat_charge_power_limit(电池还能充,优先充电):
    • 若 |set_bat − pbat_inv| < 30(已跟上)或距上次 u32_calculation_dc_total_bat_tick 超过 u32_calculation_interval_bat:刷新 tick;再按 g_u8_dc_disturbance_count 是否非零分流 —— 非零则 set_bat -= count * 100(扰动加速回退),为零则 set_bat += meter / speed 斜坡逼近;同时置 l_u8_dc_disturbance_flag = TRUE。
    • 否则(未跟上):仅在 u8_disturbance_flag == FALSE 时刷新 tick 并 set_bat += meter / speed。
  3. 其余(电池已达最大充电功率,需限制 PV):若 |max_feed + meter| > para->u8_speed_test_13,set_inv = meter + max_feed + pinvt。

区间二:买电(meter > s32_system_self_consumption):先无条件 set_inv = meter + max_feed + pinvt(完全放开 PV),再按「已跟上或电池节拍超时」分支:

区间三:稳定区(−50 ≤ meter ≤ 自耗):set_inv = meter + max_feed + pinvt,然后

收尾

if (l_u8_dc_disturbance_flag == TRUE) g_u8_dc_disturbance_count++ 且饱和到 10;
else                                  g_u8_dc_disturbance_count = 0;

if (|set_bat_power| < s32_system_control_accuracy) set_bat_power = 0;   // 死区
if (set_inv_power < 0)                            set_inv_power = 0;

g_t_logic_info.s32_dc_total_set_bat_power  = set_bat_power;
g_t_logic_info.s32_dc_total_set_inv_power  = set_inv_power;
g_t_logic_info.s32_dc_total_set_grid_power = set_inv_power - s32_pbackupt;

4.3 DC 三相不平衡自发自用主算法(dc_control_three_phase_power_self_use_calculate,892)

A/B/C 三相各有一整块结构完全相同的代码(A 相 982-1238、B 相 1240-1496、C 相 1498-1755),只是把变量后缀换成 a/b/c,并用 l_u32_test[0/1/2] 记录走到哪一步(调试用)。三相之间的耦合通过「其余两相」的比较实现。

公共前置量

l_s32_max_feed_power                        = s32_max_feedin_power;
l_s32_single_phase_max_feed_power           = s32_max_feedin_power / 3;
l_s32_inv_single_phase_rated_output_power   = s32_inv_rated_output_power / 3;
l_s32_single_ac_max_power                   = 单相额定 + s32_inv_power_fine_tuning_range;
l_s32_load_power_X = max(pinvX + pgrid_meterX, 0),并钳到单相额定;
l_s32_ctrl_inv_X_phase_power = g_t_logic_info.s32_dc_three_phase_set_inv_X_power;  // 以当前设定为起点
l_s32_ctrl_bat_power         = g_t_logic_info.s32_dc_three_phase_set_bat_power;

每相的三分支

统一收尾(1757-1808)

if (三相 |meter| 都 < 50)                              // 三相都进入逻辑平衡
    if (|bat_realtime - ctrl_bat| > 200) 按偏差/5 校准 ctrl_bat;

if (ctrl_bat > -50 && ctrl_bat < 0) ctrl_bat = 0;      // 充电死区

三相各钳到 [10, 单相额定];                                // 注意:最小 10W(不是 0)
写回 g_t_logic_info.s32_dc_three_phase_set_inv_a/b/c_power 与 s32_dc_three_phase_set_bat_power;

4.4 强充 / 强放 / 电池功率控制 / 无电池 / 油机

注意这里没有写 s32_dc_total_set_bat_power,与 AC 侧同名函数的行为不一致(AC 侧会同时给出充放电限值)。

4.5 限幅函数

4.6 削峰填谷

填谷 dc_time_valley_fill_calculate()(1869) 是三状态滞环:

state 0: pgrid > valley + delta → 1;  pgrid >= valley → 2
state 1: pgrid < valley         → 0;  pgrid <= valley + delta → 2
state 2: pgrid > valley + delta → 1;  pgrid < valley → 0

state 0(已在谷上方过冲): error = pgrid - (valley + delta);  // 负
state 1(已在谷内过高)  : error = pgrid - valley;            // 正
state 2(已达标)        : 不改动
last_bat_power += error / speed;

然后按符号钳到 ±充放电上限,写入 g_t_logic_info.s32_dc_total_set_bat_power,并把 s32_dc_total_set_inv_power 固定设为 5(W)。static s32 s32_last_bat_power 在声明处初始化为 0(dc_control.c:1872),而代码注释写的是「需在初始化时赋值」,二者不一致。

填谷入口 dc_ctrl_time_valley_fill_command()(1951):dc_time_valley_fill_calculate() → dc_control_total_power_limit()。

削峰 dc_time_peak_clip_calculate()(1963):

if (pgrid >= peak) {
    set_bat = (pinvt + |pgrid - peak|) * 1.1;
    set_inv = set_bat;
} else if (pgrid <= peak - delta) {
    set_bat = pinvt - |pgrid - peak| / speed;
    set_inv = set_bat;
}

削峰入口 dc_ctrl_time_peak_clip_command()(1987) 结构与 AC 侧同构:

static s8 status = INITIAL_IDLE, old_status = INITIAL_IDLE;
闸门 → dc_control_total_power_limit();            // 先限幅
pgrid < peak 且 old_status != POWER_REGULATION_STATE → NO_INVERTER_POWER_STATE
否则                                                 → POWER_REGULATION_STATE
NO_INVERTER_POWER_STATE : set_inv = 0
POWER_REGULATION_STATE  : old_status = POWER_REGULATION_STATE; dc_time_peak_clip_calculate();
                          若 (pinvt + pgrid) < peak → old_status = NO_INVERTER_POWER_STATE, set_inv = 0, set_bat = 0

注意:退出判据用的是 s32_pinvt + s32_pgrid_metert(实际量),而 AC 侧 ac_ctrl_time_peak_clip_command() 用的是 s32_ac_total_set_inv_power + s32_pgrid_metert(设定量),两侧判据不同源。

4.7 通信协议帧 / 超时重试

本文件不实现任何通信协议:不组帧、不做校验(CRC/和校验/奇偶)、不重试、不直接收发 UART/CAN/以太网/SCI。它只消费已由 midware/meter、midware/bms、midware/inverter 解析好的实时量,并产出三个/六个功率设定值。唯一的「超时」概念是 4.1 里的计算节拍超时(u32_calculation_interval / u32_calculation_interval_bat),作用是「电池功率若长时间没跟上设定值就放开扰动计数」,不是通信重试。

4.8 与 uCOS-II 任务的配合

4.9 关键全局变量的读写与触发条件

变量读/写触发条件与含义
g_t_logic_info.s32_dc_total_set_bat_power读+写电池功率设定(负为充电、正为放电,由 dc_control_total_power_limit() 的钳位方向与 ..._bat_force_charge 赋值 −充电上限 可判定)。被 39/83/120/479/504/1869/1963/1987 改写
g_t_logic_info.s32_dc_total_set_inv_power读+写逆变器 DC 侧有功设定,恒 ≥ 0(多处显式下限截 0)
g_t_logic_info.s32_dc_total_set_grid_power读+写并网点设定 = 逆变设定 − s32_pbackupt,每次写入都随 s32_dc_total_set_inv_power 一起刷新(83/120/170/183/479/504)
g_t_logic_info.s32_dc_three_phase_set_bat_power读+写三相不平衡电池设定,被 750/818/839/877/892/1832 改写
g_t_logic_info.s32_dc_three_phase_set_inv_a/b/c_power读+写三相各相有功设定;892 以当前值为起点做增量迭代,最后钳到 [10, 单相额定]
g_u8_dc_disturbance_count读+写每拍按 l_u8_dc_disturbance_flag 自增(饱和 10)或清 0;!= 0 时电池功率按 count * 100 加速回退。被 midware/inverter/inverter.c:2755-2762 读取生成位掩码
g_t_logic_info.t_logic_control_parameter.u16_dc_disturbance_count只读与 g_u8_dc_disturbance_count 同名不同物:前者来自配置/参数(logic.h:237),本文件 281/336 行用其做回退量,但它在本文件内从未被写入
g_t_logic_info.t_logic_control_parameter.u32_calculation_dc_total_inv_tick / ..._dc_total_bat_tick / ..._dc_three_phase_inv_tick读+写节拍时间戳,见 4.1
g_t_logic_info.t_logic_control_parameter.u32_calculation_dc_total_bat_tick读+写电池侧节拍,与 u32_calculation_interval_bat 配合判定「设置值末跟上实际值」
g_t_logic_info.s16_bat_control_power / s16_inv_control_power只读上位指令的下发功率,仅在 170/877 使用

5. 对外接口

导出的函数与全局变量(供谁调用):

导出符号调用方
g_u8_dc_disturbance_count(u8 全局变量)midware/inverter/inverter.c:41(extern)、inverter.c:2755、inverter.c:2757、inverter.c:2762
dc_control_total_power_limit()logic/logic.c:1745、logic/dc_control.c:1954、logic/dc_control.c:1998
dc_control_total_power_bat_force_charge()logic/logic.c:1764
dc_control_total_power_bat_force_discharge()logic/logic.c:1785
dc_control_total_power_bat_power_control()logic/logic.c:1806
dc_control_total_power_self_use_calculate()logic/logic.c:1857
dc_control_total_power_no_bat_calculate()logic/logic.c:2026
dc_control_total_power_gc_chgpower_calculate()logic/logic.c:2100
dc_control_three_phase_power_limit()logic/logic.c:1746
dc_control_three_phase_power_bat_force_charge()logic/logic.c:1765
dc_control_three_phase_power_bat_force_discharge()logic/logic.c:1786
dc_control_three_phase_power_bat_power_control()logic/logic.c:1807
dc_control_three_phase_power_self_use_calculate()logic/logic.c:1858
dc_control_three_phase_power_no_bat_calculate()logic/logic.c:2027
dc_ctrl_time_peak_clip_command()logic/logic.c:558
dc_ctrl_time_valley_fill_command()logic/logic.c:567
dc_time_valley_fill_calculate()无外部调用(仅 dc_control.c:1953)
dc_time_peak_clip_calculate()无外部调用(仅 dc_control.c:2016)

本文件不导出结构体/枚举(全部来自 logic/logic.h)。

本文件调用的外部函数/变量:

名称来源模块
g_t_logic_info / para_tables[]logic/logic.h:646-647,定义于 logic/logic.c:36、logic/logic.c:52
bms_read_relay_status()midware/bms/bms.h:1185(dc_control.c:263,仅用于电池满后 15W/50W 判别)
get_maxfeedin_priority_flag()logic/logic.h:708(dc_control.c:849)
meter_read_actpower(PV_METER, PHASE_T)midware/meter/meter.h:471(仅 dc_control.c:1868,计算 l_s32_pv_power_t)
inverter_read_pv_volt() / inverter_read_bus_volt() / inverter_read_bat_volt() / inverter_read_grid_actpower()midware/inverter/inverter.h(仅 DEBUG_LOGIC 打印段 dc_control.c:733-734)
OSTimeGet() / abs() / printf()uCOS-II / C 标准库 / 调试串口

6. 依赖关系

依赖(include 与使用时):

被依赖(谁 include / 调用它):

7. 备注与风险点

  1. 当前构建配置下第 31~2031 行全部不参与编译:INVERTER_TYPE 硬编码为 INVERTER_NULL(midware/inverter/inverter.h:172),INV_DC_CTRL 未定义;Keil 工程 user/EMS_3.0.uvprojx 的 <Define> 只有 USE_STDPERIPH_DRIVER, GD32F407。该文件只在「DC 控机型」配置下生效,静态审查时容易误判其有效性;唯一在任何配置下都有效的是第 19 行的 g_u8_dc_disturbance_count。
  1. dc_control_total_power_bat_power_control() 存在死存储(dc_control.c:172-173):
       g_t_logic_info.s32_dc_total_set_inv_power = abs(g_t_logic_info.s16_inv_control_power);
       g_t_logic_info.s32_dc_total_set_inv_power = -g_t_logic_info.s16_bat_control_power;   // 立即覆盖

第一行是残留代码,无任何效果。此外本函数既不写 s32_dc_total_set_bat_power 也不做符号判据,与 AC 侧 ac_control_total_power_bat_power_control() 的行为(区分充放电、给限值)明显不对称。

  1. dc_control_total_power_limit() 把并网设定钳到非负(dc_control.c:64-74):s32_dc_total_set_grid_power = 逆变设定 − s32_pbackupt,当后备功率大于逆变设定(常见于夜间备电)时该值为负,但限幅函数会把它钳到 0,语义上等于「不允许反向并网」。若后续模块依赖该字段表达取电方向,会丢失信息。
  1. 三相不平衡的 A 相与 B/C 相判据不一致(dc_control.c:992 vs 1250 vs 1508):
       A 相:if (l_s32_single_phase_max_feed_power + l_s32_meter_power_a < -50)
       B 相:if (l_s32_single_phase_max_feed_power + l_s32_meter_power_b < 0)
       C 相:if (l_s32_single_phase_max_feed_power + l_s32_meter_power_c < 0)

三相比对同一物理量使用了不同阈值,会导致「同样工况下 A 相走 max-feedin 限制分支、B/C 相走放开馈网分支」的三相不对称行为,是大概率的手写复制遗漏。

  1. 对 logic/ac_control.c 的隐含链接依赖(当前未触发):本文件通过 logic/logic.h / para_tables 与 AC 侧耦合,而 three_unbalance_power_inv_single_phase_full_cnt() 这类共用辅助函数定义在 logic/ac_control.c:1123 且被 INV_AC_CTRL 包裹 —— 若将来 dc_control.c 复用 AC 侧函数,而编译配置只开了 INV_DC_CTRL 未开 INV_AC_CTRL,会直接链接失败。本文件当前未调用任何 AC 侧函数,是安全的;dc_control.c:849 调用的 get_maxfeedin_priority_flag() 定义在 logic/logic.c(不在任何条件编译内),也是安全的。
  1. s32_bat_total_power 与 s32_pbat_inv 的符号约定混用:s32_bat_total_power 来自 parallel_read_system_bat_power() → bms_read_total_power()(midware/bms/bms.c:3475,由 BMS 电压 × 电流得到),而 s32_pbat_inv 来自逆变器采集。代码在同一个 if 里混用两者(如 dc_control.c:270 用 l_s32_dc_total_set_bat_power 与 l_s32_bat_charge_power_limit 比较、dc_control.c:274 与 l_s32_pbat_inv 比较;dc_control.c:1104、1362、1621 用 charge_limit + bat_total_power > 100)。若两个来源的「充电为正/为负」约定不同,这些判据会在某些工况下反向。文件中没有任何注释说明换算关系,属跨模块隐含约定风险。
  1. 两套扰动计数器语义重复:文件全局 g_u8_dc_disturbance_count(19 行,被 inverter.c 使用)与 dc_control_total_power_gc_chgpower_calculate() 内 static 的 s_u8_dc_disturbance_count(513 行)是两个独立变量,而 u16_dc_disturbance_count(g_t_logic_info,logic.h:237)又被 281/336 行当作回退量读取却在本文件内从不写入。三个同义字段并存,极易出现「计数在涨但回退量恒为 0」的静默失效。
  1. 注释与代码矛盾的电池功率赋值(dc_control.c:244、261、265,以及 dc_control.c:547、556):注释写「电池充满后,控制电池功率归零」,代码却在电池仍充电(bat_total_power > 60)时赋 charge_limit − bat_total_power(充电上限为 0 时为负值),否则赋固定 +15W / +50W(正为放电)。这意味着「电池充满」时反而下发一个小功率放电指令,仅靠上层 dc_control_total_power_limit() 把负值钳成 0 来兜底。语义可疑,需现场波形确认是否为有意为之。
  1. dc_control_total_power_gc_chgpower_calculate() 的节拍闸门被注释掉(dc_control.c:515-520):该函数每次调用都会完整执行,且它会读 s_s32_... / 静态扰动计数,其执行频次完全取决于调用方(logic/logic.c:2100 的油机分支)的调用次数,与其它 DC 函数的节拍控制方式不一致。
  1. dc_time_peak_clip_calculate() 使用浮点字面量(dc_control.c:1968):(pinvt + |pgrid − peak|) * 1.1 在 s32 表达式中引入 double,在 GD32F407(Cortex-M4F,单精度 FPU)上会走软双精度路径,既增加耗时又会对结果做隐式截断。工程内其它地方一律用整数比例,此处是唯一的浮点混用。
  1. dc_time_valley_fill_calculate() 的 magic number 与初值:g_t_logic_info.s32_dc_total_set_inv_power = 5;(dc_control.c:1941)没有注释也没有宏;static s32 s32_last_bat_power = 0;(dc_control.c:1872)带的注释是「需在初始化时赋值」,但代码并未在任何初始化流程里赋值,属遗留 TODO。
  1. dc_control_three_phase_power_limit() 的不可达分支(dc_control.c:763-809):对每一相都是 if (< 10) → 10; else if (> 单相额定) → 单相额定; else if (< 0) → 0;。第一个 if 已经把所有权值 < 10(含负数)的输入改成 10,因此第三个 else if (< 0) 永远不可达。属复制粘贴残留,无功能影响但显示限幅顺序的意图与实现不符(若要「先钳负为 0 再抬到 10」应把 < 0 判据前置)。
  1. 三相不平衡主算法以「当前设定值」为迭代起点(dc_control.c:977-980):l_s32_ctrl_inv_X_phase_power = g_t_logic_info.s32_dc_three_phase_set_inv_X_power;。由于 logic.c 之后还会跑 dnsp_ramp_dc_control_handle() 等改写流程,这个「起点」可能已经被上一级改过,形成两级闭环叠加,调参时难以归因。
  1. u8_regulator_speed 直接做除数且从不校验是否为 0:全文共有 53 处引用该字段(Grep 统计),其中约 48 处形如 ... / l_u8_regulator_speed(如 dc_control.c:287、296、353、359、366、375、575、621、627、634、1000、1022、1047、1073、1107、1111、1142、1150、1167、1173、1179、1180、1258、1281、1305、1331、1365、1369、1400、1408、1425、1431、1437、1438、1516、1540、1564、1590、1624、1628、1659、1667、1684、1690、1697 等)。该值由逆变器特性整定(在 logic/logic.c 按型号赋值),本文件没有任何 0 值保护。一旦型号未识别或配置缺失导致该值为 0,会产生除零(Cortex-M4 上表现为除零陷阱或未定义结果,取决于编译选项与 SCB->CCR.DIV_0_TRP)。
  1. dc_control_total_power_self_use_calculate() 中 dc_ctrol_para_tables 的变量名拼写错误(dc_control.c:205,ctrol 应为 control)且索引 u8_inv_type 无边界校验。当前 inverter_get_special_control_inv_type() 只返回 0/1,para_tables[2] 不会越界;但一旦增加型号,索引就越界读。
  1. 调试痕迹:dc_control.c:730 与 dc_control.c:1810 各有 l_u16_test = l_u16_test; / l_u32_test[0] = l_u32_test[0]; 的自赋值(压制未使用告警);dc_control.c:1116 的三相不平衡主算法用 l_u32_test[3] 记录了多达 6 层嵌套的条件路径号,仅在 DEBUG_LOGIC 下打印,属「用变量记录执行路径」的调试手法,正式代码里保留会误导阅读。
  1. dc_control_total_power_bat_force_discharge() 中 s32_bat_total_power 与 s32_ppv_inv 相关注释被注释掉(dc_control.c:133、141-144):// - g_t_logic_info.t_logic_control_parameter.s32_ppv_inv 与 // if (set_bat < 0) set_bat = 0; 两处被注释,说明该处语义曾多次改动;当前实现允许 set_bat 为负(即强放模式下反而给充电设定),依赖 dc_control_total_power_limit() 兜底。
  1. dc_control_three_phase_power_self_use_calculate() 单函数 940 行、三层深嵌套、A/B/C 三段近乎复制:任一处修改都需要同步改三遍,本文件已出现第 4 点所述的不一致。这是本文件最大的可维护性风险。