ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

智能驾驶行为安全评价:指标、算法与Python实现

智能驾驶行为安全评价:指标、算法与Python实现

简介:这份智能驾驶行为安全评价方法白皮书,由多位行业专家与机构参编,面向自动驾驶研发、测试评价及安全监管人员,系统阐释了功能安全、预期功能安全、行为安全、ODD/ODC合理性、人机交互安全等十余个评价维度,重点围绕“合理可预见且可避免”展开技术、法律伦理与用户体验三个层面的深度剖析。资源为单个PDF文档,体积约10.5MB,内容结构完整,包含智能驾驶安全概念综述、行为安全概念、场景枚举方法、交互场景参数化过程及封闭道路低速场景实践案例,并配有参编单位与专家信息,便于读者把握权威视角。目前已有132人学习使用。读者可借此理解自动驾驶安全评价的多维框架,掌握行为安全中场景覆盖度定义与参数化方法,为构建安全评价体系或开展相关研究提供参考依据。

1. 智能驾驶行为安全评价:先回答“评价什么”,再谈“怎么算”

如果把一辆测试车放到封闭场地连续跑一百圈,AEB 一次没误触发,评价人员通常会给它一个接近满分的评价。可同一个系统到了真实路口,面对缓慢横穿的行人连续三次不减速,问题才暴露出来——我们给“安全”打分时,多数时候只看有没有发生碰撞、接管或紧急制动,很少盯着方向盘转角、油门刹车深度、车头时距这些持续变化的行为量。智能驾驶行为安全评价方法,说的就是把这套过程性行为变量变成可度量、可比较、可追溯的安全评价体系。它适合算法工程师做版本回归、测试工程师做场景验收,也适合安全团队做驾驶行为风险分级。全文会沿着指标设计、数据准备、算法选型到工程落地这条线展开,过程中的关键坑我会逐个点出来。

2. 把安全拆成指标与数据:纵向、横向、场景交互怎么量化

行为安全评价的第一关,不是选模型,而是定义指标。一个算不明白的指标,后面再漂亮的算法都是空转。业界通常把驾驶行为分成三个维度:纵向操控、横向操控、场景交互。每个维度都要有明确的原始信号来源、计算公式和风险阈值参考,否则测试团队拿到结果也没法追溯。

2.1 纵向行为指标:TTC、THW 与急减速事件

纵向维度看的是系统对车距和车速的控制能力。最常用的两个量是 TTC(Time To Collision,碰撞时间)和 THW(Time Headway,车头时距),它们经常被混用,但物理含义完全不同。TTC 是相对距离除以相对速度,回答“如果两车维持当前状态,多久会撞上”;THW 是相对距离除以本车速度,回答“按当前车速,几秒后会到达前车当前位置”。低速跟车时 THW 会变得很大,显得安全,但 TTC 可能因为前车急刹而迅速变小,所以两个指标必须同时看。

指标原始信号计算公式风险参考阈值注意点
THW本车速度、前车纵向距离前车距离 / 本车速度小于 1.0s 高风险,1.0~2.0s 关注本车速度接近 0 时无意义,需加速度下限
TTC前车相对距离、相对速度相对距离 / 相对车速小于 1.0s 紧急,小于 3.0s 预警仅在前车相对本车为接近状态时有意义
急减速次数纵向加速度加速度小于 -3.0m/s² 且持续 0.3s 以上每 10 分钟超过 1 次需排查与 AEB 触发区分开,避免重复计数

急减速事件的定义要具体到“持续时长”,否则一次 0.1s 的加速度尖峰会被误判成风险事件。我一般用加速度低于 -3.0m/s² 且持续时间大于等于 0.3s 作为一个事件,短脉冲如果峰值超过 -4.5m/s² 也单独计一次。这样既能过滤传感器噪声,又不会漏掉真正的紧急制动。

2.2 横向行为指标:车道偏移稳定性与转向平滑性

横向维度衡量的是车辆是否稳定保持在车道内、方向控制是否平滑。车道偏移标准差是最直接的量:取一个滑窗内的车道中心偏移量算标准差,高速公路场景 0.3m 以内的偏移标准差是可以接受的,超过 0.5m 基本说明系统在“画龙”。

