TMS BOOK · ACADEMY 讲义

模式状态机的完备性核对与可验证性设计

大纲的完整展开版——讲师授课蓝本 / 学员自学材料

K4-05 模式状态机的完备性核对与可验证性设计

课程代码 K4-05 · 板块 K 控制、软件与标定 / 嵌入式软件与开发 时长 约 3.5~4.0 小时(5 讲) 前置 K3-01 整车热管理控制策略总览与模式管理;K4-02 基于模型开发(MBD):Simulink 建模与代码生成;B3-04 热泵型整车热管理架构(多通阀一体化方案);G8-06 冷却液侧集成模块(CIM):阀岛/泵/膨胀壶一体化架构 本讲义定位 讲师授课蓝本 / 学员自学讲义,是 K4-05 大纲的完整展开版


按任务导航

你手上的事 直接看 还要配
评审一台已建好的模式状态机,判「核过了没有」 第 1 讲:逐格填表算完备率、同状态出边两两不交叠 第 3 讲(到不到得了)· 第 5 讲(三份证据怎么接进出口判据)
把架构侧的模式表与阀位真值表翻成软件层 guard 第 2 讲:三个落点各给判据,另有一个窗口型落点 第 4 讲(寻零期那张合法阀位子集表)· 第 1 讲(阈值必带伴生项)
给一个过渡态定超时时长与超时之后去哪 第 3 讲:夹逼结构与三选一去向,逐个过渡态显式选定 第 1 讲(过渡态必须各占一行,否则超时无处可挂)
写上电初模式与异常复位恢复路径的规则表 第 4 讲:判定规则表的八列输入、信任存值的与条件 第 2 讲(窗口型不变式)· 第 3 讲(等回执的过渡态)
签一份软件验证出口判据,判这句「通过」管到哪 第 5 讲:三类证据的分工、分母口径与结论三态 第 3 讲(分母要先剔不可达)· 第 1 讲(完备率是门禁)

本课不覆盖:模式集怎么收全、迟滞带与最小驻留怎么取 → K3-01 整车热管理控制策略总览与模式管理;模式表怎么反推 → B3-04 热泵型整车热管理架构(多通阀一体化方案);阀位组合真值表怎么穷举 → G8-06 冷却液侧集成模块(CIM):阀岛/泵/膨胀壶一体化架构;回路铁律的物理机理 → B3-01 冷却液回路拓扑:串/并联、多回路耦合与模式切换;切换的执行时序(水侧三段式与断流窗口 → K3-09 冷却液回路模式切换的执行时序:泵—阀联动、断流窗口与切换序列表,冷媒侧三段式与换向压力冲击 → K3-04 热泵与多通阀协调控制);上下电次序、就绪时间与休眠编排 → K3-11 热管理域的上下电时序、run-on 编排与休眠期能耗预算;非易失载体选型与掉电写一致性 → K4-06 控制器非易失存储设计:学习值、诊断数据与累计量的持久化;执行器寻零算法本体 → G4-01 电子膨胀阀(EXV)结构、控制与选型 K1-02 执行器驱动:电子阀/泵/风扇/压缩机 PWM C2-03 风门驱动电机与执行器(步进/有刷/PWM)选型 G8-05 集成模块的装配、检漏与售后可维护性;断电落点与失效安全档 → G12-03 执行器硬件接口与电气规格;降级等级、重试限次取值与故障码 → K5-02 热管理故障处理与降级策略;建模、代码生成与判定/条件/MC-DC → K4-02 基于模型开发(MBD):Simulink 建模与代码生成;在环阶梯、故障注入与需求覆盖率 → K4-03 MIL/SIL/HIL 验证流程;策略层二维表体检与切换质量验收页 → K3-13 模式表/场景表与仲裁规则的静态体检:可达性、死锁与切换质量;通用软件测试理论与模型检验的算法原理 → 本课自设禁区,不讲。以及任何一个具体的时长、门限与比例——迟滞带、最小驻留、去抖时间、过渡态超时、覆盖率出口目标、抖动率上限、重试限次与退避间隔、断电时长门槛、上电就绪时间与峰值电流预算——由本项目自己的整定与验证策略、以及所引体系文件的现行版本给出,⛔ 本课一个数都不给(唯一给出的那个数是完备率的判据值 100%,它由定义推出、不是经验值)。


引言:这一类病不会让任何一条用例失败

评审会上最常听见的一句结论是「状态机已经核过了」,而几乎没有人追问它指的是哪一件事核过了。它可能指有人把建模环境里那张图从头翻了一遍;可能指跑过一轮工具的自动检查、没报错;也可能指所有功能用例都通过了。这三种「核过了」查到的东西互不重叠,而它们写进会议纪要之后长得一模一样。⇒ 本课要做的第一件事,是把这句话拆成三份可以签字的东西

本课的输入是三样已经存在的产物:模式集与仲裁优先级(归 K3-01 整车热管理控制策略总览与模式管理)、架构侧的模式表(归 B3-04 热泵型整车热管理架构(多通阀一体化方案))与阀位组合真值表(归 G8-06 冷却液侧集成模块(CIM):阀岛/泵/膨胀壶一体化架构)、以及一台已经在建模环境里画出来的模式状态机(K4-02 基于模型开发(MBD):Simulink 建模与代码生成 的产物)。输出固定为三份报告:

  • 完备性核对报告——完备率、二义性清单与每一处已消解方式;
  • 静态核对报告——不可达状态与死迁移清单及处置、等待图无环证明或破除方案、性质证明的三态记录;
  • 覆盖准则声明——本项目取哪一档、分母口径与剔除清单、豁免论证。

三份报告分别建立三种判断力:一张表完不完备一张图到不到得了、会不会锁死一句「通过」管到哪儿为止。⇒ 本课全程只判三件事:这一格填了没有、填得矛不矛盾到不到得了。⛔ 它不判「这一格填得对不对」——那是功能逻辑,归 K3-01 整车热管理控制策略总览与模式管理K3-04 热泵与多通阀协调控制。这条分界要先立住:立不住,每一次评审都会滑进「这个模式该不该这么走」的争论,而那恰恰是本课查不了、也不该查的那一层。

