从需求到认证的完整流程

📋 前言

在当今复杂的嵌入式系统开发中,模型测试已成为确保产品质量和安全性的关键环节。特别是在汽车、轨道交通等安全关键领域,系统化的模型测试不仅是技术要求,更是法规合规的必要条件。

本文将为您详细介绍模型测试的核心概念、方法和最佳实践,帮助您建立一套完整的测试体系。
备注:团队的学习笔记分享,如果需要相关模型测试的工具请联系我们(support@softor.com.cn)文章中如果写的有错误,请批评指正。


🎯 为什么需要模型测试?

1️⃣ 验证模型正确性

2️⃣ 评估模型性能

3️⃣ 保证模型稳定性

4️⃣ 满足功能安全标准

在高安全要求的行业,模型测试是满足功能安全标准的必要条件:


🔒 功能安全标准认证

主要认证标准

标准适用领域说明
IEC 61508工业自动化功能安全通用标准
EN 50128轨道交通铁路应用软件开发标准
ISO 25119农业机械农业和林业机械安全标准
IEC 62304医疗设备医疗器械软件生命周期标准
ISO 26262汽车电子道路车辆功能安全标准(最新版支持最高工具置信度水平 TCL 3,可达到最高安全级别 ASIL D)
ASPICE汽车软件汽车软件过程改进和能力评定

为什么需要标准认证?


📝 测试内容详解

1. 基于需求的测试

模型和代码的功能测试

什么是基于需求的测试?

基于需求的测试就是根据产品的功能需求来设计测试用例,确保模型和代码能够正确实现所有要求的功能。简单来说,就是”按要求测试”,确保系统做了它应该做的事情。

测试内容:

测试方法:

  1. 1. 需求分析:仔细阅读需求文档,提取出所有需要测试的功能点
  2. 2. 测试用例设计:为每个功能点设计具体的测试场景
  3. 3. 测试执行:运行测试用例并记录结果
  4. 4. 结果验证:检查实际输出是否与预期结果一致

实际例子:自适应巡航控制系统(ACC)

业务场景:在高速公路上,ACC系统需要根据前方车辆的速度自动调整本车速度,以保持安全距离。

需求:当前方车辆减速时,ACC系统应自动减速以保持安全距离(安全距离 = 速度 × 0.3秒)

测试用例

  1. 1. 正常跟随场景:前方车辆以100km/h行驶,测试车辆以100km/h跟随,验证安全距离保持在约8.3米(100km/h × 0.3秒)
  2. 2. 前方车辆减速场景:前方车辆从100km/h突然减速至60km/h,验证测试车辆是否也自动减速至60km/h,并保持约5米的安全距离
  3. 3. 前方车辆停止场景:前方车辆完全停止,验证测试车辆是否安全停止,且与前方车辆保持约2米的停车距离
  4. 4. 前方车辆加速场景:前方车辆从60km/h加速至100km/h,验证测试车辆是否平稳加速跟随

代码示例(简化的ACC控制逻辑):

void acc_control(float target_speed, float front_vehicle_speed, float distance)
{
    float safe_distance = target_speed * 0.3; // 安全距离计算公式
    
    if (distance < safe_distance) {
        // 距离过近,需要减速
        if (front_vehicle_speed < target_speed) {
            set_vehicle_speed(front_vehicle_speed);
        } else {
            set_vehicle_speed(target_speed);
        }
    } else {
        // 距离合适,保持目标速度
        set_vehicle_speed(target_speed);
    }
}

测试覆盖:确保减速、加速、停止等所有功能需求都被完全测试覆盖

2. 测试执行阶段(MiL/SiL/PiL/HiL)

什么是虚拟集成测试?

虚拟集成测试(Virtual Integration Testing)是指在虚拟环境中对嵌入式系统进行测试的方法,通过模拟真实环境来验证系统的功能和性能。它不需要实际的硬件,可以在开发早期就进行测试,大大降低了测试成本和风险。

虚拟集成测试的四个阶段

在嵌入式软件测试中,根据测试执行环境的不同,分为以下四个阶段:

