ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

电子电气架构设计实战:从需求拆解到架构验证的闭环

电子电气架构设计实战:从需求拆解到架构验证的闭环 简介一份面向汽车电子电气架构师及整车开发工程师的专业资料聚焦如何在分布式向中央计算区域控制演进的趋势下做好车载网络拓扑、功能安全、网络安全、电源模式管理与ECU负载等关键设计。内容既有对某鹏X-EEA3.0、广汽星灵HPC、长城GEEP3.0等新架构的对比解读也覆盖从整车需求分解到控制器功能分配的具体方法可帮助读者厘清架构设计的核心逻辑与常见注意事项。资源为1个PDF文件大小477KB内容精炼、偏工程实践适合正在从事或计划转入电子电气架构领域的工程师参考。目前已获251人学习下载是一份可用于快速建立整体认知、辅助架构评审与方案设计的实用资料。1. 电子电气架构师接需求前先想清楚架构的边界做电子电气架构的人最容易犯的一个错是拿到需求就开始画拓扑图。真正到了实车联调你才会发现返工最狠的部分往往不是线束而是电源状态机、通信矩阵和 OTA 刷写窗口——这些都是拓扑图上看不见的东西。电子电气架构师要交付的不是一张 CAN/CAN FD/Ethernet 组网图而是一套把功能、带宽、休眠电流、诊断、刷写和信息安全同时约束住的决策集。这篇文章不搬理论按我从需求输入到架构评审的完整链路把需要反复确认和落地的点捋一遍。适合正在做电子电气架构规划、以及从软件方向转过来做系统设计的工程师。2. 电子电气架构的需求输入怎么变成设计决策需求评审会上最常见的场面是产品经理给了一页很粗的 Feature 描述然后问架构师“这个能不能做”。能不能做不是靠拍脑袋而是靠需求拆解。电子电气架构师如果跳过拆解直接进设计通信矩阵里就会多出一堆“先用着再调”的冗余信号最后变成整车厂和供应商互相扯皮的导火索。2.1 从用户场景拆出最小功能单元以 L2 辅助驾驶为例“支持 L2”不是一条需求而是一组可验证的功单元ACC、AEB、LKA、TSR、驾驶员监控。每个单元要继续往下拆拆到通信矩阵和软件组件能直接引用的粒度。我一般按四个维度拆触发条件车速范围、静态/动态目标、驾驶员输入优先级执行动作制动减速度、转向扭矩、提示信息的具体表现失效表现传感器被遮挡、目标丢失时系统在多少毫秒内做什么降级路径是从 L2 直接退出还是先降级到 ACC 保持再由人接管。没有这一步你不知道要给总线留多少信号、哪些信号周期必须小于 100ms、哪些控制器之间需要小于 10ms 的端到端延迟。架构设计的第一张表不是网络节点图而是“功能分解表”。2.2 非功能需求要在设计前量化功能需求解决“做什么”非功能需求解决“做到什么程度”。电子电气架构里恰恰是非功能需求最容易被拖到评审后期才补一补就是大改。下面几个指标必须在架构定型前量化指标常见量化目标对架构的影响上电到仪表就绪2s 以内决定 MCU 选型、是否从休眠而非冷启动整车休眠电流3mA 以内限制 CAN 周期唤醒、禁止以太网 PHY 持续供电整车 OTA 刷写总时长30min 内必须支持并行刷写、预留回滚分区、诊断链路留够带宽信息安全安全启动 SecOCHSM 算力与密钥管理通信矩阵要预留 MAC 字段这条表里的每一项都会反向约束拓扑。比如“2s 内仪表就绪”很多方案靠的是“座舱域控制器不休眠只挂低功耗 SRAM 保持上下文”那么休眠电流的预算就要重新算。把这些指标摆到需求评审桌上产品经理才会理解为什么你说“这个功能可以但要把唤醒时间从 100ms 改成 500ms”。2.3 用需求跟踪矩阵锁住设计决策需求拆完之后要落到一份可持续维护的跟踪表里。我不建议只在 Excel 里维护更推荐把需求描述和分配结果写成结构化文件让脚本在每次架构变更时自动检查“有没有需求还没分配控制器”。一个轻量但可落地的做法是用 YAML 维护需求再用一个简单脚本做质量门。# requirements.yaml 示例 - id: REQ-EEA-001 description: ACC 激活状态下驾驶员踩下制动踏板后 500ms 内必须退出 ACC asil: B domain: ADAS assigned_ecu: zh_cu_adas - id: REQ-EEA-002 description: 整车休眠电流不得大于 3mA asil: QM domain: Body assigned_ecu: - id: REQ-EEA-003 description: OTA 刷写期间座舱允许黑屏但仪表必须每 100ms 发送心跳 asil: A domain: Cockpit assigned_ecu: zh_cu_cockpitimport yaml with open(requirements.yaml, encodingutf-8) as f: reqs yaml.safe_load(f) for r in reqs: if not r.get(assigned_ecu): print(f[ERROR] {r[id]} 没有分配到控制器先补需求负责人) elif r.get(asil) not in (QM, None): print(f[CHECK] {r[id]} 是功能安全需求验证计划里要有故障注入)脚本逻辑很简单第一遍扫出没有分配控制器的需求第二遍把功能安全相关需求单独标出来提醒做故障注入验证。这里的asil直接取 A/B/C/DQM表示非功能安全。日常维护时只要在每次架构评审前跑一遍就能避免“需求表更新了架构图没跟上”的低级返工。3. 电子电气架构的网络拓扑与通信矩阵怎么定网络拓扑是电子电气架构师最常被要求交付的图纸但它不是设计的目标而是带宽、成本和实时性博弈的结果。拓扑应该是在通信矩阵算完之后反推出来的而不是先画一张星级结构图再往里填数据。3.1 拓扑不是画出来的是算出来的选总线之前先明确这条链路在传什么数据、周期多少、延迟多大。下面是几个我在选型时常用的判断维度总线类型速率典型用途架构阶段注意点LIN20kbit/s车窗、座椅、门锁等低速开关控制节点少、周期长注意共地干扰CAN FD最高 8Mbit/s动力、底盘、车身控制以及诊断单帧最大 64 字节负载率要留余量Ethernet100M/1G域间大流量、SOA 服务、视频、OTA交换机流量整形、VLAN、时间同步车载以太网 PNC100M 起步部分网络唤醒、服务发现休眠时 PHY 供电策略要单独评估目前做软件定义汽车的平台主流方向是“中央计算 区域控制器”也就是中央计算单元负责高算力功能区域控制器做 I/O 和供电分配区域之间用车载以太网互联传感器和执行器还留在 CAN FD / LIN 上。选型时不要被“大家都在上以太网”带偏车窗控制就是 LIN 更省成本ADAS 视频流就是 Ethernet 更合适架构师要的是让每一条数据找到性价比最高的通路。3.2 先算负载率再谈带宽一个能直接抄的脚本通信矩阵阶段最基础的验证是总线负载率。很多人等到台架联调才拿 CANoe 测负载一测就超然后回头改 DBC。更稳妥的做法是在 DBC 刚生成时就用脚本估算每条总线的负载率超标的报文周期和长度在评审前就改完。下面这个脚本只依赖 Python 标准库直接从 DBC 文件里读取报文长度和周期按标准 CAN 帧格式估算总线负载率。import os def dbc_to_frame_list(path): frames [] period_by_id {} with open(path, encodingutf-8, errorsignore) as f: for line in f: line line.strip() # DBC 报文定义行例如: BO_ 512 EngineData: 8 Vector__XXX if line.startswith(BO_ ): parts line.split() msg_id int(parts[1]) msg_len int(parts[2].rstrip(:)) frames.append({id: msg_id, len: msg_len}) # DBC 周期属性行例如: BA_ GenMsgCycleTime BO_ 512 100; elif line.startswith(BA_ GenMsgCycleTime BO_): parts line.split() msg_id int(parts[3]) cycle_ms int(parts[4].rstrip(;)) period_by_id[msg_id] cycle_ms for f_ in frames: f_[period] period_by_id.get(f_.get(id), None) return frames def estimate_bus_load(dbc_path, baudrate500000): frames dbc_to_frame_list(dbc_path) bits_per_sec 0 overhead_bits 42 # 标准CAN帧固定开销: SOF仲裁场控制场CRCACKEOF for f_ in frames: if not f_.get(period): continue frame_rate 1000.0 / f_[period] # 100ms 周期 - 10 帧/秒 bits_per_sec frame_rate * (overhead_bits 8 * f_[len]) # 乘 1.2 作为位填充和 CAN 控制器额外开销的余量 return bits_per_sec / baudrate * 1.2 if __name__ __main__: for dbc in os.listdir(.): if dbc.endswith(.dbc): load estimate_bus_load(dbc) print(f{dbc}: 总线负载率 {load:.1%})脚本里baudrate默认是按 500kbit/s 算的如果你的项目用的是 CAN FD把baudrate改成对应速率即可但 CAN FD 的帧头和 CRC 开销与标准 CAN 不同最好在估算结果上再多留 10% 的裕量。负载率建议控制在线下 50%长期跑在 60% 以上的总线扩展一个新功能就得动一次架构。3.3 服务接口与小信号并存别把 SOME/IP 做成“高级 CAN 报文”中央计算架构下SOME/IP 几乎是必选项但很多人把 SOA 设计成了“把原来的 100 个 CAN 信号换成 100 个 SOME/IP 事件”这是最典型的过度设计。信号型通信和服务型通信各有位置周期性信号、状态量、低频控制量用信号交互更直接跨域调用、能力发现、按需调用才适合服务化。服务接口定义我建议在架构阶段就用结构化文件落下来而不是等工具链生成。比如一个座椅位置服务可以先写成下面这样service_id: 0x1234 instance_id: 0x0001 events: - event_id: 0x8001 name: SeatPositionEvent cycle: 100ms data: - {name: SeatPosition, type: float32, unit: mm} methods: - method_id: 0x0010 name: SetSeatPosition input: {seat: uint8, position: uint16} output: {result: uint8}这里的关键不是格式而是设计边界SeatPositionEvent是周期事件适合订阅方需要持续刷新的场景SetSeatPosition是方法调用适合用户主动操作场景。架构师要控制的是“这个服务该不该存在”服务数量一旦膨胀到几百个服务发现、订阅管理和刷写兼容性都会变成灾难。我的习惯是单域服务数量控制在几十个以内低频状态量优先用 Getter 按需读取而不是全部发布成事件。3.4 通信矩阵变更时如何查影响面架构演进过程中DBC 和 ARXML 不可能不改。真正拉开差距的是改完之后能不能在一小时内说清影响面。通信矩阵里每一处变更都会跨控制器传导变更类型影响对象必须验证项信号长度或起始位变更所有接收该信号的 ECU信号解析一致性、物理值范围报文周期调整总线负载率、超时监控逻辑接收方超时时间与降级策略事件改为周期发送服务发现、订阅方缓存带宽增量、订阅时序新增一个以太网服务交换机 VLAN、流量整形帧优先级、端到端延迟这套影响面分析不能靠开会最好用版本对比脚本把 DBC 或 ARXML 的差异自动导出来再挂到架构评审单上。评审时不要只问“这块软件改不改”要问“这条信号的接收方有没有超时监控周期变了之后监控阈值要不要一起变”问过三代就没人敢随便改周期了。4. 电子电气架构的电源模式与休眠唤醒设计电源管理是电子电气架构里最不性感但返工率最高的一层。很多项目在台架阶段发现整车休眠电流超标查到最后往往是某个 ECU 在 OFF 挡还被周期唤醒而这个 ECU 的唤醒源是架构阶段随手画的一条线。电源模式必须在架构设计阶段就定出状态机和每个状态的准入条件。4.1 电源模式状态机的设计粒度整车电源模式不能只分“开/关”两挡但也不能复杂到每个 ECU 一个状态。我一般按六个状态设计再根据平台定位裁剪状态整车供电典型允许网络退出条件OFF仅保留唤醒电路部分 CAN 总线监听唤醒报文门把手、钥匙、充电插头触发ACC娱乐与附件供电座舱、网关电源按钮 OFFON全车供电全网络启动发动机 / ReadyCRANK_RUN关键 ECU 保持供电动力与底盘发动机运行或车辆 ReadySERVICE_MODE诊断供电诊断使能 ECU诊断会话结束这里最容易漏的是 SERVICE_MODE。没有它诊断仪插上去之后 ECU 需要从正常状态强行切到诊断刷写模式很多软件 Bug 就是在这条切换路径上炸的。4.2 用脚本校验状态迁移至少有一条返回路电源状态机也是代码也会有死锁。评审时让各控制器把状态迁移表交上来然后用脚本统一扫一遍比在评审会上口头问“你这个状态怎么回来”效率高得多。STATES [OFF, ACC, ON, CRANK_RUN, SERVICE_MODE] TRANSITIONS { OFF: [ACC, SERVICE_MODE], ACC: [OFF, ON], ON: [ACC, CRANK_RUN, SERVICE_MODE, OFF], CRANK_RUN: [ON], SERVICE_MODE: [OFF, ON], } for state in STATES: exits TRANSITIONS.get(state, []) if not exits: print(f[ERROR] {state} 没有任何合法退出路径会卡死在当前状态) elif state ! ON and ON not in exits and OFF not in exits: print(f[WARN] {state} 无法回到 ON 或 OFF确认是否需要中间状态)脚本只做一件事确认每个状态至少有一条回到 ON 或 OFF 的路径。如果某个状态既不能回 ON 也不能回 OFF那它就只能靠硬复位退出这在实车上就是没电的假死现象。把这个检查放进 CI电源状态机每次变更都会自动触发验证。4.3 休眠电流、唤醒源与网络管理要联动设计休眠电流超标绝大多数不是硬件漏电而是网络管理没做干净。CAN 总线上一个节点还在周期性发 NM 报文整条总线就睡不着以太网上一个 PHY 被唤醒整个交换机就被拖起来。架构阶段至少要把这三类参数定下来每个 ECU 的 NM 参数NM 报文周期、超时时间通常 10ms 到 1s 不等每条总线的唤醒源清单本地唤醒、远程唤醒、PNC 部分网络唤醒应用层周期任务的最小频率最低频率的任务必须设计成“业务触发式”不能在休眠周期里持续占 CPU。我一般建议在每个区域控制器里加一个“休眠准入检查”所有外部请求都结束后才允许总线进入预休眠而不是等 NM 超时兜底。诊断、OTA 都会主动请求总线保持唤醒如果让它们在后台悄悄运行整车永远进不了深睡。4.4 跨域电源管理的常见冲突最后说一个最容易被忽略的冲突OTA 刷写和电源模式。很多车的 OTA 流程要求整车上电到 ON但用户可能只是想在停车后静默刷一个座舱应用。如果架构只允许“ON 挡才能刷写”那每一次夜间刷写都要把用户叫醒体验极差。常见做法是引入一个“刷写模式”介于 OFF 和 ACC 之间只给刷写相关的域控制器供电其他域保持休眠。这个模式必须和休眠电流目标一起验证否则夜间刷写完蓄电池就没电了。5. 电子电气架构师做架构验证的最小闭环5.1 把架构决策固化成可回归的检查架构评审的最大问题是“评审时讲得很清楚评审后没有人再验证”。最小闭环是让架构决策变成自动化检查项。把前面 3.2 的负载率估算函数抽到一个公共模块里然后在每次通信矩阵变更后跑一段回归脚本from dbc_tools import estimate_bus_load # 复用 3.2 的函数 def architecture_regression(dbc_files, baudrate500000): failures [] for dbc in dbc_files: load estimate_bus_load(dbc, baudrate) if load 0.5: failures.append(f{dbc} 总线负载率 {load:.1%} 超过设计阈值 50%) return failures if __name__ __main__: problems architecture_regression([body.dbc, powertrain.dbc]) if problems: for p in problems: print([FAIL], p) raise SystemExit(1) print([PASS] 本轮架构检查未发现负载率超限)这段检查可以在本地跑也可以挂到 CI 上。它的价值不在于算出精确负载而在于每次 DBC 变更都自动提醒你“这个改动会不会突破架构设计边界”不用等人肉评审。5.2 架构评审时必问的五个“如果”再往后走架构师的功力体现在预判冲突。下面这五个问题是我在评审时一定会问出来的建议你评审前先自己答一遍如果休眠电流超标你会先砍唤醒源还是先改拓扑改了拓扑之后线束重量和成本谁承担如果同一个以太网服务被 50 个节点订阅订阅分发、流控和启动时序怎么设计如果 OTA 刷写和诊断请求同时进来网关按什么优先级仲裁如果 L2 功能后续升级 L3当前中央计算单元的算力余量够不够 20% 以上如果某个区域控制器整体失效哪些功能降级、哪些功能由冗余通路接管降级后仪表给驾驶员什么提示这五个问题没有标准答案但每个问题都指向一条必须闭环的架构链条。用 5.1 的脚本跑完负载和状态机检查再把这五个问题逐条过一遍能留下来的架构方案才值得往下做详细设计。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

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