diff --git a/hardware/eda/Containerfile b/hardware/eda/Containerfile index 0559bf4..0545c6f 100644 --- a/hardware/eda/Containerfile +++ b/hardware/eda/Containerfile @@ -32,6 +32,10 @@ RUN apt-get update && apt-get install -y --no-install-recommends nodejs npm && \ npm install -g netlistsvg && \ npm cache clean --force && apt-get clean && rm -rf /var/lib/apt/lists/* +# gnuplot: render ngspice simulation results as PNG plots +RUN apt-get update && apt-get install -y --no-install-recommends gnuplot-nox && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + # Point SKiDL / KiCad CLI at the installed libraries (reproducible, not ad-hoc). ENV KICAD9_SYMBOL_DIR=/usr/share/kicad/symbols \ KICAD9_FOOTPRINT_DIR=/usr/share/kicad/footprints \ diff --git a/hardware/eda/sim/plots.gp b/hardware/eda/sim/plots.gp new file mode 100644 index 0000000..4ee6722 --- /dev/null +++ b/hardware/eda/sim/plots.gp @@ -0,0 +1,39 @@ +# Render the PM_K-1 ngspice simulation data to PNG plots. +# Run inside the container AFTER the sims have written their .data files: +# ./run.sh bash -lc 'cd /work/hardware/kicad; for s in ...; do ngspice -b ../eda/sim/$s.cir; done; gnuplot /work/hardware/eda/sim/plots.gp' +set terminal pngcairo size 1000,560 font "Sans,11" +set grid +set key box +P = "/work/hardware/eda/sim/plots/" + +set logscale x +set xlabel "Frequency (Hz)" + +set output P."input_loading.png" +set title "Input loading: line (25k) vs instrument (1M) input -- why Hi-Z preserves the pickup" +set ylabel "Level (dB)" +plot "/work/hardware/eda/sim/input_loading.csv" u 1:2 w l lw 2 t "line input (25k ohm)", \ + "" u 3:4 w l lw 2 t "instrument input (1M ohm)" + +set output P."stage1_cmrr.png" +set title "Stage 1 receiver: common-mode leakage vs resistor match (lower = better; perfect match ~ -inf, off scale)" +set ylabel "Output leakage (dB, Vcm = 1V)" +plot P."stage1_cmrr.data" u 1:2 w l lw 2 t "0.1% mismatch", \ + "" u 3:4 w l lw 2 t "1% mismatch" + +set output P."stage2_recon.png" +set title "Stage 2 DAC reconstruction filter -- flat to 20 kHz, -3 dB near 75 kHz" +set ylabel "Gain (dB)" +plot P."stage2_recon.data" u 1:2 w l lw 2 t "filter response" + +set output P."stage4_driver.png" +set title "Stage 4 balanced output -- differential response (flat across the audio band)" +set ylabel "Differential gain (dB)" +plot P."stage4_driver.data" u 1:2 w l lw 2 t "hot - cold differential" + +unset logscale x +set output P."stage1_phantom.png" +set title "Stage 1 protection: +48V phantom hit at the op-amp input -- clamped, then decays to ~0" +set xlabel "Time (s)" +set ylabel "Op-amp input (V)" +plot P."stage1_phantom.data" u 1:2 w l lw 2 t "V(op-amp input)" diff --git a/hardware/eda/sim/plots/.gitignore b/hardware/eda/sim/plots/.gitignore new file mode 100644 index 0000000..f9e8176 --- /dev/null +++ b/hardware/eda/sim/plots/.gitignore @@ -0,0 +1 @@ +*.data diff --git a/hardware/eda/sim/plots/input_loading.png b/hardware/eda/sim/plots/input_loading.png new file mode 100644 index 0000000..eaff010 Binary files /dev/null and b/hardware/eda/sim/plots/input_loading.png differ diff --git a/hardware/eda/sim/plots/stage1_cmrr.png b/hardware/eda/sim/plots/stage1_cmrr.png new file mode 100644 index 0000000..4ba7495 Binary files /dev/null and b/hardware/eda/sim/plots/stage1_cmrr.png differ diff --git a/hardware/eda/sim/plots/stage1_phantom.png b/hardware/eda/sim/plots/stage1_phantom.png new file mode 100644 index 0000000..e46f279 Binary files /dev/null and b/hardware/eda/sim/plots/stage1_phantom.png differ diff --git a/hardware/eda/sim/plots/stage2_recon.png b/hardware/eda/sim/plots/stage2_recon.png new file mode 100644 index 0000000..ec43bf2 Binary files /dev/null and b/hardware/eda/sim/plots/stage2_recon.png differ diff --git a/hardware/eda/sim/plots/stage4_driver.png b/hardware/eda/sim/plots/stage4_driver.png new file mode 100644 index 0000000..103df92 Binary files /dev/null and b/hardware/eda/sim/plots/stage4_driver.png differ diff --git a/hardware/eda/sim/stage1_cmrr.cir b/hardware/eda/sim/stage1_cmrr.cir index f0c8913..45cabda 100644 --- a/hardware/eda/sim/stage1_cmrr.cir +++ b/hardware/eda/sim/stage1_cmrr.cir @@ -52,5 +52,6 @@ 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." +wrdata ../eda/sim/plots/stage1_cmrr.data vdb(outb) vdb(outc) .endc .end diff --git a/hardware/eda/sim/stage1_phantom.cir b/hardware/eda/sim/stage1_phantom.cir index 6e20714..2fb4e96 100644 --- a/hardware/eda/sim/stage1_phantom.cir +++ b/hardware/eda/sim/stage1_phantom.cir @@ -35,5 +35,6 @@ echo " op-amp input PEAK during the +48V step : $&vn_peak V (clamped near a + 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.)" +wrdata ../eda/sim/plots/stage1_phantom.data v(n) .endc .end diff --git a/hardware/eda/sim/stage2_recon.cir b/hardware/eda/sim/stage2_recon.cir index 1f206dc..efd1f00 100644 --- a/hardware/eda/sim/stage2_recon.cir +++ b/hardware/eda/sim/stage2_recon.cir @@ -31,5 +31,6 @@ echo echo " passband @1kHz : $&g_1k dB" echo " @20kHz (audio edge) : $&g_20k dB (want ~0 dB = flat)" echo " -3dB corner : $&f_3db Hz (well above audio; attenuates DAC HF residue)" +wrdata ../eda/sim/plots/stage2_recon.data vdb(out) .endc .end diff --git a/hardware/eda/sim/stage4_driver.cir b/hardware/eda/sim/stage4_driver.cir index 22dd16f..c5dd874 100644 --- a/hardware/eda/sim/stage4_driver.cir +++ b/hardware/eda/sim/stage4_driver.cir @@ -34,5 +34,6 @@ echo echo " differential @1kHz : $&d_1k dB @20kHz : $&d_20k dB (flat across audio)" echo " hot phase: $&ph_hot rad ; cold phase: $&ph_cold rad (~pi rad = 180 deg apart = balanced/antiphase)" echo " differential @1MHz : $&d_1meg dB (build-out+cable rolloff stays above audio)" +wrdata ../eda/sim/plots/stage4_driver.data vddb .endc .end