转向平滑性可以用转向熵来量化。把方向盘转角变化量离散到直方图,再算信息熵,公式为:

H = -Σ p(x) * log2(p(x))

其中 x 是相邻时刻方向盘转角差值,p(x) 是差值落在某个分箱的概率。熵越高,说明转向角变化越杂乱,系统在频繁找正方向。低速泊车场景转向熵天然偏高,所以这个指标要按车速区间分开评估,不能一刀切。

2.3 场景交互指标:限速、变道与切入避险

行为安全不能只看自车状态,还要看系统在具体交通场景里的交互行为。限速合规是底线指标,我通常给限速值加 5km/h 容差,超过这个值的时间占比超过 10% 就要扣分。变道行为看两个量:打灯到完成变道的时长,以及变道全程与被超越车辆的 TTC 最小值,TTC 小于 2s 的变道会被测试团队直接标记为危险变道。

前车切入场景需要单独建事件。常见做法是检测相邻车道车辆横向位移穿过本车车道边界的时间点,然后从切入前 2s 到切入后 5s 截取一段行为数据,统计这段窗口内的最小 TTC 和本车减速度。这类事件在普通评价指标里很容易被平均掉,所以必须做事件级切片。

2.4 指标归一化与时间对齐:评价稳定性的前提

指标算完还不等于能进模型。多传感器数据的时间戳不对齐,计算出的 TTC 会出现虚假跳变,分数时高时低。数据准备阶段必须做三件事:统一时间基准到纳秒级;对缺失帧做插值,但跳变超过 0.5s 的片段直接丢弃;按 10s 窗口、5s 步长切分,保证相邻窗口有重叠但不至于过度平滑。

归一化方面我不建议用均值加标准差。驾驶行为数据长尾严重,一次急刹就能把均值拉偏,用中位数加 MAD(绝对中位差)做稳健标准化更可靠。每个指标的归一化参数要从全量历史数据里标定,而不是只从当前测试段里算,否则换一段路分数就会整体漂移。

3. 评价算法选型:规则评分、学习模型与风险场,哪一种适合你

指标定义清楚之后,下一个问题是把多维度指标融合成一个安全分数。融合方式没有绝对最优解,取决于你手里的数据量、对可解释性的要求、以及这个评价结果要用于什么决策。做量产安全评价的底线是:每个低分都能说清楚因为什么而低。

3.1 规则评分:权重明确、可审计,适合作为出厂底线

规则评分是把每个指标映射成扣分项或者加分项,再用加权求和得到总分,公式为

Score = 100 - Σ w_i * f_i(x_i)

其中 f_i 是第 i 个指标的惩罚函数,w_i 是权重。规则评分最大的优点是可审计:一个 45 分的窗口,能看到是因为 TTC 过低扣了 35 分,还是因为频繁急减速扣了 15 分。测试评审会上拿这个打分过程当证据,效率非常高。

规则评分的落地步骤通常是这样:先为每个指标设一个“合格线”和“危险线”,比如 TTC 大于 3s 不扣分、小于 1s 扣 35 分、中间线性过渡;再按指标重要性定权重,纵向指标权重最高,横向次之,场景交互指标做事件级额外扣分;最后在测试集上跑一遍,和分级员的主观评价做一致性对比,反向调整阈值。

权重怎么定是规则评分最容易“翻车”的环节。我不建议直接拍脑袋定权重,而是先跑一版默认权重,再找一条典型测试数据让两三个测试工程师分别给出主观评分,用 Spearman 相关系数看算法分和主观分是否一致,哪段路偏差大就调整对应指标的阈值。这种“人机一致性校准”虽然土,但非常管用。

3.2 学习模型:让离线评价跟上复杂场景

规则评分能覆盖大部分场景,但面对“多车博弈”“近距离切入”这类复杂事件,规则阈值很难穷举。常见做法是引入学习模型,把行为序列映射成安全分数。输入特征可以包括本车速度、加速度、横向偏移、方向盘转角、前车距离、前车相对速度,以及周围目标的轨迹序列;输出既可以是 0~100 的回归分数,也可以是安全等级的分类结果。