图1 本课射程与交付物的结构图。中央一个主蓝主框,标注本课:一台已建成的模式状态机的静态体检。左侧四个输入框各带独立标签与来源课号:模式集与仲裁优先级来自 K3-01,模式表来自 B3-04,阀位组合真值表来自 G8-06,已建成的状态机模型来自 K4-02。右侧三个青绿输出框各带标签与一行内容:完备性核对报告,含完备率、二义性清单与已消解方式;静态核对报告,含不可达与死迁移清单及处置、等待图无环证明或破除方案、性质证明三态记录;覆盖准则声明,含取哪一档、分母口径与剔除清单、豁免论证。三个输出框汇入右端一个方框,写下游出口判据与用例矩阵,去向 K4-03。外围一圈灰底虚线框,逐个只写去向不写内容:功能逻辑对不对去向 K3-01 与 K3-04,代码层缺陷去向 K4-02 与 K4-01,标定值去向 K6-01,切换执行时序去向 K3-09 与 K3-04,域级上下电次序去向 K3-11,降级等级与故障码去向 K5-02,失效安全落点去向 G12-03,策略层二维表体检去向 K3-13。左下角一个橙色框写本课的入口三问:这一格填了没有,填得矛不矛盾,到不到得了。图上不含任何数值、等级号与条款号。本图为定性结构示意,框的大小、位置与距离不代表重要性、调用关系或先后,⛔ 不得据图读取任何数值、比例或位置关系。
图1 要读出三件事:一、本课的交付物是三份具体报告,⛔ 不是「把状态机看了一遍」;二、外围那一圈虚线框不是不重要,是判据源在别处——图上只给去向,⛔ 一个限值、一个等级号、一条条款都没给;三、左下角那一框就是本课的全部射程:只判「填了没有、矛不矛盾、到不到得了」这三问,⛔ 不判「这一格填得对不对」。⚠ 本图画的是课程射程与交付物的划分,⛔ 不是软件架构图、⛔ 不是数据流图;框的大小、位置与距离不代表重要性、调用关系或先后。本图为定性结构示意,⛔ 不得据图读取任何数值、比例或位置关系。

钉子①:结构缺陷不产生失败,它产生沉默

状态机的病不长在功能逻辑里,长在结构上;而结构缺陷的共同现场表现是:不报错。

四条逐条对照:

  • 迁移表里的一格空着——这个事件在这个状态下不匹配任何分支,被静默丢弃 ⇒ 现场是「按了没反应、也没有故障码」,既不进故障管理,也不留任何痕迹;
  • 陷阱态(进得去出不来)——它每一拍都在正常地等一个完成事件,而那个事件已经不会来了;
  • 优先序绑在绘图顺序上——重排一次图,行为就翻转,而功能代码一行都没改,任何 diff 都看不出来;
  • 死锁——两个主体都在按自己写下的规则正常等待,各自的逻辑单独看全对

四条的末端是同一个词:沉默。而沉默不会以「某条用例失败」的形式出现在任何一份测试报告里——报告上那一栏是空的,不是红的。

图2 结构缺陷从表上到现场的四条因果链。四条横向链竖排并列,每条三段、段与段之间用箭头连接,各段有独立文字标签。链一:表上,某状态对某事件是空格;运行期,事件不匹配任何分支、被静默丢弃;现场,按了没反应也没有故障码。链二:表上,过渡态有出边但只等一个完成事件、无超时;运行期,每一拍都在正常等待;现场,进得去出不来且不置码。链三:表上,两条出边的守卫条件可同时成立、靠绘图顺序消解;运行期,重排一次图优先序翻转;现场,行为变了而功能代码一行没改、任何 diff 都看不出。链四:表上,两个主体互相等待对方先动作;运行期,双方都按自己写下的规则正常等待;现场,各自的逻辑单独看全对。四条链右端汇入同一个警示红竖框,框内一行大字写共同现场表现:不报错;其下两行小字写,不会以某条用例失败的形式出现在任何一份测试报告里,本课的方法全部在跑之前、在表上和图上做。每条链的第一段用主蓝标出,标明它写在表上。图上不含任何数值。本图为定性因果示意,四条链的上下次序不代表发生频率或严重度,⛔ 不得据图读取任何数值、频次或时长。
图2 要读出两件事:一、四类结构缺陷的末端全部落在同一个框——它们的共同表现是「不报错」,⛔ 不是「报了个不好懂的错」;二、每条链的第一段都写在「表上」,⇒ 能查它的时点在建表阶段,⛔ 不是在台架上跑用例的阶段。⚠ 「共同表现是不报错」这条归纳是本课补的,⛔ 不是本课程体系既有、⛔ 不是任何标准既有。本图画的是缺陷部位到运行期行为再到现场表现这条因果链,⛔ 不是故障树、⛔ 不是失效率排序;四条链的上下次序不代表发生频率或严重度。本图为定性因果示意,⛔ 不得据图读取任何数值、频次或时长。

⇒ 三条推论,本课的整个做法都由它们决定:

  1. 本课全部方法都在跑之前做、在表上和图上做,⛔ 不是靠跑用例找出来的。动态测试为什么在原理上够不到这一层,第 5 讲给判据。
  2. 「结构」这个词在本课有确切所指——行头、列头、格、边、优先序、超时、初值,一共七样。⛔ 它不是「代码写得整不整齐」。
  3. 所以本课每一条判据都刻意写成可机检的形式:完备率是一个数、互斥性是一条布尔恒等式、无环是一条图论性质。写成这个样子,是为了能交给工具去证,⛔ 不是为了在评审会上逐条争论。

钉子②:每一个「满分」的分母都是你自己填的

把分母填小,比值就好看,而填小分母的那个动作,看起来正是「把工作做完」。本课有三处同形:

那个「满分」 它的分母是什么 它够不到的那一层
完备率 100% 行数 × 列数——两侧都是你自己收的 没进行头的那一整行、没进列头的那一整列
迁移覆盖率 100% 只含已经写进表里的那些迁移 从没被写下来的那条规则
模型检验工具报回来的一句「过了」 你写下的那几条性质 性质写漏的、写得太弱的、被 stub 掉的那部分

⇒ 三条推论:

  1. 一份「通过」必须同时说清三件事:它是哪一类证据、分母口径是什么、它够不到的那一层由谁补。需求覆盖答「该测的测了没」,结构与迁移覆盖答「有没有从没跑到的地方」,静态核对答「有没有从没写下来的地方」——三者互不替代,缺任一类都不算过出口。
  2. 分母口径必须带版本号,并随表一起冻结。两份报告的分母版本不同,结论就不可比,也不能互相引用。
  3. 凡是把已判定的不可达项留在分母里的做法,都会逼团队去编凑分用例 ⇒ 分母的清洗是第 3 讲的输出,也是第 5 讲能不能报数的前提。

反钉子:把空格填满,完备率就到 100%,这张表就完备了

本课最容易被读反的一条:「把迁移表的空格填满,完备率就到 100%,这张表就完备了。」

它的前半截完全正确:完备率确实是把空格填满才涨上去的,它也确实该做成提交门禁。本课程体系把「完备率 = 100%」立成一条硬判据,理由是它由定义推出:既然每一格空着都是一处未定义行为,那么「没有未定义行为」这句话的数学形式就是分子等于分母。⛔ 它不是经验值、不是行业统计值,也⛔ 不是任何标准里的条款。正因为前半截对、而且完备率是本课交出的第一个,读者极容易把「把这个数做到 100%」当成第 1 讲的全部任务。

为什么它是反的:完备率=已写下确定去向的格数 ÷(行数 × 列数)——本课把它记作 C_table = N_filled /(N_state × N_event)——分子是你填的,分母也是你填的。填格只动分子,而决定这张表管不管用的是分母:行头(状态集)与列头(事件集)收全了没有。一张漏了「寻零中」这一行、漏了「执行器完成回执」这一列的表,把剩下的格全部填满,算出来是一个货真价实的 100%,而它对漏掉的那一整行、那一整列一个字都没定义

