🔧

二次谐波制动 · 模块重构分析

Protect_SecondHarBrake — 配电保护逻辑模块深度重构方案
🔴 建议立即重构 模块: 保护逻辑 579 行 / 1 .c + 1 .h
← 返回项目总览
9
函数
2
⚡ 高风险
4
🟡 中风险
6
🟢 低风险(含2条误报)
~60%
重复代码占比
3 阶段
重构计划
🤖
Codex gpt-5.6-luna 中等推理
🏗️ 1. 现状架构
函数清单
函数行号行数职责调用者
SecondHarBrake_ParamInit 65-8016 初始化制动系数和有效时间 系统初始化
SecondHarBrake_faFdStateIsOC 93-310218 判断当前是否在过流状态(制动前提)
⚠️ 含6段重复逻辑
faFdBrakeJudge
faFdIsBrakeDeal 320-34021 退出制动时复位过流定时器 外部
faFdIsBrake 349-37224 核心制动判据: 二次谐波 / 基波 ≥ 比例? CheckSecondHarmonicBrake
ShouldSkipBrake 375-39925 前置条件: 是否跳过制动判断 faFdBrakeJudge
SecondHar_Brake_Enable 400-41819 检查制动功能是否启用 ShouldSkipBrake
UpdateBrakeStatus 429-44416 更新制动状态 + 事件记录 faFdBrakeJudge
CheckSecondHarmonicBrake 448-46114 遍历三相执行制动判据 faFdBrakeJudge
faFdBrakeJudge 468-578111 主状态机: 制动判断 + 去抖 + 超时 外部保护逻辑
调用链
外部保护任务 faFdBrakeJudge
├─ ShouldSkipBrake
│   └─ SecondHar_Brake_Enable
├─ adCalculateSecHar (外部)
├─ SecondHarBrake_faFdStateIsOC
├─ CheckSecondHarmonicBrake
│   └─ faFdIsBrake
└─ UpdateBrakeStatus

外部依赖: gHarm2Value gaProtYcBuf faFdRunPara
数据流
gaProtYcBuf[] 遥测数据
adCalculateSecHar() 计算谐波
gHarm2Value[fd][phase] 二次谐波值
faFdIsBrake(基波, 谐波, 比例)
faFdInfo[fd].BrakeRatioTime 计时器
faFdInfo[fd] oc_timer / oc_flag
FA_SBI_HAR_BRAKE 硬遥信位
faFdBrakeJudge 状态机
IDLE
初始/非过流
→ 过流触发 →
JUDGE
判断中·去抖·超时
→ 谐波比达标 →
BRAKE
制动中·倒计时
→ 计时结束 →
END
退出制动·复位
🔍 2. 发现的问题
🔴 高风险
🔴 P1. 核心函数极度过流检测重复 ×6
SecondHarBrake_faFdStateIsOC() 中三段式过流检测的相同逻辑(3相循环 + 阈值判断 + 返回比判断 + 启动标志)被完整复制了 6 次: 广州模式×3 段 + 非广州模式×1 + fcous ×1 + vsp5 ×2。每次复制的区别仅在于:读取的阈值的配置来源不同(faFdRunPara.oc_limit vs fcousFdRunPara.oc_limit vs gVspRunPara.value_XJOverFault) 以及启用的 condition 条件不同(region 判断、enable 判断、sect 范围判断)。 这是典型的 Copy-Paste 编程,修改一个地方的阈值逻辑需要同步修改 6 处。
Protect_SecondHarBrake.c:103-307
🟢 P2. ~~制动判据公式问题~~ 已确认为误报
Codex 误报。 SecondHar 和 Fundamental 变量中实际存储的是 码值²/2(已平方), 代码中的 (QWORD)SecondHar * 100 * 100(QWORD)Fundamental * Ratio * Ratio 公式量纲正确,不需要再次平方。注释中的"平方比较"是对原始码值的描述, 变量已经进行了预计算处理。

修正原因:用户确认数据表示为 码值²/2,公式无误。
Protect_SecondHarBrake.c:354-358 (Codex AI 发现 · 经用户确认为误报)
🟢 P3. ~~wBrakeRatio 单位冲突~~ 已确认为误报
Codex 误报。 这不是 bug,是参数设置的单位差异:中山地区使用 20(代表 %,Ratio>100 不触发), 非中山地区直接使用 0.2(直接比例,Ratio>100 正常通过)。两种配置在不同场景下都正确工作,不存在失效问题。