测试阶段英文全称说明特点测试环境
MiLModel-in-the-Loop模型在环测试在模型层面进行仿真测试,验证模型逻辑正确性Simulink/Stateflow等建模环境
SiLSoftware-in-the-Loop软件在环测试在宿主机上运行生成的代码,验证代码功能PC/工作站(Windows/Linux)
PiLProcessor-in-the-Loop处理器在环测试在目标处理器上运行代码,验证处理器兼容性目标ECU或仿真器
HiLHardware-in-the-Loop硬件在环测试在实际硬件环境中测试,验证系统集成实际ECU + 传感器/执行器

各阶段详细说明

1. MiL(Model-in-the-Loop)- 模型在环测试

2. SiL(Software-in-the-Loop)- 软件在环测试

3. PiL(Processor-in-the-Loop)- 处理器在环测试

4. HiL(Hardware-in-the-Loop)- 硬件在环测试

虚拟集成测试的优势

  1. 1. 早期发现问题:在开发早期就能进行测试,降低后期修复成本
  2. 2. 降低测试成本:不需要大量实际硬件,减少测试设备投入
  3. 3. 提高测试效率:自动化程度高,可以快速执行大量测试用例
  4. 4. 增强测试覆盖率:可以模拟各种边界和异常情况
  5. 5. 支持持续集成:可以集成到CI/CD流程中,实现自动化测试

测试流程:

需求分析 → 模型设计 → MiL测试 → 代码生成 → SiL测试 → PiL测试 → HiL测试 → 实车测试

实际应用场景

汽车电子领域

工业自动化领域

航空航天领域

3. 背靠背测试

全自动等效性测试

什么是背靠背测试?

背靠背测试就像是让两个学生做同一份试卷,然后对比他们的答案是否一致。在模型测试中,就是让模型和生成的代码执行相同的测试用例,然后对比它们的输出结果,确保代码生成过程没有引入错误。

测试内容:

测试方法:

  1. 1. 基准测试:在原始模型环境(如Simulink)中运行测试用例,获取基准输出(MiL)
  2. 2. 代码测试:在目标环境(如生成的C代码)中运行相同测试用例(SiL/PiL)
  3. 3. 结果对比:自动对比两组输出结果
  4. 4. 差异分析:标记差异并生成测试报告

实际例子:发动机燃油喷射控制

业务场景:发动机控制系统需要根据转速、负载等参数精确计算燃油喷射量,以确保发动机高效运行。

模型与代码

测试用例

测试场景转速(rpm)负载(%)预期燃油喷射量(ms)
怠速工况800102.5
部分负荷2000504.8
全负荷40001008.2
急加速3000→450080→1006.5→9.0

测试过程

  1. 1. MiL测试:在Simulink中运行上述测试用例,记录模型的燃油喷射量输出作为基准
  2. 2. SiL测试:在宿主机上运行生成的C代码,使用相同的测试用例
  3. 3. PiL测试:在目标ECU处理器上运行代码,使用相同的测试用例
  4. 4. 结果对比:自动对比三种环境下的输出结果
  5. 5. 差异分析:如果结果不一致,分析原因并修复

代码示例(自动生成的燃油喷射控制代码):

float calculate_fuel_injection(float rpm, float load)
{
    // 基于转速和负载的燃油喷射量计算
    float base_injection = 0.001 * rpm + 0.05 * load;
    float correction = 0.0;
    
    // 温度修正
    if (engine_temp < 60.0) {
        correction = 0.5;
    }
    
    return base_injection + correction;
}

4. 覆盖率分析

代码及模型覆盖率统计(死代码检测)

什么是覆盖率分析?

覆盖率分析就像是检查我们的测试用例是否覆盖了所有的代码路径,确保没有遗漏任何重要的功能。它可以帮助我们发现哪些代码没有被测试到,哪些代码可能是多余的(死代码)。

测试内容:

测试方法:

  1. 1. 数据收集:在测试执行过程中收集覆盖率数据
  2. 2. 报告生成:生成详细的覆盖率报告
  3. 3. 路径分析:分析未覆盖的代码路径
  4. 4. 用例补充:针对未覆盖的路径补充测试用例
  5. 5. 死代码处理:识别并处理死代码
  6. 6. 圈复杂度计算:使用McCabe方法计算圈复杂度

