Add example notebook population script

Creates 8 curated example notebooks via the API:
- RC Lowpass Filter (AC analysis)
- Voltage Divider (DC operating point)
- RC Step Response (transient)
- RLC Bandpass Filter (AC analysis)
- Diode Half-Wave Rectifier (transient)
- LED I-V Characteristic (DC sweep)
- Inverting Op-Amp Amplifier (transient)
- CMOS Inverter (DC transfer characteristic)
This commit is contained in:
Ryan Malloy 2026-02-13 03:55:55 -07:00
parent 9b2737ef77
commit da3532c1aa

297
scripts/populate-examples.sh Executable file
View File

@ -0,0 +1,297 @@
#!/bin/bash
# Populate SpiceBook with example notebooks
# Usage: ./populate-examples.sh [BASE_URL]
BASE="${1:-https://spicebook.warehack.ing}"
API="$BASE/api"
create_notebook() {
local title="$1"
curl -s -X POST "$API/notebooks" \
-H "Content-Type: application/json" \
-d "{\"title\": \"$title\"}"
}
add_cell() {
local nb_id="$1" type="$2" source="$3" after="$4"
local body="{\"type\": \"$type\", \"source\": $(echo "$source" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))')}"
if [ -n "$after" ]; then
body=$(echo "$body" | python3 -c "import sys,json; d=json.load(sys.stdin); d['after_cell_id']='$after'; print(json.dumps(d))")
fi
curl -s -X POST "$API/notebooks/$nb_id/cells" \
-H "Content-Type: application/json" \
-d "$body"
}
update_cell() {
local nb_id="$1" cell_id="$2" source="$3"
curl -s -X PUT "$API/notebooks/$nb_id/cells/$cell_id" \
-H "Content-Type: application/json" \
-d "{\"source\": $(echo "$source" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))')}"
}
run_cell() {
local nb_id="$1" cell_id="$2"
curl -s -X POST "$API/notebooks/$nb_id/cells/$cell_id/run" | python3 -c "import sys,json; d=json.load(sys.stdin); print(f' Simulation: {d.get(\"elapsed_seconds\",\"?\"):.3f}s, {len(d.get(\"variables\",[]))} variables')" 2>/dev/null || echo " (run skipped)"
}
get_cell_id() {
echo "$1" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])"
}
get_nb_id() {
echo "$1" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])"
}
get_first_cell_id() {
local nb_id="$1"
curl -s "$API/notebooks/$nb_id" | python3 -c "import sys,json; print(json.load(sys.stdin)['cells'][0]['id'])"
}
echo "=== Populating SpiceBook examples at $BASE ==="
echo
# ─────────────────────────────────────────────────────────────────────
# 1. RC Lowpass Filter
# ─────────────────────────────────────────────────────────────────────
echo "1. RC Lowpass Filter..."
nb=$(create_notebook "RC Lowpass Filter")
nb_id=$(get_nb_id "$nb")
md_id=$(get_first_cell_id "$nb_id")
update_cell "$nb_id" "$md_id" '# RC Lowpass Filter
A first-order passive lowpass filter using a single resistor and capacitor. The cutoff frequency is:
**f_c = 1 / (2 * pi * R * C) = 1 / (2 * pi * 1k * 100n) = 1.59 kHz**
Below the cutoff, the signal passes through. Above it, the output rolls off at -20 dB/decade.' > /dev/null
spice=$(add_cell "$nb_id" "spice" '* RC Lowpass Filter - AC Analysis
V1 in 0 AC 1
R1 in out 1k
C1 out 0 100n
.ac dec 100 1 1meg
.end' "$md_id")
spice_id=$(get_cell_id "$spice")
run_cell "$nb_id" "$spice_id"
echo " Created: $nb_id"
# ─────────────────────────────────────────────────────────────────────
# 2. Voltage Divider
# ─────────────────────────────────────────────────────────────────────
echo "2. Voltage Divider..."
nb=$(create_notebook "Voltage Divider")
nb_id=$(get_nb_id "$nb")
md_id=$(get_first_cell_id "$nb_id")
update_cell "$nb_id" "$md_id" '# Resistive Voltage Divider
The most fundamental analog circuit. Two resistors divide an input voltage:
**V_out = V_in * R2 / (R1 + R2) = 12V * 10k / (10k + 10k) = 6V**
This DC operating point analysis confirms the hand calculation.' > /dev/null
spice=$(add_cell "$nb_id" "spice" '* Voltage Divider - DC Operating Point
V1 in 0 DC 12
R1 in out 10k
R2 out 0 10k
.op
.end' "$md_id")
spice_id=$(get_cell_id "$spice")
run_cell "$nb_id" "$spice_id"
echo " Created: $nb_id"
# ─────────────────────────────────────────────────────────────────────
# 3. RC Step Response
# ─────────────────────────────────────────────────────────────────────
echo "3. RC Step Response..."
nb=$(create_notebook "RC Step Response")
nb_id=$(get_nb_id "$nb")
md_id=$(get_first_cell_id "$nb_id")
update_cell "$nb_id" "$md_id" '# RC Circuit Step Response
When a voltage step is applied to an RC circuit, the capacitor charges exponentially:
**V(t) = V_final * (1 - e^(-t/RC))**
The time constant tau = R * C = 1k * 1u = 1 ms. After 5 time constants (5 ms), the capacitor is >99% charged.' > /dev/null
spice=$(add_cell "$nb_id" "spice" '* RC Step Response - Transient Analysis
V1 in 0 PULSE(0 5 0 1n 1n 10m 20m)
R1 in out 1k
C1 out 0 1u
.tran 0.01m 10m
.end' "$md_id")
spice_id=$(get_cell_id "$spice")
run_cell "$nb_id" "$spice_id"
echo " Created: $nb_id"
# ─────────────────────────────────────────────────────────────────────
# 4. RLC Bandpass Filter
# ─────────────────────────────────────────────────────────────────────
echo "4. RLC Bandpass Filter..."
nb=$(create_notebook "RLC Bandpass Filter")
nb_id=$(get_nb_id "$nb")
md_id=$(get_first_cell_id "$nb_id")
update_cell "$nb_id" "$md_id" '# Series RLC Bandpass Filter
A second-order bandpass filter using a resistor, inductor, and capacitor in series. The output is taken across the resistor.
**Center frequency: f_0 = 1 / (2*pi*sqrt(L*C)) = 1 / (2*pi*sqrt(10m*100n)) = 5.03 kHz**
**Quality factor: Q = (1/R) * sqrt(L/C) = (1/100) * sqrt(10m/100n) = 3.16**
The Q factor determines the bandwidth: BW = f_0 / Q = 1.59 kHz' > /dev/null
spice=$(add_cell "$nb_id" "spice" '* Series RLC Bandpass Filter
V1 in 0 AC 1
L1 in mid 10m
C1 mid out 100n
R1 out 0 100
.ac dec 200 100 100k
.end' "$md_id")
spice_id=$(get_cell_id "$spice")
run_cell "$nb_id" "$spice_id"
echo " Created: $nb_id"
# ─────────────────────────────────────────────────────────────────────
# 5. Diode Half-Wave Rectifier
# ─────────────────────────────────────────────────────────────────────
echo "5. Diode Half-Wave Rectifier..."
nb=$(create_notebook "Diode Half-Wave Rectifier")
nb_id=$(get_nb_id "$nb")
md_id=$(get_first_cell_id "$nb_id")
update_cell "$nb_id" "$md_id" '# Half-Wave Rectifier with Smoothing Capacitor
A diode passes only the positive half-cycles of an AC input. Adding a filter capacitor smooths the output to approximate DC.
The ripple voltage depends on the load current and capacitor size:
**V_ripple = I_load / (f * C) = (10V/1k) / (60Hz * 100u) = 1.67V**
Compare the waveforms with and without the filter capacitor by toggling traces.' > /dev/null
spice=$(add_cell "$nb_id" "spice" '* Half-Wave Rectifier with Filter Cap
V1 in 0 SIN(0 10 60)
D1 in rect 1N4148
R1 rect out_filtered 10
C1 out_filtered 0 100u
R2 out_filtered 0 1k
* Unfiltered output for comparison
D2 in out_unfiltered 1N4148
R3 out_unfiltered 0 1k
.model 1N4148 D(Is=2.52e-9 Rs=0.568 N=1.752 BV=100 IBV=100u)
.tran 0.1m 100m
.end' "$md_id")
spice_id=$(get_cell_id "$spice")
run_cell "$nb_id" "$spice_id"
echo " Created: $nb_id"
# ─────────────────────────────────────────────────────────────────────
# 6. DC Sweep - LED I-V Curve
# ─────────────────────────────────────────────────────────────────────
echo "6. LED I-V Curve..."
nb=$(create_notebook "LED I-V Characteristic")
nb_id=$(get_nb_id "$nb")
md_id=$(get_first_cell_id "$nb_id")
update_cell "$nb_id" "$md_id" '# LED I-V Characteristic Curve
A DC sweep reveals the exponential current-voltage relationship of a diode. The LED model shows:
- Below ~1.8V: negligible current (off region)
- At ~1.8V: forward voltage threshold
- Above 1.8V: current increases exponentially
The series resistor (220 ohm) limits current to safe levels for driving the LED from a 5V supply.' > /dev/null
spice=$(add_cell "$nb_id" "spice" '* LED I-V Curve - DC Sweep
V1 supply 0 DC 5
R1 supply anode 220
D1 anode 0 LED_RED
.model LED_RED D(Is=1e-20 N=1.8 Rs=2 BV=5 IBV=10u)
.dc V1 0 5 0.01
.end' "$md_id")
spice_id=$(get_cell_id "$spice")
run_cell "$nb_id" "$spice_id"
echo " Created: $nb_id"
# ─────────────────────────────────────────────────────────────────────
# 7. Inverting Op-Amp
# ─────────────────────────────────────────────────────────────────────
echo "7. Inverting Op-Amp..."
nb=$(create_notebook "Inverting Op-Amp Amplifier")
nb_id=$(get_nb_id "$nb")
md_id=$(get_first_cell_id "$nb_id")
update_cell "$nb_id" "$md_id" '# Inverting Op-Amp Amplifier
A classic op-amp configuration with gain set by the feedback network:
**A_v = -R_f / R_in = -10k / 1k = -10**
The input signal (100 mV, 1 kHz sine) is amplified to 1V and inverted. The op-amp is modeled as an ideal voltage-controlled voltage source with very high gain.
Note the 180-degree phase inversion between input and output.' > /dev/null
spice=$(add_cell "$nb_id" "spice" '* Inverting Op-Amp Amplifier
* Input signal
V1 inp 0 SIN(0 0.1 1k)
* Power supplies
VCC vcc 0 DC 15
VEE vee 0 DC -15
* Ideal op-amp subcircuit
.subckt opamp inp inn out vcc vee
E1 out 0 inn inp -1e6
.ends opamp
* Circuit
R1 inp inv 1k
R2 inv out 10k
X1 0 inv out vcc vee opamp
.tran 0.01m 5m
.end' "$md_id")
spice_id=$(get_cell_id "$spice")
run_cell "$nb_id" "$spice_id"
echo " Created: $nb_id"
# ─────────────────────────────────────────────────────────────────────
# 8. CMOS Inverter
# ─────────────────────────────────────────────────────────────────────
echo "8. CMOS Inverter..."
nb=$(create_notebook "CMOS Inverter")
nb_id=$(get_nb_id "$nb")
md_id=$(get_first_cell_id "$nb_id")
update_cell "$nb_id" "$md_id" '# CMOS Inverter Transfer Characteristic
The fundamental digital logic gate: a complementary pair of NMOS and PMOS transistors.
- When V_in is LOW (0V): PMOS is ON, NMOS is OFF, output is HIGH (VDD)
- When V_in is HIGH (5V): NMOS is ON, PMOS is OFF, output is LOW (0V)
- The switching threshold is near VDD/2 = 2.5V
The DC sweep reveals the sharp voltage transfer characteristic that makes CMOS logic possible.' > /dev/null
spice=$(add_cell "$nb_id" "spice" '* CMOS Inverter - DC Transfer Characteristic
VDD vdd 0 DC 5
VIN in 0 DC 0
* PMOS: source=vdd, gate=in, drain=out, bulk=vdd
M1 out in vdd vdd PMOD W=10u L=1u
* NMOS: source=0, gate=in, drain=out, bulk=0
M2 out in 0 0 NMOD W=5u L=1u
.model NMOD NMOS(VTO=0.7 KP=110u GAMMA=0.4 LAMBDA=0.04 PHI=0.65)
.model PMOD PMOS(VTO=-0.7 KP=50u GAMMA=0.57 LAMBDA=0.05 PHI=0.65)
.dc VIN 0 5 0.01
.end' "$md_id")
spice_id=$(get_cell_id "$spice")
run_cell "$nb_id" "$spice_id"
echo " Created: $nb_id"
echo
echo "=== Done! Created 8 example notebooks ==="
echo "Visit: $BASE"