3. 场景构造入门
场景(Scenario)是无人车仿真测试的核心载体,它定义了被测车辆(DUT, Device Under Test)在特定时间与空间范围内所面临的全部外部条件与任务要求。从工程实践角度看,场景并非简单的“地图+障碍物”叠加,而是一个包含道路拓扑、交通参与者行为、环境状态、通信条件及任务目标的结构化数据集合。场景构造的质量直接决定了仿真测试的有效性与置信度——一个构造粗糙的场景可能无法触发目标算法缺陷,而一个过度复杂的场景又可能引入难以复现的随机噪声。因此,理解场景的形式化定义、掌握场景元素的分解方法、熟练运用场景描述语言(如OpenSCENARIO、ASAM OpenX系列),是构建高价值仿真测试用例的基石。
上图展示了场景构造的总体框架:场景定义位于中心,左侧为静态元素(描述“在哪里”),右侧为动态元素(描述“发生了什么”),底部为场景描述语言(描述“如何编码”)。静态元素通常由高精地图或OpenDRIVE文件承载,动态元素则由OpenSCENARIO等语言定义时序行为。两者通过场景管理器在仿真运行时同步绑定,共同构成一个可执行、可复现的测试用例。
3.1 场景定义与层次化分类
核心原理:场景定义需要区分三个层次——功能场景(Functional Scenario)、逻辑场景(Logical Scenario)与具体场景(Concrete Scenario)。功能场景使用自然语言描述测试意图,例如“前车紧急制动,本车需避免碰撞”;逻辑场景引入参数化变量,如“前车初始速度范围为60~80 km/h,制动减速度范围为-4~-6 m/s²”;具体场景则将参数赋值为确定数值,生成可执行的仿真用例。这种分层设计使得测试用例既能覆盖参数空间,又能保持语义可追溯性。
判断方法:在工程实践中,场景分类还需考虑测试目标。按照ISO 21448(SOTIF)与ASAM OpenX标准,场景可划分为:
- 基于法规的场景:如Euro NCAP的AEB(自动紧急制动)测试规程,场景参数固定,用于合规验证。
- 基于事故统计的场景:从自然驾驶数据或事故数据库中提取典型冲突场景,如路口鬼探头、高速匝道汇入。
- 基于边缘探索的场景:通过参数随机化或对抗生成网络(GAN)构造极端工况,如传感器部分失效、路面附着系数突变。
| 场景层次 | 描述方式 | 参数状态 | 典型用途 |
|---|---|---|---|
| 功能场景 | 自然语言/图形化 | 无参数 | 需求分析、测试意图沟通 |
| 逻辑场景 | 参数化描述(范围/分布) | 参数未赋值 | 参数空间探索、覆盖率分析 |
| 具体场景 | 数值化定义(确定值) | 参数已赋值 | 仿真执行、回归测试 |
3.2 场景元素分解:从道路到天气
操作流程:场景元素的分解应遵循“先静态后动态、先宏观后微观”的顺序。具体步骤如下:
- 道路拓扑建模:定义车道数、车道宽度、曲率、坡度、超高以及道路连接关系(交叉口类型、匝道长度)。在OpenDRIVE中,使用
planView描述道路几何,使用laneSection描述车道属性。 - 交通标志与信号:包括限速牌、停止线、导向箭头、信号灯相位与配时。需注意标志的可视范围与遮挡关系,这直接影响感知模块的输入。
- 动态障碍物定义:设置车辆、行人、两轮车的初始位置、速度、加速度及轨迹。在OpenSCENARIO中,通过
PrivateAction和Trajectory定义其运动行为。 - 环境与天气:包括光照强度、雨量、雪量、雾浓度、路面附着系数。天气参数不仅影响传感器(摄像头、激光雷达)的噪声模型,还影响车辆动力学(如制动距离)。
- 通信与传感器条件:定义V2X通信延迟、丢包率,以及传感器故障注入(如摄像头遮挡、雷达多径干扰)。
案例拆解:以“雨天夜间行人横穿”场景为例,其元素分解如下:
- 道路:双向四车道城市道路,车道宽3.5m,限速50km/h,无中央隔离带。
- 标志:前方50m处有人行横道预告标志,路面有停止线。
- 动态障碍物:行人以1.4m/s速度从右侧路缘出发,横穿两条车道;对向车道有一辆速度为40km/h的来车(开启近光灯)。
- 天气:中雨(降雨量15mm/h),路面附着系数0.5,环境照度50lux。
- 传感器条件:摄像头镜头有雨滴附着(模拟脏污),激光雷达点云噪声增加20%。
该场景的目标是验证AEB系统在低附着、低能见度条件下对行人目标的识别与制动性能。通过调整行人速度(1.0~2.0 m/s)和降雨量(5~30 mm/h),可生成一组逻辑场景,用于探索系统性能边界。
3.3 场景描述语言:OpenSCENARIO与DSL实践
核心原理:场景描述语言是将场景元素编码为机器可读格式的桥梁。目前行业主流是ASAM OpenSCENARIO(XML格式),它支持描述动态行为、轨迹、时间触发条件与事件。一个典型的OpenSCENARIO文件包含RoadNetwork(引用OpenDRIVE文件)、Entities(定义车辆与行人)、Storyboard(定义行为序列与触发条件)。
操作流程:编写OpenSCENARIO场景通常遵循以下步骤:
- 定义
FileHeader,声明版本与作者信息。 - 在
RoadNetwork中引用高精地图文件(.xodr)与3D模型(.fbx/.glb)。 - 在
Entities中声明所有参与对象,包括DUT、目标车辆、行人,并指定其初始位置与朝向。 - 在
Storyboard中创建Init(初始化动作)与Story(主行为序列)。使用Act、Maneuver、Event组织行为,通过Condition(如距离、速度、时间)触发事件。 - 使用
ParameterDeclaration定义可变参数,便于批量生成具体场景。
<!-- OpenSCENARIO 片段示例:前车紧急制动 -->
<ScenarioDefinition>
<ParameterDeclarations>
<ParameterDeclaration name="lead_speed" parameterType="double" value="20.0"/>
<ParameterDeclaration name="brake_decel" parameterType="double" value="-5.0"/>
</ParameterDeclarations>
<Entities>
<ScenarioObject name="Ego">
<Vehicle category="car">
<Performance maxSpeed="50" maxAcceleration="10" maxDeceleration="15"/>
<BoundingBox>...</BoundingBox>
</Vehicle>
</ScenarioObject>
<ScenarioObject name="LeadCar">
<Vehicle category="car">...</Vehicle>
</ScenarioObject>
</Entities>
<Storyboard>
<Init>
<Actions>
<Private entityRef="Ego">
<PrivateAction>
<TeleportAction><Position><LanePosition roadId="1" s="10" laneId="0"/></Position></TeleportAction>
</PrivateAction>
</Private>
<Private entityRef="LeadCar">
<PrivateAction>
<TeleportAction><Position><LanePosition roadId="1" s="40" laneId="0"/></Position></TeleportAction>
</PrivateAction>
</Private>
</Actions>
</Init>
<Story name="BrakeStory">
<Act name="Act1">
<ManeuverGroup name="MG1" maximumExecutionCount="1">
<Actors><EntityRef entityRef="LeadCar"/></Actors>
<Maneuver name="BrakeManeuver">
<Event name="BrakeEvent">
<Action name="DecelAction">
<PrivateAction>
<LongitudinalAction>
<SpeedAction>
<SpeedActionDynamics dynamicsShape="step" dynamicsDimension="time" value="0.5"/>
<SpeedActionTarget>
<AbsoluteTargetSpeed value="0.0"/>
</SpeedActionTarget>
</SpeedAction>
</LongitudinalAction>
</PrivateAction>
</Action>
<StartCondition>
<ConditionGroup>
<Condition name="DistanceCondition" delay="0">
<ByValue>
<DistanceCondition value="25" freespace="false" rule="lessThan"/>
</ByValue>
</Condition>
</ConditionGroup>
</StartCondition>
</Event>
</Maneuver>
</ManeuverGroup>
</Act>
</Story>
</Storyboard>
</ScenarioDefinition>
常见误区:初学者常将OpenSCENARIO视为“脚本语言”,试图在其中编写复杂的逻辑判断(如if-else)。实际上,OpenSCENARIO是声明式语言,其触发条件(Condition)应基于场景状态(距离、速度、时间)而非算法逻辑。复杂的决策应放在DUT的自动驾驶算法中,而非场景描述中。此外,场景中的Condition应避免使用时间作为唯一触发条件,因为仿真步长、物理引擎差异可能导致时序偏移,建议使用相对距离或相对速度作为触发依据。
3.4 场景库构建与质量评估
核心原理:单个场景的价值有限,场景库的构建需要关注覆盖率与冗余度。覆盖率指场景对参数空间、道路类型、行为模式的覆盖程度;冗余度则指多个场景是否在测试同一算法缺陷。常用的评估指标包括:参数组合覆盖率、场景相似度(基于编辑距离或特征向量)、功能触发率(场景是否成功触发目标功能)。
操作流程:构建场景库的推荐流程为:
- 从事故数据库、自然驾驶数据集(如highD、INTERACTION)中提取关键冲突片段。
- 将冲突片段抽象为功能场景,并定义参数范围。
- 使用参数采样方法(如拉丁超立方、正交实验)生成具体场景。
- 在仿真平台中批量执行,记录通过/失败/超时结果。
- 使用聚类算法(如DBSCAN)分析失败场景的共性,补充边界场景。
| 评估维度 | 指标示例 | 工具/方法 |
|---|---|---|
| 参数覆盖率 | 速度范围覆盖比例、天气类型覆盖数 | 覆盖率矩阵、组合测试 |
| 行为多样性 | 变道次数、紧急制动次数、行人横穿次数 | 行为标签统计 |
| 场景相似度 | 平均编辑距离、余弦相似度 | Python脚本(scikit-learn) |
| 功能触发率 | AEB触发次数/总场景数 | 仿真日志分析 |
总结复盘:场景构造是仿真测试的“输入工程”,其质量直接决定测试结论的可信度。本章重点阐述了场景的分层定义(功能/逻辑/具体)、元素分解方法(静态+动态)、描述语言实践(OpenSCENARIO)以及场景库构建策略。在实际项目中,建议建立“场景需求-场景实现-场景验证”的闭环流程:每个场景都应有明确的测试目标,实现后需通过“场景自检”(检查地图匹配、行为合理性、参数范围)方可入库。下一阶段,我们将深入探讨场景参数化与自动生成技术,以应对海量测试用例的需求。