PM_K-1 hardware: reproducible EDA container (KiCad 9 + ngspice)

Pinned toolchain under hardware/eda/ so the design can be checked/simulated
identically in the future (system KiCad is 7.0, which has no CLI ERC):
- Containerfile: Ubuntu 24.04 + KiCad 9 (PPA) + ngspice + python3.
- run.sh: build-if-needed + run with the repo mounted; lands in hardware/kicad.
- sim/input_loading.cir: ngspice deck proving the line(25k) vs instrument(1M)
  input-loading decision — Hi-Z preserves a +16dB pickup resonance the 25k load
  flattens to -3dB.

Verified: KiCad 9.0.9, ngspice-42, ERC runs clean (0 violations) on
pm_k1_core.kicad_sch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Me Here 2026-05-30 19:17:54 -05:00
parent 87caa933ea
commit bcfa5dd7f0
6 changed files with 138 additions and 0 deletions

View file

@ -0,0 +1,28 @@
# Reproducible EDA toolchain for the PM_K-1 core board.
#
# Why this exists: the system KiCad is 7.0 (no CLI ERC). This pins a known,
# rebuildable environment so the design can be checked/simulated identically
# years from now — fitting for a device meant to outlive its tools.
#
# KiCad 9 -> schematic capture, CLI ERC/DRC, netlist/PDF/Gerber export
# ngspice -> SPICE simulation of the analog audio circuits
# python3 -> scripting / BOM / skidl-style helpers
#
# Build/run via ../eda/run.sh (or: podman build -t pmk1-eda:9.0 .)
FROM docker.io/library/ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN apt-get update && apt-get install -y --no-install-recommends \
software-properties-common ca-certificates gnupg && \
add-apt-repository -y ppa:kicad/kicad-9.0-releases && \
apt-get update && apt-get install -y --no-install-recommends \
kicad \
ngspice \
python3 python3-pip python3-venv \
git make && \
apt-get clean && rm -rf /var/lib/apt/lists/*
WORKDIR /work
CMD ["bash"]

36
hardware/eda/README.md Normal file
View file

@ -0,0 +1,36 @@
# PM_K-1 EDA environment
A reproducible container with the tools to design, check, and simulate the core board —
so the work doesn't depend on whatever happens to be installed on a given machine, now or
in 50 years.
## What's inside
- **KiCad 9** — schematic capture + PCB layout, and a CLI (`kicad-cli`) that can run
**ERC** (Electrical Rules Check) and DRC, and export netlists/PDF/Gerbers.
- **ngspice** — SPICE simulator for validating the analog audio circuits before we commit
copper (op-amp stages, filters, input loading, etc.).
- **python3** — scripting, BOM munging, optional code-defined-schematic helpers.
## Why a container?
The system KiCad here is 7.0, whose CLI can't run ERC (that arrived in KiCad 8). Rather than
fight the host, we pin a known toolchain. Anyone — including future-you — rebuilds the exact
environment with one command.
## Use it
```bash
cd hardware/eda
./run.sh # interactive shell, lands in hardware/kicad/
./run.sh kicad-cli version # confirm KiCad 9
./run.sh kicad-cli sch erc pm_k1_core.kicad_sch # run ERC on the schematic
./run.sh ngspice -b ../eda/sim/input_loading.cir # run a simulation (cwd is kicad/)
```
`run.sh` builds the image on first use, then mounts the whole repo at `/work` (so KiCad sees
`hardware/`). Use `RUNTIME=docker ./run.sh …` to use Docker instead of Podman.
## Layout
```
eda/
Containerfile # the pinned toolchain (KiCad 9 + ngspice + python)
run.sh # build-if-needed + run with the repo mounted
sim/ # ngspice decks (SPICE simulations of the analog circuits)
```

24
hardware/eda/run.sh Executable file
View file

@ -0,0 +1,24 @@
#!/usr/bin/env bash
# Build (first time) and run the PM_K-1 EDA container with the repo mounted.
#
# ./run.sh # interactive shell in hardware/kicad/
# ./run.sh kicad-cli sch erc pm_k1_core.kicad_sch
# ./run.sh ngspice -b sim/some.cir
#
# Override the runtime with RUNTIME=docker ./run.sh ...
set -euo pipefail
IMG="pmk1-eda:9.0"
EDA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # hardware/eda
REPO_DIR="$(cd "$EDA_DIR/../.." && pwd)" # repo root
RUNTIME="${RUNTIME:-podman}"
if ! "$RUNTIME" image inspect "$IMG" >/dev/null 2>&1; then
echo ">> building $IMG (first run, a few minutes)…" >&2
"$RUNTIME" build -t "$IMG" "$EDA_DIR"
fi
# Mount the whole repo so KiCad/ngspice see hardware/ ; land in hardware/kicad.
flags=(--rm -v "$REPO_DIR":/work:Z -w /work/hardware/kicad)
[[ -t 0 && $# -eq 0 ]] && flags+=(-it)
exec "$RUNTIME" run "${flags[@]}" "$IMG" "${@:-bash}"

1
hardware/eda/sim/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.csv

View file

@ -0,0 +1,47 @@
* PM_K-1 : input loading -- line receiver (25k) vs Hi-Z instrument buffer (1M)
*
* This is the circuit-level proof of a decision we made by hand: why a guitar/bass
* needs a HIGH-impedance input. A passive pickup is inductive, so the load impedance
* it sees shapes its tone. Plug it into a low impedance and you damp its resonance
* and lose treble + level; a high-Z buffer preserves it.
*
* Pickup model: open-circuit source + winding resistance + inductance + self-capacitance.
* Plus a typical ~300 pF guitar cable. We drive two identical pickup+cable networks
* from one ideal source and load them differently, then compare.
*
* Run: ngspice -b sim/input_loading.cir (from inside the EDA container)
.title PM_K-1 input loading: line 25k vs instrument 1M
Vpu src 0 AC 1
* --- Branch A: LINE input, ~25k receiver impedance ---
RdcA src a1 6k
LpuA a1 a2 3
CpuA a2 0 150p
CcabA a2 0 300p
RinA a2 0 25k
* --- Branch B: INSTRUMENT input, 1M Hi-Z buffer ---
RdcB src b1 6k
LpuB b1 b2 3
CpuB b2 0 150p
CcabB b2 0 300p
RinB b2 0 1meg
.ac dec 100 10 100k
.control
run
meas ac a_1k find vdb(a2) at=1000
meas ac b_1k find vdb(b2) at=1000
meas ac a_peak max vdb(a2) from=1000 to=20000
meas ac b_peak max vdb(b2) from=1000 to=20000
echo
echo " Level @1kHz : line(25k)= $&a_1k dB inst(1M)= $&b_1k dB"
echo " Resonant peak : line(25k)= $&a_peak dB inst(1M)= $&b_peak dB"
echo " -> the 25k load drags the signal down and flattens the pickup's natural peak;"
echo " the 1M input preserves level and tone. Hence the switchable Hi-Z front end."
wrdata ../eda/sim/input_loading.csv vdb(a2) vdb(b2)
.endc
.end

View file

@ -1,6 +1,8 @@
# KiCad generated/derived outputs
*.pdf
*.net
*.svg
*.rpt
*-bak
*.kicad_prl
fp-info-cache