读者会做错的那个具体动作:拿到一张现成的迁移表(多半是从上一代平台或架构侧的模式表转过来的),直接开始逐格补空;补完算出 100%,把它当绿灯交上去,并据此判定「完备性这一项已经过了,可以进下一道工序」。⛔ 他不会回头去问「行头列头是谁给的、收全了没有」——因为那个数已经满分了。⇒ 后果不是「差一点」,是他刚刚亲手把「还没查」变成了「已经查过」:后面每一道工序都会信任这个结论,可达性分析在缺行的图上做、迁移覆盖率在缺行的分母上算、模型检验对不存在的那一行无从报告。★ 这正是假的好消息比坏消息更不容易被质疑的地方——60% 会让人继续查,100% 让人停手

同一个形状在本课还会以三种面貌再出现,各自在它该被点破的地方点破:一条 else 兜底被当成「这一行不会有未定义行为」(第 1 讲)· 迁移覆盖率 100% 被当成「状态机测过了」(第 5 讲)· 工具报「无不可达状态」被当成「状态机对了」,以及把「无定论/超时」读成「通过」(第 5 讲)。

⚠ 本课另有一个方向不同的做反动作,成因与上面这条无关,单独落在第 4 讲:热态复位后立刻把所有执行器强制归零,可能比不归零更危险

交之前,先花五分钟做这一件事

拿你手上那张迁移表,先别补空格,按下面三步走一遍:

  1. 重数行头——五类逐类点名:热功能模式 × 车辆使用态、三个端点态、非用户模式、过渡态降级与安全态。后两类是本课补的,它们在架构侧那张稳态模式表上本来就不占行,照抄模式表当行头必然整类漏掉。
  2. 重数列头——七类逐类点名,且粒度先冻结再数:同一物理量、同一方向、同一处置的门限合成一个事件,处置不同或来源不同即分列。逐类怎么点名、冻结规则怎么用,第 1 讲逐条给。
  3. 重算一次比值,与你上次报出去的那个数并排放着看。

这一步的读法:比值掉下去的那一部分,就是你上次报的那个 100% 里从来没有被定义过的东西——分子一格没少,只是分母终于算对了。⇒ 判出来之后的下一个动作是:先把行头列头冻结、写上版本号,再逐格填。⛔ 反过来做(先填格、后补行),每补一行都要把整张表的比值与可达集作废重算,而重算这件事一旦被跳过,你手上就同时有两个版本的分母。

什么时候这条结论不成立:如果行头列头已经冻结并带版本号,且冻结之后没有人改过表,那么补空格确实就是这一项的全部工作——完备率这条判据的有效期,正是从行列冻结那一刻起,到下一次改表为止。⇒ 所以「表的版本号」不是文档规矩,它是这个数成不成立的前提

第 1 讲 迁移表:把「状态机做完了没有」换成一张能逐格核的表

现场对「这台状态机做完了没有」最常见的争执,不是「逻辑对不对」,而是「你说的做完了,指的是哪一件事做完了」。同一句「状态机已经核过了」,可能指有人把图从头到尾看了一遍,可能指跑过一轮模型检验,也可能指用例全绿。三件事互不覆盖,而它们在会议纪要上长得一模一样。

这一讲把这句话拆成可交付的东西:先把状态机的完备性从「图上看着没漏」换成一张行=状态、列=事件的二维表,让它变成能逐格核、能算成一个数、能当提交门禁的东西;再把这张表上会长出来的两类结构缺陷——格上的空白与边上的二义——各自配一条可机检的判据。后面四讲都挂在这张表上:第 2 讲往格里填 guard,第 3 讲在这张表生成的图上查可达性与死锁,第 4 讲补上电那几行,第 5 讲用它当覆盖率的分母。

本讲先钉住几个记号,全课统一、后面各讲照用:

记号 指什么 单位
N_state 迁移表的行数=状态集元素个数
N_event 迁移表的列数=事件集元素个数
N_filled 已写下确定去向的格数
C_table 迁移表完备率=N_filled /(N_state × N_event) 无量纲,以百分数表述
g_i 同一状态第 i 条出边的守卫条件(布尔式) 布尔(无量纲)
prio(i) 同一状态第 i 条出边的优先序序号 无量纲(序数)
s / e 状态序号(第 s 行)/事件序号(第 e 列) 无量纲(序数)
ΔT_hys / t_dwell_min 迟滞带/最小驻留时间(本讲只查它在不在,⛔ 不参与任何数值运算) K / s

⚠ i 与 j 在本课专门用来数同一状态的出边,只出现在 g_i ∧ g_j 与 prio(i) 里;数状态用 s、数事件用 e、数任何「个数」一律写成 N_〈被数的东西〉。⛔ 全课不写不带下标的 g——同一状态有多条出边是常态,不带下标就没法把互斥判据写出来。

1.1 本课的坐标系:三样输入,三份可签署的报告

本课的输入是三样,全部是别人已经交出来的东西:

  1. 模式集与仲裁优先级——K3-01 整车热管理控制策略总览与模式管理 交付;
  2. 架构侧的两张表——B3-04 热泵型整车热管理架构(多通阀一体化方案) 的模式表、G8-06 冷却液侧集成模块(CIM):阀岛/泵/膨胀壶一体化架构 的阀位组合真值表;
  3. 一台已经在建模环境里画出来的模式状态机——K4-02 基于模型开发(MBD):Simulink 建模与代码生成 的产物。

⇒ 本课不建模式集、不建模型,本课做的是给这三样做一次静态体检。

本课的输出是三份可签署的报告,它们各自回答一个不同的问题:

报告 它回答哪一个问题 里面必须有什么 在哪一讲交
完备性核对报告 这张表上,每一格都有定义了吗? 完备率 C_table(带表的版本号)· 二义性清单与每条的已消解方式 第 1 讲(本讲)
静态核对报告 写下来的这些,到得了、出得来吗? 不可达状态与死迁移清单及逐条处置 · 等待图的无环证明或破除方案 · 性质证明的三态记录 第 3、5 讲
覆盖准则声明 我们据以宣布「测过了」的分母是什么? 本项目取哪一档 · 分母口径与剔除清单 · 豁免项与论证 第 5 讲

为什么先立报告再讲方法。因为开头那句争执的根源就是没有靶子:三个人说的「核过了」各指一件事,谁也没说错,只是从来没人写下来要交什么。先把三份报告立起来,后面四讲每讲一条判据,都能明确落到某一份报告的某一行上;也才有资格接进 K4-03 MIL/SIL/HIL 验证流程 的用例矩阵与出口判据——那边要的是可签署的证据,⛔ 不是一句「已核对」。

本课的射程只有三问,一句话说完:这一格填了没有?填得矛不矛盾?到不到得了?

本课不判「这一格填得对不对」——某个模式下该选哪条控制律、该走哪个阀位,那是功能逻辑,归 K3-01 整车热管理控制策略总览与模式管理K3-04 热泵与多通阀协调控制。本课判的是结构:填了没有、填得矛不矛盾、到不到得了(第三问含「出不出得来」——第 3 讲把它拆成可达性与陷阱态两侧查)。这条边界要在动手之前就说清,否则完备性核对会变成一场功能评审,而结构缺陷仍然一条都没查。

