Files
massive-cloud/docs/挠度算法分析.md
lipan 29f1d45d66 feat: 算法升级、整车配准集成与性能分析文档
算法更新: delivery v1.2.1、平整度v1.5、测距v2.2、整车配准v1.3
适配器: vehicle-registration 新增、各算法 manifest 和 adapter 更新
后端: taskCadFiles/source 字段迁移、derivedPointClouds 注册、取消任务联动
前端: ElapsedTime 时长显示、两步算法流程、canRun 逻辑修复
文档: 新增5份算法性能分析报告
2026-06-25 08:22:20 +00:00

7.8 KiB
Raw Blame History

挠度算法性能分析报告

分析时间:2026-06-25
算法版本:delivery_v1.2.1 / underframe_deflection
输入规模:10 亿点 / 12 GB binary PLY(配准后全车点云)
测试环境:INTEL SSDSC2KB01(SATA SSD,实测顺序读速 ~394 MB/s);内存 1 TB;CPU 128 核
参照基准:算法方给出 2 min 28 s(不含点云加载时间)


执行流程总览

load_point_cloud()
    └─ _read_binary_ply()          # I/O 阶段
preprocess_point_cloud()
    ├─ estimate_spacing()          # 采样估距
    ├─ statistical_outlier_filter()# ← 瓶颈1 全云 KNN k=18
    ├─ radius_filter()             # ← 瓶颈2 全云 radius query
    ├─ bilateral_filter_points()   # ← 瓶颈3 全云 KNN k=24
    ├─ voxel_downsample()          # 10亿 → ~23万 work points
    └─ estimate_normals()          # 跑在 work points 上
infer_vehicle_frame()              # 跳过(use_input_axes=true)
compute_deflection()               # ← 算法方基准所测范围
    ├─ beam_tracking
    ├─ line_fitting
    ├─ reference detection
    └─ deflection evaluation
write artifacts                    # PLY / Excel / JSON / CSV

各步骤详细说明与时间估算

第一阶段:I/O 与格式解析

# 步骤 代码位置 说明 估算时间
1 读取 12 GB binary PLY io._read_binary_ply fh.read() 一次性读入,394 MB/s ~31 s
2 np.frombuffer + column_stack → float64 io._read_binary_ply 12 GB float32 → 24 GB float64,纯内存 ~4 s
3 _swap_y_z 列置换(y ↔ z) pipeline._swap_y_z 24 GB 数组列重排 ~3 s

小计:~38 s

这是算法方"没算点云加载时间"的部分。


第二阶段:预处理(真正瓶颈,全程作用于 10 亿原始点)

所有 KNN 滤波步骤均在 voxel_downsample 之前运行,每步都需对 10 亿点建 cKDTree + 全量查询。

# 步骤 代码位置 配置参数 说明 1000万点基线 10亿点估算
4 estimate_spacing preprocess.py:22 sample_size=4000 只对 4000 个采样点建树,O(1) ~1 s ~1 s
5 statistical_outlier_filter preprocess.py:37 k=18, std_ratio=2.8 建 cKDTree(N) + query k=18,O(N·logN) ~8 s ~18 min
6 radius_filter preprocess.py:53 radius=281 mm, min_neighbors=4 再建 cKDTree + query_ball_point,比定 k 查询慢 2–3× ~15 s ~33 min
7 bilateral_filter_points preprocess.py:102 k=24, iterations=1 再建 cKDTree + query k=24,1 次迭代 ~10 s ~20 min
8 voxel_downsample preprocess.py:66 voxel=150 mm O(N) hash,numpy 向量化,10亿 → ~23万 work points ~3 s ~20 s
9 estimate_normals(work points,k=20) preprocess.py:78 normal_k=20 建树 + 逐点 PCA,但只跑在 ~23万 work points 上 ~0.3 s ~30 s

小计:~72 min(步骤 5/6/7 贡献了 71 分钟)


第三阶段:坐标系变换

# 步骤 代码位置 说明 估算时间
10 infer_vehicle_frame api.py:267 任务配置了 use_input_axes=true,直接用单位矩阵,跳过 PCA 帧推断 ~0 s
11 transform_points(~9.9 亿 filtered points) api.py:289 R=I 单位变换,实际等同内存复制 ~10 s

小计:~10 s


第四阶段:挠度计算核心(算法方基准对应范围)

