简介面向辅助驾驶与自动紧急制动AEB控制算法研究人员该代码包基于Simulink与Prescan联合仿真提供了一套完整可运行的AEB控制策略实现。内容涵盖毫米波雷达与视觉目标检测、相对距离与相对速度解算、分级制动决策以及制动指令信号生成并针对前方碰撞风险给出了从预警到全力制动的处理流程便于理解自动紧急制动系统的工作机制。压缩包共725个文件体积约7.51MB以mdl模型、m脚本、mat数据为主要代码与数据文件同时包含osg场景文件、png/jpg图像和fig曲线图其中Euro NCAP相关测试图片和雷达数据图可用于对照分析标准工况下的控制效果。已有3706人下载学习说明该资源受到ADAS方向开发者关注。通过研读源码和配套数据读者可以快速掌握基于模型的控制策略设计方法并借助Prescan虚拟场景完成算法验证与参数标定尤其适合初学者进行二次开发和工程实践。1. 辅助驾驶AEB的控制策略源代码不是黑匣子而是一串能跑的状态判断跑高速遇到前车急刹驾驶员脚还没来得及从油门换到制动踏板AEB 已经把减速请求发给了车身稳定系统。这个反应不是玄学而是辅助驾驶 AEB 的控制策略源代码里一串由目标筛选、TTC 计算和分级制动状态机组成的判断链条。做过量产项目的同行都知道这套决策逻辑本身不复杂真正让人熬夜的是传感器目标不稳定、标定参数互相打架、仿真通过实车翻车。下面按我自己的落地经验把 AEB 控制策略从架构、源码到参数标定和调试避坑完整拆一遍适合正在做 AEB 算法、智能网联汽车竞赛或者底盘控制器的工程师照着能复现也知道边界在哪。2. AEB控制策略的分层架构从传感器目标到制动请求的完整链路2.1 一条纵向控制链路从毫米波雷达目标到 ESC 制动请求量产车上的 AEB 通常不会单独存在于某个黑盒子里而是作为 ADAS 域控或底盘域控里的一个功能模块。前雷达和前视摄像头各自输出目标列表融合模块做时间对齐和目标匹配生成带稳定 ID 的 trackAEB 策略从这个 track 列表里选出最危险目标结合本车车速、横摆角速度和驾驶员踏板状态在决策周期内算出需要的减速度请求请求走出总线到 ESC由 ESC 完成建压和轮缸压力闭环。如果方案里只有单目摄像头没有毫米波雷达AEB 一般只能覆盖中低车速场景高速工况必须依赖雷达的距离和速度测量这是选型层面需要先想清楚的事。这条链路每一个环节都在吃时间预算。以我做过的一个前雷达加前摄方案为例传感器原始数据到 track 输出大约 40 到 80msAEB 决策模块跑 50ms 周期制动请求到 ESC 再到压力真正起来还要 200 到 400ms。把三段加一起感知到制动力出现的端到端延迟在 300 到 500ms。记住这个数字后面再看 TTC 阈值时就会明白为什么不能直接把论文里的 1.5s 拿来用。2.2 分层选型为什么 AEB 决策要拆成四级而不是一个函数算到底把整条链路拆成目标筛选、危险判定、策略决策、执行接口四层是我在量产项目里的习惯做法。第一个原因是传感器失效模式完全不同。雷达对静止金属物体会出现点目标抖动摄像头逆光时可能把白色卡车当作无效目标如果所有逻辑塞进一个函数上游一抖动整个策略输出就会跟着抖。分层之后目标筛选层负责剔除古怪的 track决策层只吃筛选后的相对距离、相对速度和横向位置即便上游抽风策略层也不会立刻输出一个疯狂的减速度请求。第二个原因是周期差异。目标列表刷新可以做到 20ms 一次策略决策层通常 50ms 或 100ms 一次执行层的 ESC 也有自己的通信周期。硬要把这些周期揉在一个循环里就会出现时间抖动做控制策略评估的时候很难复现问题。第三个原因是回归测试需要。每一版改动之后我要分别回放目标筛选前和策略输出后的日志确认问题出在哪一层不分层就没法定位。如果只是做竞赛或者快速原型两层也能跑但上了量产我强烈建议把四层分清楚问题定位和变更管理的效率会差很多。2.3 危险目标锁定一个目标筛选函数的最小实现决策层拿到的不是传感器原始点而是一串融合后的 tracks。下面给一个目标筛选的最小实现逻辑只做四件事排除无效目标、排除太远目标、排除车道外目标、按 TTC 挑最危险的一个。// 输入融合后的 tracks只取本车前方目标 // 输出最危险目标MIO的索引没有则返回 -1 int select_most_threatening(const std::vectorTrack tracks, float lane_half_width, // 本车道半宽通常 1.0~2.0m float max_range) // 决策用最大探测距离通常 80~150m { int mio_index -1; float severity 1e9f; // 数值越小越危险 for (size_t i 0; i tracks.size(); i) { const Track t tracks[i]; if (!t.obj_valid || t.age 3) continue; // 至少连续 3 帧才信 if (t.range max_range) continue; // 太远先不管 if (std::abs(t.lateral_offset) lane_half_width * 1.2f) continue; // 横向出车道 // 对本车道前向目标先算 TTC让策略层不要吃原始距离 float d t.range; float v_rel t.range_rate; // 负数表示接近 float ttc (v_rel -0.1f) ? (-d / v_rel) : 1e9f; // 接近时才有意义 // 用 TTC 排序TTC 相同再看距离距离近的优先 float s ttc; if (s severity) { severity s; mio_index static_castint(i); } } return mio_index; }这个实现的逻辑要点t.age 3 是为了防止噪声点第一帧就进入决策但代价是目标刚出现的前两帧不会被响应lateral_offset 乘以 1.2 是给目标宽度留余量卡车宽度两米多半宽阈值不能卡得太死v_rel 小于 -0.1m/s 才计算 TTC接近速度为零或远离时直接给一个极大值交给后面的距离模型处理。实际项目里我还会加上目标类别权重行人和自行车比静止卡车更敏感紧急时宁可对卡车误报也不能对行人漏报。2.4 控制时序50ms 决策、20ms 刷新与时间预算AEB 决策模块我固定跑 50ms 周期输入缓存必须带时间戳不能用收到新目标就立刻触发的事件式写法否则 CAN 总线上一个抖动策略就提前或延后一拍。目标筛选用 20ms 更新一次给决策层保留一帧待处理。在这个 50ms 决策周期里要完成解析目标、危险判定、制动请求生成、与驾驶员意图仲裁。单帧耗时超过 10ms 就会拖垮整体节奏这也是为什么不要在决策循环里写文件日志或调试打印日志逻辑必须放到独立线程。驾驶员意图仲裁的优先级也是这个模块里容易漏掉的部分。我的顺序是制动踏板介入大于油门踏板介入油门大于转向避让转向避让大于 AEB 自身请求。驾驶员只要踩下制动踏板超过 0.1 的归一化开度AEB 立刻让权退出不跟驾驶员抢方向盘和刹车。另外要处理失效降级ESC 报故障时策略不能在故障状态下继续请求制动要立即回到 IDLE 并给 HMI 报警。3. 核心控制逻辑实现TTC计算、安全距离模型与分级制动状态机3.1 TTC 估算从相对距离与相对速度推导的关键边界TTC 的定义没有争议假设相对运动状态不变从当前时刻到碰撞发生的时间。最简单表达是 TTC -d / v_rel其中 d 是目标相对距离v_rel 是相对速度接近时为负。这个公式里最关键的边界是 v_rel 接近零此时 TTC 趋向无穷大低速排队工况根本等不到触发。所以要引入本车道停止距离模型做兜底估算自车以当前最大减速度刹停需要的距离与目标当前位置和运动做比较。实际工程里我常用修正版 TTC把自车当前减速度考虑进去估算如果现在全力制动能不能在到达目标位置前停下来。这个修正会让触发时间比纯运动学 TTC 更早避免在接近时刻才发现刹不住。离散化实现时注意两个细节对 d 和 v_rel 做一阶低通滤波的系数要分开距离滤波时间常数约 0.2s速度滤波约 0.1s两套系数避免把噪声一起放大滤波后再做除法并且要防止除零。传感器延迟大的方案里TTC 计算还要额外预留一段链路延迟距离也就是用 TTC 减去 300 到 500ms 端到端延迟后再做判断否则算出来能刹住实际已经晚了。提示TTC 进入判定前必须保证 v_rel 先经过滤波否则在低速接近场景会频繁跳变AEB 会一抖一抖。3.2 两级预警与三级制动安全距离模型与应用条件低速场景用距离模型高速场景用 TTC 模型两条腿走路才能覆盖两种极端工况。距离模型解决的是低速排队问题自车从当前速度以最大减速度刹停需要的距离减去目标车到停止线或当前位置的相对距离。TTC 模型解决的是高速接近问题前车突然减速或静止TTC 快速缩短策略按梯度介入。触发级别典型判定条件期望动作预警TTC 2.0~2.5s且驾驶员无干预仪表声音加视觉提醒不制动部分制动TTC 1.2~1.6s或距离模型预测会碰撞请求 0.3~0.4g 减速降低碰前相对速度全力制动TTC 0.6~1.0s或目标几乎不可避请求 0.8~1.0g 减速停车后进入 HOLD保持制动自车停止或目标停止后维持制动压力最长 2s等待驾驶员接管这些数字是起点不是终点。同一辆车雷达标定差异、制动系统冷热态差异都会让最优阈值偏移 0.2 到 0.4s。所以我在项目里会把阈值做成外部参数表而不是写死常量。所有标定参数来自同一个参数文件C 代码和 Simulink 模型共用一份具体原因放到 3.4 说。3.3 分级制动状态机参考实现与状态迁移条件这里给出一个最简但结构完整的分级制动状态机参考实现。状态从 IDLE 出发逐级进入 WARN、PARTIAL、FULL停车后进入 HOLD驾驶员介入任意时刻都能退出。// AEB 分级制动状态机参考实现决策周期 50ms // 状态IDLE - WARN - PARTIAL - FULL - HOLD enum class AebPhase { IDLE, WARN, PARTIAL, FULL, HOLD }; AebOutput compute_aeb(const AebInput in) { // 用 static 状态变量保存当前相位和进入时刻 static AebPhase phase AebPhase::IDLE; static float phase_enter_ms 0.0f; const float ttc in.ttc_valid ? in.ttc : 999.0f; AebOutput out{}; out.warn_hmi (phase AebPhase::WARN); out.brake_request false; // 驾驶员油门或制动介入快速退出 AEB 干预 const bool driver_override in.driver_throttle 0.15f || in.driver_brake 0.1f; switch (phase) { case AebPhase::IDLE: if (ttc params.ttc_warn) { // 进入预警 phase AebPhase::WARN; phase_enter_ms in.t_ms; } break; case AebPhase::WARN: if (driver_override) phase AebPhase::IDLE; else if (ttc params.ttc_partial) { // 部分制动 phase AebPhase::PARTIAL; phase_enter_ms in.t_ms; } else if (ttc params.ttc_warn params.hysteresis) { phase AebPhase::IDLE; // 带滞回退出防抖 } break; case AebPhase::PARTIAL: if (driver_override) phase AebPhase::IDLE; else if (ttc params.ttc_full) { phase AebPhase::FULL; // 全力制动 phase_enter_ms in.t_ms; } else if (ttc params.ttc_partial params.hysteresis) { out.brake_request true; out.decel_request params.decel_partial; phase AebPhase::WARN; } else { out.brake_request true; out.decel_request params.decel_partial; } break; case AebPhase::FULL: if (driver_override) phase AebPhase::IDLE; else if (in.v_host 0.5f) { // 接近停止进入保持 phase AebPhase::HOLD; phase_enter_ms in.t_ms; } else { out.brake_request true; out.decel_request params.decel_full; // 通常 0.8~1.0g } break; case AebPhase::HOLD: out.brake_request true; out.hold_brake true; out.decel_request (in.t_ms - phase_enter_ms params.hold_time_ms) ? params.decel_full : 0.0f; // HOLD 超时释放 if (driver_override || in.t_ms - phase_enter_ms params.hold_time_ms) phase AebPhase::IDLE; break; } return out; }这段逻辑的关键是进入阈值和退出阈值不同也就是滞回。WARN 在 ttc 大于 warn 阈值加 hysteresis 时才退出防止临界点反复跳变。driver_override 只要满足就立刻让出控制权避免和驾驶员抢刹车这一条是量产安全审查时必看的点。参数 ttc_warn、ttc_partial、ttc_full、hysteresis、hold_time_ms、decel_partial、decel_full 全部来自参数表不在代码里改。注意制动踏板阈值 0.1 是偏保守的取值因为驾驶员已经踩下制动踏板时AEB 应当立即让权哪怕只踩了一点。3.4 从 C 代码到 Simulink Stateflow两种落地路径的对应关系实际落地的路径无非两种手写 C/C 代码适合 MCU 或基于 Linux 的域控Simulink Stateflow 适合快速迭代和 MIL/SIL 测试。Stateflow 里的对应关系很直观每个 state 对应这里的 enumtransition 条件直接写成 ttc params.ttc_xxx进入动作记录 enter time 到 local variable输出用 output port 接到底层驱动。最容易出问题的是仿真步长和实际部署周期的差异模型里默认连续时间到了嵌入式设备是离散采样所以模型里必须把采样时间显式设为 0.05s否则逻辑在仿真里正确上车就行为异常。我一般会强调单一参数源。无论 C 版还是 Simulink 版所有阈值都从一个参数头文件或 m 文件生成避免模型里填了一版、手写代码里又填了一版。同一套策略两处不一致后期换参数必出事故。4. 三大必调参数与标定路径TTC阈值、减速度梯度与误触发抑制4.1 TTC 阈值不能照抄从 Euro NCAP 场景到路段实测网上能搜到的很多 AEB 教程和代码模板阈值基本是固定的预警 2.5s、全力制动 0.6s。这套值放在某一台车上也许成立换个传感器延迟 60ms、ESC 建压 300ms 的车效果就差很远。做控制策略评估的时候我看两个指标而不是只测一件事误触发率和成功避免碰撞率。先按初版参数表开始标定再逐步修正。参数初值区间影响因素ttc_warn2.0~2.5s驾驶风格、HMI 接受度ttc_partial1.2~1.6s目标筛选质量、执行延迟ttc_full0.6~1.0s最大减速度、传感器延迟hysteresis0.3~0.5s目标跟踪稳定性注意低速跟车时 TTC 不再适用要切换停止距离模型所以这张阈值表只覆盖 v_rel 小于 -0.5m/s 的接近场景。标定流程我习惯先仿真跑边界再用实车逐项验证一次只调一个维度否则多个参数联动出了问题根本不知道是谁引起的。Euro NCAP 的测试场景只是底线实际开发还要覆盖国内场景里的低速加塞、电瓶车斜穿、路侧护栏等工况这些都会反过来压缩 TTC 阈值的安全余量。提示阈值初值只用于启动标定量产前必须结合传感器延迟和执行端压力测试结果修正不能拿模板值直接发版。4.2 减速度梯度jerk上限、prefill 预填充与压力时延补偿这一节讲期望减速度怎么发。制动请求太陡乘员会前后点头jerk 控制在 2~5 m/s^3 比较合理舒适场景取 2紧急场景放宽到 8 到 10但只是瞬间到达不能持续。另一个常被忽略的是 prefill 预填充危险等级一进入 WARN就向 ESC 发一个 2~4 bar 的预填充请求让制动片贴盘真正需要全力制动时能节省约 200ms 的建压时间。这个动作要在状态机里单独占一个输出位不能等 FULL 才发。还有压力时延补偿。做法是接收 ESC 返回的主缸压力用一阶滞后模型估算实际压力如果期望减速度和实际减速度的差值持续 0.3s 超过 0.2g就认为执行端异常或制动系统老化需要重新标定。只盯 TTC 不看实际建压曲线标定做得再细也是盲调。4.3 误触发抑制弯道曲率修正与置信度门控误触发是 AEB 项目里最常见的投诉来源。典型场景是弯道里出现静止卡车或护栏目标横向位置明明在相邻车道却被雷达目标选进来。处理方法我分两步第一步是曲率修正用自车横摆角速度和车速估算本车道中心线再预测目标在当前时刻的横向偏移。# 弯道曲率修正示例用 yaw_rate 预测目标横向偏移 # yaw_rate 单位 rad/sv_host 单位 m/slookahead 单位 s import numpy as np def curvature_target_offset(dist, lateral_offset, yaw_rate, v_host, lookahead1.2): if yaw_rate 0.05: # 近似直线不修正 return lateral_offset radius v_host / max(abs(yaw_rate), 0.02) heading_change v_host * lookahead / max(radius, 1.0) # 目标在弯道切出时横向偏移会随行驶距离放大 predicted_offset lateral_offset - dist * np.sin(heading_change) return predicted_offset这个函数的逻辑是当自车带 yaw_rate 过弯时目标此刻的 lateral_offset 不能直接信因为弯道里相邻车道的静止车在自车坐标系里很可能被算到本车道内。把自车转角放到预测里折算后如果 predicted_offset 超过 lane_half_width 的 1.2 倍就直接把该目标的危险等级降为 0。参数注意lookahead 取 1.0 到 1.5s太大会在 S 弯反而把真正的前车剔除yaw_rate 小于 0.05 rad/s 时不做修正避免直线小幅摆动放大误差。第二步是置信度门控。对于雷达目标要求连续出现 3 到 5 帧且位置变化满足匀加速假设才允许参与危险评估单帧点迹一律不触发任何制动目标 ID 跳变后要重新累计年龄。这两个机制配合基本能压住井盖、临时铁板、隧道墙壁这些金属反射噪点。5. AEB策略调试避坑五个反复翻车的场景与排查路径5.1 现象低速接近时 TTC 乱跳AEB 一抖一抖的低速排队场景下自车和目标车相对速度接近零雷达测得的 v_rel 噪声能到正负 0.3m/s这时候算出来的 TTC 会在 0.8s 到 1.9s 之间反复跳。现象是仪表预警闪烁严重时部分制动也会被反复触发。原因就是直接用原始 v_rel 除距离噪声没有过滤。解决方法是把 v_rel 单独低通滤波时间常数取 0.2s同时在 v_rel 绝对值小于 0.5m/s 时切换到距离模型。另外给制动请求加一个最小持续时长 0.5s避免状态机在 WARN 和 PARTIAL 之间来回切。排查时打开日志先看 v_rel 原始值和滤波后的值如果滤波后还是跳问题多半在融合模块的卡尔曼参数不在 AEB 策略本身。5.2 现象弯道内静止目标误触发高速上突然给你一脚重刹右弯内出现静止卡车本应只在相邻车道雷达却把它当正前方目标策略直接全制动。原因是没有用弯道曲率修正目标横向位置也没有利用目标历史轨迹。解决启用第四章 4.3 的 predicted_offset 降级逻辑另外看目标 track 的历史横向位置如果横向偏移变化超过 0.3m 且方向一直朝车道外侧移动就把它标记为弯道外目标不参与 TTC 计算。实车验证时专找半径 200 到 500m 的盘桥弯道把静态护栏、静止车辆和真正在本车道慢行的目标各跑几遍。注意弯道出口处目标从弯道外进入正前方降级逻辑要能快速恢复不能因为历史标记把真正的前车一直压住。5.3 现象仿真全部通过实车一开就疯狂误报这是最经典的翻车现场。仿真器里的传感器模型太干净目标列表规规矩矩噪声符合理想分布真实雷达有天线罩反射、多径散射、前方车辆花纹反射差异还有雨天水滴和隧道口电磁干扰。解决方法不是把仿真做得更复杂而是建立传感器黑匣子把实车采集的雷达 CAN 报文和摄像头目标按时间戳录下来回注给 AEB 策略模块用真实输入跑回归测试。回归通过后再做纯虚拟场景测试重点测边界工况。两条腿走路虚拟场景负责测逻辑完备性实车回注负责测传感器噪声下的鲁棒性。录包时注意所有设备的时间戳必须同步到同一时钟域否则回注数据错位等于拿错误输入做测试。5.4 现象液压制动时延让实际减速度迟到 300ms标定越调越乱现象是策略请求 0.8g实际减速度 0.4g 迟了几百毫秒才出现策略检测到减速度不足又加大请求最终产生过度制动。原因有两层ESC 从收到请求到轮缸压力达到目标值存在时间常数冷车和热车差异明显另一个是制动片的空行程没有被填补。解决方法是同时处理两个环节。决策模型里加一阶滞后补偿把已知的执行延迟预判进去危险等级一到 WARN 就发 prefill 2 到 4 bar抵消空行程。排查时把期望减速度和实际减速度两条曲线叠加如果差值超过 0.2g 并持续 0.3s 以上先查执行端别急着调上游阈值。5.5 现象误报和漏报一起来调一个参数另一个立刻恶化把 ttc_full 调低能减少误报但对高速近距离突发目标就漏了调高又回到误报状态。原因是全局单一阈值根本覆盖不了所有车速和相对速度组合。解决方法是把阈值从常量改成二维 map横轴是自车速度纵轴是相对速度落在不同区间取不同阈值横向偏移也参与决策权重。标定工作流固定为先固定一组初值跑完整回归集统计误报率和漏报率再在二维 map 上做小步调整一次只动一个区间。不要用先调大试试、再调小试试的玄学法。这也是为什么我强调回归集里必须同时包含误报场景和漏报场景否则调参就是盲人摸象。6. 验证AEB策略的最后一公里Euro NCAP场景复现与数据回放复盘6.1 复现 Euro NCAP 四类场景卡住策略边界的测试表验证 AEB 最直接的手段是复现 Euro NCAP 的经典场景CCRs 前车静止、CCRm 前车匀速、CCRb 前车制动、VRU 行人横穿。这套场景也是很多智能网联汽车竞赛 AEB 赛题的底子。我每次改完参数都先过这四组表格是项目里最常用的设置场景测试意图主机参考车速通过判据CCRs静止目标识别40~80km/h 分档不碰撞或碰撞速度低于阈值CCRm同速前车威胁评估50km/h 附近不应误触制动平顺CCRb前车制动响应50km/h 以上成功避免或显著降速VRU行人及弱势交通参与者20~60km/h按行人位置分近侧和远侧验证6.2 数据回放复盘三条曲线对齐与时间戳校对实车和仿真测试完我会立刻做数据回放只看三样东西相对距离曲线、TTC 与制动请求曲线、实际减速度与主缸压力曲线。三条曲线按时间戳对齐后能直接回答策略有没有在正确时刻介入以及执行端有没有忠实执行。对不齐时优先校对时钟域CAN 报文、摄像头目标和决策日志如果来自不同设备都要先同步到同一时间基准否则看到的就是一场混乱。这里有一个我保留了三年的习惯每一次测试不论通过与否都完整保留原始报文和数据文件包括那些误报、漏报的坏数据。重新标定新参数时旧的坏数据是最有价值的回归样本。参数永远跟着数据集走而不是跟着感觉走。这一步做完AEB 策略才算真正闭环。希望帮到你。本文还有配套的精品资源点击获取