易错点。① 把本课当成建模工具的操作教程去读——工具怎么点归工具供应商文档,本课交付的是判据;② 以为交出这三份报告就等于状态机「对了」——它们证明的是结构上没有未定义的地方,⛔ 不是「策略选对了」。

⚠ 本课全部的时间量、门限量与覆盖率目标值一律是平台相关量、本课不给数(每一处都会写明由谁给出、由什么夹出上下界);而三份报告的结构与它们各自回答的问题与平台无关,可以直接照用。

1.2 交付物先定形:格数=N_state × N_event,完备的判据是逐格有确定去向

完备的判据不是「箭头画全了」,而是「每个状态对每个事件都有确定去向」。

这两句话的差别不是措辞,是能力不对等

  • 能表达「有哪些迁移」;
  • 表达不了「哪些组合没有迁移」——一张画得很干净的图,和一张漏了半列的图,长得一模一样。

⇒ 所以第一交付物必须是,不是图。表的骨架:行=状态(第 s 行),列=事件(第 e 列),格数=N_state × N_event。每一格必须写下确定去向——迁到哪个状态,或者显式的「保持不动」。

空格是什么。空格在生成代码里就是「这个事件在这个状态下不匹配任何分支」,运行期表现是事件被静默丢弃。现场表现是那句最难归因的话:按了没反应,也没有故障码。它之所以最难归因,是因为它既不进故障管理、也不留任何痕迹——你手上唯一的信息是「用户说没反应」,而日志里什么都没有。

一个格里到底要写下什么。四样,缺任一样这一格都不算填好:

格里必须有 写成什么样 缺了会怎样
① 确定去向 迁到哪个状态,或显式「保持不动」 空格 ⇒ 事件被静默丢弃
② 守卫条件 g_i 布尔表达式,⛔ 不是一句中文描述 判不了两条出边会不会同时成立
③ 优先序 prio(i) 一个写在表里可读的序号 谁赢交给工具的内部次序(见 1.7)
④ 若目标是过渡态:超时时长 t_to 与超时去向 两样都写在这一格里 超时逻辑落在故障管理那一侧,就不在这张表的分母里,也不会被静态核对看见(第 3 讲展开)

「保持不动」有两种写法,行为不同,必须写明是哪一种。

  • 消费并忽略——这个事件在本层被吃掉,上层与下一拍都收不到
  • 不消费——本层不动作,事件继续向上层或下一拍传递。

在层级/并行状态机里这两种的行为完全不同:把「消费并忽略」误写成「不消费」,事件会被外层的另一条迁移接走,现场表现是「子状态说不动、父状态却迁走了」;反过来则是外层永远收不到这个事件。而两种写法在表格上都可以只写「保持不动」四个字——不写清楚,落到代码里就是两种实现,且没有任何一道检查看得见这个差别。

不许用「—」「N/A」「无」表示保持不动——这三种写法落盘之后与空格不可区分,等于把刚填的格又变回空的。

表的右侧还要另接三列,它们不算在 N_filled 里,但缺了这张表就核不完:else 兜底(每个状态的必填项,见 1.5)、二义性(本状态的出边两两是否恒不交叠,见 1.7)、表版本号(报完备率必须带它,见 1.6)。

图3 一张放大的迁移表骨架:左侧行头标注「状态 s=第 s 行」,顶部列头标注「事件 e=第 e 列」,交叉处为格。四个格被放大成气泡并各带独立文字标签——气泡一「确定去向:迁到哪个状态」;气泡二「显式『保持不动』,并注明是『消费并忽略』还是『不消费、留给上层或下一拍』」;气泡三为警示红斜纹填充的「空格 ⇒ 未定义行为」,旁注「⛔『—』『N/A』『无』落盘后与空格不可区分」;气泡四「本格附带三样:guard 表达式 g_i、优先序 prio(i),若目标是过渡态则加超时时长 t_to 与超时去向」。表右侧另接三列窄列,各带独立列标签:「else 兜底(每个状态必填,动作须是安全侧的显式动作)」「二义性:本状态出边两两是否恒不交叠」「表版本号」。表下方一行公式条:N_state(行数)× N_event(列数)=格数,已写下确定去向的格数=N_filled。表体只画示意性的少数几行几列。本图为定性结构示意,表体的行数列数无实义,⛔ 不得据图读取任何规模或数值。
图3 迁移表的解剖:一格里必须写下什么、右侧那三列为什么不算进 N_filled。本图为定性结构示意,表体的行数列数无实义,⛔ 不得据图读取任何规模或数值。

易错点。① 把「评审时逐条看箭头」当成完备性核对——箭头是分子那一侧的东西,看再多遍也回答不了分母;② 以为工具的默认语义会兜底——不同层级、不同工具版本的默认语义并不一样,把行为交给默认值就是把行为交给一个没人写下来的约定

⇒ 今天就能做的那个动作:把你手上那张迁移图里任选一个状态,横着数一遍事件列,看有几列你说不出它在这个状态下会发生什么。说不出的那几列就是空格,⛔ 不是「不会发生」。

1.3 行头(状态集)必须先收全再谈完备率,否则算出来是一个货真价实的假 100%

完备率的分母是 N_state × N_event。行头收不全,分母就小,比值就高。一张漏了一整行的表,把剩下的格全部填满,算出来是一个货真价实的 100%——而它对漏掉的那一整行一个字都没定义

⇒ 所以顺序是死的:先收行头,再谈完备率。行头必须含下面五类,逐类点名、一类不许省:

# 这一行从哪儿来 包含什么 收全责任在谁
热功能模式 × 车辆使用态构成的二维模式空间 由本项目的模式集给出 K3-01 整车热管理控制策略总览与模式管理
三个端点态 Init / Shutdown / Sleep K3-01 整车热管理控制策略总览与模式管理
非用户模式 产线下线检测(EOL)/售后服务/运输存放/诊断激励 K3-01 整车热管理控制策略总览与模式管理
过渡态这一类是本课补的 阀在走行程/压缩机在升速/寻零在进行/跨域授权在等回执 本讲
降级态与安全状态这一类是本课补的 等级体系与各级进出条件归 K5-02 热管理故障处理与降级策略,去激励默认位归 I7-02 失效安全(Fail-safe)与冗余设计 本讲只要求它进同一张表

①②③ 的收全责任在 K3-01 整车热管理控制策略总览与模式管理本讲只负责把它们摆进表的行头并逐格填。④⑤ 两类是本课归纳补上的行头分类,⛔ 不是本课程体系既有的分类——请在自己的报告里照此标注。

④ 为什么必须各自占一行。判据一句话:凡是有时长、且要等一个完成事件的动作,就是一个过渡态。过渡态不占行,第 3 讲的「超时时长与三选一去向」就无处可挂——一个不在表上的状态,不可能有哪一格写着它的超时去向,于是「过渡态没配超时」这类缺陷在表上永远不可见。⚠ 过渡态怎么命名、它在电源模式机里摆在哪一层,归 K3-11 热管理域的上下电时序、run-on 编排与休眠期能耗预算;本课要的只有一条结构要求:它必须是行头里的一行