覆盖率标准:

覆盖类型要求适用场景
语句覆盖100%基础要求
分支覆盖100%安全关键功能
MC/DC覆盖100%最高安全等级(ASIL D)

圈复杂度(Cyclomatic Complexity)

什么是圈复杂度?

圈复杂度(Cyclomatic Complexity)是由Thomas McCabe提出的一种软件度量指标,用于评估代码的复杂度和可测试性。它反映了程序中独立路径的数量。

计算公式:

圈复杂度 = E - N + 2P

其中:

简化计算方法:

圈复杂度 = 判定节点数量 + 1

判定节点包括:if语句、while循环、for循环、case语句等。

圈复杂度标准:

圈复杂度代码质量建议
1-10低风险代码简单,易于测试和维护
11-20中等风险代码复杂度适中,需要关注
21-50高风险代码复杂,建议重构
>50极高风险代码过于复杂,必须重构

实际例子:

// 圈复杂度 = 4(3个if + 1)
void abs_control(float speed, float brake_pressure, float wheel_speed)
{
    float slip_ratio = (speed - wheel_speed) / speed;
    
    if (speed > 100 && brake_pressure > 50 && slip_ratio > 0.2) {  // 判定1
        apply_abs_pulse();
    } else if (speed > 50 && slip_ratio > 0.15) {  // 判定2
        apply_abs_regular();
    } else if (brake_pressure > 70) {  // 判定3
        apply_regular_brake();
    } else {
        apply_light_brake();
    }
}

圈复杂度在测试中的作用:

  1. 1. 测试用例数量:圈复杂度表示至少需要多少个测试用例才能覆盖所有可能的执行路径
  2. 2. 代码质量评估:高圈复杂度通常意味着代码难以理解和维护
  3. 3. 重构指导:当圈复杂度过高时,建议将函数拆分为多个小函数
  4. 4. 安全标准要求:ISO 26262等安全标准对圈复杂度有明确要求

降低圈复杂度的方法:

  1. 1. 函数拆分:将复杂函数拆分为多个小函数
  2. 2. 使用策略模式:用多态替代复杂的条件判断
  3. 3. 卫语句:尽早返回,减少嵌套层级
  4. 4. 状态机:用状态机管理复杂的状态转换

降低圈复杂度示例:

// 原始代码:圈复杂度 = 5
void process_order(Order* order) {
    if (order != NULL) {
        if (order->status == PENDING) {
            if (order->amount > 1000) {
                if (order->customer->vip_level > 2) {
                    apply_discount(order, 0.2);
                } else {
                    apply_discount(order, 0.1);
                }
            } else {
                process_normal(order);
            }
        } else {
            reject_order(order);
        }
    }
}

// 重构后:圈复杂度 = 2
void process_order(Order* order) {
    if (order == NULL) return;
    
    if (order->status != PENDING) {
        reject_order(order);
        return;
    }
    
    if (order->amount > 1000) {
        apply_vip_discount(order);
    } else {
        process_normal(order);
    }
}

void apply_vip_discount(Order* order) {
    if (order->customer->vip_level > 2) {
        apply_discount(order, 0.2);
    } else {
        apply_discount(order, 0.1);
    }
}

实际例子:防抱死制动系统(ABS)控制

业务场景:ABS系统需要根据车速和制动压力自动调整制动模式,以防止车轮抱死。

代码示例

void abs_control(float speed, float brake_pressure, float wheel_speed)
{
    // 计算滑移率
    float slip_ratio = (speed - wheel_speed) / speed;
    
    if (speed > 100 && brake_pressure > 50 && slip_ratio > 0.2) {
        // 高速高压力下的ABS控制
        apply_abs_pulse();
    } else if (speed > 50 && slip_ratio > 0.15) {
        // 中速下的ABS控制
        apply_abs_regular();
    } else if (brake_pressure > 70) {
        // 高压力下的常规制动
        apply_regular_brake();
    } else {
        // 低速或低压力下的轻度制动
        apply_light_brake();
    }
}

覆盖率测试

1. 语句覆盖测试用例

