4、场景参数化:参数定义、参数空间、参数组合方法

好,咱们接着聊。前面几章我们把场景库的骨架搭起来了,从逻辑场景到具体场景,从自然驾驶数据到法规标准。但说实话,光有这些还不够。你想想看,一个典型的切入场景,光主车速度、目标车速度、相对距离、切入角度、切入时间这几个参数,就能组合出成千上万种情况。要是每个场景都手写,那得写到猴年马月去?

所以,这一章的核心就四个字:参数化。说白了,就是把场景里的可变因素提炼出来,变成可以调节的旋钮。这样我们就能用一套模板,批量生成海量测试用例。我个人习惯,把参数化分成三步走:参数定义、参数空间、参数组合。咱们一步步来看。

4.1 参数定义:找到那些“旋钮”

参数定义,就是回答一个问题:这个场景里,哪些东西是可以变的?

我刚开始做参数化的时候,犯过一个典型的错误——恨不得把所有东西都参数化。结果呢?参数列表长得像购物清单,组合起来数量爆炸,根本跑不完。后来我学乖了,只关注那些对系统性能有显著影响的参数。

一般来说,参数可以分成这么几类:

  • 静态参数:道路结构(直道、弯道、坡度)、车道数、车道宽度、交通标志位置等。这些在场景启动前就定好了。
  • 动态参数:车辆初始位置、初始速度、加速度、切入时间、相对距离等。这些是场景运行过程中变化的。
  • 环境参数:光照强度(白天、黄昏、夜晚)、天气(晴、雨、雪、雾)、路面附着系数等。
  • 目标物参数:目标物类型(轿车、卡车、自行车、行人)、目标物尺寸、目标物行为意图等。

举个例子,一个典型的“前车切入”场景,我通常会定义以下参数:

参数名称 符号 单位 典型取值范围 说明
主车初始速度 V_ego km/h [30, 120] 主车巡航速度
目标车初始速度 V_target km/h [20, 110] 切入车辆初始速度
初始相对距离 D_init m [10, 100] 两车纵向距离
切入角度 θ deg [5, 45] 目标车切入轨迹与主车行驶方向的夹角
切入持续时间 T_cut s [2, 8] 从开始变道到完成变道的时间
路面附着系数 μ - [0.2, 0.9] 低附着代表湿滑路面

嗯,这里要注意:参数定义不是越多越好。我见过有人把“车窗是否打开”都定义成参数,这就有点过了。关键是要聚焦于那些能触发系统边界行为的参数

我的小技巧: 每次定义完参数,我都会问自己一个问题——“如果这个参数不变,会不会漏掉某个关键的失效模式?” 如果答案是“会”,那这个参数就必须保留。

4.2 参数空间:划定“安全区”与“危险区”

参数定义好了,接下来就是划定每个参数的取值范围。这个取值范围,就是参数空间。

参数空间不是随便定的。你不能说“主车速度0到500km/h”,那没有意义。参数空间的边界,应该基于真实世界的物理约束系统的设计运行域(ODD)

我个人习惯把参数空间分成三个区域:

  • 核心区域:ODD明确覆盖的范围。比如某L2级系统ODD规定“适用车速0-130km/h”,那核心区域就是[0, 130]。
  • 边界区域:ODD边界的附近。比如[130, 140]或者略低于0的倒车场景。这些地方最容易出问题。
  • 扩展区域:超出ODD但物理上可能存在的范围。比如车速140以上。这些场景通常用于鲁棒性测试,看看系统会不会“懵掉”。

举个例子,对于“前车切入”场景的参数空间,我可能会这样定义:

参数空间定义(示例):
- V_ego: [30, 130] km/h,步长10 km/h → 11个值
- V_target: [20, 120] km/h,步长10 km/h → 11个值
- D_init: [10, 100] m,步长10 m → 10个值
- θ: [5, 45] deg,步长5 deg → 9个值
- T_cut: [2, 8] s,步长1 s → 7个值
- μ: [0.2, 0.9],步长0.1 → 8个值

你看,每个参数取几个离散值,组合起来就是 11×11×10×9×7×8 = 609,840 种组合。六十万!这还只是一个场景模板。所以,参数空间一定要合理规划,不然就是给自己挖坑。