⑤ 为什么必须进同一张表、同一张图。因为「互相等待对方先降级」这类环恰恰只在降级路径上闭合——只体检正常路径会系统性漏检。I7-02 失效安全(Fail-safe)与冗余设计 已经把这条动作写死:把降级迁移画进同一张图再查一次环。两张表分开查,跨表的那个环两边都查不出来。

沿单一线索数行头,会整类漏掉什么。

  • 只数「用户能感知的模式」——整类漏掉 ③④⑤;
  • 直接照架构侧的模式表抄行头(最省事、也最常见的做法)——整类漏掉 ④。原因是架构侧那张表是稳态枚举,过渡态在它上面本来就不占行。

易错点。① 拿架构侧模式表当行头(上一条);② 把非用户模式当成「不是软件的事」而不进表;③ 先算完备率再补行头——补一行之后,C_table 与第 3 讲的可达状态集、可达迁移集全部作废重算,⇒ 报数必须带表的版本号,两份版本号不同的报告结论不可比。

⚠ 五类各有几行是平台相关量、本课不给数——它取决于本车的架构、执行器数与场景集。本讲给的是逐类点名的收全动作:照上面五行各数一遍,你就能算出自己那张表的行数。

1.4 列头(事件集)的粒度必须先冻结再算数

列头是分母的另一半,它比行头多一个麻烦:粒度。同一件事,写成一列还是五列,全凭习惯——而这个选择直接乘进格数。

先按来源分七类,逐类点名。前五类由本课程体系的既有口径给出,后两类是本课归纳补上的

# 事件类 说明
温度/压力门限越界
用户或场景请求
故障置位与撤销 置位与撤销是两个方向,⛔ 不是一个
超时 没有外部触发者,是状态机自己产生的
外部授权回执 只在含不可支配热源(发动机/增程器)的架构里出现;分类依据=K3-01 整车热管理控制策略总览与模式管理 的直辖/可请求/完全自治三段划分
上下电与电源模式事件本课补 点火状态跳变、唤醒源触发、休眠请求、刷写后首次启动
执行器完成/失败回执本课补 寻零完成、阀到位、压缩机达速、加热器允许通电

⑥ 漏掉的后果:第 4 讲整讲的入口全在这一类;漏掉它,上电路径在这张表上根本不存在,于是「上电走哪条路」这件事永远由代码里的一段初始化顺序隐式决定。

⑦ 漏掉的后果:它是过渡态唯一的正常出边。漏掉它,过渡态就只剩「超时」一条出边——等于把「正常完成」这条最常走的路径从来没有表达过

沿「谁触发的」这条线索数事件,会整类漏掉 ④ 与 ⑦:④ 没有外部触发者;⑦ 在多数人的心智模型里是「输出」,不是事件源。

粒度的冻结规则(本课统一):同一物理量、同一方向、同一处置的门限合成一个事件;处置不同或来源不同即分列。

它要挡住的是两个方向相反的失真:

  • 同一连续量的多个阈值拆成多个事件 ⇒ 表按乘法膨胀,逐格填变成不可能完成的工作量,于是团队开始留空格——表膨胀最终是以空格结算的
  • 不同来源的事件并成一个 ⇒ 丢掉「谁触发的」。同一个「需要制冷」,来自用户按键还是来自电池请求,处置完全不同,并成一列之后这个差别在表上消失。

冻结之后再改列头,C_table 与可达集同样全部作废重算——和补行头是一样的代价。

图4 左右两块拆账条。左块标题「行头:状态集(N_state)」,竖向五段堆叠,每段一个独立标签:①热功能模式 × 车辆使用态 ②三端点态 Init / Shutdown / Sleep ③非用户模式(产线下线检测 / 售后服务 / 运输存放 / 诊断激励)④过渡态(阀在走行程 / 压缩机在升速 / 寻零在进行 / 跨域授权在等回执)⑤降级态与安全状态。右块标题「列头:事件集(N_event)」,竖向七段堆叠:①温度/压力门限越界 ②用户或场景请求 ③故障置位与撤销 ④超时 ⑤外部授权回执 ⑥上下电与电源模式事件 ⑦执行器完成/失败回执。左块的④⑤与右块的⑥⑦用青绿虚框并标「本课补」。两块之间画一个乘号与结果框「分母=N_state × N_event」。图下方一条警示红横带,左端写「只数『用户能感知的模式』会整类漏掉 ③④⑤」,右端写「只沿『谁触发的』数会整类漏掉 ④(无外部触发者)与 ⑦(执行器被当成输出而不是事件源)」,带上用红叉标出对应的段。最右侧一个孤立框:「填格只动分子;⛔ 分母漏了的那一整行/整列,一个字都没定义」。本图为定性拆账示意,段的高度与面积不代表任何数量,⛔ 不得据图读取规模。
图4 分母的两侧:行头五类、列头七类,青绿虚框那四类是本课补的。图下方那条红带标出的,是沿单一线索枚举会整类漏掉的段——它们不是「少数几行」。本图为定性拆账示意,段的高度与面积不代表任何数量,⛔ 不得据图读取规模。

易错点。边填格边改列头——每改一次,前面数出来的那个比值就作废;② 把「事件」与「信号」混为一谈——一个信号可以产生多个事件(越上界、回落到下界各一个),⛔ 不是一信号一列;③ 把 ⑦ 当成「查询执行器状态字」而不是事件——那会让状态机去轮询,而轮询与「等一个不会到来的事件」在卡住时的表现一模一样,都是安安静静地停在原地。

⇒ 今天就能做的那个动作:把你那张表的列头拿出来,逐列问一句「这一列的触发者是谁」。答得出来的落进 ①②③⑤,答「没有触发者」的是 ④,答「执行器」的是 ⑦;一列都归不进 ⑥⑦ 的表,多半就是漏了这两类

1.5 else 兜底与逐格填写是两件事,⛔ 不得互相替代

else 兜底是每个状态的必填项。每个状态必须有一条「上述条件均不成立」的默认分支,且它的动作必须是安全侧的显式动作——进入某个已定义的保守状态、置一个标志、或者显式地保持并计数。

不能是一条什么都没写的空分支。原因有两层:没有 else 的判定节点在生成代码里是一条落空的路径,条件都不成立时程序从判定节点直接掉出去,行为由工具的默认语义决定;而写成「什么都不做」看起来最安全,实际上它丢掉了「这次落空曾经发生过」这条信息——同样的落空发生一万次和发生一次,在系统里没有任何差别。⚠ else 的动作取什么是策略问题,归 K3-01 整车热管理控制策略总览与模式管理K5-02 热管理故障处理与降级策略;本讲只要求它存在、且动作是写得出来的。

★ 而 else 不把该行的任何一格算作已填。这是本讲最容易被当成「优化」的一条:

  • else 回答的是:这个状态的判定节点看到了这个事件、而列出的条件都不成立时怎么办;
  • 逐格填写回答的是:这个事件在这个状态下有没有被看到

两问的主语不同一个状态可以既有 else、又有空格。那个根本没有进入该状态任何判定节点的事件,连 else 都碰不到——它在更外层就被丢弃了。

一个事件到达某个状态,只有三种归宿:

