diff --git a/hardware/eda/Containerfile b/hardware/eda/Containerfile index fa58eb3..15d4933 100644 --- a/hardware/eda/Containerfile +++ b/hardware/eda/Containerfile @@ -19,10 +19,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ add-apt-repository -y ppa:kicad/kicad-9.0-releases && \ apt-get update && apt-get install -y --no-install-recommends \ kicad \ + kicad-symbols \ + kicad-footprints \ ngspice \ python3 python3-pip python3-venv \ git make && \ - apt-get clean && rm -rf /var/lib/apt/lists/* + apt-get clean && rm -rf /var/lib/apt/lists/* && \ + pip3 install --no-cache-dir --break-system-packages skidl WORKDIR /work CMD ["bash"] diff --git a/hardware/eda/sim/stage1_cmrr.cir b/hardware/eda/sim/stage1_cmrr.cir new file mode 100644 index 0000000..f0c8913 --- /dev/null +++ b/hardware/eda/sim/stage1_cmrr.cir @@ -0,0 +1,56 @@ +* PM_K-1 Stage 1 : balanced line receiver -- why CMRR needs matched resistors +* +* A balanced receiver rejects "common-mode" noise -- hum/interference that appears +* equally on both signal wires -- by SUBTRACTING the two wires. How well it cancels +* (its Common-Mode Rejection Ratio, CMRR) depends entirely on how well its four +* resistors match. This is the circuit-level reason we chose the laser-trimmed +* THAT1240 instead of a discrete op-amp + four 1% resistors. +* +* Three identical unity-gain difference amplifiers, driven common-mode (same 1V on +* both inputs), with 0% / 0.1% / 1% mismatch on one resistor. +* CMRR(dB) = -20*log10(|Vout|) since differential gain = 1 and Vcm = 1V. +* +* Run: ngspice -b ../eda/sim/stage1_cmrr.cir + +.title Stage1 line receiver CMRR vs resistor match + +Vcm cm 0 AC 1 ; common-mode drive: both inputs tied to cm + +* ---- A: perfectly matched ---- +EA outa 0 vpa vma 1e6 +R1a cm vma 10k +R2a outa vma 10k +R3a cm vpa 10k +R4a vpa 0 10k + +* ---- B: 0.1% mismatch on one resistor ---- +EB outb 0 vpb vmb 1e6 +R1b cm vmb 10k +R2b outb vmb 10k +R3b cm vpb 10k +R4b vpb 0 10.01k + +* ---- C: 1% mismatch on one resistor ---- +EC outc 0 vpc vmc 1e6 +R1c cm vmc 10k +R2c outc vmc 10k +R3c cm vpc 10k +R4c vpc 0 10.1k + +.ac dec 10 100 10k +.control +run +meas ac acm_a find vm(outa) at=1000 +meas ac acm_b find vm(outb) at=1000 +meas ac acm_c find vm(outc) at=1000 +let cmrr_a = -20*log10(acm_a) +let cmrr_b = -20*log10(acm_b) +let cmrr_c = -20*log10(acm_c) +echo +echo " CMRR perfect match : $&cmrr_a dB (limited only by the amplifier)" +echo " CMRR 0.1% mismatch : $&cmrr_b dB" +echo " CMRR 1% mismatch : $&cmrr_c dB" +echo " -> hand-matched 1% resistors give poor rejection; the THAT1240's" +echo " laser-trimmed internal resistors are how we get >90 dB for free." +.endc +.end diff --git a/hardware/eda/sim/stage1_phantom.cir b/hardware/eda/sim/stage1_phantom.cir new file mode 100644 index 0000000..6e20714 --- /dev/null +++ b/hardware/eda/sim/stage1_phantom.cir @@ -0,0 +1,39 @@ +* PM_K-1 Stage 1 : input protection -- a +48V phantom-power step at the jack +* +* "Phantom power" is +48V DC that mixers put on their MIC inputs. If it ever reaches +* our input (miswire, wrong cable, our OUT plugged into a phantom'd input), a bare +* op-amp input would die. Our protection makes it a non-event: +* - a series DC-BLOCKING film cap passes audio (AC) but blocks the +48V (DC), +* - a series resistor + clamp diodes to the +/-15V rails survive the turn-on EDGE +* (the cap passes the fast step before it charges). +* +* We hit the input with a +48V step at t=1ms and watch the OP-AMP INPUT node. +* +* Run: ngspice -b ../eda/sim/stage1_phantom.cir + +.title Stage1 phantom protection + +Vin in 0 PWL(0 0 1m 0 1.001m 48 5 48) ; +48V appears at t=1ms, stays + +C1 in a 1u ; DC-blocking film cap (audio passes, DC blocked) +Rs a n 1k ; series current limit +Rb n 0 1meg ; bias / input impedance (audio high-pass corner ~0.16 Hz) + +.model Dclamp D(Is=1e-14 N=1 Rs=10) +Dp n vp Dclamp ; clamp to +15 +Dn vn n Dclamp ; clamp to -15 +Vp vp 0 15 +Vn vn 0 -15 + +.tran 2m 5 +.control +run +meas tran vn_peak max v(n) from=1m to=5 +meas tran vn_final find v(n) at=4.9 +echo +echo " op-amp input PEAK during the +48V step : $&vn_peak V (clamped near a +/-15 rail)" +echo " op-amp input STEADY-STATE : $&vn_final V (DC blocked by the cap)" +echo " -> +48V at the jack becomes a clamped blip that decays to ~0. Nothing is harmed;" +echo " a wrong patch only ever sounds wrong. (Audio passes -- the high-pass is ~0.16 Hz.)" +.endc +.end diff --git a/hardware/kicad/skidl_REPL.erc b/hardware/kicad/skidl_REPL.erc new file mode 100644 index 0000000..e69de29 diff --git a/hardware/kicad/skidl_REPL.log b/hardware/kicad/skidl_REPL.log new file mode 100644 index 0000000..f3ccbc7 --- /dev/null +++ b/hardware/kicad/skidl_REPL.log @@ -0,0 +1,9 @@ +WARNING: KICAD8_SYMBOL_DIR environment variable is missing, so the default KiCad symbol libraries won't be searched. @ [/work/hardware/kicad/:995=>/work/hardware/kicad/:488] +WARNING: KICAD6_SYMBOL_DIR environment variable is missing, so the default KiCad symbol libraries won't be searched. @ [/work/hardware/kicad/:995=>/work/hardware/kicad/:488] +WARNING: KICAD9_SYMBOL_DIR environment variable is missing, so the default KiCad symbol libraries won't be searched. @ [/work/hardware/kicad/:995=>/work/hardware/kicad/:488] +WARNING: KICAD_SYMBOL_DIR environment variable is missing, so the default KiCad symbol libraries won't be searched. @ [/work/hardware/kicad/:995=>/work/hardware/kicad/:488] +WARNING: KICAD7_SYMBOL_DIR environment variable is missing, so the default KiCad symbol libraries won't be searched. @ [/work/hardware/kicad/:995=>/work/hardware/kicad/:488] +WARNING: fp-lib-table file was not found. Component footprints are not available. +WARNING: fp-lib-table file was not found. Component footprints are not available. +WARNING: fp-lib-table file was not found. Component footprints are not available. +WARNING: fp-lib-table file was not found. Component footprints are not available.