避坑指南: 我曾经在一个项目中,把参数步长设得太细(比如速度步长1km/h),结果组合数量直接爆炸,仿真集群跑了整整两周还没跑完。后来我把步长改成10km/h,一周就跑完了,而且关键问题一个都没漏。记住:步长不是越细越好,够用就行

4.3 参数组合方法:从“穷举”到“聪明地穷举”

参数空间有了,接下来就是怎么组合这些参数。最笨的方法就是全因子组合——每个参数的所有取值都互相配对。但就像刚才算的,六十万种组合,就算每个场景跑1分钟,也得跑一年多。不现实。

所以,我们需要一些聪明的组合方法。我常用的有这么几种:

4.3.1 边界值分析

这是我最喜欢的方法。经验告诉我,系统失效往往发生在参数的边界附近。比如速度的上下限、距离的最近点、角度的最大值。所以,我会重点测试每个参数的边界值,以及边界值的“邻居”。

举个例子,对于V_ego = [30, 130],我可能会测试:30, 40, 120, 130 这四个值。而不是从30到130每个都测。

4.3.2 正交实验设计

当参数很多的时候,正交实验设计是个好办法。它能用最少的组合数,覆盖到参数之间的“两两交互”。说白了,就是保证每一对参数的所有取值组合都至少出现一次。

比如我们有6个参数,每个参数取5个值。全因子组合是 5^6 = 15625 种。但用正交表,可能只需要 25 种或 50 种组合。效率提升是数量级的。

4.3.3 基于风险的采样

这个方法更高级一些。我们会根据历史数据、专家经验或者先验知识,给每个参数组合打一个“风险分”。风险高的组合优先测试,风险低的可以少测甚至不测。

比如,根据自然驾驶数据统计,相对速度差大 + 相对距离小 的组合,事故风险最高。那我们就重点测试这些组合。

4.3.4 组合示例

在实际项目中,我通常会把几种方法混着用。比如:

  1. 先用边界值分析,挑出每个参数的边界值。
  2. 然后用正交实验设计,把这些边界值组合起来。
  3. 最后,根据风险评分,补充一些“高风险”组合。

这样既能保证覆盖率,又能控制测试数量。我上一个项目,用这种方法把六十万种组合压缩到了 2000 种,关键问题一个都没漏。

核心思想: 参数组合不是要“测遍所有可能”,而是要“用最少的测试,覆盖最多的失效模式”。记住这个原则,你的测试效率会提升一个档次。

4.4 实战:一个参数化场景的生成流程

说了这么多,咱们来个实战演练。假设我们要生成一批“前车切入”场景的测试用例。

第一步:定义参数

我们选定了6个关键参数:V_ego, V_target, D_init, θ, T_cut, μ。每个参数的含义和取值范围见上面的表格。

第二步:划定参数空间

每个参数取5个值(包括边界和中间值),比如V_ego取 [30, 50, 80, 110, 130]。

第三步:选择组合方法

我们用正交实验设计。查一下标准正交表 L25(5^6),意思是25次实验,覆盖6个5水平因子。嗯,正好合适。

第四步:生成参数组合矩阵

根据正交表,我们得到25组参数组合。比如:

组合1: V_ego=30, V_target=20, D_init=10, θ=5, T_cut=2, μ=0.2
组合2: V_ego=30, V_target=50, D_init=30, θ=15, T_cut=3, μ=0.4
...
组合25: V_ego=130, V_target=120, D_init=100, θ=45, T_cut=8, μ=0.9

第五步:生成具体场景

把每一组参数填入场景模板,生成25个具体的OpenSCENARIO文件。每个文件就是一个独立的测试用例。

第六步:补充高风险组合

根据经验,我们再加5组“高风险”组合,比如“高速+近距离+大角度”。这样总共30个测试用例,就可以提交给仿真平台了。

你看,整个过程就像搭积木一样。参数化让场景生成变得自动化、批量化。这也是为什么我说,参数化是场景库构建的基石

最后提醒一句: 参数化不是一劳永逸的。随着系统迭代和ODD扩展,参数定义和参数空间都需要不断更新。我每个季度都会review一次参数库,看看有没有需要调整的地方。保持迭代,才能让场景库始终“锋利”。