归宿 发生了什么 行为定义了吗
匹配某条出边 ⇒ 按 prio(i) 决出的那条迁移执行 已定义,可追溯
都不成立 ⇒ 落到 else,执行安全侧的显式动作 已定义,且这次落空被记录
根本没被看到 ⇒ 在更外层就被丢弃,连 else 都碰不到 未定义,不置码、不留痕

归宿三就是表上的空格。⇒ 用一条 else 替掉整行的逐格填写,在图上更干净、判定节点更少,而落盘之后整行的未定义行为原样留着

图5 左端入口框「一个事件到达状态 s」,向右经过一个菱形判定「这个事件进入了本状态的任何一个判定节点吗?」,分两支。『是』支再经第二个菱形「列出的条件里有成立的吗?」,再分两支:归宿一(青绿)「匹配某条出边 ⇒ 按 prio(i) 决出的那条迁移执行」;归宿二(橙)「都不成立 ⇒ 落到 else,执行安全侧的显式动作」。『否』支直通归宿三(警示红斜纹)「根本没被看到 ⇒ 在更外层就被丢弃,连 else 都碰不到」,其下一行小字「这一格在表上是空格」。三条归宿下方各挂一个结果条:归宿一「行为已定义,可追溯」;归宿二「行为已定义,且这次落空被记录」;归宿三「行为未定义,不置码、不留痕」。图右侧一个孤立的对照小框,框内画同一个状态既有 else 又有一列空格(else 打勾、空格打叉),旁注「⛔ 一条 else ≠ 整行已填」。本图为定性流程示意,⛔ 不得据图读取任何时序、耗时或概率。
图5 一个事件的三种归宿:else 管的是「看到了但条件都不成立」,逐格填写管的是「有没有被看到」——所以右侧那个对照框里的状态,既有 else 又有空格。本图为定性流程示意,⛔ 不得据图读取任何时序、耗时或概率。

易错点。① 把 C_table 的分子按「有 else 的行 = 整行已填」算——那会把完备率直接虚高一大截,而虚高的方向恰好是「不用再查了」;② 反过来,因为这一条就取消 else——两者都是必填项,⛔ 不是二选一

⇒ 判据一句话:逐格看,⛔ 不是逐分支看。

1.6 完备率 C_table:判据是 100%,且这个数只判「有没有定义」

把前面几节合起来,就得到本课交付的第一个数:

C_table = N_filled /(N_state × N_event),完备判据 C_table = 100%。 其中 N_filled = 已写下确定去向的格数;显式写「保持不动」计入,空格不计入,一条 else 不能把整行算满

为什么判据是 100% 而不是某个统计值。因为它由定义推出,⛔ 不是经验值、⛔ 不是行业统计值:既然每一格空着都是一处未定义行为,那么「没有未定义行为」这句话的数学形式就是分子等于分母。⚠ 它是本课程体系立的提交门禁,⛔ 不是任何标准的条款,也没有哪个编号的标准给过它——请在自己的报告里照此标注。

它的工程用途是把「这张表完不完备」变成一个可机检、可当提交门禁的数:评审据此直接打回,不必逐条争论。

⚠ 方向性:它只判「有没有定义」,⛔ 不判「定义得对不对」。填错一格照样 100%。正确性靠逐格条件表达式的评审与下游用例,⛔ 不靠这个比值。

★ 到这里必须把一句话掰开:「把迁移表的空格填满,完备率就到 100%,这张表就完备了。」

这句话的前半截完全正确——完备率确实是把空格填满才涨上去的,它也确实该做成提交门禁。正因为前半截对,后半截才特别容易跟着一起被接受。

反的是后半截。C_table = N_filled /(N_state × N_event),分子是你填的,分母也是你填的。填格只动分子,而决定这张表管不管用的是分母——行头与列头收全了没有。⇒ 一张漏了「寻零中」这一行、漏了「执行器完成回执」这一列的表,把剩下的格全部填满,算出来是一个货真价实的 100%,而它对漏掉的那一整行、那一整列一个字都没定义

后果不是「差一点」。拿到一张现成的表就直接逐格补空、补完算出 100% 交上去的人,刚刚亲手把「还没查」变成了「已经查过」——后面所有工序都会信任这个结论:可达性分析在缺行的图上做、迁移覆盖率在缺行的分母上算、模型检验对不存在的行无从报告。★ 而且它比一个坏消息更难被拦住:60% 会让人继续查,100% 让人停手。

手算一遍——这一步不能省。这个数太容易被当成工具输出的一个指标,而亲手数一遍行头列头是唯一能让人意识到「分母是我自己填的」的动作。下面这个算例的所有数字都是教学假设,不对应任何平台

设你从上一代平台转来一张迁移表,行头 6 行(Init/Shutdown/Sleep 三个端点态、座舱制冷、座舱制热、降级),列头 5 列(温度门限越界、用户请求、故障置位、故障撤销、超时)。逐格看下来有 3 个格是空的:

这一步 N_state N_event 格数 N_filled C_table
第一次算(照拿来的表) 6 5 30 27 90.0%
补一行「寻零中」之后再算(该行整行为空) 7 5 35 27 77.1%

第一次算完,你会做的动作是把那 3 个空格补上,得到 30 / 30 = 100%,交卷。这就是本课要拦住的那一刻——那 3 个格确实补对了,而「寻零中」这一整行第一次算的时候一个字都没定义,它却让比值看起来更好看。

算例的全部意义在第二行:补一行,分子不变、分母涨、比值掉。(就算你先把 3 个空格填满再补这一行,也只有 30 / 35 ≈ 85.7%——同一个方向。)

(上表所有数字全部是教学假设,不对应任何平台。)⛔ 禁止照抄取用这个算例的规模,⛔ 也不得由它反推「热管理状态机的典型规模是多少」——规模是平台相关量,本课给的是怎么算出你自己那张表的规模行数=上面五类逐类点名之和,列数=七类按冻结规则合并之后的条数

同一个形状在本课后面还会出现两次,⇒ 见到「一个满分」时先问一句「这个分母是谁给的」:迁移覆盖率的分母只含已经写进表里的迁移,从没被写下来的那条规则不会失败、它产生沉默;模型检验的分母是你写下的那几条性质,性质写漏、写得太弱、模型被替换掉的部分,它一律不报。两者的展开都在第 5 讲,这里只把形状先给你。

