3. 场景构造入门

场景(Scenario)是无人车仿真测试的核心载体,它定义了被测车辆(DUT, Device Under Test)在特定时间与空间范围内所面临的全部外部条件与任务要求。从工程实践角度看,场景并非简单的“地图+障碍物”叠加,而是一个包含道路拓扑、交通参与者行为、环境状态、通信条件及任务目标的结构化数据集合。场景构造的质量直接决定了仿真测试的有效性与置信度——一个构造粗糙的场景可能无法触发目标算法缺陷,而一个过度复杂的场景又可能引入难以复现的随机噪声。因此,理解场景的形式化定义、掌握场景元素的分解方法、熟练运用场景描述语言(如OpenSCENARIO、ASAM OpenX系列),是构建高价值仿真测试用例的基石。

场景构造核心要素与描述语言映射 场景定义(Scenario) 时间+空间+任务+环境约束 静态场景元素 • 道路拓扑(车道数/曲率/坡度) • 路面标识(车道线/停止线) • 交通标志(限速/禁行/指示) • 固定设施(护栏/路缘/建筑) • 道路连接关系(交叉口/匝道) • 交通信号灯(相位/配时) • 临时施工区/锥桶 → OpenDRIVE / 高精地图 动态场景元素 • 交通参与者(车辆/行人/骑手) • 运动轨迹(速度/加速度/航向) • 行为意图(变道/超车/让行) • 交通流密度与交互 • 天气(雨/雪/雾/光照) • 通信(V2X/信号遮挡) • 传感器噪声/故障注入 → OpenSCENARIO / 逻辑场景 场景描述语言:OpenSCENARIO XML / Python API / 领域特定语言(DSL)

上图展示了场景构造的总体框架:场景定义位于中心,左侧为静态元素(描述“在哪里”),右侧为动态元素(描述“发生了什么”),底部为场景描述语言(描述“如何编码”)。静态元素通常由高精地图或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 场景元素分解:从道路到天气

操作流程:场景元素的分解应遵循“先静态后动态、先宏观后微观”的顺序。具体步骤如下:

  1. 道路拓扑建模:定义车道数、车道宽度、曲率、坡度、超高以及道路连接关系(交叉口类型、匝道长度)。在OpenDRIVE中,使用planView描述道路几何,使用laneSection描述车道属性。
  2. 交通标志与信号:包括限速牌、停止线、导向箭头、信号灯相位与配时。需注意标志的可视范围与遮挡关系,这直接影响感知模块的输入。
  3. 动态障碍物定义:设置车辆、行人、两轮车的初始位置、速度、加速度及轨迹。在OpenSCENARIO中,通过PrivateAction和Trajectory定义其运动行为。
  4. 环境与天气:包括光照强度、雨量、雪量、雾浓度、路面附着系数。天气参数不仅影响传感器(摄像头、激光雷达)的噪声模型,还影响车辆动力学(如制动距离)。
  5. 通信与传感器条件:定义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场景通常遵循以下步骤:

  1. 定义FileHeader,声明版本与作者信息。
  2. 在RoadNetwork中引用高精地图文件(.xodr)与3D模型(.fbx/.glb)。
  3. 在Entities中声明所有参与对象,包括DUT、目标车辆、行人,并指定其初始位置与朝向。
  4. 在Storyboard中创建Init(初始化动作)与Story(主行为序列)。使用Act、Maneuver、Event组织行为,通过Condition(如距离、速度、时间)触发事件。
  5. 使用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应避免使用时间作为唯一触发条件,因为仿真步长、物理引擎差异可能导致时序偏移,建议使用相对距离或相对速度作为触发依据。

实战复盘:在某主机厂的AEB系统开发中,测试团队构造了“前车切入”场景。初始版本使用固定时间(3秒后)触发前车变道,导致在低性能服务器上运行时,由于仿真帧率波动,前车切入位置偏差达2米,测试结果不稳定。后改为“当两车相对距离小于15米时触发变道”,场景复现率从78%提升至99.5%。这提示我们:场景描述语言中的触发条件应优先选择物理量(距离、速度、加速度),而非时间量。

3.4 场景库构建与质量评估

核心原理:单个场景的价值有限,场景库的构建需要关注覆盖率与冗余度。覆盖率指场景对参数空间、道路类型、行为模式的覆盖程度;冗余度则指多个场景是否在测试同一算法缺陷。常用的评估指标包括:参数组合覆盖率、场景相似度(基于编辑距离或特征向量)、功能触发率(场景是否成功触发目标功能)。

操作流程:构建场景库的推荐流程为:

  1. 从事故数据库、自然驾驶数据集(如highD、INTERACTION)中提取关键冲突片段。
  2. 将冲突片段抽象为功能场景,并定义参数范围。
  3. 使用参数采样方法(如拉丁超立方、正交实验)生成具体场景。
  4. 在仿真平台中批量执行,记录通过/失败/超时结果。
  5. 使用聚类算法(如DBSCAN)分析失败场景的共性,补充边界场景。
评估维度指标示例工具/方法
参数覆盖率速度范围覆盖比例、天气类型覆盖数覆盖率矩阵、组合测试
行为多样性变道次数、紧急制动次数、行人横穿次数行为标签统计
场景相似度平均编辑距离、余弦相似度Python脚本(scikit-learn)
功能触发率AEB触发次数/总场景数仿真日志分析
风险说明:场景库并非越大越好。过多的相似场景会消耗计算资源,且可能掩盖关键缺陷。建议定期使用“变异分析”剔除冗余场景——对场景参数施加微小扰动,若测试结果不变,则说明该场景对参数不敏感,可考虑合并或删除。

总结复盘:场景构造是仿真测试的“输入工程”,其质量直接决定测试结论的可信度。本章重点阐述了场景的分层定义(功能/逻辑/具体)、元素分解方法(静态+动态)、描述语言实践(OpenSCENARIO)以及场景库构建策略。在实际项目中,建议建立“场景需求-场景实现-场景验证”的闭环流程:每个场景都应有明确的测试目标,实现后需通过“场景自检”(检查地图匹配、行为合理性、参数范围)方可入库。下一阶段,我们将深入探讨场景参数化与自动生成技术,以应对海量测试用例的需求。