# 矢量几何比对:Altium 侧 JSON 怎么导 `cmp_vec.py` 要两个目录:`kicad_vec/` 由 `dump_kicad_vec.py` 生成; `altium_vec/` 得你在 Claude 会话里用 eda-agent 的 MCP 工具查出来再写盘 —— LangGraph 进程里没有 MCP,这一步必须由会话来做。 --- ## 目录结构 ``` _migration\gerber\ ├── altium_vec\ meta.json vias.json pads.json tracks.json ├── kicad_vec\ meta.json vias.json pads.json tracks.json (dump_kicad_vec.py 生成) └── layer_map.json ``` --- ## altium_vec 各文件的格式 `cmp_vec.py` 的 `load()` 容忍三种外壳:裸 list、`{"vias": [...]}`、`{"objects": [...]}`, 所以直接把 MCP 返回的结果落盘一般就能用。字段名**区分大小写**,按下表来。 ### meta.json ```json { "unit_note": "eda-agent 返回的是整数 mil,读数精度 ±0.5mil = 12.7um", "scale_to_mm": 0.0254, "counts": {"tracks": 10206, "arcs": 108, "pads": 3010, "vias": 2209} } ``` `scale_to_mm` 是 `cmp_vec.py` 唯一会读的字段(也可以用 `--scale-to-mm` 覆盖)。 eda-agent 返回整数 mil,所以是 `0.0254`。 ### vias.json — 来自 `pcb_get_vias` 小写字段: ```json {"vias": [{"x": 22046, "y": 33005, "size": 20, "hole_size": 12, "net": "VCC3V3", "low_layer": "TopLayer", "high_layer": "BottomLayer"}]} ``` `cmp_vec.py` 只用 `x` / `y`,其余留着供人核对。 ### tracks.json — 来自 `obj_query`(PCB 文档,Track 对象) **大写**字段(obj_query 原样返回 Altium 的属性名),值可以是字符串: ```json {"objects": [{"Layer": "TopLayer", "X1": "21739", "Y1": "33141", "X2": "21859", "Y2": "33141", "Width": "6", "Net": "PS232_RX"}]} ``` `cmp_vec.py` 用 `Layer` / `X1,Y1` / `X2,Y2`,按中点逐层匹配。 ### pads.json — 来自 `obj_query`(Pad 对象) ```json {"objects": [{"Name": "", "X": "22666", "Y": "32072", "Layer": "TopLayer", "Net": "GND", "HoleSize": "0", "TopXSize": "59", "TopYSize": "118", "Rotation": "90"}]} ``` 用 `X` / `Y`。 --- ## layer_map.json Altium 层名 → KiCad 层名。**必须逐工程写,不能套公式** —— `MidLayerN` 到 `InN.Cu` 的对应取决于叠层顺序,想当然会全错。 ```json { "TopLayer": "F.Cu", "MidLayer1": "In2.Cu", "MidLayer3": "In5.Cu", "MidLayer2": "In7.Cu", "BottomLayer": "B.Cu" } ``` (上面是 GQ_EXCT7G_V1 的真实映射,注意 MidLayer2/3 是反的。) 怎么定:不带 `--layer-map` 跑一次 `cmp_vec.py`,它会打印两侧每层的走线条数, 按计数配对;再用 `pcb_get_layer_stackup`(Altium 侧)和 `get_layer_list` (KiCad 侧)核对叠层顺序。内电层(负片平面)通常没有走线,不进 map。 --- ## 跑一遍 ```powershell # 1) KiCad 侧(下面的 KiCad python 路径取自 ~/skills_env.md 的 KICAD_PYTHON) & "D:\KiCad\10.0\bin\python.exe" dump_kicad_vec.py ` --board "E:\Kicad_design\FOO\FOO.kicad_pcb" ` --out "E:\Kicad_design\FOO\_migration\gerber\kicad_vec" # 2) Altium 侧:在会话里用 eda-agent 查,按上面的格式写进 altium_vec\ # 3) 先不给 layer_map,看两侧每层走线数,定映射 python cmp_vec.py --altium-vec ...\altium_vec --kicad-vec ...\kicad_vec # 4) 写好 layer_map.json 再跑完整比对 python cmp_vec.py --altium-vec ...\altium_vec --kicad-vec ...\kicad_vec ` --layer-map ...\layer_map.json --report ...\vec_result.json ``` 退出码 0 = 全部图元匹配。 --- ## 结果怎么读 - `unmatched_altium` 和 `unmatched_kicad` **都要是 0**。只看一边会漏掉 「KiCad 多出来的图元」。 - `residual mm` 的 max 应该在容差内且远小于容差(XMOD/GQ 实测中位数在 1um 量级)。 如果 max 贴着容差上限,多半是平移标定被拉偏了 —— 先查两侧过孔数是否相等。 - 两侧过孔数不同 → 质心标定必然偏。先查是导入丢了过孔,还是 Altium 侧 `obj_query` 漏了层,别硬比。 - 某一层大面积 unmatched,而其它层是 0 → 十有八九是 `layer_map.json` 配错了。