图6 上下两栏,画同一张小规模迁移表的两个版本,取值与正文算例逐字同值。上栏标题「第一次算」:表体为 6 行 × 5 列,逐格标记「已填」(浅灰底)或「空」(警示红斜纹),共 27 格已填、3 格空;右侧一个计算条三行各带独立标签:N_state = 6 · N_event = 5 · N_filled = 27,下面一行 C_table = N_filled /(N_state × N_event)= 90.0%。下栏标题「补一行『寻零中』之后再算」:同一张表多出一整行,该行 5 格整行为空并用警示红框出;右侧同样三行计算条 N_state = 7 · N_event = 5 · N_filled = 27 与一行结果 C_table = 77.1%,并用一支向下的箭头标注「分子不变、分母涨 ⇒ 比值掉」。两栏之间一条横向连接线,线上写「补的这一行,第一次算的时候一个字都没定义」。图右下角一个橙色声明框:「本算例的行数、列数与已填格数均为教学假设值,⛔ 不对应任何平台、⛔ 禁止照抄取用,⛔ 也不得据此反推热管理状态机的典型规模」。左下角一行判据:完备判据 C_table = 100%(本课程体系立的提交门禁)。本图的表规模为教学假设,⛔ 不对应任何平台、⛔ 不得据图反推状态机的典型规模。
图6 完备率手算算例:C_table 的三个输入全部是你自己数出来的;补一行之后分子不变、分母涨、比值掉——只算第一次等于没算。本图的表规模为教学假设,不对应任何平台,⛔ 禁止照抄取用,⛔ 不得据图反推状态机的典型规模。

报这个数的两条纪律(两条都不满足就别报):① 行头与列头没冻结之前不报;② 报的时候带上表的版本号——版本号不同的两份报告,分母不是同一个东西,结论不可比。

易错点。① 方向性用反:拿 C_table = 100% 去论证「这张表填的内容是对的」;② 在行头列头未冻结前报这个数;③ 只算第一次不算「补一行之后」那一次——那一次才是算例的全部意义

1.7 同一状态的两条出边:互斥、全序,还是绑在绘图顺序上

格上的病讲完了,接下来是边上的病。判据同样写成一条布尔恒等式:

∀ i ≠ j,g_i ∧ g_j ≡ 假;若不恒假,则必须存在显式且稳定的优先序,prio(i) ≠ prio(j)。

这是本课交给模型检验工具的第一条自定义性质(第 5 讲接手),也是它必须写成布尔恒等式而不是一句中文要求的原因——中文要求交不给求解器。⚠ 它同样是本课程体系立的判据,⛔ 不是某标准的条款。

为什么二义性和空格是同一类病。两条 guard 同时成立时,「谁赢」必须由某个东西决定。如果表里和模型里都没写,那么决定它的就是工具的内部次序——而那不是任何人设计过的东西。⇒ 二义性不是「偶尔会走错」,它是行为没有被定义,只是长在边上而不是格上。

同一个状态的两条出边,只可能是下面三态之一:

长什么样 行为定义了吗 可机检的强度
A:恒不交叠 g_i ∧ g_j ≡ 假 已定义 最强——可交给求解器逐对判定
B:会交叠,但有显式全序 prio(i) ≠ prio(j),写在表/模型里可读 已定义 中——只能验「序号互不相同」,验不了这个次序是不是设计者要的
C:会交叠,靠绘制顺序 表里和模型里都没写,谁在前谁赢 未定义

★ 本课把「稳定」的定义钉死:稳定 = 换一个工具版本、重排一次迁移图,行为不变。

不许把「稳定」理解成「每次跑结果一样」——绘制顺序也是确定的,每次跑结果都一样,而它一改图就翻转。态 C 的现场是:改一次图或换一次工具版本,优先序翻转,而功能代码一行都没改——任何 diff 都看不出来,任何回归用例只要没恰好覆盖那个冲突组合也发现不了。这正是本课那根钉子的典型实例:结构缺陷不产生失败,它产生沉默。

图7 三栏并列,每栏画同一个状态 s 引出两条出边(分别标 g_1 / prio(1) 与 g_2 / prio(2)),栏顶各有独立标题与一行判据。栏一「态 A:恒不交叠」——两条出边下方一个布尔条写 ∀ i≠j,g_i ∧ g_j ≡ 假;结论条(青绿)「行为已定义,可交给求解器逐对判定」。栏二「态 B:会交叠,但有显式全序」——布尔条写 g_1 ∧ g_2 不恒假,旁边一张两行小表写 prio(1) ≠ prio(2) 且写在表/模型里可读;结论条(青绿)「行为已定义,机检只能验『序号互不相同』」。栏三「态 C:会交叠,且靠绘制顺序」——两条出边旁画一支『工具内部绘制次序』的灰色虚线箭头,下方并排画同一张图重排前/重排后两个缩略,两者的胜出出边用不同颜色标出;结论条(警示红)「行为未定义:改一次图或换一次工具版本,优先序翻转,而功能代码一行没改」。三栏底部一条横带:「『稳定』=换工具版本、重排一次图,行为不变;⛔ 不是『每次跑结果一样』——绘制顺序也是确定的,每次都一样,一改图就翻转」。本图为定性结构示意,两个缩略图的布局无实义,⛔ 不得据图读取任何工具行为。
图7 同一状态两条出边的三态:只有 A 与 B 的行为是被定义过的;C 的两个缩略图胜出出边不同——这就是「行为变了而任何 diff 都看不出来」的全部现场。本图为定性结构示意,⛔ 不得据图读取任何工具行为。

易错点。① 只检查「看起来会冲突」的那几对——两两全查是可机判的,没有理由抽查;② 用「实际不会同时发生」当理由跳过——那是对输入的假设,而假设必须写下来变成 guard 的一部分,否则它不受任何检查保护;③ 两条出边同优先级并列——那等于把结果交给到达次序,而到达次序不受设计控制;④ 只在有冲突的地方定优先序——今天不冲突的两条边,明天改一次 guard 就可能冲突 ⇒ 优先序应当在建表时就全序给定。

1.8 二义性消解只有三种合法写法,选了哪一种必须写下来

判出交叠之后,合法的消解写法只有三种

写法 可读性 可机检性 引入新状态? 主要后遗症
① 把 guard 改成互斥(给其中一条加互补条件) 随条件变长而下降 最高(判据回到布尔恒等式恒假) 条件越写越长、越难读;改一条可能在别的对上造出新交叠
② 显式定优先序 最好 只能验「序号互不相同」,验不了次序是否是设计者要的 次序的理由不写下来,下一个人不知道为什么是这个序
③ 合成一条出边,进入目标状态后在其内部再分流 图上最干净 中(复杂度搬进状态内部) 新中间状态同样要进行头、逐格填、配超时

三种都合法,选哪一种是代价权衡,⛔ 不是对错题。但必须写明选了哪一种及理由——混着用还不留记录的后果很具体:下一个人看不出这里曾经有过冲突,改 guard 时把消解掉的冲突又打开,而那时它已经不在任何一份评审记录里了。

★ 只有 ③ 会引入新状态,⇒ 它的代价不止在这一处:新中间状态要占行头的一行、要逐格填、要配超时,并且会让 C_table 重算(分母涨)。这不是反对 ③,是提醒它的账要一次算完。

