Files
calibration/tests/README.md

6.9 KiB
Raw Permalink Blame History

测试说明

用途: 说明合成 pytest 与旧车 S2 线下试验的边界(避免误读)。日常跑通请先看根目录 README

试验 是否默认 pytest 在证明什么 不在证明什么
合成数据 算法链路正确、能收回已知 yaw / δt 实车安装精度、平移可交付
旧车 S2 否(线下手工) 主机时间旧数据上流水线能跑完;质量门会拒绝坏结果 外参真值;新车可用性

1. 自动化测试(合成数据 / pytest

入口:tests/test_v1_pipeline.py
命令:

cd <仓库根目录>
python -m pytest -q
测试 输入 在测什么 期望结果
test_rotation_handeye_recovers_yaw 合成运动对(无点云) 旋转手眼能否收回已知 yaw 旋转误差 < 1°
test_time_offset_on_synthetic 合成会话(故意加 δt 模长相关粗估时间偏置
test_signed_time_offset_refine_improves_or_keeps 同上 + 真值 R 有符号三轴 δt 精修 不比粗估明显更差
test_preintegration_bias_jacobian_matches_finite_difference 随机陀螺序列 旋转预积分 J_bg 与有限差分一致(松阈值)
test_imu_preintegration_recovers_constant_accel_translation 常值加速度 完整预积分 Δv/Δp 接近解析值
test_imu_preintegration_bias_jacobian_finite_difference 随机 IMU J_bg/J_ba 一阶修正 与重积分接近
test_synthetic_pipeline_rejects_noisy_icp_but_keeps_time_audit synthetic end-to-end strict rotation quality gate + time audit noisy ICP is blocked; delta-t remains accurate
test_synthetic_pipeline_full_se3_smoke synthetic end-to-end full-SE(3) smoke test returns an explicit accepted/rejected/blocked status
test_planar_yaw_is_not_full_rotation_or_translation_observable pure-yaw motion pairs degeneracy detection full rotation/translation observability is rejected
test_multi_axis_motion_is_rotation_and_translation_observable multi-axis motion pairs positive observability case rotation and translation pass
test_translation_prior_is_reported_but_not_accepted_when_unobservable planar motion + CAD prior prior semantics prior is reported but not accepted as calibration
test_handeye_rejects_a_small_fraction_of_gross_rotation_outliers motion pairs with a gross outlier residual-distribution gate solve is rejected
test_motion_pairs_reject_low_fitness low-fitness registration fitness gate no motion pair is emitted
test_motion_pairs_reject_imu_and_lidar_discontinuities timestamp gaps continuity gates cross-gap pairs are rejected

合成数据由 tools/generate_synthetic_session.py 生成(墙面点云 + 已知外参 yaw 与 δt)。
一键复现见根目录 READMEtools/reproduce_synthetic.py


2. 旧车 S2 线下试验(不在默认 pytest 里)

用了什么数据

内容
车辆 / 批次 S2 验证集(S2_scheme1_validation)数据在网盘的“室外车数据\IMU-雷达标定数据”
典型路径 D:\IMU_calibration\work\S2_scheme1_validation\(历史目录名;含 imu.csv + 雷达会话)
IMU 时间 主机 UTC 接收时间(串口块到达时刻),不是 IMU 设备时间
雷达时间 dlog 导出的主机侧 unix_time_ns,不是 MSOP 设备时间
帧率特征 雷达约 1 Hz 量级,关键帧间隔偏长
配置烟测 config/s2_old_smoke.yaml(仅声明为旧数据烟测,不当交付)

这些数据只能用来验证流水线能否跑通,不能当作新车外参真值来源。
blocked 是质量门的预期结果,不是「算法突然坏了」。

做了什么测试

对同一批 S2 中间格式多次跑 cli run,例如:

  • 预积分加强后的输出目录(本机历史名如 out_scheme2_preint
  • 有符号 δt / 联合精修后的输出(本机历史名如 out_scheme2_phaseA
  • tools/compare_s2_runs.py 对比两次 summary.json

命令形态(路径按本机实际修改;雷达会话目录若仍叫 scheme2_session 为历史命名):

python -m imu_lidar.cli run `
  --vehicle-config config\s2_old_smoke.yaml `
  --imu D:\IMU_calibration\work\S2_scheme1_validation\imu.csv `
  --lidar D:\IMU_calibration\work\S2_scheme1_validation\scheme2_session `
  --output path\to\out_s2 `
  --mode rotation_only `
  --time-offset-search-s 2.0

python tools\compare_s2_runs.py path\to\out_old\summary.json path\to\out_new\summary.json

得到什么结果(记录摘要)

指标 预积分加强一轮 有符号 δt / 精修一轮
status blocked(预期) blocked(预期)
手眼 RMS 15.0° 14.5°
手眼中位数 6.8°
δt 2.0 s 1.75 s(有修正)
相关峰 很弱(约 0.18 仍弱(约 0.13
结论 链路可跑 残差略降,但 不当交付外参

原因归纳:

  1. 时间戳是主机时间,相关峰弱,δt / yaw / 零偏互相耦合;
  2. 雷达约 1 Hz,运动对间隔长,IMU 侧更易漂;
  3. 质量门主动 blocked,避免把坏结果当成安装参数。

正式标定必须改用设备时间(IMU device_timestamp、雷达 MSOP 设备时)重新采集后再跑。


3. 配准结果怎么目视检查

标定跑完后(合成或实车):

python tools\visualize_pair_3d.py `
  --lidar examples\synthetic_session\lidar `
  --imu examples\synthetic_session\imu.csv `
  --summary examples\synthetic_session\out\summary.json `
  --pair-index 0 `
  --save-png examples\synthetic_session\out\pair0_overlay.png

交互窗口快捷键:14 切换叠点模式;N/] 下一运动对,P/[ 上一运动对。
无显示器时加 --no-gui --save-png ... 只出俯视图 PNG。