# Test Catalog — All 47 Tests Every test in [`test/test_circuit/test/`](../../test/test_circuit/test/) enumerated: the circuit under test, what physics it validates, and the numerical expectation. ## Baseline — hand-rolled MNA solver (25 tests) ### `passive.test.js` — 11 tests Tests the linear DC solver on textbook passives. | # | Test | Circuit | Expected | Tolerance | |---|---|---|---|---| | 1 | Voltage divider | 9V → 1k + 2k | V(out) = 6.0 V | 3 decimals | | 2 | Equal-R divider | 5V → 1k + 1k | V(b) = 2.5 V | 3 decimals | | 3 | Ohm's law | 5V, 220Ω | I = 22.7 mA | 5 decimals | | 4 | Three 3kΩ parallel | series with 1k | V(p) = 1.5 V | 3 decimals | | 5 | Current source + R | 1 mA into 2.2kΩ | V = 2.2 V | 3 decimals | | 6 | Pot wiper at 50% | 10k pot, 5V | V = 2.5 V | 2 decimals | | 7 | Pot sweep 0→1 | 5 steps | monotonic increase | ≥ −10 mV slack | | 8 | NTC resistance @ 25°C | β=3950 | R = 10 000 Ω | within 1 Ω | | 9 | NTC temperature monotonicity | T ∈ {0, 25, 50} | R(0) > R(25) > R(50) | textbook ranges | | 10 | NTC + 10k divider | T ∈ {0, 25, 50} | V_A0 matches expected per table | per-point tolerance | | 11 | Switch open/closed | 5V → 1k → switch → GND | open: 4.9–5.0 V, closed: < 50 mV | | ### `transient_rc.test.js` — 3 tests | # | Test | Circuit | Expected | Tolerance | |---|---|---|---|---| | 1 | RC charging @ τ | 10k, 100µF, 5V | V(τ) ≈ 3.16 V | ±5% | | 2 | 5τ settling | 1k, 1µF, 3.3V | V(5τ) > 99% V | hard bound | | 3 | Capacitor discharge | pre-charged 5V → 10k | V(τ) in [1.5, 2.2] V | manual bounds | ### `diodes.test.js` — 7 tests | # | Test | Circuit | Expected | |---|---|---|---| | 1 | Forward diode + 1k + 5V | Shockley default | V_d ∈ [0.55, 0.75] V, I ∈ [4, 5] mA | | 2 | Reverse diode | diode blocks | V_a < 10 mV | | 3 | Red LED + 220Ω + 5V | | V_f ∈ [1.8, 2.3] V, I ∈ [10, 16] mA, brightness > 0.5 | | 4 | Blue LED higher Vf than red | | V_blue > V_red, V_blue ∈ [2.8, 3.6] V | | 5 | LED brightness with supply | V ∈ {2.0, 3.0, 5.0} | monotonic, dim at 2V, bright at 5V | | 6 | BJT switch ON | V_b = 5V, R_b = 10k | V_CE < 0.8 V | | 7 | BJT switch OFF | V_b = 0 | V_CE > 4.9 V | ### `avr_blink.test.js` — 2 tests Uses the real `fixtures/blink.hex` (copied from Velxio's test fixtures). | # | Test | What it validates | |---|---|---| | 1 | Toggles pin 13 | After 2 s of AVR time, observed ≥ 3 edge transitions on D13; both 0 and 1 states visible | | 2 | Drives simulated LED | Pin-13 voltage fed into a `VoltageSource`, 220 Ω + red LED; LED brightness switches between < 1% and > 50% | ### `e2e_pot_pwm_led.test.js` — 1 test Uses `potToPwmProgram()` (hand-assembled: reads A0, writes to OCR0A for PWM on D6). Circuit: `+5V → pot (10k) → A0 / GND` plus `D6 → 220Ω → red LED → GND`. Sweep wiper 0.0 → 0.25 → 0.50 → 0.75 → 1.00: | Wiper | V_A0 | PWM duty | I_LED | Brightness | |---|---|---|---|---| | 0.00 | 0.000 V | 0.0 % | 0.00 mA | 0.000 | | 0.25 | 1.250 V | 24.7 % | 0.00 mA | 0.000 | | 0.50 | 2.500 V | 49.8 % | 3.26 mA | 0.163 | | 0.75 | 3.750 V | 74.9 % | 8.77 mA | 0.439 | | 1.00 | 5.000 V | 100.0 % | 14.38 mA | 0.719 | Assertions: duty at 0% < 5%, duty at 100% > 90%, brightness monotonic, final > 0.5, initial < 0.05. ### `e2e_thermistor.test.js` — 1 test Uses `adcReadProgram()` + NTC + pullup divider. Circuit: `+5V → 10kΩ → A0 → NTC → GND`. Per temperature T ∈ {0, 15, 25, 35, 50} °C: | T_set | V_A0 | ADC raw | R_ntc (true) | R_meas (recovered) | T_meas | |---|---|---|---|---|---| | 0 °C | 3.854 V | 789 | 33 621 Ω | 33 718 Ω | −0.05 °C | | 15 °C | 3.065 V | 627 | 15 837 Ω | 15 833 Ω | 15.01 °C | | 25 °C | 2.500 V | 511 | 10 000 Ω | 9 980 Ω | 25.04 °C | | 35 °C | 1.971 V | 403 | 6 506 Ω | 6 500 Ω | 35.02 °C | | 50 °C | 1.320 V | 270 | 3 588 Ω | 3 586 Ω | 50.02 °C | Assertion: `|T_meas − T_set| < 1 °C` at every point. Achieved: < 0.05 °C. ## ngspice — `spice_*.test.js` (22 tests) ### `ngspice_smoke.test.js` — 1 test The minimal possible smoke test. | # | Test | Netlist | Expected | |---|---|---|---| | 1 | Boot + voltage divider | `V 9 → R 1k → R 2k → GND, .op` | `V(out) = 6.0` | ### `spice_passive.test.js` — 3 tests All run with `.op`: | # | Circuit | Expected | |---|---|---| | 1 | 9V → 1k + 2k | V(out) = 6 V | | 2 | Three 3kΩ parallel + 1k series from 3V | V(p) = 1.5 V | | 3 | 1 mA current source into 2.2kΩ | V(a) = 2.2 V | ### `spice_transient.test.js` — 2 tests | # | Test | `.tran` | Expected | |---|---|---|---| | 1 | RC charging | 10m 3 | V(τ) ≈ 3.16 V, V(5τ) > 90% | | 2 | RLC underdamped oscillation | 10u 30m, R=1Ω, L=10mH, C=10µF | zero-crossings imply f ≈ 503 Hz, ±15 % | ### `spice_ac.test.js` — 2 tests | # | Test | `.ac` | Expected | |---|---|---|---| | 1 | RC low-pass Bode | 20 ppd, 10 Hz – 1 MHz | f₋₃dB ∈ [900, 1100] Hz; low-freq gain ≈ 0 dB; −20 dB/decade rolloff; phase @ cutoff ≈ −45° | | 2 | Parallel-tank RLC bandpass | 30 ppd, 10 Hz – 1 MHz | peak near 5033 Hz (±20%), passive so max gain ≈ 0 dB; 10×f₀ rejection > 15 dB below peak | ### `spice_active.test.js` — 6 tests | # | Test | Analysis | Expected | |---|---|---|---| | 1 | Diode forward (1N4148 model) | `.op` | V_a ∈ [0.55, 0.80] V | | 2 | Bridge rectifier (4 diodes + sine 6V/50Hz) | `.tran 0.1m 40m` | peak output 4.2–5.4 V, always positive | | 3 | Common-emitter amp (2N2222, 12V, ~1kHz input, bypassed R_E) | `.tran 10u 6m` | voltage gain > 30 | | 4 | N-MOS Level-1 switch, V_gate=5V | `.op` | V(drain) < 1.0 V | | 5 | N-MOS Level-1 off, V_gate=0 | `.op` | V(drain) > 4.9 V | | 6 | Op-amp inverting amp (E-source, R_in=1k, R_f=10k) | `.op` | V(out) ≈ −2.0 V | ### `spice_digital.test.js` — 4 tests All gates implemented with B-sources using `u()` step function. | # | Gate | Rows tested | |---|---|---| | 1 | AND | 4 (truth table) | | 2 | NAND | 4 | | 3 | XOR | 4 | | 4 | AND → RC low-pass | `.tran 10u 20m` — verifies filter ripple < 1.5 V, raw AND swings 0–5 V, filtered mean in (0, 5) | ### `spice_555_astable.test.js` — 1 test RC relaxation oscillator built from a Schmitt-switch (S-element with hysteresis). - R = 10 kΩ, C = 10 nF - `SMOD: Vt=2.5, Vh=0.833, Ron=100, Roff=1G` - `.tran 0.5u 2m` Expected: output toggles, ≥ 3 rising edges detected in the steady-state window; measured frequency between 500 Hz and 50 kHz (wide range because behavioral model differs from ideal 555 math). Typical measured: ~7 kHz. ### `spice_avr_mixed.test.js` — 3 tests The flagship mixed-signal demonstrator. #### Test 1 — NTC → ngspice → ADC → sketch For each T ∈ {0, 25, 50} °C: 1. ngspice `.op` solves `10k pullup + R_ntc(T)` 2. `avr.setAnalogVoltage(0, V(a0))` 3. `avr.runCycles(500_000)` runs `adcReadProgram()` 4. Read `ADCH/ADCL` registers directly → reconstruct 10-bit result Expected results match textbook within ±5 LSB: | T | V(a0) from ngspice | ADC raw from avr8js | |---|---|---| | 0 °C | 3.854 V | 789 | | 25 °C | 2.500 V | 512 | | 50 °C | 1.320 V | 270 | #### Test 2 — Sketch → PWM → ngspice RC → filtered DC For V_A0 ∈ {1.0, 2.5, 4.0} V: 1. Run `potToPwmProgram()` with the given analog voltage 2. Read PWM duty (must match `V_A0 / 5` ± 0.05) 3. Feed `duty × 5` as DC source into `R=10k, R_load=10MΩ` in ngspice 4. `.op` gives filtered DC output — should match duty × 5 within 0.1 V Measured: | V_A0 | duty | V_filt | expected | |---|---|---|---| | 1.0 V | 20.0 % | 0.999 V | 1.00 V | | 2.5 V | 50.2 % | 2.507 V | 2.51 V | | 4.0 V | 80.0 % | 3.996 V | 4.00 V | #### Test 3 — Co-simulation loop (AVRSpiceBridge) The bridge runs the AVR in 1 ms slices, re-solving ngspice between each. Pot wiper is moved mid-test. - wiper = 0.25 → 5 slices run → expected ADC ≈ 256 (0.25 × 1023). Measured: **256**. Tolerance ±20 LSB. - wiper moves to 0.75 → 5 more slices → expected ADC ≈ 767. Measured: **768**. Demonstrates that ngspice + avr8js can be cleanly co-simulated quasi-statically. ## Pass/fail history All 47 tests passed as of 2026-04-15. Running `npm test` from `test/test_circuit/` is the canonical verification. Expected wall-clock: ~5 seconds on an i7. Full command output: ``` ✓ test/ngspice_smoke.test.js (1 test) 372ms ✓ test/spice_passive.test.js (3 tests) 358ms ✓ test/spice_transient.test.js (2 tests) 629ms ✓ test/spice_ac.test.js (2 tests) 340ms ✓ test/spice_active.test.js (6 tests) 600ms ✓ test/spice_digital.test.js (4 tests) 420ms ✓ test/spice_555_astable.test.js (1 test) 609ms ✓ test/spice_avr_mixed.test.js (3 tests) 800ms ✓ test/passive.test.js (11 tests) 8ms ✓ test/transient_rc.test.js (3 tests) 22ms ✓ test/diodes.test.js (7 tests) 15ms ✓ test/avr_blink.test.js (2 tests) 2400ms ✓ test/e2e_pot_pwm_led.test.js (1 test) 90ms ✓ test/e2e_thermistor.test.js (1 test) 121ms Test Files 14 passed (14) Tests 47 passed (47) Duration ~5 s ```