图8 三行 × 四列的对照阵,行头是三种消解写法、列头是四项代价,每格填一句短判断且各带独立标签。行①「把 guard 改成互斥(给其中一条加互补条件)」:可读性=随条件变长而下降;可机检性=最高(判据回到布尔恒等式恒假);引入新状态=否;主要后遗症=条件越写越长、越难读,改一条可能在别的对上造出新交叠。行②「显式定优先序」:可读性=最好;可机检性=只能验『序号互不相同』,验不了次序是否是设计者要的;引入新状态=否;主要后遗症=次序的理由不写下来,下一个人不知道为什么是这个序。行③「合成一条出边,进入目标状态后在其内部再分流」:可读性=图上最干净;可机检性=中(复杂度搬进状态内部);引入新状态=是;主要后遗症=新中间状态同样要进行头、逐格填、配超时。右侧一列结论条:「三选一并写明理由,⛔ 不许混着用还不留记录——下一个人看不出这里曾经有过冲突,改 guard 时会把消解掉的冲突又打开」。行③的『引入新状态=是』用橙色高亮并画一支箭头指回行头堆叠图,箭上写「补一行 ⇒ 分母涨,C_table 重算」。四列代价一律为定性判断,图上不出现任何评分、权重、星级或排序数值。本图为定性权衡示意,格内判断不可比大小,⛔ 不得据图读取任何数值或打分。
图8 三种消解写法的四项代价:可机检性最强的是①、可读性最好的是②,两者不可兼得——所以必须写明选了哪一种及理由。本图为定性权衡示意,格内判断不可比大小,⛔ 不得据图读取任何数值或打分。

易错点。① 选了 ③ 却忘了给新中间状态补行——那等于用一处二义性换来一处空行;② 选了 ① 之后不重跑两两互斥检查——改一条 guard 可能在别的对上造出新的交叠。

⇒ 落成一行可以照抄的记录格式:〈状态〉的〈出边 i〉与〈出边 j〉曾交叠 | 选用写法〈①/②/③〉| 理由〈一句〉| 消解后已重跑两两互斥检查〈是/否〉。这一行进完备性核对报告的二义性清单。

1.9 本讲只做结构性检查,一个阈值也不定——唯一加的那条结构规则

本讲一个阈值也不定。迟滞带 ΔT_hys、最小驻留 t_dwell_min、去抖时间的取法与整定次序K3-01 整车热管理控制策略总览与模式管理K1-01 热管理传感器信号处理与故障诊断,⛔ 本课不给数、⛔ 也不给取法。

本讲只加一条结构规则:

guard 里凡出现阈值,就必须有对应的迟滞或去抖伴生项;缺伴生项即打回。

为什么这条规则属于本课而不是整定课。因为它判的不是「取多少」,而是「有没有」——纯结构判据,能在表上机检。而缺伴生项的后果恰恰落在本课射程里:阈值附近的测量噪声会让同一条迁移在两个状态之间来回翻转,而每一次翻转在逻辑上都完全合法——它不是一处写错的逻辑,它是一条被写对了的迁移在噪声下的正常表现。它的账要到第 5 讲的切换质量验收上才结(切换次数 N_switch 在那一讲是验收量)。

⚠ 伴生项改变的是结构:把一条判定线换成一条带宽度的带、给状态加一段最小驻留——⛔ 不是把阈值挪一挪。带宽与位置由 K3-01 整车热管理控制策略总览与模式管理K1-01 热管理传感器信号处理与故障诊断 给出,本课只查它在不在

图9 上下两栏共用一条横向时间轴,轴上无刻度、无数值,轴末标「时间(无刻度)」。上栏「无伴生项」:一条带噪声的被测量折线在一条水平门槛线附近来回穿越,门槛线画成一条无数值的实线,线右端标注「门槛值由 K3-01 / K1-01 给出,本课不给」;折线下方一条状态条随每次穿越在两个状态色块间来回翻转,翻转处各点一个独立标记,状态条右端一个计数标签「切换次数 N_switch ↑」。下栏「有伴生项」:同一条噪声折线,门槛改画成一条带宽度的带,带上下沿标 ΔT_hys,带整体画成可沿纵轴自由平移,行尾标注「带宽与位置由 K3-01 / K1-01 给出,本课只查它在不在」;另在状态条上标出一段 t_dwell_min 的最小驻留区,同样无刻度;状态条只翻转一次。两栏右侧一个共用结论框:「本课只判『有没有伴生项』,⛔ 不判『取多少』;缺伴生项即打回」,并有一支箭头指向第 5 讲的抖动候选表。本图为定性时序示意,波形为手绘,⛔ 不得据图取任何数值、时长或翻转次数。
图9 缺伴生项时,同一条迁移在阈值附近来回翻转——而每一次翻转在逻辑上都完全合法。图上门槛线与迟滞带均无刻度、可沿纵轴自由平移:这些量本课一个都不给,行尾已标明由谁给出。本图为定性时序示意,波形为手绘,⛔ 不得据图取任何数值、时长或翻转次数。

这条规则的下游用途:任意一对互为反向的迁移,若两条 guard 用的是同一个阈值而没有伴生项,它就是一个抖动候选——直接进第 5 讲切换质量的静态候选表。⇒ 这是一条在还没有任何日志的时候、光看表就能列出来的清单。

易错点。① 把这条规则读成「本课要求加多大的迟滞」——⛔ 不要求,只要求;② 反过来,因为「本课不定阈值」就在 guard 里裸写阈值、连伴生项的位置都不留——那会把整定工作推到没有地方可以落的位置上。

1.10 本讲收口:完备性核对报告的交付规格与提交前自查

本讲交出的是三份报告里的第一份。它的规格是固定的,⛔ 与平台无关:

完备性核对报告必须含 判它合不合格
表的版本号 缺它,这份报告与下一份不可比
行头清单,逐类点名(五类) 五类各写出本项目的条目,缺哪一类要写明为什么
列头清单 + 冻结规则的执行说明(七类) 哪几个门限合成了一列、依据是什么
C_table 与它的三个输入(N_state、N_event、N_filled) 三个数都要能被第二个人独立数出来
二义性清单:每条写明状态、两条出边、选用的消解写法、理由、是否已重跑两两互斥检查 一条不留记录都不行
阈值伴生项检查结果:哪些 guard 里有阈值、各自的伴生项是什么、缺哪几处 判「有没有」,⛔ 不判「取多少」

提交前照着走一遍的自查(八条,全部只看表、不跑任何用例):

  1. 行头五类逐类点名过了吗?过渡态与降级态在不在行头里?
  2. 列头七类逐类点名过了吗?上下电事件与执行器完成/失败回执在不在列头里?
  3. 列头冻结了吗?冻结之后还改过吗?改过就重算。
  4. 每一格都有确定去向吗?「保持不动」是显式写的吗?写明了是「消费并忽略」还是「不消费」吗?
  5. 表里还有「—」「N/A」「无」这三种写法吗?有就等于空格。
  6. 每个状态都有 else 吗?它的动作是写得出来的安全侧动作吗?——并且,你没有拿它顶替任何一格吧?
  7. 每个状态的出边两两都判过 g_i ∧ g_j ≡ 假吗?不恒假的,prio(i) 是写下来的全序吗?
  8. guard 里出现阈值的地方,伴生的迟滞或去抖项都留了位置吗?

⇒ 八条全过,C_table 才有资格被报出来;报的时候连表的版本号一起报。第 2 讲开始往这些格子里填 guard——而填 guard 的前提,正是这张表的行头列头已经在这一讲里冻住了。

后面还有 4 讲正文 · 关键公式 · 案例拆解 · 常见误区 · 动手做

会员专属

后续为会员深水区内容——四库数据与深度拆解。

查看会员方案