修正原因:用户确认中山维护上单位是 %(设 20 即 20%),非中山设 0.2(直接比值),两种配置均正确。
Protect_SecondHarBrake.c:49-56 + 340-343 (Codex AI 发现 · 经用户确认为误报)
SecHarOcStartFlag[FA_FD_NUM][SECBRAKENUM][3] 是函数内部 static 3D 数组, 用于跟踪每段过流的启动状态。这意味着: (1) 单次调用会产生跨周期副作用 (2) 无法进行纯函数测试 (3) 重启后首次调用数组全零,与运行状态的连续性不一致 (4) 与其他保护模块的启动标志(faFdInfo.oc_flag)重复
Protect_SecondHarBrake.c:98
🔴 P3. 10+ extern 全局变量裸奔
文件顶部声明了 10 个 extern 全局变量(faFdPara[], faFdRunPara[], faFdInfo[], faPublicPara[], fcousFaPara[], fcousFdRunPara[], faSoftYBRunPara, faMemoInfo[], faPtInfo[], gHarm2Value[][], netproEnable[], vsp5Enable[], faEnable[], fcousEnable[], gVspRunPara[])。 这些应在统一模块头文件中声明,而非每个 .c 重复写一遍 extern。
Protect_SecondHarBrake.c:22-36
🟡 中风险
🟡 P4. faFdBrakeJudge 状态机函数 111 行, 状态变量散布
111 行的函数中散布着 5 个 static 局部变量(inbrake, outbrake, BrakeJudgeStart, BrakeJudgeEnd, BrakeJudgeCount), 状态转换逻辑与去抖/计时逻辑混在同一个循环里,难以推导状态一致性。
Protect_SecondHarBrake.c:468-578
🟡 P5. #if 0 死代码残留
第 280-306 行是 #if 0 包裹的废弃分布式逻辑(wh 20230905 废弃), 包含完整的过流检测代码副本。如果不清理,后续维护者无法判断哪些是有效的。
Protect_SecondHarBrake.c:280-306
🟡 P6. 函数的入参缺乏封装
faFdIsBrake(DWORD Fundamental, DWORD SecondHar, WORD Ratio) 接受 3 个松散参数, 但调用方需要自己从 gaProtYcBufgHarm2Value 中取出数据。 应改为接受 fd + phase 或结构体指针。
Protect_SecondHarBrake.c:349
🟡 P7. faFdIsBrake 中使用 QWORD 运算
制动判据公式为 Harm² × 100² > Fundamental² × Ratio²,使用 QWORD(64位)做乘法。 由于 GD32H7 硬件可能未启用硬件 64 位乘法器,编译器会生成软乘法,对性能有影响。 可以优化为浮点比较或分步比较以避免 64 位运算。
Protect_SecondHarBrake.c:367-368
🟢 低风险
🟢 P8. 中文 GB2312 编码注释
所有注释为中文字符,非 UTF-8 编码环境会显示为乱码。且函数注解风格不统一(有的在 c 文件、有的在 h 文件)。
🟢 P9. 函数命名不一致
部分函数为 PascalCase(SecondHarBrake_ParamInit),部分为 CamelCase(faFdBrakeJudge),部分混合下划线(ShouldSkipBrake)。
🟢 P10. 魔法数字 "0x81"
多处使用 0x81 作为 enable 标志的比较值,且无宏定义说明含义。
🟢 P11. BrakeRatioTime 单位隐含依赖
参数初始化时除以 FA_CYCLE_TIMER 约定每 tick 减 1,但 faFdBrakeJudge 中的 decrement 并未显式说明这个单位约定,导致维护者容易改出 bug。
📋 3. 三阶段重构计划
1

安全重构 · 零行为变更

  • 提取过流检测公共逻辑为 isPhaseOverCurrent()
  • 将二层嵌套的 for 循环提取为 checkAllPhasesOverCurrent()
  • 删除 #if 0 死代码段
  • 0x81 提取为宏 FA_ENABLE_MASK
  • 将 extern 声明移到 .h 中统一管理
🟢 风险极低 · 逻辑不变 · 编译即可验证
📄 phase1_second_har_brake.c   📄 .h
2

架构优化 · 状态机分离

  • faFdBrakeJudge 的 3 个 state + 2 个 counter 封装为 BrakeSM 结构体
  • 状态机提取为 faFdBrakeJudge_Run()faFdBrakeJudge_Reset()
  • 隐式状态(变量组合)→ 显式枚举 BrakeState
🟡 中风险 · 需充分回归测试
📄 phase2_brake_sm.c   📄 .h
3

