尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ISO 26262功能安全项目实战:基于模型的设计与代码生成落地指南

ISO 26262功能安全项目实战:基于模型的设计与代码生成落地指南 1. 从手写C代码到模型驱动ISO 26262项目为什么绕不开基于模型的设计做汽车电子功能安全的同行大概都有这种体会项目一旦挂上ISO 26262的标签整个开发流程的严谨程度会陡然上升一个量级。以前写个电机控制逻辑手撸几百行C代码跑通就行现在同样一个控制功能你得拿出需求追溯矩阵、结构覆盖率报告、边界值测试用例、代码与模型的一致性证明——光是文档就能堆满一个文件柜。我参与过三个ASIL B到ASIL D级别的量产项目前两个项目试图用传统手写代码的方式硬扛26262的流程要求结果在验证阶段被审核方反复打回最惨的一次是代码评审时发现一个手写状态机的边界条件遗漏直接导致项目延期六周。后来团队痛定思痛全面转向基于模型的设计Model-Based DesignMBD路线用Simulink搭建控制算法模型通过Embedded Coder自动生成产品级C代码。这个转变带来的不只是效率提升更重要的是它天然契合ISO 26262对开发过程可追溯、可验证、可复现的核心诉求。模型本身就是一份可执行的规格说明需求可以链接到模型元素模型可以链接到生成的代码代码可以链接到测试用例——整条链路在工具链里是打通的。这篇文章面向的是正在或即将在ISO 26262项目中落地MBD的嵌入式软件工程师、功能安全经理和系统架构师。我会从实际项目经验出发拆解MBD在功能安全项目中的完整落地路径包括工具链配置、建模规范、代码生成策略、验证与确认活动以及那些只有踩过坑才知道的细节。无论你用的是Simulink加Embedded Coder这套经典组合还是正在评估其他建模工具这里面的思路和方法论都是通用的。2. 功能安全语境下MBD工具链的选型与资质确认2.1 为什么工具资质确认是第一个要过的坎ISO 26262-8第11章对工具置信度Tool Confidence LevelTCL有明确要求。简单说你得证明你用的建模和代码生成工具不会在开发过程中引入未被检测到的错误。TCL的判定取决于两个维度工具对安全相关输出的影响程度TITool Impact和工具失效被检测到的概率TDTool Diagnostic Coverage。如果TI为高且TD为低TCL就是最高的3级意味着你需要对工具进行资质确认Qualification。Simulink和Embedded Coder在MathWorks的官网上有专门的IEC Certification Kit和ISO 26262相关的资质确认文档包包括工具认证报告、缺陷列表、使用限制说明等。但这里有个常见的误解很多人以为买了这个文档包就万事大吉了。实际上工具供应商提供的资质确认材料只是起点你还需要结合自己的具体使用场景做补充验证。比如你用Embedded Coder的某个优化选项生成了代码而这个选项在供应商的资质确认范围内没有被覆盖那你就得自己补做验证。我的做法是在项目启动阶段就建立一份工具使用清单列出所有用到的Simulink模块库、代码生成配置项、验证工具如Simulink Test、Polyspace然后逐一对照供应商的资质确认文档标记出哪些在覆盖范围内、哪些需要补充验证。这份清单在后续的审核中会被反复查阅提前做好能省掉大量返工。2.2 建模工具与验证工具的组合策略一个完整的MBD工具链通常包含这几个环节建模Simulink/Stateflow、仿真验证Simulink Test/Design Verifier、静态检查Polyspace/MISRA Checker、代码生成Embedded Coder、代码级验证Polyspace Code Prover/Unit Test。每个环节的工具都需要做资质确认但策略可以有所不同。对于建模工具重点确认的是模块的语义正确性和仿真引擎的数值精度。Simulink的仿真引擎经过大量工业验证资质确认材料相对完善但要注意不同求解器Solver的适用场景和精度差异。对于代码生成工具重点确认的是生成代码与模型语义的一致性以及优化选项对代码行为的影响。Embedded Coder的资质确认文档里会列出已知的限制条件比如某些模块组合在特定配置下可能生成不符合预期的代码这些限制条件必须在使用中严格遵守。验证工具方面Polyspace的资质确认材料比较充分但要注意它本身的误报率和漏报率。在实际项目中我通常会把Polyspace的检查结果和Simulink Test的测试结果做交叉验证两者都通过才认为该模块的验证是充分的。2.3 工具链版本管理与配置冻结功能安全项目对工具链版本的管理要求极其严格。一旦项目进入正式开发阶段工具链版本就必须冻结任何升级都需要走变更控制流程。我见过一个项目因为中途升级了MATLAB版本导致生成的代码在某个边界条件下行为发生了变化虽然最终定位到是求解器默认参数调整导致的但排查过程耗费了大量精力。建议的做法是在项目启动时就确定工具链的完整版本号包括MATLAB、Simulink、Embedded Coder、编译器、静态检查工具等并记录在配置管理计划中。同时把代码生成配置Configuration Parameters导出为脚本文件纳入版本控制。这样即使换了开发机器也能保证生成代码的一致性。3. 面向ASIL等级的Simulink建模规范与架构约束3.1 模型架构的分层与模块化原则ISO 26262对软件架构设计有明确要求包括层次化、模块化、高内聚低耦合等。在Simulink中这些要求体现为模型的分层架构。我的习惯是把模型分为三层应用层Application Layer、基础软件层Basic Software Layer和硬件抽象层Hardware Abstraction Layer。应用层放控制算法基础软件层放调度、诊断、故障管理等服务硬件抽象层放寄存器读写、外设驱动等与具体MCU相关的逻辑。这种分层的好处是应用层模型可以做到完全与硬件无关方便做SILSoftware-in-the-Loop和PILProcessor-in-the-Loop测试。基础软件层和硬件抽象层则可以通过模型引用Model Reference的方式独立开发和验证。Simulink的模型引用功能在这里非常关键它允许你把一个大模型拆成多个独立可测试的子模型每个子模型可以单独做单元测试和覆盖率分析。需要注意的是模型引用会增加代码生成的复杂度。每个被引用的模型会生成独立的C文件和头文件接口定义需要严格管理。我通常会用Simulink的接口编辑器Interface Editor来定义模型间的数据接口确保类型、维度、采样时间都明确无误。3.2 建模规范MISRA Simulink与MAAB的取舍MathWorks自己有一套建模规范叫MAABMathWorks Automotive Advisory Board风格指南后来演化为MISRA Simulink规范。这两个规范有重叠也有差异实际项目中怎么选我的经验是如果项目明确要求符合MISRA标准那就以MISRA Simulink为准MAAB作为补充如果没有强制要求可以以MAAB为基础根据项目实际情况做裁剪。不管选哪个有几条规则是必须遵守的。第一禁止使用未定义的采样时间所有模块的采样时间必须显式指定。第二禁止在模型中使用浮点数做精确比较必须用容差。第三禁止使用递归函数调用和动态内存分配。第四所有Stateflow状态机必须有明确的默认转移和完整的条件覆盖。第五禁止使用Simulink中标记为不建议用于代码生成的模块。这些规则听起来简单但在实际建模中很容易被违反。我的做法是在Simulink中配置Model Advisor把选定的规范规则集导入每次模型更新后自动运行检查。Model Advisor可以生成检查报告这份报告在功能安全审核时是重要的证据材料。3.3 针对ASIL D的额外约束如果项目要求达到ASIL D建模约束会进一步收紧。首先必须使用经过资质确认的模块子集Simulink中有些模块虽然功能强大但不在资质确认范围内就不能用。其次必须做结构覆盖率分析包括语句覆盖、分支覆盖、MC/DCModified Condition/Decision Coverage。Simulink Design Verifier可以自动生成满足MC/DC的测试用例但生成的用例需要人工审核其合理性。另外ASIL D要求对模型进行形式化验证或等价性检查。Simulink Design Verifier的属性证明功能可以用来验证模型是否满足某些安全属性比如输出永远不会超过某个阈值。但形式化验证的计算复杂度很高通常只对关键模块做不会全模型铺开。还有一个容易被忽略的点ASIL D要求对代码生成器的输出做独立验证。也就是说你不能只依赖Embedded Coder的资质确认材料还需要用独立的工具或方法验证生成的代码与模型语义一致。常用的做法是用Polyspace Code Prover对生成代码做静态分析或者用Simulink Test做模型与代码的等价性测试Back-to-Back Testing。4. Embedded Coder代码生成配置与优化实战4.1 代码生成配置的关键参数解析Embedded Coder的配置参数有上百个但真正影响功能安全和代码质量的也就那么几十个。我按重要性排个序重点说几个容易出问题的。首先是系统目标文件System Target File。对于汽车电子项目通常选ert.tlcEmbedded Coder或autosar.tlc如果项目用AUTOSAR架构。ert.tlc生成的是紧凑高效的C代码适合大多数嵌入式项目。如果项目有AUTOSAR要求那就得用autosar.tlc生成的代码会遵循AUTOSAR的软件组件模板。其次是代码生成目标Code Generation Objectives。Embedded Coder提供了几个预设目标比如Execution efficiency、RAM efficiency、MISRA C:2012 compliance等。我的建议是优先选MISRA C:2012 compliance然后在满足合规的前提下再优化效率。因为功能安全项目对代码规范的符合性是硬性要求效率可以后续通过其他手段优化。第三是代码替换库Code Replacement LibraryCRL。CRL允许你用目标编译器的优化函数替换标准数学函数比如用ARM CMSIS-DSP库替换Simulink的数学运算。这能显著提升代码效率但前提是CRL本身经过验证。如果项目对功能安全要求高使用CRL需要额外的资质确认。第四是浮点与定点配置。如果目标MCU没有FPU浮点运算单元必须把模型中的浮点运算转换为定点运算。Simulink提供了Fixed-Point Designer工具来做这个转换但转换过程需要仔细验证数值精度。我通常会用Simulink的定点工具做自动转换然后通过仿真对比转换前后的输出差异确保精度损失在可接受范围内。4.2 生成代码的结构与接口管理Embedded Coder生成的代码结构取决于模型的配置。默认情况下每个模型会生成一个C文件和一个头文件包含模型的初始化函数、步进函数和终止函数。如果用了模型引用每个子模型也会生成独立的文件。接口管理是代码生成中最容易出问题的环节。Simulink模型的输入输出端口需要映射到C函数的参数或全局变量。我通常会用Simulink的Code Mapping功能把模型端口显式映射到存储类Storage Class比如ExportedGlobal、ImportedExtern、ModelDefault等。对于安全相关信号建议用Volatile存储类防止编译器优化导致信号读写顺序变化。还有一个细节生成代码中的数据类型必须与模型中的数据类型严格一致。Simulink默认会用double类型但在嵌入式项目中这会导致代码体积和运行时间都不可接受。必须在模型中将信号和参数的数据类型显式指定为single、int32、uint16等并在代码生成配置中设置Default data type为合适的类型。4.3 代码生成后的静态检查与合规验证代码生成完成只是第一步接下来必须做静态检查。Polyspace Bug Finder和Code Prover是常用的工具。Bug Finder主要查运行时错误比如数组越界、空指针解引用、整数溢出等。Code Prover做更深入的形式化分析可以证明某些运行时错误不存在。对于MISRA C:2012合规性Polyspace提供了MISRA检查规则集。但要注意Polyspace的MISRA检查结果会有误报需要人工审核。我的做法是先把所有MISRA违规分为三类必须修复的如未初始化变量、隐式类型转换、可以偏离的如某些规则在特定场景下不适用、误报的。对于可以偏离的需要写偏离申请Deviation Request说明理由并获得功能安全经理的批准。另外生成代码的注释质量也很重要。Embedded Coder可以自动生成注释包括模型元素与代码行的对应关系。这些注释在代码评审和追溯性分析时非常有用。建议在配置中开启Generate comments和Traceability选项。5. 模型与代码的验证确认活动从SIL到PIL的完整闭环5.1 模型级验证Simulink Test与Design Verifier的配合模型级验证是MBD流程中最核心的验证环节。Simulink Test用来管理测试用例、执行测试、生成报告。Design Verifier用来做形式化分析和自动测试用例生成。两者配合使用可以覆盖大部分验证需求。我的流程是这样的先用Design Verifier对模型做属性证明验证一些关键的安全属性比如输出不会超过物理极限、状态机不会进入死锁状态。然后用Design Verifier自动生成满足MC/DC覆盖率的测试用例。这些用例会导入Simulink Test作为回归测试的基础。最后人工补充一些边界条件和异常场景的测试用例这些是自动生成工具难以覆盖的。Simulink Test的测试评估Test Assessment功能很实用可以在测试执行过程中实时检查信号是否满足预期条件。比如你可以设置一个评估规则当输入超过阈值时输出应在100ms内切换到安全状态。这种时序相关的验证用手动方式很难做用Test Assessment就很方便。5.2 SIL与PIL测试验证生成代码与模型的一致性SIL测试是在PC上运行生成的代码验证代码行为与模型仿真一致。PIL测试是在目标MCU上运行生成的代码验证代码在真实硬件上的行为。这两个测试是功能安全项目中的强制要求用来证明代码生成过程没有引入错误。SIL测试的配置相对简单用Simulink的SIL/PIL Simulation功能把模型替换为生成的代码然后运行相同的测试用例对比输出差异。关键是要设置合理的容差因为浮点运算在PC和MCU上的结果可能有微小差异。我通常会把容差设为1e-6对于定点运算则要求完全一致。PIL测试需要目标硬件的支持配置起来麻烦一些。需要为目标MCU创建PIL通信接口通常用串口或JTAG。PIL测试的执行速度比SIL慢很多因为每次步进都要通过通信接口与目标板交互。所以PIL测试通常只跑关键测试用例不会全量跑。这里有个坑PIL测试的采样时间必须与模型配置一致否则测试结果没有意义。另外PIL测试时目标MCU的中断处理、看门狗、时钟配置等都会影响代码行为需要确保这些底层配置与最终产品一致。5.3 覆盖率分析与测试充分性评估ISO 26262对测试覆盖率有明确要求。对于ASIL A和B要求语句覆盖和分支覆盖对于ASIL C和D还要求MC/DC覆盖。Simulink Coverage工具可以分析模型覆盖率Polyspace可以分析代码覆盖率。覆盖率分析的关键是测试充分性的论证。达到100%的覆盖率不等于测试充分因为覆盖率只说明代码被执行了不说明执行结果是否正确。我通常会把覆盖率分析与需求追溯结合起来每个需求至少有一个测试用例覆盖每个测试用例至少验证一个需求。这样既能保证覆盖率又能保证需求验证的完整性。对于未覆盖的代码必须给出合理解释。比如某些防御性代码如默认分支在正常运行时不会被执行但为了安全必须保留。这类未覆盖代码需要在安全分析报告中说明其必要性和合理性。6. 那些只有踩过坑才知道的实操细节6.1 模型引用与代码生成的冲突处理模型引用在大型项目中几乎是必用的但它和代码生成有一些冲突点。最常见的问题是被引用模型的采样时间与顶层模型不一致导致生成的代码出现速率转换Rate Transition问题。Simulink会在速率转换处自动插入Rate Transition模块但这些模块的行为在代码生成时可能不符合预期。我的解决方案是在模型架构设计阶段就统一采样时间策略。所有子模型的采样时间必须是顶层模型采样时间的整数倍且速率转换必须显式处理不能依赖Simulink的自动插入。对于必须做速率转换的地方用明确的Rate Transition模块并配置为Ensure data integrity during data transfer。另一个问题是模型引用的接口数据类型不一致。比如顶层模型用double子模型用singleSimulink会在接口处自动做类型转换但生成的代码可能包含隐式类型转换违反MISRA规则。解决办法是在接口编辑器里显式定义数据类型确保顶层和子模型一致。6.2 Stateflow状态机的代码生成陷阱Stateflow是建模状态机的好工具但它的代码生成有一些陷阱。首先Stateflow默认使用double类型做状态变量这在嵌入式项目中很浪费。需要在Stateflow中显式指定状态变量的数据类型通常用uint8或uint16就够了。其次Stateflow的During和Entry动作在代码生成时的执行顺序需要特别注意。如果动作之间有依赖关系执行顺序错误会导致逻辑错误。我通常会在Stateflow中避免复杂的动作组合把逻辑拆分成多个简单的状态和转移。第三Stateflow的并行状态Parallel States在代码生成时会生成多个执行分支如果并行状态之间有数据竞争生成的代码行为可能不确定。对于安全相关逻辑建议避免使用并行状态改用顺序状态机。6.3 代码生成配置的版本兼容性MATLAB每年发布两个版本每个版本的Embedded Coder配置参数都可能变化。如果项目周期跨版本或者团队成员的MATLAB版本不一致就会出现生成的代码不一致的问题。我的做法是在项目启动时创建一个代码生成配置脚本把所有配置参数用MATLAB命令的方式写出来纳入版本控制。每次代码生成前先运行这个脚本确保配置一致。同时在项目文档中明确记录MATLAB和Embedded Coder的版本号所有团队成员必须使用相同版本。如果项目中途必须升级MATLAB版本需要做完整的回归测试对比升级前后生成的代码差异评估影响范围。这个工作量很大所以能避免就避免。6.4 与底层软件的集成调试生成的代码最终要集成到完整的ECU软件中与底层驱动、操作系统、通信栈等一起编译链接。这个集成过程经常出问题。最常见的问题是生成的代码与底层软件的接口不匹配。比如生成的代码期望某个全局变量是uint16类型但底层软件定义的是uint8。这类问题在编译时可能不会报错但运行时会出现数据截断。解决办法是在集成前做接口一致性检查用脚本自动对比生成代码的头文件与底层软件的头文件。另一个问题是生成的代码对栈空间的需求。Simulink生成的代码默认使用静态内存分配但如果模型中有大型数组或复杂函数调用栈空间需求可能超过MCU的可用栈。需要在代码生成配置中设置栈大小限制并在集成测试中监控栈使用情况。还有一个实际经验生成的代码在调试时单步执行可能因为编译器优化而跳转混乱。建议在调试阶段关闭编译器优化-O0等功能验证通过后再开启优化-O2或-Os并做回归测试。7. 从项目实践看MBD在功能安全中的边界与扩展7.1 MBD不是银弹适用场景与局限性基于模型的设计在功能安全项目中确实能解决很多问题但它不是万能的。对于控制算法、状态机、信号处理这类逻辑密集型功能MBD的优势非常明显。但对于底层驱动、通信协议栈、复杂数据结构操作这类功能手写代码可能更直接、更高效。我的经验是应用层软件用MBD底层软件用手写代码两者通过明确的接口交互。这样既能享受MBD在功能安全流程上的优势又能避免在不适合的场景强行用MBD带来的额外复杂度。另外MBD对团队技能有要求。建模人员需要同时懂控制算法和嵌入式软件还要熟悉功能安全流程。如果团队缺乏这类复合型人才MBD的落地会很困难。我见过一些项目买了Simulink和Embedded Coder但因为没人会用最后还是回到手写代码的老路。7.2 与AUTOSAR的协同如果项目采用AUTOSAR架构Simulink和Embedded Coder提供了AUTOSAR Blockset来做软件组件建模和代码生成。AUTOSAR Blockset可以生成符合AUTOSAR规范的ARXML描述文件和软件组件代码与AUTOSAR工具链如DaVinci Configurator、EB tresos集成。但AUTOSAR和MBD的集成有一些坑。首先AUTOSAR的RTERuntime Environment生成需要ARXML文件而Simulink生成的ARXML可能不完全符合特定AUTOSAR工具链的要求需要手动调整。其次AUTOSAR的端口和接口定义与Simulink的端口映射需要仔细配置否则生成的代码无法正确集成。我的建议是在项目早期就搭建一个最小可用的AUTOSAR加MBD集成环境跑通一个简单的软件组件验证工具链的兼容性。不要等到项目中期才发现集成问题那时候改起来代价很大。7.3 持续集成与自动化验证功能安全项目对验证的重复性和一致性要求很高手工执行验证流程容易出错。我强烈建议搭建持续集成CI环境把模型检查、代码生成、静态分析、单元测试等环节自动化。具体的做法是用Jenkins或GitLab CI作为CI平台每次代码提交后自动触发以下流程运行Model Advisor检查建模规范、用Simulink Test执行回归测试、用Embedded Coder生成代码、用Polyspace做静态分析、生成验证报告。如果任何环节失败自动通知相关人员。这套CI流程的搭建需要前期投入但长期来看能大幅提升验证效率和一致性。特别是在功能安全审核时CI生成的验证报告是强有力的证据材料。7.4 功能安全审核中的常见问题与应对最后说说功能安全审核。审核方通常会关注几个方面工具资质确认是否完整、建模规范是否落实、验证覆盖率是否达标、追溯性是否完整、变更管理是否规范。我遇到最多的审核问题是追溯性不完整。审核方会随机抽取一个需求要求你展示从需求到模型、从模型到代码、从代码到测试用例的完整追溯链路。如果中间有断点就会被开不符合项。解决办法是用需求管理工具如DOORS、Polarion与Simulink建立链接确保每个模型元素都能追溯到需求每个测试用例都能追溯到模型元素。另一个常见问题是变更管理不规范。功能安全项目中的任何变更包括模型修改、配置调整、工具升级都需要走变更控制流程评估影响范围并做回归测试。我见过一个项目因为修改了一个看似无关的模型参数导致生成的代码在某个边界条件下行为变化因为没有做回归测试问题直到集成测试才发现。说到底MBD在ISO 26262项目中的应用工具和技术只是一部分更重要的是流程和意识。把功能安全的理念融入到日常开发的每一个环节而不是等到审核前才临时抱佛脚这才是项目成功的关键。我在实际项目中的体会是前期在流程和工具链上多花一个月后期能省下至少三个月的返工时间。这笔账怎么算都划算。
返回列表