# Altium Scripts **Convention:** All Python scripts use **.env** for input/output paths (and optional settings); you can override any value via **CLI**. All scripts write JSON output to the **`outputs/`** folder by default. Copy `.env.example` to `.env` and edit. --- ## Capacitors by net pair **Script:** `CapacitorsByNetPair.pas` Finds all **two-pad components** on the PCB that share the same two nets (e.g. decoupling capacitors between VCC and GND). Outputs a JSON file with: - **Key:** net pair (e.g. `"GND|VCC"`), sorted so the same pair is always grouped - **Value:** for each net pair: - List of capacitors: designator, value string, package (footprint), and capacitance in farads - **Total capacitance** for that net pair (sum of all caps between those two nets) ### How to run 1. Open your **PcbDoc** in Altium Designer. 2. **DXP → Run Script…** (or **File → Run Script…** depending on version). 3. Browse to `CapacitorsByNetPair.pas` and run it. 4. Choose a save location for the JSON file when prompted. ### JSON output format ```json { "GND|VCC": { "total_capacitance_F": 2.2e-05, "total_capacitance_str": "22uF", "capacitors": [ { "designator": "C1", "value": "10uF", "package": "0805", "capacitance_F": 1e-05 }, { "designator": "C2", "value": "12uF", "package": "0805", "capacitance_F": 1.2e-05 } ] }, "GND|VDD": { "total_capacitance_F": 1e-06, "total_capacitance_str": "1uF", "capacitors": [ { "designator": "C10", "value": "1uF", "package": "0603", "capacitance_F": 1e-06 } ] } } ``` ### Protel PCB 2.8 ASCII — easier (Python, no Altium) **Yes — Protel PCB 2.8 ASCII is easier.** It’s plain text, so you can parse it with Python and no OLE/binary handling. You don’t need Altium running. 1. **Export from Altium:** Open your PcbDoc → **File → Save As** (or **Export**) → choose **PCB 2.8 ASCII** or **Protel PCB ASCII** if your version offers it. Some versions use **File → Save Copy As** with format “PCB Binary/ASCII” or similar. 2. **Run the Python script** on the exported `.pcb` / `.PcbDoc` (ASCII) file: ```bash python3 capacitors_by_net_pair.py board.PcbDoc python3 capacitors_by_net_pair.py board.PcbDoc -o out.json ``` **Input/output from .env:** Copy `.env.example` to `.env` and set `INPUT_FILE` and `OUTPUT_FILE`. The script reads these when the optional `python-dotenv` package is installed; CLI arguments override them. Without `.env`, you can still pass the input file and `-o` on the command line. By default the JSON is written to **`outputs/capacitors_by_net_pair.json`** (the `outputs/` directory is created if needed). See **`capacitors_by_net_pair.py`** for the script. It parses COMP/PATTERN/VALUE and NET/PIN data from the ASCII file and produces the same JSON shape as the DelphiScript. **Test file:** `tests/sample_protel_ascii.pcb` is a minimal Protel PCB 2.8 ASCII sample. Run: ```bash python3 capacitors_by_net_pair.py tests/sample_protel_ascii.pcb -o tests/out.json ``` --- ## Compare component locations (two Protel files) **Script:** `compare_protel_locations.py` Loads two Protel PCB 2.8 ASCII files and reports **which components have moved** between them. Component position is the centroid of pin coordinates. Output is written to `outputs/compare_locations.json` by default. - **Moved:** designators with different (x, y) in file2, with old position, new position, and distance. - **Only in file1 / only in file2:** components that appear in just one file. **Usage:** ```bash python3 compare_protel_locations.py board_v1.pcb board_v2.pcb python3 compare_protel_locations.py board_v1.pcb board_v2.pcb -o outputs/compare_locations.json ``` Use **.env** (optional): set `FILE1`, `FILE2`, and `COMPARE_OUTPUT`; CLI arguments override them. Use `--threshold N` to set the minimum position change to count as moved (default 1.0). **Test:** `tests/sample_protel_ascii.pcb` and `tests/sample_protel_ascii_rev2.pcb` (C1 and C2 moved in rev2): ```bash python3 compare_protel_locations.py tests/sample_protel_ascii.pcb tests/sample_protel_ascii_rev2.pcb ``` --- ## Spreadsheet diff by designator **Script:** `diff_spreadsheets.py` Compares two spreadsheets (`.xlsx` or `.csv`) on a designator column. Data is read **from row 10** by default (first 9 rows skipped). Outputs which designators are only in file1, only in file2, or in both. **Usage:** ```bash pip install pandas openpyxl python3 diff_spreadsheets.py sheet1.xlsx sheet2.xlsx -o outputs/spreadsheet_diff.json ``` Options: `--designator-col 0` (0-based column index), `--start-row 9` (0-based; 9 = row 10). Env: `SHEET1`, `SHEET2`, `DIFF_OUTPUT`. **Test:** `tests/sheet1.csv` and `tests/sheet2.csv` (designators from row 10): ```bash python3 diff_spreadsheets.py tests/sheet1.csv tests/sheet2.csv --start-row 9 ``` --- ## Find bottom termination parts (QFN, DFN, BGA) by description **Script:** `find_bottom_termination_parts.py` Reads the same spreadsheet format (designator column, data from row 10) plus **description** and optionally **package** columns. Finds components whose description or package indicates **bottom termination**, including: - **Package types:** QFN, DFN, BGA, LGA, SON, MLF, MLP, WDFN, WQFN, VQFN, etc. - **Generic:** “bottom termination” (e.g. with 0201 or 0402) Outputs matching designators, description, package, and the matched pattern to `outputs/bottom_termination_parts.json`. **Usage:** ```bash python3 find_bottom_termination_parts.py sheet.xlsx --description-col 1 python3 find_bottom_termination_parts.py sheet.xlsx --description-col 3 ``` Env: `SHEET`, `BOTTOM_TERM_OUTPUT`, `DESCRIPTION_COL` (default 1), `START_ROW` (default 9). No package column; only description is searched. **Test:** `tests/sheet_with_descriptions.csv` (description col 3): ```bash python3 find_bottom_termination_parts.py tests/sheet_with_descriptions.csv --description-col 3 --start-row 9 ``` ### Notes - Only components with **exactly two pads** (each on a net) and **designator starting with `C`** are included (treated as capacitors). To include all two-pad parts, edit the script and remove the `And (UpperCase(Copy(Component.Name.Text, 1, 1)) = 'C')` condition. - Capacitance is parsed from the component **Value** parameter (e.g. `10uF`, `100nF`, `22pF`) and totalled in farads. Supported suffixes: F, mF, uF/µF, nF, pF. - Package is taken from the component’s **Pattern** (footprint) name. - If your Altium version uses different parameter or footprint property names, you may need to adjust the script (e.g. `DM_ComponentParameterName` / `DM_ComponentParameterValue`, or `Pattern` vs `Footprint`).