代码质量 · 现代化

  • 统一编码风格(命名规范 Uncrustify)
  • 添加 Doxygen 风格函数注释
  • 转换所有中文字符串为英文或 UTF-8
  • 添加单元测试桩(Mock gaProtYcBuf, gHarm2Value)
  • 考虑浮点运算替代 QWORD 乘法
  • 添加 Logging 宏替代直接调用 printf
🟢 低风险 · 纯风格 + 文档优化
📐 4. 核心重构 Before / After
关键优化: 消除 6 重复制粘贴 — SecondHarBrake_faFdStateIsOC
❌ Before: 6 次重复粘贴 // 广州模式, 段1
if (REGION_SELECT_GUANGZHOU) {
  for (phase = 0; phase < 3; phase++) {
    if (buf > limit) {
      flag = 1; result = TRUE;
    } else if (buf > limit * ret) {
      if (flag) result = TRUE;
    } else { flag = 0; }
  }
}
// 重复: 广州模式, 段2 (同上)
// 重复: 广州模式, 段3 (同上)
// 重复: 非广州模式... (同上)
// 重复: fcous... (同上)
// 重复: vsp5 段1... (同上)
// 重复: vsp5 段2... (同上)
====== 6 次完全相同 ======
✅ After: 1 次 + 配置驱动 // 过流检测阶段配置表
typedef struct {
  BYTE fd; BYTE sect; BYTE phase;
  DWORD threshold;
  DWORD retRatio;
} OcCheckConfig;

// 统一的过流检测函数
static BOOL checkOcPhase(OcCheckConfig* cfg) {
  DWORD val = gaProtYcBuf[... + cfg->phase];
  if (val > cfg->threshold) {
    faFdInfo[cfg->fd].oc_flag[cfg->sect][cfg->phase] = TRUE;
    return TRUE;
  } else if (val > ... * retRatio) {
    return faFdInfo[...].oc_flag[...];
  } else { faFdInfo[...].oc_flag[...] = FALSE; }
  return FALSE;
}

// 从配置表驱动, 而非粘贴代码
for (i = 0; i < cfgCount; i++) { result |= checkOcPhase(&cfg[i]); }
关键优化: 状态机封装 — faFdBrakeJudge
❌ Before: 状态变量+逻辑混杂 BOOL faFdBrakeJudge(BYTE fd)
{
  static BYTE inbrake = 0;
  static BYTE outbrake = 0;
  static BYTE BrakeJudgeStart = FALSE;
  static BYTE BrakeJudgeEnd = FALSE;
  static int BrakeJudgeCount = ...
  // ... 111 行状态机 + 去抖 + 计时混在一起
}
✅ After: 显式状态机结构体 typedef enum {
  BRAKE_IDLE, BRAKE_JUDGING,
  BRAKE_ACTIVE, BRAKE_EXIT
} BrakeState;

typedef struct {
  BrakeState state;
  BYTE debounceEnter;
  BYTE debounceExit;
  WORD timeoutCount;
} BrakeSM;

BOOL faFdBrakeJudge(BYTE fd) {
  BrakeSM* sm = &brakeSM[fd];
  switch (sm->state) {
    case BRAKE_IDLE: ... break;
    case BRAKE_JUDGING: ... break;
    case BRAKE_ACTIVE: ... break;
    case BRAKE_EXIT: ... break;
  }
}
🎯 5. 影响范围
Phase 1 影响
Protect_SecondHarBrake.c Protect_SecondHarBrake.h SecHarOcStartFlag (迁移)
Phase 1 只改这一个 .c 文件和 .h 文件。extern 迁移到 .h 后,其他文件只需包含该头文件(已有 include 的不用改)。
Phase 2 影响
Protect_SecondHarBrake.c Protect_SecondHarBrake.h 新增: Protect_Common.c/h FANEW.h (新增 BrakeSM 结构体) faFdInfo (新增字段)
新增一个通用保护模块文件。需要修改 FANEW.h 添加 BrakeSM 结构体到 faFdInfo 或独立数组。 faFdIsBrakeDeal 的调用者也需检查。
Phase 3 影响
Protect_SecondHarBrake.c/h 全局: 整个 PRODUCT 目录的编码风格 FA_ENABLE_MASK FA_CYCLE_TIMER (加注释)
Phase 3 为纯美化改动, 可与主业务并行开发, 不阻塞版本发布。
💡 核心结论

重构后文件预计从 579 行 → ~250 行,减少 57%。

重构关键是把 "3 路 for 循环 × 3 相 × 6 种模式 = 54 个条件分支" 的野蛮展开, 抽象为 "配置表 + 统一函数" 的模式。

推荐策略: 立即执行 Phase 1(安全、无风险),Phase 2 结合下次功能迭代一起做,Phase 3 有空再做。