序列特征一般用 LSTM 或 Transformer 编码,这件事在离线评价里并不复杂,只需要把窗口数据整理成固定长度的序列,训练一个回归头即可。要注意的是它的黑匣子问题。我见过有的团队把学习模型分数直接作为发布依据,结果低分窗口说不出来为什么低,最后评审会开成了“玄学讨论会”。所以学习模型适合做“第二道筛子”:规则评分分数高、但学习模型分数低的窗口,强制进入人工复核队列,而不是直接作为最终结论。

训练数据需要覆盖足够多的危险场景样本。如果自有数据里危险片段占比过低,需要做正样本过采样或数据增强,否则模型会把所有样本都学到平均分附近,完全失去分辨力。

3.3 风险场模型:从行为到风险的时空投影

风险场是另一种思路,把道路环境中的每个交通参与者投影成一个风险势场,本车行为的安全性由它在场中的位置和速度共同决定。简化表达为:

R = Σ w_i * exp(-d_i / λ) * g(v_rel_i)

其中 d_i 是第 i 个目标与本车的距离,v_rel_i 是相对速度,λ 是距离衰减系数。风险场的优势在于能同时表达“距离近”和“速度快”的叠加效应,比单看一个 TTC 更接近人类的危险感知。

做离线评价时,风险场通常不作为独立评分器,而是当辅助切片工具。把风险场输出高、但规则评分不低的窗口找出来,人工看一遍,往往能发现规则体系里漏掉的危险场景。这个用途在数据驱动测试阶段价值很大:它帮你把“规则没定义的危险”找出来,补充到指标库或测试场景库里。

3.4 选型建议与混合架构

现实项目里很少只选一种。我常用的交付方案是“规则为主、学习为辅、风险场做异常发现”的三层架构。规则评分作为硬底线,分数低于某个阈值的窗口直接挂起;学习模型对规则评分在 70~90 分之间的模糊地带做二次排序;风险场定期全量扫描一遍历史数据,产出规则系统漏检的疑似危险片段,供测试团队确认后反哺规则。

模型类型可解释性数据依赖落地成本适用边界
规则评分高,可逐项审计低,指标标定即可低通用场景、版本回归、法规审查
学习模型低,难以逐项解释高,需大量标注中高复杂交互、模糊场景二次筛选
风险场中,与时空相关中,需目标轨迹中异常场景发现、数据挖掘

对刚起步的团队,我建议先只做规则评分。一套结构清晰的规则体系跑上半年,积累的数据足够多以后再引入学习模型,否则会陷入“标注数据太少、模型效果差、没有效果所以没人愿意标注”的死循环。

4. 用 Python 在本地跑通驾驶行为安全评价最小流水线

这一章给一套可以直接复现的最小流水线,用 pandas 加 numpy 就能运行,不依赖深度学习框架。数据用一个自采集的高速公路跟车 CSV 模拟,字段结构和真实 CAN 采集基本一致。

4.1 数据字段与采样要求

CSV 至少需要包含以下列,采样率 10Hz 起步,越高越好。真实项目中这些字段通常来自 CAN 总线、定位模块和感知融合模块。

字段名含义单位说明
time_s统一时间戳秒所有传感器对齐后的纳秒时间换算
speed_ms本车速度m/s来自轮速或纵向速度估计
accel_ms2纵向加速度m/s²正值加速,负值减速
lat_accel_ms2横向加速度m/s²用于横向稳定性辅助判断
steer_deg方向盘转角度左正右负或反之需统一
lane_offset_m车道中心偏移米正值偏向左侧
lead_dist_m前车距离米本车道最近目标
lead_rel_speed_ms前车相对本车速度m/s正为远离,负为接近
limit_speed_ms当前道路限速m/s来自地图或视觉限速识别

4.2 数据清洗与时间对齐

拿到原始 CSV 后的第一步是清洗。时间戳不单调、相邻采样间隔跳变超过 0.5s、速度字段缺失的行,都需要处理。注意,跳变片段要直接丢弃整段,而不是插值,因为长时间间隙插值出来的 TTC 完全没有物理意义。