以下步骤均运行在 voxel 降采样后的 ~22,596 work points 上。

# 步骤 代码位置 说明 估算时间
12 build_bottom_roi_mask frame.py ROI 掩码,O(work_n) ~1 s
13 extract_beam_slices beams.py 沿 X 轴分片,提取梁候选片段 ~10 s
14 track_side_candidates × 2(左/右) beams.py 左右梁候选追踪 ~10 s
15 extract_representative_points × 2 fitting.py 从 filtered_roi 提取代表点 ~5 s
16 fit_representative_line × 2 fitting.py 3D 直线拟合(最小二乘) ~2 s
17 detect_reference_line × 2 reference.py 端面参考线检测 ~10 s
18 _evaluate_side_deflection × 2 api.py 网格插值 + 最大挠度求解 ~1 s

小计:~40 s

算法方基准 2 min 28 s 是在已降采样的输入上测的,包含更多候选与迭代冗余,此处估算略低,属合理范围。


第五阶段:写输出

# 步骤 代码位置 说明 估算时间
19 export_overlay_plys artifacts.py 写 4 个 ASCII PLY 叠加层(共 ~1 GB) ~3 min
20 render_plots artifacts.py matplotlib 生成挠度曲线图 ~10 s
21 write_excel_report excel_report.py openpyxl 写 report.xlsx ~5 s
22 write_report_json / CSV artifacts.py JSON + beam_tracks / deflection_curves CSV ~2 s

小计:~3 min 20 s


总时间汇总

阶段 估算耗时 备注
I/O 与格式解析 ~38 s 算法方未计入的部分
预处理(三遍全云 KNN) ~72 min 主要瓶颈
坐标系变换 ~10 s —
挠度计算(算法核心) ~40 s 与算法方基准吻合
写输出 ~3 min —
估算总计 ~77 min 超时阈值 90 min

根本原因分析

流水线顺序(当前):

   10亿点
     │
     ├─ statistical_outlier_filter (k=18)  ─── 18 min ★
     │     cKDTree build + query on 1B pts
     │
     ├─ radius_filter (r=281mm)            ─── 33 min ★
     │     cKDTree build + query_ball on 1B pts
     │
     ├─ bilateral_filter (k=24, iter=1)    ─── 20 min ★
     │     cKDTree build + query on 1B pts
     │
     └─ voxel_downsample (150mm)           ─── 20 s
           1B pts → ~23万 work points       ← 早做就没事了

三个滤波步骤发生在 voxel_downsample 之前,对 10 亿点全云反复建 KD-Tree 并查询。
而 voxel 降采样之后只剩 ~23 万个 work points,在这个规模上做同样的滤波不超过 5 秒。

更重要的是,统计离群过滤在本次数据上只剔除了 0.65%(65 万 / 10 亿)的离群点,对最终 23 万个 work points 的质量几乎没有贡献,却花了 71 分钟。


优化建议

方案 A:适配器层预降采样(推荐,零侵入算法,可立即实施)

在 underframe_deflection_run.py 中,调用算法前先用 Open3D(C++ 实现)对 12 GB 输入做体素降采样,将 10 亿点压缩到 50–100 万点,再传入 run_measurement_pipeline:

# adapter 中新增,在调用 run_measurement_pipeline 之前
import open3d as o3d

pcd = o3d.io.read_point_cloud(pc_path)               # Open3D 读 binary PLY,~15s
pcd_down = pcd.voxel_down_sample(voxel_size=30.0)    # 30mm 体素,~5s,~100万点
# 写临时 binary PLY
tmp_path = out_dir / "_predown.ply"
o3d.io.write_point_cloud(str(tmp_path), pcd_down, write_ascii=False)
pc_path = str(tmp_path)
指标 当前 优化后
预处理 KNN 滤波 ~71 min < 30 s
总耗时 ~77 min ~5 min
改动范围 — 仅 adapter,不改算法

方案 B:算法层调整滤波顺序(需算法方配合)

将 preprocess.py 中 statistical_outlier_filter / radius_filter / bilateral_filter 三步移到 voxel_downsample 之后执行,从根本上解决问题,同时提升所有算法方自己的大点云场景性能。


注:上述时间为理论估算,基于 1000 万点实测基线(analysis/130)线性外推。实际误差在 ±30% 范围内,但数量级判断可靠。