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:
parent
87caa933ea
commit
bcfa5dd7f0
6 changed files with 138 additions and 0 deletions
28
hardware/eda/Containerfile
Normal file
28
hardware/eda/Containerfile
Normal 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
36
hardware/eda/README.md
Normal 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
24
hardware/eda/run.sh
Executable 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
1
hardware/eda/sim/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
*.csv
|
||||
47
hardware/eda/sim/input_loading.cir
Normal file
47
hardware/eda/sim/input_loading.cir
Normal 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
|
||||
2
hardware/kicad/.gitignore
vendored
2
hardware/kicad/.gitignore
vendored
|
|
@ -1,6 +1,8 @@
|
|||
# KiCad generated/derived outputs
|
||||
*.pdf
|
||||
*.net
|
||||
*.svg
|
||||
*.rpt
|
||||
*-bak
|
||||
*.kicad_prl
|
||||
fp-info-cache
|
||||
|
|
|
|||
Loading…
Reference in a new issue