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 种组合。六十万!这还只是一个场景模板。所以,参数空间一定要合理规划,不然就是给自己挖坑。
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 组合示例
在实际项目中,我通常会把几种方法混着用。比如:
- 先用边界值分析,挑出每个参数的边界值。
- 然后用正交实验设计,把这些边界值组合起来。
- 最后,根据风险评分,补充一些“高风险”组合。
这样既能保证覆盖率,又能控制测试数量。我上一个项目,用这种方法把六十万种组合压缩到了 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个测试用例,就可以提交给仿真平台了。
你看,整个过程就像搭积木一样。参数化让场景生成变得自动化、批量化。这也是为什么我说,参数化是场景库构建的基石。