357 lines
16 KiB
Markdown
357 lines
16 KiB
Markdown
# Component Catalog
|
||
|
||
Every component validated by at least one test across the two pipelines. "JS API" is the hand-rolled MNA pipeline; "SPICE card" is the ngspice netlist syntax.
|
||
|
||
## Passive
|
||
|
||
### Resistor
|
||
|
||
| | |
|
||
|---|---|
|
||
| JS API | `new Resistor(name, nodeA, nodeB, resistance)` |
|
||
| SPICE card | `Rname a b value` |
|
||
| Parameters | `value` in Ω (use `k`, `Meg`, etc.) |
|
||
| Stamp | Linear, symmetric |
|
||
| Tested in | `passive.test.js`, `spice_passive.test.js` |
|
||
|
||
### Voltage source (DC / PULSE / SIN / PWL / AC)
|
||
|
||
| | |
|
||
|---|---|
|
||
| JS API | `new VoltageSource(name, nodePlus, nodeMinus, voltage)` — DC only |
|
||
| SPICE cards | `V1 + - DC 5` / `V1 + - PULSE(0 5 0 1n 1n 1u 2u)` / `V1 + - SIN(0 1 1k)` / `V1 + - PWL(0 0 1m 5)` / `V1 + - AC 1` |
|
||
| Notes | Adds an extra MNA row. Branch current accessible via `circuit.branchCurrent('V1')`. |
|
||
|
||
### Current source
|
||
|
||
| | |
|
||
|---|---|
|
||
| JS API | `new CurrentSource(name, nodeFrom, nodeTo, current)` |
|
||
| SPICE card | `I1 from to DC 1m` |
|
||
| Convention | Current flows **from** `from` **into** `to` through the source. |
|
||
|
||
### Capacitor
|
||
|
||
| | |
|
||
|---|---|
|
||
| JS API | `new Capacitor(name, a, b, capacitance, initialV = 0)` |
|
||
| SPICE card | `C1 a b 100u IC=0` |
|
||
| Integration | Hand-rolled: backward Euler. ngspice: trapezoidal by default. |
|
||
| Notes | `.ic` or `IC=` sets initial voltage for transient. In DC, cap is open. |
|
||
|
||
### Inductor (ngspice only)
|
||
|
||
| | |
|
||
|---|---|
|
||
| JS API | *(not implemented in the hand-rolled solver)* |
|
||
| SPICE card | `L1 a b 10m IC=0` |
|
||
| Tested in | `spice_transient.test.js` (RLC ringing), `spice_ac.test.js` (LC bandpass) |
|
||
|
||
### Potentiometer (two-resistor model)
|
||
|
||
| | |
|
||
|---|---|
|
||
| JS API | `new Potentiometer(name, topNode, wiperNode, bottomNode, totalR, wiperPos)` |
|
||
| SPICE | Two resistors in series; recompute values from `wiperPos` when user moves wiper |
|
||
| `wiperPos` | 0.0 = wiper at bottom, 1.0 = wiper at top |
|
||
| Tested in | `passive.test.js` (sweep test), `e2e_pot_pwm_led.test.js`, `spice_avr_mixed.test.js` |
|
||
|
||
### NTC thermistor
|
||
|
||
| | |
|
||
|---|---|
|
||
| JS API | `new NTCThermistor(name, a, b, { R0, T0, beta })` — β-model |
|
||
| SPICE | `R` with value computed from temperature: `R(T) = R0 · exp(β · (1/T − 1/T0))` |
|
||
| Defaults | `R0 = 10 000 Ω`, `T0 = 298.15 K` (25 °C), `β = 3950` |
|
||
| Tested in | `passive.test.js`, `e2e_thermistor.test.js`, `spice_avr_mixed.test.js` |
|
||
|
||
### Switch
|
||
|
||
| | |
|
||
|---|---|
|
||
| JS API | `new Switch(name, a, b, closed)` with `set(true|false)` |
|
||
| SPICE card | `S1 a b ctrl 0 SMOD` + `.model SMOD SW(Vt=... Vh=... Ron=... Roff=...)` |
|
||
| Hysteresis | **ngspice switch retains state between `Vt−Vh` and `Vt+Vh`** — essential for latches/oscillators |
|
||
|
||
## Non-linear (diodes)
|
||
|
||
### Shockley diode
|
||
|
||
| | |
|
||
|---|---|
|
||
| JS API | `new Diode(name, anode, cathode, { Is, n, Vclamp })` |
|
||
| SPICE | `D1 a c DMOD` + `.model DMOD D(Is=1e-14 N=1)` |
|
||
| Equation | `I_d = Is · (exp(V_d / (n·Vt)) − 1)` with `Vt ≈ 0.02585 V` @ 300 K |
|
||
| Convergence | `pnjlim` voltage limiting on each Newton iter |
|
||
| Tested in | `diodes.test.js`, `spice_active.test.js` |
|
||
|
||
### LED (colored diode)
|
||
|
||
| | |
|
||
|---|---|
|
||
| JS API | `new LED(name, anode, cathode, color)` where color ∈ { `red`, `green`, `yellow`, `blue`, `white` } |
|
||
| SPICE | `D1 a c LED_RED` with `.model LED_RED D(Is=1e-20 N=1.7)` etc. |
|
||
| Brightness | `I_forward / rated_current`, clipped to [0, 1] |
|
||
| Tuned parameters | Red: `Is=1e-20, n=1.7`; Green: `1e-22, 1.9`; Yellow: `1e-21, 1.8`; Blue/White: `1e-28, 2.0` |
|
||
| Tested in | `diodes.test.js`, `avr_blink.test.js`, `e2e_pot_pwm_led.test.js` |
|
||
|
||
Brightness table at 5 V through 220 Ω:
|
||
|
||
| Color | V_f measured | I_forward | Brightness |
|
||
|---|---|---|---|
|
||
| Red | ~2.0 V | 13.6 mA | 0.68 |
|
||
| Yellow | ~2.1 V | 13.2 mA | 0.66 |
|
||
| Green | ~2.2 V | 12.7 mA | 0.64 |
|
||
| Blue | ~3.1 V | 8.6 mA | 0.43 |
|
||
| White | ~3.1 V | 8.6 mA | 0.43 |
|
||
|
||
### Zener / PN junction with breakdown (ngspice only)
|
||
|
||
| | |
|
||
|---|---|
|
||
| JS API | *(not implemented — Shockley diode only)* |
|
||
| SPICE | `.model D1N4733 D(Is=1e-9 BV=5.1 IBV=10m)` |
|
||
| Use case | Voltage regulation, overvoltage protection |
|
||
|
||
## Non-linear (three-terminal)
|
||
|
||
### NPN BJT
|
||
|
||
| | |
|
||
|---|---|
|
||
| JS API | `new BJT_NPN(name, collector, base, emitter, { Is, betaF, betaR })` — simplified Ebers-Moll |
|
||
| SPICE | `Q1 c b e Q2N2222` + `.model Q2N2222 NPN(Is=1e-14 Bf=200)` |
|
||
| Tested in | `diodes.test.js` (switch mode), `spice_active.test.js` (common-emitter amp) |
|
||
| Limitation (JS model) | Doesn't capture deep saturation; `V_CE,sat` measures ~0.7 V instead of 0.1–0.3 V |
|
||
| Recommendation | For accurate BJT work, use the ngspice pipeline with Gummel-Poon parameters |
|
||
|
||
### MOSFET (ngspice only)
|
||
|
||
| | |
|
||
|---|---|
|
||
| SPICE | `M1 d g s b NMOS_L1 L=1u W=100u` + `.model NMOS_L1 NMOS(Level=1 Vto=1.0 Kp=50u Lambda=0.01)` |
|
||
| Model level | 1 (Shichman-Hodges): `I_d = (Kp · W/L) · ((V_gs − V_th) · V_ds − V_ds²/2)` for linear region |
|
||
| Higher levels | Level 3, BSIM3/4 available in full ngspice; not all compiled into WASM build |
|
||
| Tested in | `spice_active.test.js` (switch ON/OFF) |
|
||
|
||
## Controlled sources (SPICE only)
|
||
|
||
| Card | Type | Example |
|
||
|---|---|---|
|
||
| `Ename plus minus ctrl+ ctrl− gain` | VCVS (ideal op-amp) | `Eopa out 0 inp inm 1e6` |
|
||
| `Gname plus minus ctrl+ ctrl− gm` | VCCS | `Gtc out 0 in 0 1m` |
|
||
| `Hname plus minus Vsense gain` | CCVS | Needs a 0 V source to sense current |
|
||
| `Fname plus minus Vsense gain` | CCCS | |
|
||
|
||
We use VCVS extensively for behavioral op-amp modeling. See `spice_active.test.js` (inverting amplifier) and `spice_555_astable.test.js` (Schmitt via `Bopa` limited to 0..5 V by `limit()`).
|
||
|
||
## Behavioral sources (SPICE only — **key to mixed-signal**)
|
||
|
||
The `B` card computes a voltage (or current) from an arbitrary expression:
|
||
|
||
```spice
|
||
Bname node+ node− V = expression
|
||
Bname node+ node− I = expression
|
||
```
|
||
|
||
Supported functions (non-exhaustive):
|
||
|
||
- Arithmetic: `+ − * / ^` (exponent)
|
||
- Comparisons: `<`, `<=`, `>`, `>=`, `==`, `!=`
|
||
- Logical: `&&`, `||`, `!`
|
||
- Math: `sin`, `cos`, `tan`, `atan`, `asin`, `acos`, `exp`, `log`, `log10`, `sqrt`, `abs`, `min`, `max`
|
||
- Step: `u(x)` — unit step (Heaviside). 1 if x > 0 else 0.
|
||
- Clamp: `limit(x, lo, hi)`
|
||
- Ternary: `a ? b : c`
|
||
- Time: `time` (the current simulation time)
|
||
|
||
Our truth-table-validated gates:
|
||
|
||
| Gate | Expression |
|
||
|---|---|
|
||
| NOT | `5 * (1 - u(V(a) - 2.5))` |
|
||
| AND | `5 * u(V(a)-2.5) * u(V(b)-2.5)` |
|
||
| NAND | `5 * (1 - u(V(a)-2.5) * u(V(b)-2.5))` |
|
||
| OR | `5 * (1 - (1-u(V(a)-2.5)) * (1-u(V(b)-2.5)))` |
|
||
| NOR | `5 * (1-u(V(a)-2.5)) * (1-u(V(b)-2.5))` |
|
||
| XOR | `5 * (u(V(a)-2.5) + u(V(b)-2.5) - 2*u(V(a)-2.5)*u(V(b)-2.5))` |
|
||
|
||
For flip-flops / latches, pair the above with a voltage-controlled switch (`S-element`) that has hysteresis; the switch supplies the memory.
|
||
|
||
## Sensor surrogates
|
||
|
||
| Sensor | Modeling approach |
|
||
|---|---|
|
||
| NTC temperature | `NTCThermistor` (β-model) — parameterized by host code from UI |
|
||
| Photoresistor / LDR | Resistor with `R(lux) = R_dark / (1 + k·lux)` — user/UI sets resistance |
|
||
| Pushbutton | `Switch` toggled between open/closed |
|
||
| Potentiometer | `Potentiometer` with UI-driven `wiperPos` |
|
||
| Microphone / piezo | `CurrentSource` or `VoltageSource` with PWL waveform |
|
||
| Encoder / quadrature | Two digital pins toggled by UI logic (outside the SPICE solver) |
|
||
|
||
## Integrated circuits (not yet modeled)
|
||
|
||
For the Velxio integration, these will need either ngspice `.subckt` macromodels (many available in vendor-provided SPICE libraries) or behavioral B-source blocks:
|
||
|
||
- 555 timer — vendor .subckt or our relaxation-osc behavioral model
|
||
- Shift registers (74HC595) — behavioral gate network, clocked switches
|
||
- H-bridges (L293D, DRV8833) — 4 MOSFETs or 4 switches
|
||
- Optocouplers (4N25, PC817) — BJT + LED pair in one package
|
||
- 74HC logic families (74HC00/04/08/14/32) — gate networks in 14-pin packages
|
||
- ADCs / DACs — behavioral `u()` thresholds or `limit()` scaled
|
||
|
||
## Fase 9 — catalog expansion (implemented)
|
||
|
||
The following mappers were added during fase 9 (commit fase 9.0–9.5) and are live in `frontend/src/simulation/spice/componentToSpice.ts`. The `MAPPERS` table now has 58 entries (up from 25) and `components-metadata.json` has 92 parts (up from 48). Every new component is accessible from the picker UI.
|
||
|
||
### Fase 9.1 — Logic gates (behavioral B-sources)
|
||
|
||
Every gate uses an ngspice B-source with `u()` unit-step functions and a 1 MΩ pull-down on the output (to give the node a DC path and prevent "matrix singular" errors).
|
||
|
||
| metadataId | Inputs | Output expression |
|
||
|---|---|---|
|
||
| `logic-gate-and` | A, B | `Vcc · u(V(A)−T) · u(V(B)−T)` |
|
||
| `logic-gate-or` | A, B | `Vcc · (1 − (1−u(V(A)−T))·(1−u(V(B)−T)))` |
|
||
| `logic-gate-nand` | A, B | `Vcc · (1 − u(V(A)−T)·u(V(B)−T))` |
|
||
| `logic-gate-nor` | A, B | `Vcc · (1−u(V(A)−T)) · (1−u(V(B)−T))` |
|
||
| `logic-gate-xor` | A, B | `Vcc · (u(V(A)−T) + u(V(B)−T) − 2·u(V(A)−T)·u(V(B)−T))` |
|
||
| `logic-gate-xnor` | A, B | `Vcc · (1 − XOR)` |
|
||
| `logic-gate-not` | A | `Vcc · (1 − u(V(A)−T))` |
|
||
|
||
Threshold `T = Vcc/2`. Multi-input variants (AND-3/4, OR-3/4, NAND-3/4, NOR-3/4) extend the product/sum to more terms.
|
||
|
||
### Fase 9.2 — Transistors (discrete real parts)
|
||
|
||
NMOS and PMOS use **Level=1** Shichman-Hodges with numerically sane W/L — the previous Level=3 with `W=0.1` (= 100 mm!) caused ngspice to hang. See [`circuit-emulation-gotchas.md`](circuit-emulation-gotchas.md#mosfet-convergence).
|
||
|
||
| metadataId | Polarity | Package | Typical use |
|
||
|---|---|---|---|
|
||
| `bjt-2n2222` | NPN | TO-92 | General purpose switching |
|
||
| `bjt-bc547` | NPN | TO-92 | Small-signal, hFE ~400 |
|
||
| `bjt-2n3055` | NPN | TO-3 | Power (15 A / 60 V / 115 W) |
|
||
| `bjt-2n3906` | PNP | TO-92 | General purpose (2N3904 complement) |
|
||
| `bjt-bc557` | PNP | TO-92 | Small-signal (BC547 complement) |
|
||
| `mosfet-2n7000` | NMOS | TO-92 | Logic-level (V_th ≈ 1.6 V) |
|
||
| `mosfet-irf540` | NMOS | TO-220 | Power (33 A / 100 V, V_th ≈ 3 V) |
|
||
| `mosfet-irf9540` | PMOS | TO-220 | Power P-channel |
|
||
| `mosfet-fqp27p06` | PMOS | TO-220 | Logic-level P-channel |
|
||
|
||
### Fase 9.3 — Operational amplifiers
|
||
|
||
All op-amps use a behavioral `B_out = max(vLo, min(vHi, A · (V+ − V−)))` with rails derived from `ctx.vcc`. High input impedance via 10 MΩ (or 1 TΩ for JFET input) resistors to ground on each input pin.
|
||
|
||
| metadataId | Type | Gain A | Low rail | High rail | Notes |
|
||
|---|---|---|---|---|---|
|
||
| `opamp-ideal` | VCVS | 10⁶ | unclamped | unclamped | Textbook circuits only |
|
||
| `opamp-lm358` | Dual | 10⁵ | 0.05 V | Vcc − 1.5 V | Single-supply, rail-to-rail output |
|
||
| `opamp-lm741` | Single | 2·10⁵ | 1.5 V | Vcc − 1.5 V | Classic, needs headroom |
|
||
| `opamp-tl072` | Dual (JFET) | 2·10⁵ | 2 V | Vcc − 2 V | Audio / instrumentation |
|
||
| `opamp-lm324` | Quad | 10⁵ | 0.05 V | Vcc − 1.5 V | 4× LM358 in one package |
|
||
|
||
### Fase 9.4 — Power-supply parts
|
||
|
||
| metadataId | Topology | Behavioral card |
|
||
|---|---|---|
|
||
| `reg-7805` | +5 V linear, 2 V dropout | `B_out = min(V(VIN)−V(GND)−2, 5)` |
|
||
| `reg-7812` | +12 V linear | `B_out = min(V(VIN)−V(GND)−2, 12)` |
|
||
| `reg-7905` | −5 V linear (negative rail) | `B_out = max(V(VIN)−V(GND)+2, −5)` |
|
||
| `reg-lm317` | Adjustable, 1.25 V reference | `B_out = V(ADJ) + min(V(VIN)−V(ADJ)−2, 1.25)` (referenced to ground for load current return) |
|
||
| `battery-9v` | 9 V with 1.5 Ω ESR | `V + int DC 9`, `R int − 1.5` |
|
||
| `battery-aa` | 1.5 V with 0.15 Ω ESR | " 1.5 / 0.15 |
|
||
| `battery-coin-cell` | 3 V with 10 Ω ESR (CR2032) | " 3 / 10 |
|
||
| `signal-generator` | Sine / square / DC | `SIN(off amp freq)` / `PULSE(...)` / `DC off` selected by `waveform` property |
|
||
|
||
### Fase 9.5 — Schottky, photodiode, multi-input gates
|
||
|
||
| metadataId | Model / expression |
|
||
|---|---|
|
||
| `diode-1n5817` | Schottky 20 V, `D(Is=3.3u N=1 Rs=0.025)`, Vf ≈ 0.32 V |
|
||
| `diode-1n5819` | Schottky 40 V, `D(Is=3u N=1 Rs=0.027)` |
|
||
| `photodiode` | Regular diode + current source: `I_ph = lux · 100 nA` sinking from cathode to anode |
|
||
| `logic-gate-{and,or,nand,nor}-{3,4}` | Same behavioral pattern as 2-input gates, extended to 3 or 4 inputs |
|
||
|
||
### Fase 10 — Electromechanical + IC packaging (implemented)
|
||
|
||
#### Relay (SPDT)
|
||
|
||
| metadataId | Topology |
|
||
|---|---|
|
||
| `relay` | R + L in parallel for the coil + ngspice `S` switches for NO/NC contacts with native Vt/Vh hysteresis + B-source inverter to implement the normally-closed switch (ngspice SW has no "NC" mode). Optional integrated flyback diode (cathode on COIL+, anode on COIL−). Configurable via `coil_voltage`, `coil_resistance`, `include_flyback` properties. |
|
||
|
||
#### Optocouplers
|
||
|
||
Pattern: LED + 0 V current-sense source in series + CCCS (`F` element) mirrors I_LED into the phototransistor output with the part's Current Transfer Ratio (CTR).
|
||
|
||
| metadataId | CTR |
|
||
|---|---|
|
||
| `opto-4n25` | 0.5 (50%) |
|
||
| `opto-pc817` | 1.0 (100% typical, 80–600% spread in real parts) |
|
||
|
||
#### 74HC logic ICs (multi-gate packages — 14-pin DIP)
|
||
|
||
First mapper pattern in the project that emits **multiple** B-source cards per component (one per internal gate). Pin naming follows the datasheet (e.g. 1A/1B/1Y for gate 1, up to 4Y on quad packages or 6Y on hex inverters).
|
||
|
||
| metadataId | Contents |
|
||
|---|---|
|
||
| `ic-74hc00` | 4× 2-input NAND |
|
||
| `ic-74hc02` | 4× 2-input NOR |
|
||
| `ic-74hc04` | 6× NOT |
|
||
| `ic-74hc08` | 4× 2-input AND |
|
||
| `ic-74hc14` | 6× Schmitt-trigger NOT (hysteresis via state-dependent threshold) |
|
||
| `ic-74hc32` | 4× 2-input OR |
|
||
| `ic-74hc86` | 4× 2-input XOR |
|
||
|
||
Unwired gates are skipped silently (no wasted netlist cards).
|
||
|
||
#### Flip-flops (digital simulation only)
|
||
|
||
SPICE can't do edge detection in `.op` without `ddt()`, so flip-flops live in the digital-sim layer (`PartSimulationRegistry`) and **have no SPICE mapper**. They still participate in MCU-driven circuits.
|
||
|
||
| metadataId | Behaviour on rising CLK |
|
||
|---|---|
|
||
| `flip-flop-d` | Q ← D |
|
||
| `flip-flop-t` | Q ← Q ⊕ T (toggle when T=1) |
|
||
| `flip-flop-jk` | J=0/K=0 hold, J=1/K=0 set, J=0/K=1 reset, J=1/K=1 toggle |
|
||
|
||
Implemented via a shared `edgeTriggeredFF` helper that tracks the previous CLK state, detects rising edges, and samples the data inputs.
|
||
|
||
#### L293D dual H-bridge motor driver
|
||
|
||
| metadataId | Topology |
|
||
|---|---|
|
||
| `motor-driver-l293d` | Per channel (2 channels, EN1 + IN1/IN2 + OUT1/OUT2 and EN2 + IN3/IN4 + OUT3/OUT4): `OUT = u(EN−T) · u(IN−T) · V(VCC2)`. When EN=LOW the outputs are high-impedance (weak 10 MΩ pull-down to 0). Resolves V_motor from the wired VCC2 net when available, else from `ctx.vcc`. |
|
||
|
||
## The `_customComponents` mechanism
|
||
|
||
Velxio-specific parts (everything not defined in `third-party/wokwi-elements`) are declared in `scripts/component-overrides.json` under the `_customComponents[]` array. The metadata generator ([`scripts/generate-component-metadata.ts`](../../scripts/generate-component-metadata.ts), function `applyOverrides`) injects them before the standard property-patching loop. An entry must have: `id`, `tagName`, `name`, `category`, `pinCount`, `tags` — other fields default.
|
||
|
||
Example:
|
||
|
||
```json
|
||
{
|
||
"_customComponents": [
|
||
{
|
||
"id": "logic-gate-xnor",
|
||
"tagName": "wokwi-logic-xnor",
|
||
"name": "XNOR Gate",
|
||
"category": "logic",
|
||
"properties": [],
|
||
"defaultValues": {},
|
||
"pinCount": 3,
|
||
"tags": ["logic", "gate", "xnor", "digital"]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
A drift detector at [`test/test_circuit/test/metadata_drift.test.js`](../../test/test_circuit/test/metadata_drift.test.js) fails if `components-metadata.json` is out of sync with the overrides file. The frontend CI workflow also regenerates and checks `git diff` on the JSON. Run `cd frontend && npm run generate:metadata` after any change to `component-overrides.json`.
|
||
|
||
## What the sandbox does **not** include
|
||
|
||
- **Temperature effects** on any parameter. `.model` cards support `tc1`, `tc2`, but we did not exercise them.
|
||
- **Noise sources** (`.noise` analysis). Supported by ngspice; untested here.
|
||
- **Monte Carlo** on device parameters. Would be useful for tolerance analysis.
|
||
- **Pole-zero / stability analysis**. `.pz` is in ngspice.
|
||
- **S-parameter / two-port** analysis. `.sp` available.
|
||
- **Behavioral R** (resistor whose value is an expression of another node's voltage) — supported by ngspice via the `R1 a b R='expr'` syntax. Would simplify the photoresistor case.
|