import pandas as pd import numpy as np import os def load_and_clean(path_csv): df = pd.read_csv(path_csv) # 时间戳统一转成秒,去掉缺失行 df = df[df['time_s'].notna() & df['speed_ms'].notna()].copy() df = df.sort_values('time_s').reset_index(drop=True) # 相邻采样间隔超过0.5s视为掉线,丢弃该帧及之后的数据段 dt = df['time_s'].diff().fillna(0.0) drop_idx = df.index[np.abs(dt) > 0.5] df = df.drop(drop_idx).reset_index(drop=True) return df

参数说明:0.5s 这个阈值按 10Hz 采样率来定,如果是 100Hz 的高频数据就得收紧到 0.1s。drop 之后必须 reset_index,否则后续按位置切片会出错。掉线数据直接丢弃而不是填充,是为了避免把“传感器丢失”误判成“系统驾驶行为异常”。

4.3 滑窗指标计算:核心函数

指标计算按滑窗进行,窗口长度 10s、步长 5s,重叠 50%。窗口太短会把一次正常变道切成好几段,太长又会把一瞬间的冲突平滑掉。10s 是行为评价里比较常用的起始值。

def calc_steering_entropy(steer_deg, bin_w=1.0, low=-20.0, high=20.0): if len(steer_deg) < 3: return 0.0 d = np.diff(steer_deg.values) d = d[(d >= low) & (d <= high)] bins = int((high - low) / bin_w) hist, _ = np.histogram(d, bins=bins, range=(low, high)) p = hist / hist.sum() p = p[p > 0] return float(-(p * np.log2(p)).sum()) def hard_brake_count(accel_series, thr=-3.0, min_dur=0.3, fs=10.0): mask = (accel_series.values < thr).astype(int) cnt, cur = 0, 0 for v in mask: if v == 1: cur += 1 else: if cur / fs >= min_dur: cnt += 1 cur = 0 if cur / fs >= min_dur: cnt += 1 return cnt def compute_window_metrics(df, win_s=10.0, step_s=5.0, fs=10.0): t = df['time_s'].values t_min, t_max = t[0], t[-1] starts = np.arange(t_min, t_max - win_s, step_s) rows = [] for s in starts: e = s + win_s win = df[(df['time_s'] >= s) & (df['time_s'] < e)] if len(win) < 0.5 * win_s * fs: continue v_ego = win['speed_ms'] lead_dist = win['lead_dist_m'] lead_rel = win['lead_rel_speed_ms'] approach = (lead_dist > 1.0) & (lead_rel < 0) ttc = lead_dist / (-lead_rel) min_ttc = float(ttc[approach].min()) if approach.any() else np.inf # THW低于1.0s的时间占比,弯道低速场景需要速度下限 valid_thw = v_ego > 1.0 thw = lead_dist / v_ego thw_lt1_ratio = float((thw < 1.0)[valid_thw].mean()) if valid_thw.any() else 0.0 rows.append({ 'start_time': s, 'end_time': e, 'min_ttc': min_ttc, 'thw_lt1_ratio': thw_lt1_ratio, 'hard_brake_cnt': hard_brake_count(win['accel_ms2'], fs=fs), 'lane_offset_std': float(win['lane_offset_m'].std()), 'steer_entropy': calc_steering_entropy(win['steer_deg']), 'over_limit_ratio': float((win['speed_ms'] > win['limit_speed_ms'] + 1.4).mean()), }) return pd.DataFrame(rows)

参数说明:approach条件里加lead_dist > 1.0是为了去掉雷达探测距离过近时的不稳定值;thw_lt1_ratio计算时用valid_thw做布尔索引,避免静止状态 THW 无穷大的干扰;over_limit_ratio里的 1.4m/s 大约等于 5km/h 容差。判断52 * 10 = 520是对窗口数据量的保护,窗口内有效帧不足一半时直接跳过,不然 10s 窗口里只采到 2s 数据会算出完全离谱的值。

4.4 安全评分、分级与快速出报告