2. 分支覆盖测试用例

3. MC/DC覆盖测试用例

4. 死代码检测

覆盖率报告示例

覆盖类型目标实际状态
语句覆盖100%100%
分支覆盖100%100%
MC/DC覆盖100%100%
死代码00

5. 形式化规格说明

需求形式化

什么是形式化规格说明?

形式化规格说明就是用数学语言来精确描述需求,消除自然语言的歧义,确保需求的准确性和一致性。简单来说,就是把模糊的文字描述变成精确的数学表达式。

测试内容:

测试方法:

  1. 1. 需求转换:将自然语言需求转换为形式化描述
  2. 2. 规约定义:使用形式化语言(如Z语言、B方法)定义规约
  3. 3. 可追溯性:建立需求与实现之间的可追溯性

实际例子:安全气囊系统

业务场景:安全气囊系统需要在发生碰撞时,根据碰撞严重程度决定是否弹出气囊,以保护乘客安全。

自然语言需求:当汽车发生碰撞时,安全气囊应该在合适的时机弹出

形式化规格说明

安全气囊弹出条件 = 碰撞加速度 > 30g 且 碰撞持续时间 > 10ms 且 车辆速度 > 20km/h

安全气囊不弹出条件 = 碰撞加速度 ≤ 30g 或 碰撞持续时间 ≤ 10ms 或 车辆速度 ≤ 20km/h

形式化语言表示(使用Z语言):

z
气囊弹出?: bool
气囊弹出? = (碰撞加速度 > 30) ∧ (碰撞持续时间 > 10) ∧ (车辆速度 > 20)
z

可追溯性

通过形式化描述,我们消除了”合适的时机”这样的模糊表达,明确了安全气囊弹出的具体条件,为后续的验证奠定了基础。

6. 形式化验证

形式验证

什么是形式验证?

形式验证就是使用数学方法来证明系统的正确性,通过穷举所有可能的执行路径,确保系统在所有情况下都能正确运行。这是一种最高级别的验证方法,可以提供数学上的保证。

测试内容:

测试方法:

  1. 1. 模型建立:建立系统的形式化模型
  2. 2. 属性定义:定义需要验证的属性(如安全性、活性)
  3. 3. 验证执行:使用模型检测或定理证明工具进行验证
  4. 4. 结果分析:分析验证结果并修复问题

实际例子:火车信号控制系统

业务场景:火车信号系统需要控制不同火车在轨道网络中的运行,确保不会发生碰撞。

系统需求:确保在任何情况下,同一轨道上不会有两列火车同时行驶

形式化模型

形式验证过程

  1. 1. 模型建立:使用模型检测工具(如NuSMV)建立火车信号系统的形式化模型
  2. 2. 属性定义:定义安全属性公式AG (∀s ∈ 轨道, ∀t1,t2 ∈ 火车, t1 ≠ t2 → ¬(在轨道s上(t1) ∧ 在轨道s上(t2)))
  3. 3. 验证执行:使用模型检测工具验证安全属性
  4. 4. 结果分析

代码示例(信号控制逻辑):

bool is_track_free(int track_id)
{
    for (int i = 0; i < MAX_TRAINS; i++) {
        if (trains[i].current_track == track_id && trains[i].status == RUNNING) {
            return false;
        }
    }
    return true;
}

void control_signal(int track_id, int signal_id)
{
    if (is_track_free(track_id)) {
        set_signal_green(signal_id);
    } else {
        set_signal_red(signal_id);
    }
}

验证结果

通过形式验证,我们可以确保火车信号系统的安全性,避免碰撞事故的发生。


📋 七、测试流程

7.1 测试流程概述

模型开发的测试流程包括以下7个关键阶段:

  1. 1. 需求分析
  2. 2. 测试设计
  3. 3. 功能测试
  4. 4. 等效性测试
  5. 5. 覆盖率分析
  6. 6. 形式化验证(高安全等级要求)
  7. 7. 测试报告与认证

7.2 测试流程图示

需求分析 → 测试设计 → 功能测试 → 等效性测试 → 覆盖率分析 → 形式化验证 → 测试报告与认证

