self_test.c
system_self_test_data()(:54)4.3 判定算法:system_self_test_result()(:107)4.4 与 uCOS-II 任务/事件标志的配合4.5 关键全局变量的读写4.6 编码与协议5. 对外接口6. 依赖关系7. 备注与风险点源文件路径:
logic/self_test.c所属模块:logic(能量调度核心 —— 电网/PV 电表接线自检) 代码行数:369
1. 文件职责
本文件实现 EMS 的「安装接线自检」功能:由 logic 任务在 g_t_logic_info.u8_sequencecontrol_mode == SELF_TEST_CHARGE_MODE 时每个控制周期调用一次 system_self_test()(调用点 logic/logic.c:2306),驱动一个八态状态机(待机 → 充电 → 放电,每阶段各含"静置"与"采样"两个子态)。每个静置态持续 10 秒让功率稳定,每个采样态以 500 ms 间隔连续采集电网电表、PV 电表、逆变器三相功率各 5 次,用 EWMA(EWMA_ALPHA = 0.5)求出每相均值,存入 g_t_self_test。全部三阶段数据齐备后,system_self_test_result() 比较「充电/放电时电网电表功率是否按逆变器功率反向变化」来判定电网电表断线、接线错位,以及 PV 电表接错相,结果写入 g_t_logic_info.u_self_test_result 位域;失败时最多自动重测 2 次,随后清除自检使能并置位 SELF_TEST_RESULT 信息位通知网络层上报。它处于数据流的末端判定环节:上游是被强制设定的 g_t_logic_info.t_logic_control_parameter 充电/放电限值与 bat_force_charge()/bat_force_discharge(),下游是云端上报报文。
2. 关键数据结构与宏
本文件不定义任何新类型,全部复用 logic/self_test.h 与 logic/logic.h 的定义。
| 名称 | 类型 | 说明 |
|---|---|---|
SELF_RUN_TABLE_T / g_t_self_test | 结构体 / 全局变量 | 自检运行表实例,定义于本文件 :25(= {0}),承载状态机状态与三阶段采样/均值缓存 |
SELF_STATE | 枚举 | 状态机状态:SELF_STATE_START/STANDING/STANDING_RECORD/CHARGE/CHARGE_RECORD/DISCHARGE/DISCHARGE_RECORD/END |
SAMPLE_COUNT | 宏 | 5,每阶段采样次数,即 *_power_samples 第二维长度 |
EWMA_ALPHA | 宏 | 0.5,EWMA 系数,作为 alpha 传入 calculate_dynamic_compensation() |
SELF_TEST_RESULT_U / u_self_test_result | 联合体(位域) | 定义于 logic/logic.h:466-492,位于 g_t_logic_info 内。位定义:bit0-2 = u8_grid_meter_l1/l2/l3_loss(电表断线)、bit3-5 = u8_grid_meter_l1/l2/l3_location_err(电表接反)、bit6-8 = u8_pv_meter_l1/l2/l3_location_err(PV 表位置错)、bit9 = u8_other_reason、bit10-15 保留 |
SELF_TEST_RESULT | 宏(枚举成员) | net/ems.h:265,值 0x10000,ENInfoType 的一个信息位 |
SAMPLE_COUNT = 5 对应数组 s32_*_samples[4][5] / [3][5] | — | 电网侧 4 通道(A/B/C/总),PV 与逆变器侧 3 通道 |
PHASE_A / PHASE_B / PHASE_C / PHASE_T / PHASE_ALL | 宏 | 电表/逆变器读取接口的相选择参数 |
GRID_METER / PV_METER | 宏 | 电表实例选择参数 |
METER_SAMPLING | 枚举 | midware/meter/meter.h:184,meter_get_meter_or_ct() 的返回值之一,表示该路是 CT 采样而非真实电表 |
TRUE / FALSE | 宏 | 布尔常量,来自 includes.h |
3. 函数清单
| 函数名 | 作用域 | 说明 |
|---|---|---|
calculate_dynamic_compensation | 全局(无原型声明) | 对 count 个采样做系数 alpha 的 EWMA 迭代,返回均值(截断为 s32) |
system_self_test_data | 全局(无原型声明) | 按 500 ms 间隔采样 5 次并回填三相均值到传入的 offset 数组;采满返回 TRUE |
system_self_test_result | 全局(无原型声明) | 依据三阶段均值判定电表断线/接反/PV 位置错,写 u_self_test_result 并返回判定结论 |
system_self_test | 全局(原型在 logic/logic.h:699) | 自检状态机主入口,每控制周期调用一次,推进八态流转 |
共 4 个函数,全部为全局作用域;本文件没有任何 static 函数,也没有函数指针、回调或 static inline。
4. 核心逻辑解析
4.1 状态机与迁移条件
system_self_test()(:240)用 g_t_self_test.self_state_flag 做 switch(:247),两个 static 变量 s_u8_self_test_countr(:242)与 s_s32_self_test_tick(:243)保存重试次数与阶段计时基准。迁移图如下:
| 当前状态 | 动作 | 迁移条件 | 目标状态 |
|---|---|---|---|
SELF_STATE_START | memset(&g_t_self_test,0,...) 整表清零;u_self_test_result.u16_all = 0x0000;记录 s_s32_self_test_tick | 无条件 | SELF_STATE_STANDING |
SELF_STATE_STANDING | 清零充/放功率限值、清 u8_ac_total_set_bat_forced_charge_en;#ifdef INV_DC_CTRL 下再清 s32_pgrid_metert/s32_pinvt/s32_max_feedin_power 并 bat_force_charge();#ifdef INV_AC_CTRL 下清 s32_ac_total_set_inv_power | abs(OSTimeGet()-tick) > 10*1000(10 秒静置) | SELF_STATE_STANDING_RECORD |
SELF_STATE_STANDING_RECORD | #ifdef INV_AC_CTRL 下再次清零限值与 AC 设定功率;调 system_self_test_data(offset1...) | system_self_test_data() 返回 TRUE(采满 5 点) | SELF_STATE_CHARGE |
SELF_STATE_CHARGE | s32_pgrid_metert = -s32_pinvt;s32_max_feedin_power = 0;bat_force_charge() | 静置 10 秒 | SELF_STATE_CHARGE_RECORD |
SELF_STATE_CHARGE_RECORD | 调 system_self_test_data(offset2...) | 返回 TRUE | SELF_STATE_DISCHARGE |
SELF_STATE_DISCHARGE | s32_pgrid_metert = 0、s32_pinvt = 0、充电限值 = 0、s32_bat_dischg_power_limit = parallel_read_system_max_dischg_power_limit()、s32_max_feedin_power = s32_inv_rated_output_power;bat_force_discharge() | 静置 10 秒 | SELF_STATE_DISCHARGE_RECORD |
SELF_STATE_DISCHARGE_RECORD | 调 system_self_test_data(offset3...) | 返回 TRUE | SELF_STATE_END |
SELF_STATE_END | 若 system_self_test_result() != TRUE 且 s_u8_self_test_countr < 2 则重试计数 +1;否则清零计数、u8_self_test_enable = FALSE、set_info_status(SELF_TEST_RESULT) | 无条件(同一周期内) | SELF_STATE_START |
default | 空操作 | — | — |
关键语义:SELF_STATE_END 会把状态直接写回 START,而 START 又会 memset 整表。因此只要 system_self_test_result() 返回 FALSE,就会立即从零重跑整套三阶段流程,最多重跑 2 次(共 3 轮)。TRUE 的含义是"本次判定结论明确、无需重试",而不是"接线正确"——u_other_reason 单独置位时也返回 TRUE(见 4.4)。
三个静置态(STANDING/CHARGE/DISCHARGE)都带有一处时钟回绕保护:else if(s_s32_self_test_tick > OSTimeGet()) 时把基准对齐到当前 tick(:277、:308、:337)。
4.2 采样算法:system_self_test_data()(:54)
static u8 s_u8_record_countr = 0; // 阶段内已采点数
static s32 s_s32_self_test_tick = 0; // 上次采点时刻
if (s_u8_record_countr < SAMPLE_COUNT) {
if (abs(OSTimeGet() - s_s32_self_test_tick) > 500) { // 500 ms 间隔
grid_power_samples[0..3][countr] = meter_read_actpower(GRID_METER, PHASE_A/B/C/T);
pv_power_samples[0..2][countr] = meter_read_actpower(PV_METER, PHASE_A/B/C);
inv_power_samples[0..2][countr] = g_t_logic_info.t_logic_control_parameter.s32_pinva/b/c;
tick = OSTimeGet(); countr++;
} else if (tick > OSTimeGet()) tick = OSTimeGet(); // 回绕保护
} else {
ppv_meter_offset[0..2] = calculate_dynamic_compensation(pv_power_samples[i], SAMPLE_COUNT, EWMA_ALPHA);
pgrid_meter_offset[0..3]= calculate_dynamic_compensation(grid_power_samples[i], SAMPLE_COUNT, EWMA_ALPHA);
pinv_offset[0..2] = calculate_dynamic_compensation(inv_power_samples[i], SAMPLE_COUNT, EWMA_ALPHA);
s_u8_record_countr = 0;
s_s32_self_test_tick = OSTimeGet();
return TRUE;
}
return FALSE;
要点:
- 逆变器侧不读设备,直接取
g_t_logic_info.t_logic_control_parameter的s32_pinva/b/c(由其它任务刷新)。 - 电网电表多采一路
PHASE_T(总功率),对应pgrid_meter_offset[3];PV 与逆变器只有 3 相。 - 采满后只回填 offset 数组,不清零 samples 数组;清零由三个静置态的
memset负责(:272-274、:303-305、:332-334)。 s_u8_record_countr与s_s32_self_test_tick是函数级static,与状态机状态解耦,因此SELF_STATE_START的memset(&g_t_self_test,...)不会重置它们——若上一轮在采样中途被打断,计数与时刻会延续到下一轮。
EWMA 公式(calculate_dynamic_compensation,:37):
ewma = samples[0];
for (i = 1; i < count; i++) ewma = alpha * samples[i] + (1 - alpha) * ewma;
return ewma; // float 隐式截断为 s32
alpha = 0.5 时,5 个点的权重依次为 0.0625 / 0.0625 / 0.125 / 0.25 / 0.5,即越新的点权重越高(第 i 点与第 i-1 点权重相同,因为 samples[0] 与 samples[1] 都只被"半衰"一次)。返回时直接把 float 赋给 s32 返回值,未做四舍五入,负数向零截断。
4.3 判定算法:system_self_test_result()(:107)
先判系统相数(:109):inverter_get_phase_number() == 3 || meter_get_meter_or_ct(GRID_METER) != METER_SAMPLING 走三相分支,否则走单相分支。
三相分支,对 L1/L2/L3(i = 0/1/2)各自独立判定:
| 条件 | 判定 | 写入位 |
|---|---|---|
pinv_offset2[i] < -100(充电时逆变器功率为负)且 abs(pgrid_offset2[i] - pgrid_offset1[i]) < 100(电网表读数几乎不变)且 pinv_offset3[i] > 100(放电)且 abs(pgrid_offset3[i] - pgrid_offset1[i]) < 100 | 充放电时电网表都不动 → 电表断线 | u8_grid_meter_l{1,2,3}_loss = 1 |
abs(pgrid_offset2[i] - (pgrid_offset1[i] - pinv_offset2[i])) > 300 或 abs(pgrid_offset3[i] - (pgrid_offset1[i] - pinv_offset3[i])) > 300 | 电网表变化量与逆变器功率不符 → 电表接反/位置错 | u8_grid_meter_l{1,2,3}_location_err = 1 |
| 其余 | 无故障 | 三个位清 0(含 u8_other_reason = 0) |
随后(:177)若两个充放阶段的三相逆变器功率都接近 0(abs(pinv_offset2[k]) < 100 三相全满足,或 pinv_offset3[k] 三相全满足),说明"三相均未充或均未放",直接 u16_all = 0x200(即 u8_other_reason = 1)。
单相分支(:184):
| 条件 | 判定 | 写入 |
|---|---|---|
abs(pinv_offset2[0]) < 100 或 abs(pinv_offset3[0]) < 100 | 未充或未放 | u16_all = 0x200(other_reason) |
pinv_offset2[0] < -100 且三路电网表读数与 offset1 差值都 < 100,且 pinv_offset3[0] > 100 且三路差值都 < 100 | 充放电时电网表都不动 | u16_all = 0x007(L1/L2/L3 loss 全置位)→ 电表断线 |
abs(pgrid_offset2[3] - (pgrid_offset1[3] - pinv_offset2[0])) > 300 或 abs(pgrid_offset3[3] - (pgrid_offset1[3] - pinv_offset3[0])) > 300 | 总功率变化量与逆变器功率不符 | u16_all = 0x038(L1/L2/L3 location_err 全置位)→ 电表接反 |
| 其余 | 无故障 | u16_all = 0x000 |
单相分支用总功率通道 [3] 做主判据,而三相分支用各相通道 [i],这是两分支的核心差异。
最后 PV 位置检查(:211-222),与相数无关,任一路充电/放电阶段的 PV 均值绝对值 > 200 就置位:
abs(ppv_offset1[0]) > 200 || abs(ppv_offset2[0]) > 200 || abs(ppv_offset3[0]) > 200→u8_pv_meter_l1_location_err = 1- L2、L3 同理(索引
[1]、[2])
返回值(:224):
if ((u16_all != FALSE) && (u8_other_reason != TRUE)) return FALSE; // 有明确故障 → 重测
else return TRUE; // 无故障,或仅 other_reason
4.4 与 uCOS-II 任务/事件标志的配合
本文件不创建任务、不挂起/恢复任务、不使用信号量或消息邮箱,全部计时靠 OSTimeGet()(轮询式)。ucOS-II 侧依赖只有两点:
OS_TICKS_PER_SEC = 1000(UCOSII/uCOS-CONFIG/os_cfg.h:51),故所有OSTimeGet()差值的单位是毫秒,500即 500 ms,10*1000即 10 s。- 调用者
logic任务(logic/logic.c:2912用OSFlagPend(g_t_fast_dispatch_flag, POST_PEND_FAST_ENABLE, ..., 20, &err)做 20 tick 周期等待)以约 20 ms 的节拍轮询system_self_test()。因此一个静置态的 10 秒约等于 500 个控制周期,采样态的 5 个点需要 5 个周期命中 500 ms 门槛。
自检使能与结果的下行/上行通路(共 5 段,中间经过 u8_self_test_charge 转接):
- 云端下行:
net/server.c:2132-2141的handle_server_sys_self_test_command()从Parameter1解析出 0/1 写入g_t_logic_info.u8_self_test_enable。 - 并机模块加工(含 150 秒看门狗):
midware/inverter/parallel.c:1758-1788的parallel_read_system_self_test_flag()——- 离网时强制
u8_self_test_enable = FALSE(:1762-1765); - 该位变化时切换
inverter_set_p_v_mode_down_load_flag()/inverter_set_p_f_mode_down_load_flag()(取反)并把u16_mppt_percentage设为enable ? 0 : 10000(:1767-1776); abs(OSTimeGet() - s_s32_self_test_tick) >= 150*1000(150 秒)时无条件清u8_self_test_enable(:1778-1780)——这是整个自检流程的硬性时间上限;- 返回该位。
- 离网时强制
- 转接与模式判定:
logic/logic.c:1144把返回值存进u8_self_test_charge;logic/logic.c:2201-2204判断u8_self_test_charge != FALSE时置u8_sequencecontrol_mode = SELF_TEST_CHARGE_MODE。 - 调用本文件:
logic/logic.c:2305-2306的case SELF_TEST_CHARGE_MODE:调system_self_test()。 - 结束上报:本文件
:359-360清u8_self_test_enable并set_info_status(SELF_TEST_RESULT)(net/ems.c:2722定义),由net/ems.c:2608、net/ems.c:4951的get_info_status() & SELF_TEST_RESULT触发上报。
时间预算估算:单轮自检约需 10+2(待机静置+采样)+ 10+2(充电)+ 10+2(放电)≈ 36-40 秒;SELF_STATE_END 失败时最多重跑 2 次,三轮约 110 秒,仍落在 parallel.c 的 150 秒看门狗之内,但余量不大。
4.5 关键全局变量的读写
| 变量 | 读写方向 | 位置 |
|---|---|---|
g_t_self_test(本文件定义) | 全程读写,状态机与缓存 | :25 定义;:62-73、:82-91、:112-221、:247-362 |
g_t_logic_info.t_logic_control_parameter.s32_bat_charge_power_limit / s32_bat_dischg_power_limit | 写(自检期间强制覆盖) | :257-258、:285-286、:325-326 |
g_t_logic_info.t_logic_control_parameter.s32_pgrid_metert / s32_pinvt / s32_max_feedin_power | 写 | :261-263、:298-299、:323-324、:327 |
g_t_logic_info.t_logic_control_parameter.s32_inv_rated_output_power / s32_inv_rated_input_power | 写(每次调用都从并机模块刷新) | :244-245 |
g_t_logic_info.s32_ac_total_set_inv_power | 写(#ifdef INV_AC_CTRL) | :267、:288 |
g_t_logic_info.u8_ac_total_set_bat_forced_charge_en | 写 0 | :259、:287 |
g_t_logic_info.u_self_test_result | 写(位域) | :115-221 |
g_t_logic_info.u8_self_test_enable | 写 FALSE(结束自检) | :359 |
bat_force_charge() / bat_force_discharge() | 调用 | :264、:300、:328 |
4.6 编码与协议
本文件不实现任何通信协议,不涉及帧格式、校验或超时重传;唯一对外"协议"是 set_info_status(SELF_TEST_RESULT) 这一信息位(0x10000)与云端上报的布尔约定。
5. 对外接口
导出(供外部使用):
| 名称 | 类型 | 使用方 |
|---|---|---|
system_self_test | 全局函数 | logic/logic.c:2306(case SELF_TEST_CHARGE_MODE:),原型在 logic/logic.h:699 |
g_t_self_test | 全局变量 | 仅本文件使用;extern 声明在 logic/self_test.h:50 |
calculate_dynamic_compensation | 全局函数 | 仅本文件内 10 处调用;无原型声明 |
system_self_test_data | 全局函数 | 仅本文件内 3 处调用;无原型声明 |
system_self_test_result | 全局函数 | 仅本文件内 1 处调用;无原型声明 |
被调用(本文件引用的外部符号):
| 符号 | 来源模块 |
|---|---|
OSTimeGet | UCOSII/uCOS-II |
meter_read_actpower、meter_get_meter_or_ct、GRID_METER、PV_METER、PHASE_A/B/C/T、METER_SAMPLING | midware/meter/meter.h、midware/meter/ct.h |
inverter_get_phase_number | midware/inverter/inverter.h:1966 |
parallel_read_system_rated_output_power、parallel_read_system_rated_input_power、parallel_read_system_max_dischg_power_limit | midware/inverter/parallel.h:272/302 等 |
bat_force_charge、bat_force_discharge | logic/logic.h:653-654,实现在 logic/logic.c:1761/1782 |
set_info_status、SELF_TEST_RESULT | net/ems.h:513、net/ems.h:265 |
g_t_logic_info | logic/logic.h:646 |
abs、memset | C 运行库 / includes.h |
TRUE、FALSE | includes.h |
6. 依赖关系
依赖(self_test.c:13-20):inverter.h、ct.h、logic.h、server.h、meter.h、bms.h、self_test.h、ems.h。
被依赖:
logic/logic.c:2306调用system_self_test()(原型来自logic/logic.h:699)。- 无其他文件 include
logic/self_test.h;g_t_self_test未被外部访问。
7. 备注与风险点
u16_all = 0x200会清掉同一轮里刚置位的故障位::177-181(三相)与:185-188(单相)直接整体赋值u16_all,这会覆盖:112-175刚写入的u8_grid_meter_l*_loss/_location_err位。即"电表断线且逆变器同时未充放"时,断线结论被other_reason吞掉。单相分支的0x007/0x038/0x000赋值同理,因为它们是else if链,不会与本轮前面置位冲突——只有三相分支的:177是无条件覆盖。- PV 位置错误位只置位、从不清零:
:211-222的三个if只在条件成立时写 1,没有 else 分支写 0。u16_all = 0x0000只在SELF_STATE_START(:252)执行一次,因此 PV 位一旦置位会一直保持到下一轮SELF_STATE_START。若某次system_self_test_result()因FALSE触发重测,重测期间 PV 位仍为 1(START会清),但在同一轮内多次调用system_self_test_result()(例如END之后又回到END)不会清零。 system_self_test_result()的返回值语义与函数名不符:注释写"检查电网电表接线",实际返回TRUE表示"结论明确"(含other_reason这种"根本没充放电、测不出来"的情况),返回FALSE才触发重测。按END分支:352的用法可以反推,但仅看函数名极易误读。建议改名或补注释。s_s32_self_test_tick用s32承载OSTimeGet()的u32::57、:243两处(system_self_test_data与本函数各一个)。abs(OSTimeGet() - (u32)s_s32_self_test_tick)在 tick 超过 2^31 ms(约 24.9 天)后会符号翻转,此后abs()的比较行为不可预期。工程里带有else if(tick > OSTimeGet())的回绕保护,但那只处理 tick 回绕,不处理这个有符号截断。system_self_test_data()的static计数与状态机的memset不同步:SELF_STATE_START的memset(&g_t_self_test, 0, sizeof(g_t_self_test))(:250)不会清s_u8_record_countr/s_s32_self_test_tick(它们是函数内static)。若在采样态被外部打断后重新开始,采样计数会从上次的中间值继续,可能出现"少采几个点就回填均值"的情况。建议把计数纳入SELF_RUN_TABLE_T。- 大量魔法数字:
500(采样间隔 ms)、10*1000(静置时长 ms)、100(充放电功率有效阈值 W)、300(功率变化一致性阈值 W)、200(PV 有值阈值 W)、0x007/0x038/0x200(u16_all直写值)、2(重试上限)。这些阈值分散在代码里,没有宏定义或注释说明标定依据(尤其100与300两个不同量级的判据基于什么功率基准,代码里看不出来)。0x007/0x038/0x200直接按位域布局硬编码,一旦SELF_TEST_RESULT_U的位序调整就会静默失配。 #ifdef INV_DC_CTRL/#ifdef INV_AC_CTRL在同一状态机里混合:SELF_STATE_STANDING(:256-268)与SELF_STATE_STANDING_RECORD(:283-289)都按编译开关做不同清理,但SELF_STATE_CHARGE/DISCHARGE完全走 DC 侧字段(s32_pgrid_metert、s32_max_feedin_power)而没有 AC 分支。若目标机型只定义INV_AC_CTRL,SELF_STATE_CHARGE的s32_pgrid_metert = -s32_pinvt写的是未被使用的字段,自检可能无效。calculate_dynamic_compensation用float参与中值计算::39-44混合float与s32,在 GD32F407(Cortex-M4F)上会引入软/硬浮点差异;返回值直接截断不四舍五入。同时alpha无范围校验,count无上界校验(依赖调用方恒传SAMPLE_COUNT)。DEBUG_HMI未被使用:logic/self_test.h:15定义的调试开关在本文件里没有任何#if DEBUG_HMI,属版本遗留。- 文件头与函数头注释复制错误:
:2的@file与函数头注释把system_self_test_data的名字与"检查电网电表接线"的说明重复贴给了system_self_test_result(:101-105与:48-52内容相同),且@Parameter全为空。另外logic/self_test.h与本文件是 GBK→UTF-8 有损转换的产物,部分中文注释已成 U+FFFD 乱码(见logic/self_test.h.md备注 1),本文件:16附近的中文注释同样存在该问题。 system_self_test_data回填 offset 时不清零 samples::82-91只写 offset,下一阶段由静置态的memset清 samples。这意味着三个memset(:272-274、:303-305、:332-334)如果与采样态的执行顺序被打乱(例如s_u8_record_countr未归零,见风险 5),会用上一阶段的残留数据算均值。- 自检有 150 秒硬性超时,且超时后不置任何结果位:
midware/inverter/parallel.c:1778-1780在abs(OSTimeGet() - s_s32_self_test_tick) >= 150*1000时无条件把g_t_logic_info.u8_self_test_enable清 0。这会让logic.c:2201的u8_self_test_charge变为 0,u8_sequencecontrol_mode随即离开SELF_TEST_CHARGE_MODE,system_self_test()不再被调用——状态机被冻结在当时的self_state_flag上,既不会走SELF_STATE_END,也不会set_info_status(SELF_TEST_RESULT)。也就是说超时情况下云端永远收不到自检结论。三轮重测的理论耗时约 110 秒(见 4.4),与 150 秒上限的余量只有约 40 秒,任何一次采样被 20 ms 周期节拍拉长(例如某周期恰好错过 500 ms 门槛,需再等 20 ms)都会累积推迟。建议要么放宽上限、要么在超时路径上补一个失败结论。 SELF_STATE_END的重试会重跑整轮而不仅仅是失败阶段::362在END里无条件把状态写回SELF_STATE_START,而START会memset整表并进入SELF_STATE_STANDING,于是 10 秒静置 + 充电 + 放电三阶段全部重来。若失败原因与"哪一阶段"无关(例如环境功率波动),重测的收益有限,却额外消耗 36 秒以上,与风险 12 的 150 秒上限形成相互挤压。- 自检期间会覆盖逆变器自身的降载能力:
parallel.c:1770-1773在自检使能时调用inverter_set_p_v_mode_down_load_flag(FALSE)/inverter_set_p_f_mode_down_load_flag(FALSE)(关闭逆变器 P-V / P-F 降载)并把u16_mppt_percentage设为 0。也就是说自检期间逆变器失去自身的电压/频率保护降载,且 PV 停止发电。本文件对此并不知情,但dispatch.c:514-520采用同样的做法(调频时关闭降载),两处都会关闭同一组保护,需注意叠加效应。