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:
parent
9b2737ef77
commit
da3532c1aa
297
scripts/populate-examples.sh
Executable file
297
scripts/populate-examples.sh
Executable 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"
|
||||
Loading…
x
Reference in New Issue
Block a user