指标算完就可以走规则评分。这套权重和阈值是示例性配置,真实项目必须用历史数据和主观评分校准。

def rule_score(min_ttc, thw_lt1_ratio, hb_cnt, lane_std, steer_entropy, over_limit_ratio): penalty = 0.0 if min_ttc < 1.0: penalty += 35.0 elif min_ttc < 2.0: penalty += 20.0 elif min_ttc < 3.0: penalty += 8.0 if thw_lt1_ratio > 0.1: penalty += 15.0 elif thw_lt1_ratio > 0.05: penalty += 8.0 penalty += min(15.0, hb_cnt * 5.0) if lane_std > 0.30: penalty += 10.0 if steer_entropy > 4.0: penalty += 5.0 if over_limit_ratio > 0.1: penalty += 10.0 return max(0.0, 100.0 - penalty) def grade_of(score): if score >= 90: return 'A' if score >= 80: return 'B' if score >= 70: return 'C' if score >= 60: return 'D' return 'E' def add_score(metrics): metrics['score'] = metrics.apply( lambda r: rule_score( r['min_ttc'], r['thw_lt1_ratio'], r['hard_brake_cnt'], r['lane_offset_std'], r['steer_entropy'], r['over_limit_ratio'] ), axis=1) metrics['grade'] = metrics['score'].map(grade_of) return metrics

参数说明:TTC 扣分采用阶梯式,而不是线性,是因为 1s 以下和 2s 以下的风险程度有本质差别;急减速用min(15, cnt*5)封顶,避免一个窗口里多次急刹重复叠加扣分导致分数直接归零。评分函数必须返回扣分明细,否则后续没法定位问题。

4.5 自动切出低分片段:给测试团队看的证据包

评价结果只有一个最终分数是不够的。把低分窗口的数据切片导出,测试工程师才能快速复现和分析。

def export_low_score_windows(df, metrics, out_dir='./low_score_clips', score_th=70.0): os.makedirs(out_dir, exist_ok=True) low = metrics[metrics['score'] < score_th] if len(low) == 0: print('no low_score_windows') return for _, r in low.iterrows(): win = df[(df['time_s'] >= r['start_time']) & (df['time_s'] < r['end_time'])] name = f"win_{int(r['start_time'])}_{int(r['end_time'])}_score{int(r['score'])}.csv" win.to_csv(os.path.join(out_dir, name), index=False) r.to_frame().T.to_json(os.path.join(out_dir, name.replace('.csv', '.json')), orient='records')

说明:导出的文件名里带起止时间和分数,可以直接在数据可视化工具里拖进去看。JSON 里存的是这个窗口的指标明细和扣分明细,方便评审会现场举证。这个切片的逻辑同样适用于正常高分区间的抽样留档,只是阈值方向反过来。

5. 智能驾驶行为评价的五个常见翻车点与排查办法

行为安全评价项目里,真正耗时间的往往不是算法,而是数据链路里各种“看似正常、实则离谱”的问题。下面是五个我实际遇到过的高频坑,按现象、原因、解决的路径拆开。

5.1 分数时高时低,先查时间戳对齐

现象:同一段录制数据,两次跑分结果明显不同,指标曲线在某一帧出现尖刺后恢复。查代码逻辑没问题,感官上像是评价系统不稳定。

原因:CAN、GPS、感知模块三个数据源的时间基准不一致。有的模块用的是系统启动后的相对时间,有的用的是全球定位系统秒,差一个固定偏移或者渐变漂移。滑窗切分时,一次几十毫秒的时间错位就会导致 TTC 出现虚假跳变。

解决:清洗程序里先做时间基准统一,全部转成纳秒时间戳;再用相邻插值把各传感器数据重采样到统一的 10Hz 或 100Hz 网格;最后做一次质量统计,输出有效时间占比,低于 95% 的直接拒绝该段样本。

5.2 场景一变分数就崩:分布偏移与稳健化

现象:在高速测试道上跑出来的分数分布正常,换到山区隧道或者大雨场景,同一套指标和权重产生了大面积低分,人工回看又觉得没到那么危险。

