#!/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"