this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add SC/RL SPICE netlists and parameterised SPICE test helper

sim/tline-sc.sp — short circuit (Vsc B GND 0, ΓL=−1)
sim/tline-rl.sp — resistive load (RL=100Ω param, ΓL=+1/3)
sim/run.sh — runs all *.sp files from sim/ directory

physics.test.js: replace one-off OC test with spiceCompare() helper that
- reads from sim/<tsvFile>
- skips with a clear message if the TSV hasn't been generated yet
- is called for OC, SC, and RL in one line each

To activate the new tests: cd sim && sh run.sh

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

+82 -32
+41 -32
physics.test.js
··· 4 4 5 5 const { test } = require("node:test"); 6 6 const assert = require("node:assert/strict"); 7 - const { readFileSync } = require("node:fs"); 7 + const { readFileSync, existsSync } = require("node:fs"); 8 8 const path = require("path"); 9 9 10 10 // utils.js calls window.devicePixelRatio inside getDPR(); stub it so the IIFE ··· 235 235 }); 236 236 237 237 // ──────────────────────────────────────────────────────────────────────────── 238 - // SPICE golden-reference comparison 239 - // 240 - // Netlist: tline-oc.sp 241 - // Rs1=10Ω, Z0=50Ω (L=50nH/m C=20pF/m len=1m → τ_d=1ns), RL=∞, Vg=1V 242 - // PULSE( 0 1 0 100p 100p 1u 2u ) → linear ramp, TR = 100ps = 0.1·τ_d 243 - // 244 - // TSV columns: t[s] v(a) t[s] v(b) 245 - // ──────────────────────────────────────────────────────────────────────────── 246 - 247 - // ──────────────────────────────────────────────────────────────────────────── 248 238 // totalVoltageAt: no spike at segment boundaries (multi-segment plotting bug) 249 239 // 250 240 // In smooth mode, drawSampledWave evaluates totalVoltageAt at exact boundary ··· 306 296 307 297 // ──────────────────────────────────────────────────────────────────────────── 308 298 309 - test("SPICE comparison: linear ramp, open-circuit load (tline-oc.sp)", () => { 310 - const TAU_D = 1e-9; // one-way delay in seconds 311 - const TR_NORM = 0.1; // rise time normalised to τ_d (100 ps / 1 ns) 299 + // ──────────────────────────────────────────────────────────────────────────── 300 + // SPICE golden-reference comparisons 301 + // 302 + // Common circuit (all netlists in sim/): 303 + // Z0=50Ω (LTRA l=50nH/m c=20pF/m len=1m → τ_d=1ns) 304 + // Rg=10Ω (Rs1), Vg=1V PULSE(0 1 0 100p 100p 1u 2u) → TR=100ps=0.1·τ_d 305 + // 306 + // TSV columns: t[s] v(a) t[s] v(b) 307 + // Run simulations: cd sim && sh run.sh (or ngspice <netlist>.sp individually) 308 + // ──────────────────────────────────────────────────────────────────────────── 312 309 313 - const model = { Vg: 1, Rg: 10, RL: Infinity, segments: [{ Z0: 50 }], reflectTol: 0.001 }; 314 - const waves = computeWaveParams(model); 315 - const bounce = buildBounceSeries(model, waves); 310 + // Compare every row of a SPICE TSV against the physics model. 311 + // Skips automatically if the TSV has not been generated yet. 312 + function spiceCompare(label, tsvFile, RL, TOL = 1e-4) { 313 + const TAU_D = 1e-9; 314 + const TR_NORM = 0.1; 315 + const tsvPath = path.join(__dirname, "sim", tsvFile); 316 + const skip = !existsSync(tsvPath); 316 317 317 - // Parse TSV produced by ngspice "wrdata results-tline-oc.tsv v(a) v(b)" 318 - const tsv = readFileSync(path.join(__dirname, "results-tline-oc.tsv"), "utf8"); 319 - const rows = tsv.trim().split("\n") 320 - .map((line) => line.trim().split(/\s+/).map(Number)) 321 - .filter((cols) => cols.length >= 4); 318 + test(`SPICE comparison: ${label}`, { skip: skip ? "TSV not found — run: cd sim && ngspice" : false }, () => { 319 + const model = { Vg: 1, Rg: 10, RL, segments: [{ Z0: 50 }], reflectTol: 0.001 }; 320 + const waves = computeWaveParams(model); 321 + const bounce = buildBounceSeries(model, waves); 322 322 323 - assert.ok(rows.length > 10, "TSV should have many rows"); 323 + const rows = readFileSync(tsvPath, "utf8").trim().split("\n") 324 + .map((line) => line.trim().split(/\s+/).map(Number)) 325 + .filter((cols) => cols.length >= 4); 326 + assert.ok(rows.length > 10, "TSV should have many rows"); 324 327 325 - const TOL = 1e-4; // 0.1 mV — well above floating-point noise, well below any physics error 328 + for (const [t_s, va_spice, , vb_spice] of rows) { 329 + const tn = t_s / TAU_D; 330 + const va_model = sumEventsWithLinearRamp(bounce.srcEvents, tn, TR_NORM); 331 + const vb_model = sumEventsWithLinearRamp(bounce.loadEvents, tn, TR_NORM); 332 + near(va_model, va_spice, `v(a) at t=${t_s.toExponential(3)}s`, TOL); 333 + near(vb_model, vb_spice, `v(b) at t=${t_s.toExponential(3)}s`, TOL); 334 + } 335 + }); 336 + } 326 337 327 - for (const [t_s, va_spice, , vb_spice] of rows) { 328 - const tn = t_s / TAU_D; 329 - const va_model = sumEventsWithLinearRamp(bounce.srcEvents, tn, TR_NORM); 330 - const vb_model = sumEventsWithLinearRamp(bounce.loadEvents, tn, TR_NORM); 331 - near(va_model, va_spice, `v(a) at t=${t_s.toExponential(3)}s`, TOL); 332 - near(vb_model, vb_spice, `v(b) at t=${t_s.toExponential(3)}s`, TOL); 333 - } 334 - }); 338 + // RL=∞ (open circuit) ΓL=+1, ΓS=−2/3 339 + spiceCompare("open circuit (tline-oc.sp)", "results-tline-oc.tsv", Infinity); 340 + // RL=0 (short circuit) ΓL=−1, ΓS=−2/3 341 + spiceCompare("short circuit (tline-sc.sp)", "results-tline-sc.tsv", 0); 342 + // RL=100 (resistive load) ΓL=+1/3, ΓS=−2/3 343 + spiceCompare("resistive load 100Ω (tline-rl.sp)", "results-tline-rl.tsv", 100);
+9
sim/run.sh
··· 1 + #!/bin/sh 2 + # Run all SPICE netlists in this directory. 3 + # Results are written here too (wrdata uses relative paths). 4 + # Usage: cd sim && sh run.sh 5 + cd "$(dirname "$0")" 6 + for sp in *.sp; do 7 + echo "--- $sp ---" 8 + ngspice "$sp" 9 + done
+17
sim/tline-rl.sp
··· 1 + .title T-line, resistive load 2 + * Load impedance. Edit this value to generate different test cases. 3 + .param RL = 100 4 + .model __T2 LTRA( r=0 l=5e-08 g=0 c=2e-11 len=1 ) 5 + .save all 6 + .probe alli 7 + .tran 100p 30n 8 + OT2 A GND B GND __T2 9 + Rs1 S A 10 10 + RL1 B GND {RL} 11 + V1 S GND PULSE( 0 1 0 100p 100p 1u 2u ) 12 + 13 + .control 14 + run 15 + wrdata results-tline-rl.tsv v(a) v(b) 16 + .endc 17 + .end
+15
sim/tline-sc.sp
··· 1 + .title T-line, short circuit 2 + .model __T2 LTRA( r=0 l=5e-08 g=0 c=2e-11 len=1 ) 3 + .save all 4 + .probe alli 5 + .tran 100p 30n 6 + OT2 A GND B GND __T2 7 + Rs1 S A 10 8 + Vsc B GND 0 9 + V1 S GND PULSE( 0 1 0 100p 100p 1u 2u ) 10 + 11 + .control 12 + run 13 + wrdata results-tline-sc.tsv v(a) v(b) 14 + .endc 15 + .end