原因:归一化参数是在既有数据集上拟合的,新场景速度、车距分布完全变了,原来的均值方差失效。其次是规则阈值没有按场景分开设置,雨天跟车车距大是正常的,但套用晴天的阈值就会误判。

解决:归一化改用中位数加 MAD,降低尾部极值的影响;在评价前加一个场景分类器,先识别高速、城区、隧道、雨雾等场景上下文,再套用对应场景的阈值模板。

5.3 算法高分、主观低分:权重是拍脑袋定的

现象:算法评价 90 分以上的窗口,试验车上的安全员主观感受很差,觉得系统“犹豫”“反复修正”。评审会上双方各执一词。

原因:规则评分只覆盖了能被传感器测量的指标,比如车距和加速度,但“变道意图不清”“让行姿态不果断”这类行为没有对应指标,也没有权重。权重来自个人经验而非数据标定,主观分自然对不上。

解决:做一轮小规模主客观一致性校准。取 50 个典型窗口,让 2~3 名测试工程师分别打分,再和算法分数算相关性,找出系统性偏差大的指标调整权重。额外补充行为意图类指标,比如变道前是否长时间跨线行驶、遇路口前是否有渐进式减速。

5.4 TTC 在低速场景失真:传感器与计算前提的坑

现象:低速跟车场景下 TTC 经常出现极大值或空值,导致低风险路段被误判成得分异常。

原因:TTC 的自动计算需要“前车相对本车为接近状态”这一前提,低速场景下相对速度接近 0,数值上 TTC 会被推到无穷大。另一层原因是感知模块在近距离或遮挡条件下经常切换目标 ID,相对距离一跳变,TTC 就会出现一个虚假尖峰。

解决:对相对速度做时间序列滤波,避免单帧抖动直接进入计算;TTC 只取 0 到 8s 之间的有效值;同时把 THW 纳为低速场景的主要风险指标,TTC 作为辅助参考。

5.5 离线 95 分、实车接管率高:窗口粒度与事件丢失

现象:离线评价全部跑完,平均分达到 95,实车测试时体验员仍然频繁接管。两组结论看起来完全矛盾。

原因:滑窗平均把一瞬间的冲突平滑掉了。10s 窗口里哪怕出现一次 0.8s 的紧急情况,只要其他时间平稳,平均分依然很高。更隐蔽的原因是接管事件大概率发生在窗口边界附近,被切到了相邻窗口里打散。

解决:评分报告里同时输出“窗口平均分”“窗口最小 TTC”“事件级最小 TTC”三列,低分事件按事件从触发前 2s 截到触发后 5s,而不是套用固定网格;把接管发生时的手动介入信号也录成一条独立数据流,参与评价逻辑的特殊标记。

6. 进阶用法:把评价结果变成版本回归门禁与权重闭环

行为安全评价最大的价值不在“评一次分”,而在持续回归。把评价流水线挂到常驻任务里,每个版本的算法改动后自动重跑,分数变化趋势就有了可比性。

6.1 最小回归门禁

每次算法或标定参数变更后,跑一遍固定数据集,设置三档门禁:硬门禁是低分窗口数量不得超过上一版本;对照门禁是平均分较上一版本下降不超过 2 分;趋势门禁是连续三个版本分数持续下降则自动阻止合入。门禁不是拦所有分数波动,而是拦住“没有解释的分数恶化”。

6.2 敏感度分析反推标定参数

对指标矩阵做 Spearman 相关性分析,看哪些指标与最终分数的相关性最高。把相关性排序输出后,让测试团队优先复核对标定参数,比如车道偏移阈值 0.3m 是否过松、TTC 阶梯阈值是否需要收紧。这一步相当于用评价结果反向修正数据采集质量。

6.3 权重闭环校准

每隔一个季度,从线上采集样本里抽一批新数据做人工复评,对比算法分数与主观分数的偏差,重新校准权重。我经手的几个项目里,权重在半年内通常会收敛到一个稳定值,之后系统就很少出现“分数与体验不一致”的反馈了。我的习惯是每次校准完都把新旧权重同时跑一遍回归,确认校准没有引入历史数据上的回退,再发布新版本。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进