🔄 八、开发工作流程与测试方法映射

8.1 开发与测试关系

开发阶段对应测试方法测试目标
需求分析Requirements-based Testing确保测试覆盖所有需求
模型设计功能测试、形式化规格说明验证模型功能正确性
代码生成Back-to-Back Test确保代码与模型行为一致
集成测试覆盖率分析确保代码被充分测试
系统测试形式化验证确保系统安全性

8.2 测试执行环境映射

测试方法执行环境适用阶段
功能测试MiL (Model-in-the-Loop)模型设计阶段
等效性测试MiL → SiL → PiL代码生成阶段
覆盖率分析SiL, PiL集成测试阶段
形式化验证模型级、代码级全生命周期
系统验证HiL (Hardware-in-the-Loop)系统测试阶段

8.3 测试方法应用场景


💡 九、最佳实践

9.1 测试数据准备

9.2 测试指标选择

9.3 自动化测试

9.4 持续监控


�� ISO 26262-6 软件单元测试方法

根据ISO 26262-6标准,软件单元测试需要采用以下方法:

软件单元测试方法(Table 10)

方法ASIL AASIL BASIL CASIL D说明
1a 基于需求的测试++++++++根据需求规格设计测试用例
1b 接口测试++++++++验证模块间接口正确性
1c 故障注入测试+++++通过注入故障验证容错能力
1d 资源使用测试+++++验证内存、CPU等资源使用
1e 背靠背对比测试++++++对比模型与代码输出一致性

测试用例设计方法(Table 11)

方法ASIL AASIL BASIL CASIL D说明
1a 需求分析++++++++分析需求以确定测试范围
1b 等价类生成与分析+++++++将输入划分为等价类进行测试
1c 边界值分析+++++++测试边界条件下的系统行为
1d 错误推测++++基于经验推测可能的错误

符号说明


🔧 测试套件功能

1. 功能测试套件

就像是一个测试管理员

主要功能:

实际例子:
假设我们开发一个汽车空调控制系统:

2. 背靠背测试套件

就像是一个严格的考官

主要功能:

实际例子:
开发一个发动机燃油喷射控制模型:

3. 形式测试套件

就像是一个翻译官

主要功能:

实际例子:
处理一个汽车安全系统的需求:

4. 形式验证套件

就像是一个数学证明专家

主要功能:

实际例子:
验证一个火车信号控制系统:


🚀 测试工具核心优势

提高效率

高质量测试确保按时交付优质产品:

一款工具,无限可能

一次测试部署,赋能全流程:

无缝集成

可以无缝集成到现有的工作流程和工具链中:

易用性

无需编程知识即可轻松应用于整个测试流程中:


🔄 测试流程

  1. 1. 需求分析 – 理解功能需求和安全需求,识别测试需求
  2. 2. 测试设计 – 设计测试用例(基于需求),确定测试覆盖目标,准备测试数据
  3. 3. 功能测试 – Requirements-based Testing,验证模型功能正确性
  4. 4. 等效性测试 – Back-to-Back Test,对比模型与代码输出
  5. 5. 覆盖率分析 – Coverage Analysis,统计代码/模型覆盖率,识别死代码
  6. 6. 形式化验证 – Formal Specification和Formal Verification(高安全等级要求)
  7. 7. 测试报告与认证 – 生成测试报告,准备认证文档

💡 最佳实践

测试数据准备

测试指标选择

自动化测试

持续监控


🎉 总结

模型测试是确保模型质量和安全性的关键环节。通过遵循功能安全标准(如ISO 26262、IEC 61508等),采用系统化的测试方法(Requirements-based Testing、Back-to-Back Test、Coverage Analysis等),可以有效地:

  1. 1. 验证模型的正确性和可靠性
  2. 2. 满足行业安全标准要求
  3. 3. 降低系统风险
  4. 4. 提高产品质量

在高安全要求的领域,选择合适的测试工具类型并建立完善的测试流程,是项目成功的关键保障。


**如果需要进一步的帮助或有其他问题,请随时联系我们。
support@softor.com.cn
tianpengbo@softor.com.cn
**

希望对您的项目有所帮助!

在线留言