diff --git a/scripts/populate-examples.sh b/scripts/populate-examples.sh new file mode 100755 index 0000000..c97f7f3 --- /dev/null +++ b/scripts/populate-examples.sh @@ -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"