ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Python实战:正面40%偏置碰撞测试数据分析与可视化

2026/9/3 11:55:35 拓冰建站 浏览量
Python实战:正面40%偏置碰撞测试数据分析与可视化 前一段时间在做车辆模拟碰撞相关的数据分析时一直想找一个能完整呈现“正面 40% 偏置碰撞”测试思路的练习案例。正好手头有一套模拟环境可以复现一台 2005 年的老旧 SUV 在不同碰撞条件下产生的动态响应。本文就以《【BASA】2005 Bruckell VRV 正面40%碰撞测试》为场景完整梳理从测试场景设定、数据采集再到 Python 解析与可视化的一整套流程。这篇文章比较适合对车辆碰撞安全、仿真测试数据分析和 Python 数据处理感兴趣的读者。如果你手头有类似的气囊标定数据、碰撞仿真输出或整车道路试验数据也可以在阅读过程中对比这份思路。文章不会下任何“车辆安全性好坏”的结论重点是把“如何分析一次碰撞测试结果”这件事讲清楚。1. 什么是正面 40% 偏置碰撞测试1.1 碰撞测试的基本分类车辆碰撞测试按照碰撞形式可以简单分成三大类正面碰撞、侧面碰撞和追尾碰撞。正面碰撞又可以继续细化成正面 100% 重叠刚性墙碰撞、正面 40% 偏置碰撞、正面 25% 小重叠碰撞等。不同重叠率模拟的是不同的真实事故场景100% 重叠刚性墙碰撞用来模拟整车正面直接撞墙的工况对车身纵梁、防火墙和约束系统考核比较全面。40% 偏置碰撞模拟车头一侧约 40% 的宽度与对向车辆或障碍物发生重叠碰撞这种工况对乘员舱结构强度要求更高。25% 小重叠碰撞模拟车头外侧与树、护栏等刚性物体刮擦碰撞对 A 柱、门槛梁和侧围结构压力比较大。本文提到的“正面 40% 碰撞测试”指的就是正面前方障碍物与车辆前端 40% 重叠的碰撞工况。这类试验对车辆结构侵入、假人伤害指标、安全带约束效果都有很强的区分度。1.2 为什么 40% 偏置碰撞更值得关注在实际交通事故中两车正面相撞时很少是完整的车头对车头。驾驶员通常会下意识打方向避让所以很多正面碰撞都伴随着一定偏置量。40% 偏置碰撞正是基于这种真实场景设计的。从力学角度分析车头右侧 40% 参与碰撞时吸能区域不完整碰撞力会通过左侧纵梁、副车架传递到乘员舱。如果车身结构设计不够好防火墙、A 柱下段、门槛梁就会发生明显变形进而挤压驾驶员腿部空间和仪表板区域。所以 40% 偏置碰撞测试关注的核心指标不只是整车减速过程还包括乘员舱结构侵入量A 柱是否发生弯折防火墙是否明显后移转向管柱是否发生位移门框变形是否影响车门开启在模拟环境中我们同样可以从这些维度去分析 Bruckell VRV 这台车的表现。1.3 模拟碰撞测试的特点在当前项目中我们的碰撞测试是在车辆动力学模拟软件中完成的。相比真实物理碰撞试验模拟测试有这些优点成本低不需要制造实车样件不需要报废整车。可重复性高同一参数可以反复运行测试结果不会因环境波动产生差异。参数调整方便可以通过修改碰撞重叠率、初始速度、障碍物刚度等快速对比。数据采集灵活可以同时记录成百上千个通道的传感器数据不担心传感器损坏或丢失。当然模拟测试也有局限性。它依赖车辆动力学模型、材料失效模型和接触算法结果只能无限接近真实试验不能完全替代法规认证。这也是本文反复强调的一点模拟数据用于开发阶段横向对比和趋势分析不要把它当成国家法规认证结果。2. 测试场景与数据分析环境准备2.1 BASA 项目与测试车辆信息本次测试项目代号为“BASA”可以理解为一套“基础整车安全分析”练习流程。测试对象是一台 2005 年款 Bruckell VRV这是一台带有复古风格的家用 SUV 车型轴距较长、车身较高整备质量在同级车型中属于偏大的类型。由于车辆年款较老车身结构设计更多强调舒适性和实用性对轻量化高强钢的使用比例并不高。在碰撞安全分析中老旧车型往往更容易暴露结构吸能不足、A 柱变形偏大等问题。这也是我们选择这台车作为分析样本的原因之一。下表整理了本次模拟分析的基本参数参数项设定值测试车辆2005 Bruckell VRV碰撞类型正面 40% 偏置碰撞碰撞重叠率40%试验质量整备质量 驾驶员模拟质量碰撞速度以测试场景实际设定为准地面条件干燥平整沥青路面温度环境常温 20℃ 左右需要特别说明以上参数是模拟场景中使用的预设值真实测试标准会严格按照法规要求执行。这里只是展示分析思路参数本身需要根据你自己的软件版本和场景设定来调整。2.2 数据分析软件清单在做碰撞测试数据分析之前首先确认电脑里的基础环境操作系统Windows 10/11 或 Ubuntu 20.04 均可Python 版本Python 3.8 及以上编辑器VS Code、PyCharm 或 Jupyter Notebook 任选核心依赖库pandas、numpy、matplotlib、scipy如果还没有安装这些库可以在终端中执行下面的命令pip install pandas numpy matplotlib scipy如果你使用的是 Anaconda也可以使用 conda 安装conda install pandas numpy matplotlib scipy安装完成之后可以通过一条命令检查版本是否正常python -m pip list | findstr pandas这里先不粘贴具体的版本号因为每个人的环境不同。只要 pandas、numpy、matplotlib 能正常导入就可以继续往下操作。2.3 数据文件组织方式一次典型的碰撞测试会生成多个数据文件包括车辆轨迹、姿态、速度和加速度波形等。建议在项目目录中按下列方式组织文件BASA-2005-VRV/ ├── data/ │ ├── crash_40_overlap/ │ │ ├── telemetry.csv │ │ ├── vehicle_state.csv │ │ └── intrusion_points.json │ └── readme.md ├── scripts/ │ ├── load_data.py │ ├── speed_analysis.py │ ├── acceleration_analysis.py │ └── intrusion_analysis.py └── output/ └── figures/这样的目录结构好处很明显原始数据、处理脚本和输出图表彼此隔离不容易出现误改数据文件的问题。尤其是当你手头有多组碰撞工况对比的时候建议每一组工况单独建一个数据文件夹。3. 碰撞测试结果的关键分析指标3.1 车辆速度变化曲线碰撞过程最直观的表现就是速度变化。车辆从初始速度逐步降到零整个过程一般在几十毫秒到上百毫秒内完成。速度曲线主要关注三个信息碰撞初始速度决定了碰撞能量的大小。速度归零时间点反映了碰撞吸能的持续时间。速度曲线的斜率斜率越陡说明碰撞越剧烈。如果速度曲线在短时间内发生剧烈跳变往往意味着车身结构没有充分参与吸能或者是传感器数据本身存在噪声。3.2 加速度与碰撞强度加速度是碰撞测试中最重要的物理量之一。车辆在碰撞过程中的加速度变化直接反映了乘员受到的惯性载荷大小。碰撞加速度通常用 g 表示1g 约等于 9.8 m/s²。加速度值越大乘员受到的冲击越强烈。分析加速度时一般会使用滤波处理后的波形。滤波的作用是去掉高频噪声保留与车辆结构响应相关的低频成分。常见的滤波方式包括 SAE J211 标准滤波和低通滤波。在实际代码中我们可以先计算原始加速度数据再用 scipy 的 butterworth 滤波器做平滑处理。后面的演示代码会具体展示。3.3 乘员舱侵入量除了整车的速度、加速度车身局部变形量同样是判断碰撞结果的重要指标。乘员舱侵入量主要指 A 柱、防火墙、地板、转向管柱、踏板等区域相对乘员舱原始位置的位移。侵入量越大乘员被结构挤压的风险越高。尤其对老旧 SUV 来说防火墙刚度不足时碰撞后制动踏板和转向管柱会向驾驶员方向移动这是非常危险的。在模拟软件中我们可以直接输出几个关键测量点在碰撞前后的坐标然后在 Python 中计算空间位移量。4. 基于 Python 的碰撞数据读取方法4.1 读取 CSV 遥测文件碰撞测试软件导出的数据格式并不统一常见的包括 CSV、Excel、JSON 甚至二进制格式。为了演示假设我们已经导出了一份 telemetry.csv 文件里面包含时间戳、速度、加速度等字段。下面是一段读取并预览数据的代码# 文件路径scripts/load_data.py import pandas as pd # 读取碰撞过程遥测数据 df pd.read_csv(../data/crash_40_overlap/telemetry.csv) # 查看数据列名 print(数据列名) print(df.columns.tolist()) # 查看前 5 行 print(\n前 5 行数据预览) print(df.head()) # 查看数据基本统计信息 print(\n数据统计信息) print(df.describe())运行后你会看到类似下面的输出结构数据列名 [time, speed_kmh, accel_x_g, accel_y_g, accel_z_g] 前 5 行数据预览 time speed_kmh accel_x_g accel_y_g accel_z_g 0 0.00 35.40 -0.02 0.01 1.00 1 0.02 ...注意不同模拟软件导出的列名可能不同如果直接复制这段代码发现 KeyError不用紧张先用 print(df.columns) 查看字段名再去改列名即可。4.2 时间轴对齐与空值处理碰撞数据经常会出现两种问题一是时间戳不连续二是某些传感器在某段时间内无数据。直接分析会导致曲线突变或中断因此需要先对时间轴进行检查和处理。# 文件路径scripts/load_data.py import numpy as np import pandas as pd df pd.read_csv(../data/crash_40_overlap/telemetry.csv) # 检查是否存在空值 print(每列空值数量) print(df.isnull().sum()) # 如果存在空值可以选择删除或插值 # 碰撞数据中短时间缺失采用线性插值比较合理 if df.isnull().sum().sum() 0: df df.interpolate(methodlinear, limit_directionboth) # 检查时间列是否单调递增 time_diff np.diff(df[time].values) if (time_diff 0).any(): print(警告时间轴存在非递增时刻需要排序) df df.sort_values(bytime).reset_index(dropTrue) print(数据清洗完成总记录数, len(df))这里选用线性插值而不是删除缺失行是因为碰撞过程非常短任何瞬间的缺失都可能影响后续峰值的判断。当然如果数据缺失过多整段传感器的可靠性就得打问号了。4.3 JSON 格式侵入点数据读取侵入量数据有时会以 JSON 格式保存因为里面通常包含多个测量点的三维坐标。下面演示如何读取并转换成 DataFrame# 文件路径scripts/load_data.py import json import pandas as pd # 读取侵入点数据 with open(../data/crash_40_overlap/intrusion_points.json, r, encodingutf-8) as f: intrusion_data json.load(f) # 将每个测量点转换为行记录 records [] for point_name, info in intrusion_data.items(): records.append({ point: point_name, initial_x: info[initial][x], initial_y: info[initial][y], initial_z: info[initial][z], final_x: info[final][x], final_y: info[final][y], final_z: info[final][z], }) df_points pd.DataFrame(records) # 计算合位移 df_points[displacement] ( (df_points[final_x] - df_points[initial_x]) ** 2 (df_points[final_y] - df_points[initial_y]) ** 2 (df_points[final_z] - df_points[initial_z]) ** 2 ) ** 0.5 print(df_points.sort_values(bydisplacement, ascendingFalse))这段代码会输出每个测量点在碰撞前后的三维位移量。对我们分析碰撞侵入情况非常关键。5. 碰撞数据分析与可视化实战5.1 速度曲线分析车辆碰撞的过程中车速从初始碰撞速度逐渐下降。为了观察速度变化的整体趋势我们可以绘制散点或折线图。# 文件路径scripts/speed_analysis.py import matplotlib.pyplot as plt import pandas as pd # 读取数据 df pd.read_csv(../data/crash_40_overlap/telemetry.csv) # 截取碰撞时间段比如碰撞前 0.1 秒到碰撞后 0.3 秒 mask (df[time] -0.1) (df[time] 0.3) df_crash df[mask].copy() # 将速度单位从 km/h 换算成 m/s df_crash[speed_mps] df_crash[speed_kmh] / 3.6 # 绘制速度曲线 plt.figure(figsize(10, 5), dpi120) plt.plot(df_crash[time], df_crash[speed_kmh], labelVehicle Speed (km/h), color#E74C3C, linewidth2) plt.axhline(y0, colorgray, linestyle--, linewidth0.8) plt.xlabel(Time (s)) plt.ylabel(Speed (km/h)) plt.title(2005 Bruckell VRV - Frontal 40% Overlap Crash Speed) plt.grid(alpha0.3) plt.legend() plt.tight_layout() plt.savefig(../output/figures/speed_curve.png, dpi150) plt.show()这段代码的关键点在于先过滤出碰撞时间段再绘图。如果不做时间段裁剪画出来的曲线会被前后很长一段匀速或减速过程压扁碰撞阶段的细节就看不清楚了。5.2 加速度波形计算与滤波加速度信号通常比较“毛躁”直接画原图会看到很多高频抖振。为了观察趋势需要先滤波。使用巴特沃斯低通滤波器是常见选择。下面的代码实现了 100Hz 低通滤波并绘制碰撞过程中的纵向加速度曲线# 文件路径scripts/acceleration_analysis.py import numpy as np import pandas as pd import matplotlib.pyplot as plt from scipy.signal import butter, filtfilt # 读取数据 df pd.read_csv(../data/crash_40_overlap/telemetry.csv) # 定义低通滤波函数 def lowpass_filter(data, cutoff_hz, sample_rate_hz, order4): nyquist 0.5 * sample_rate_hz normal_cutoff cutoff_hz / nyquist b, a butter(order, normal_cutoff, btypelow, analogFalse) return filtfilt(b, a, data) # 根据时间列估算采样率 dt np.median(np.diff(df[time].values)) sample_rate 1.0 / dt print(f估算采样率{sample_rate:.0f} Hz) # 截取碰撞时间段 mask (df[time] 0.0) (df[time] 0.2) df_crash df[mask].copy() # 对纵向加速度进行低通滤波 filtered_accel lowpass_filter(df_crash[accel_x_g].values, cutoff_hz100, sample_rate_hzsample_rate) # 绘制原始与滤波后加速度对比 plt.figure(figsize(12, 6), dpi120) plt.plot(df_crash[time], df_crash[accel_x_g], alpha0.3, labelOriginal Accel X, color#BDC3C7) plt.plot(df_crash[time], filtered_accel, labelFiltered Accel X (100Hz), color#2980B9, linewidth2) plt.axhline(y0, colorgray, linestyle--, linewidth0.8) plt.axhline(ynp.min(filtered_accel), color#E74C3C, linestyle:, linewidth1.5) plt.text(df_crash[time].iloc[-1], np.min(filtered_accel), fPeak: {np.min(filtered_accel):.2f} g, haright, vabottom, color#E74C3C) plt.xlabel(Time (s)) plt.ylabel(Acceleration (g)) plt.title(BASA - Bruckell VRV Frontal 40% Overlap Longitudinal Acceleration) plt.grid(alpha0.3) plt.legend() plt.tight_layout() plt.savefig(../output/figures/acceleration_curve.png, dpi150) plt.show() # 输出峰值信息 print(f滤波后纵向加速度最大负向峰值{np.min(filtered_accel):.2f} g)峰值加速度所在的时间点对应乘员受到最大惯性载荷的时刻。可以把该时间点与前面速度曲线归零的时间点做对比从而判断碰撞峰值的发生时机是否合理。5.3 侵入量变化趋势图侵入量分析主要是横向对比。我们可以把各测量点的时域侵入过程画出来考察车门框、防火墙、门槛梁是否存在过大位移。# 文件路径scripts/intrusion_analysis.py import json import matplotlib.pyplot as plt import numpy as np # 读取侵入点数据 with open(../data/crash_40_overlap/intrusion_points.json, r, encodingutf-8) as f: intrusion_data json.load(f) # 初始化图表 plt.figure(figsize(12, 6), dpi120) # 每个测量点都包含时域位移信息 for point_name, info in intrusion_data.items(): if series not in info: continue time_series np.array(info[series][time]) displacement_series np.array(info[series][displacement]) plt.plot(time_series, displacement_series, linewidth1.5, labelpoint_name) plt.xlabel(Time (s)) plt.ylabel(Intrusion Displacement (mm)) plt.title(BASA - Key Cabin Points Intrusion Timeline) plt.grid(alpha0.3) plt.legend(locupper left) plt.tight_layout() plt.savefig(../output/figures/intrusion_timeline.png, dpi150) plt.show()绘制侵入量时间历程的好处是我们可以判断变形是发生在碰撞瞬间还是在碰撞后期依然持续增大。如果在车辆速度归零之后侵入量还在增长说明结构存在“压溃后继续蠕变”的情况。5.4 多工况对比思路实际数据分析中单次测试结果并不能说明问题。横向对比是很常用的手段比如对比 40% 偏置碰撞与 100% 正面碰撞的加速度峰值。你可以把多组数据放在同一个 DataFrame 中管理然后用分组统计的方式计算峰值# 文件路径scripts/multi_case_compare.py import pandas as pd # 假设已有多个工况的文件列表 file_list [ (40%_overlap, data/crash_40_overlap/telemetry.csv), (100%_frontal, data/crash_100_frontal/telemetry.csv), ] rows [] for case_name, file_path in file_list: df pd.read_csv(file_path) # 只统计碰撞后 0~0.2 秒的数据 df_crash df[(df[time] 0.0) (df[time] 0.2)] peak_g df_crash[accel_x_g].min() rows.append({case: case_name, peak_accel_g: round(peak_g, 2)}) summary pd.DataFrame(rows) print(summary)这种横向对比输出非常适合用来快速观察不同工况的差异。6. 常见报错与排查清单在做碰撞数据分析的过程中有一些高频问题经常出现。下面整理成表格方便大家排查。问题现象常见原因解决思路读取 CSV 后提示 Column not found软件导出的列名与代码不一致先打印 columns 字段确认实际列名时间轴不连续导致曲线断裂模拟帧率波动或导出丢帧使用 np.diff 检查时间间隔做重采样处理加速度曲线噪声非常大未进行滤波或采样率过高使用巴特沃斯低通滤波器选择合适截止频率速度曲线碰撞后没有归零数据导出范围被截断检查导出时间范围延长碰撞后记录时间JSON 文件读取为字符串json.load 前没有正确打开文件检查文件编码使用 utf-8 打开matplotlib 中文乱码系统缺少中文字体绘图时设置 rc 参数指定中文字体峰值加速度数值偏大原始信号包含高频噪声检查滤波截止频率和滤波器阶数侵入量曲线不平滑测量点接触算法抖动使用滑动平均或增加数据导出频率6.1 JSON 文件编码问题详解Windows 系统下导出的 JSON 文件经常使用 UTF-8 编码但也可能有部分工具使用 GBK。如果直接读取报编码错误可以改成with open(file_path, r, encodingutf-8-sig) as f: data json.load(f)utf-8-sig 会自动去除带 BOM 的文件头适合大多数从 Windows 导出的文件。6.2 滤波器参数如何选择SAE J211 是汽车碰撞试验中比较常用的滤波标准不同通道对应不同频率等级。例如车身结构加速度通道通常使用 CFC 60假人头部加速度通道使用 CFC 1000假人颈部力通道使用 CFC 1000本文只是 Python 演示采用了简化的 100Hz 低通滤波思路。实际工程中应该严格按照对应法规标准来滤波。模拟数据对比时要保证多组数据使用完全相同的滤波参数否则结果没有可比性。7. 碰撞测试项目中的工程建议7.1 数据命名与版本管理一次整车级别的碰撞分析会涉及非常多的数据文件。如果不做数据命名规范过两周再回来看完全不知道每个文件对应什么工况。建议命名规则日期_车辆代号_碰撞类型_速度_重复次数例如20250104_BruckellVRV_F40_64kmh_run01.csv这样可以避免文件重名、覆盖和漏算。开发中用到 Git 管理时还要注意不要把上百 MB 的数据文件直接提交到代码仓库建议采取数据文件与脚本分离的方式。7.2 数据采集与备份策略碰撞模拟虽然不会像真实试验那样一次撞毁几台车但运行时如果忘记导出数据或软件崩溃同样会导致数据丢失。建议运行前检查输出路径是否存在。每个工况运行完成后立即备份到独立目录。碰撞关键通道建议使用冗余记录。数据处理脚本输出统一存放不要覆盖原始数据。7.3 结果评价的安全边界这里必须强调一点模拟碰撞数据只能用于研发阶段的参数趋势分析不能直接用来申报或证明某款车满足法规安全要求。不同软件版本、不同车辆模型参数之间的差异可能导致结果偏差很大。我们在公开平台讨论 Bruckell VRV 这类模拟测试时也应该保持严谨的态度。不要使用“某车不安全”“某车垃圾”等绝对化表述。因为车辆型号属于虚构游戏车型不是真实品牌车辆。模拟测试中驾驶员模型、约束系统模型都做了一定简化。一次碰撞测试结果无法代表车辆在真实复杂事故中的所有表现。从数据分析的角度看我们要关注的是方法流程是否规范、数据处理是否合理、结论是否可复现。7.4 报告输出的最小要素一份完整的碰撞数据分析报告至少需要包含以下内容测试目的与工况说明车辆参数与模型版本信息数据通道列表与采样率说明滤波方法与处理参数关键结果图表量化指标统计表异常数据说明结论与局限性分析这样写出来的分析报告才具备可追溯性也方便他人复核。8. 完整脚本整合与运行为了方便你直接复现这里提供一份整合后的分析主脚本。把下面代码保存到 scripts/main_analysis.py然后在项目根目录执行即可。# 文件路径scripts/main_analysis.py BASA - 2005 Bruckell VRV 正面 40% 碰撞测试数据分析示例 仅用于模拟环境数据分析学习不代表真实车辆安全评价。 import json import numpy as np import pandas as pd import matplotlib.pyplot as plt from scipy.signal import butter, filtfilt # 全局配置 DATA_DIR ../data/crash_40_overlap OUTPUT_DIR ../output/figures # 1. 读取遥测数据 telemetry_path f{DATA_DIR}/telemetry.csv df pd.read_csv(telemetry_path) # 数据清洗与排序 if df.isnull().sum().sum() 0: df df.interpolate(methodlinear, limit_directionboth) time_diff np.diff(df[time].values) if (time_diff 0).any(): df df.sort_values(bytime).reset_index(dropTrue) # 2. 读取侵入点数据 intrusion_path f{DATA_DIR}/intrusion_points.json with open(intrusion_path, r, encodingutf-8-sig) as f: intrusion_data json.load(f) def lowpass_filter(data, cutoff_hz, sample_rate_hz, order4): nyquist 0.5 * sample_rate_hz normal_cutoff cutoff_hz / nyquist b, a butter(order, normal_cutoff, btypelow, analogFalse) return filtfilt(b, a, data) # 3. 计算碰撞阶段统计指标 df_crash df[(df[time] 0.0) (df[time] 0.2)].copy() dt np.median(np.diff(df[time].values)) sample_rate 1.0 / dt filtered_accel lowpass_filter(df_crash[accel_x_g].values, cutoff_hz100, sample_rate_hzsample_rate) peak_accel np.min(filtered_accel) speed_min df_crash[speed_kmh].min() print(碰撞阶段分析结果) print(f估算采样率: {sample_rate:.0f} Hz) print(f滤波后纵向峰值加速度: {peak_accel:.2f} g) print(f碰撞阶段最低速度: {speed_min:.2f} km/h) # 4. 侵入点位移统计 print(\n关键测量点侵入量统计) for point_name, info in intrusion_data.items(): initial info.get(initial, {}) final info.get(final, {}) displacement ( (final[x] - initial[x]) ** 2 (final[y] - initial[y]) ** 2 (final[z] - initial[z]) ** 2 ) ** 0.5 print(f{point_name}: {displacement:.2f} mm) # 5. 绘制关键图表 fig, axes plt.subplots(2, 2, figsize(14, 10), dpi120) # 子图1速度曲线 ax axes[0][0] df_full_time df[(df[time] -0.1) (df[time] 0.3)] ax.plot(df_full_time[time], df_full_time[speed_kmh], color#E74C3C, linewidth2) ax.set_xlabel(Time (s)) ax.set_ylabel(Speed (km/h)) ax.set_title(Vehicle Speed vs Time) ax.grid(alpha0.3) # 子图2加速度曲线 ax axes[0][1] ax.plot(df_crash[time], df_crash[accel_x_g], alpha0.3, color#BDC3C7) ax.plot(df_crash[time], filtered_accel, color#2980B9, linewidth2) ax.axhline(ypeak_accel, color#E74C3C, linestyle:) ax.set_xlabel(Time (s)) ax.set_ylabel(Acceleration (g)) ax.set_title(Longitudinal Acceleration (Filtered)) ax.grid(alpha0.3) # 子图3侵入量时间历程 ax axes[1][0] for point_name, info in intrusion_data.items(): if series not in info: continue series_time np.array(info[series][time]) series_disp np.array(info[series][displacement]) ax.plot(series_time, series_disp, linewidth1.5, labelpoint_name) ax.set_xlabel(Time (s)) ax.set_ylabel(Displacement (mm)) ax.set_title(Key Points Intrusion Timeline) ax.grid(alpha0.3) ax.legend(fontsize8) # 子图4侵入量条形图 ax axes[1][1] points [] disp_values [] for point_name, info in intrusion_data.items(): initial info.get(initial, {}) final info.get(final, {}) displacement ( (final[x] - initial[x]) ** 2 (final[y] - initial[y]) ** 2 (final[z] - initial[z]) ** 2 ) ** 0.5 points.append(point_name) disp_values.append(displacement) ax.bar(points, disp_values, color#16A085) ax.set_xlabel(Measure Points) ax.set_ylabel(Total Displacement (mm)) ax.set_title(Final Intrusion by Measure Point) plt.setp(ax.get_xticklabels(), rotation30, haright) plt.tight_layout() plt.savefig(f{OUTPUT_DIR}/basa_summary.png, dpi150) plt.show() print(\n图表已输出到, OUTPUT_DIR)执行方式cd scripts python main_analysis.py如果你使用 Jupyter Notebook也可以直接按单元格拆分运行。这样更容易观察每一步的数据形状和中间结果。9. 总结与下一步学习建议通过这次《【BASA】2005 Bruckell VRV 正面40%碰撞测试》的数据分析我们完整走了一遍“场景理解 - 数据读取 - 数据清洗 - 速度分析 - 加速度分析 - 侵入量分析 - 可视化呈现”的项目流程。从技术层面可以掌握这几个关键点正面 40% 偏置碰撞测试的基本原理和分析维度碰撞数据常见的 CSV、JSON 文件读取和处理方法速度曲线、加速度波形、侵入量数据在 Python 中的可视化方式低通滤波在加速度信号处理中的应用多工况对比分析的基本思路模拟碰撞数据的局限性和工程合规边界如果你是刚开始接触车辆数据分析建议下一步从这几件事入手多跑几个不同速度、不同重叠率的碰撞场景把数据放在同一套脚本里做横向对比。尝试加入假人模型重点关注头部加速度、胸部压缩量和颈部受力等伤害指标。继续学习信号处理知识深入理解不同滤波频率对结果的影响。模拟环境中一次碰撞的完整数据往往隐藏着大量值得挖掘的信息。先把数据读取和清洗这一步做扎实后续不管是做结构优化、约束系统标定还是生成评测报告都会顺手很多。如果文章里这段代码和排查思路对你有帮助可以先收藏备用。后面有更多实战数据再继续补充分析细节。