Part 14
Symbulator in a notebook
The solver as a Python package, used from a Jupyter notebook: a circuit is a string, an answer is a SymPy expression, and the Evaluate and Solve cards are two functions. With the notebooks to start from.
Last updated 2026-09-20
The app and the package are one solver. What a card does to a circuit, a cell in a notebook does, and the answers are the same ones.
What a notebook adds is Python. An answer is a SymPy expression, so it substitutes, differentiates, plots, and goes on into the rest of a calculation.
Getting set up
On your own computer, in a terminal:
pip install symbulator[notebook]That brings JupyterLab, NumPy and Matplotlib with the package. On Google Colab the package is not installed, and the notebooks below begin with a cell that installs it there and does nothing anywhere else:
import sys
if "google.colab" in sys.modules:
%pip install -q symbulator matplotlibA circuit is a string
The description is the one the Input File card takes, an element to a line or the elements joined by colons. The circuit description has the grammar.
from symbulator import dc, draw
divider = """
e1,1,0,12
r1,1,2,1'k
r2,2,0,2'k
"""
draw(divider)draw shows the schematic under the cell, from the description alone, as the app does. dc runs the analysis and returns every answer in the circuit:
res = dc(divider)
res["v2"]8Answers have the app's names. Either spelling finds an answer, ir1 or i_r1; the package stores the second.
res["ir1"], res["i_r1"], res["pr1"](1/250, 1/250, 2/125)The answers are exact because the values are, and a value may be a symbol, as in the app:
sym = dc("e,1,0,vs:r1,1,2,ra:r2,2,0,rb")
sym["vr2"]rb*vs/(ra + rb)Being SymPy, it takes a value for each symbol with subs:
sym["vr2"].subs({"vs": 10, "ra": 4000, "rb": 6000})6The Rounding setting is rounded, which returns a copy and leaves the exact answers alone:
res.rounded(4)["ir1"]0.004000The analyses
Each choice in Analysis is a function, and each tool of Find equivalent is one too. Nodes are given as strings.
| In the app | In a cell |
|---|---|
| DC | dc(circuit) |
| AC, with ω | ac(circuit, omega=1000) |
| FD | fd(circuit) |
| TR | tr(circuit) |
| Thévenin / Norton | th(circuit, "2", "0") |
| Resistance / impedance | er(circuit, "1", "0") |
| Two-port parameters | port(circuit, "1", "3", "z") |
In AC, omega is a number, a symbol's name such as "w", or an expression. The equivalent tools take domain="ac" and an omega the same way. An AC answer is complex, and polar shows it as magnitude and angle:
from symbulator import ac, polar
rl = "e,1,0,10:r,1,2,50:l,2,0,0.05"
ac(rl, omega=1000)["ir"]0.1 - 0.1*Ipolar(ac(rl, omega=1000)["ir"])0.1414∠-45.00°A TR answer is a function of t, the symbol the answers use. Import it to use the same one, and at substitutes a time by name:
from symbulator import tr, t
rc = "e,1,0,10:r,1,2,1'k:c,2,0,1'u"
tr(rc)["v2"]10 - 10*exp(-1000*t)tr(rc).at("v2", t=0.001)6.32120558828558The capacitor's voltage is the voltage of node 2, since its other end is ground. That is how to read any voltage that a TR or FD result does not give.
What TR and FD do not give. A TR or FD result holds the node voltages and the element currents, and nothing worked out from them: no element's voltage drop and no element's power. DC and AC store both. TR and FD leave them out because every answer stored costs an inverse Laplace transform, and these are one subtraction and one product away from what is stored. The drop across an element is the difference of the node voltages at its two ends, ground counting as zero:
res = tr(rc)
res["v1"] - res["v2"]10*exp(-1000*t)That is the voltage across r. The power it consumes is the drop times its current, the rule DC uses for every element:
(res["v1"] - res["v2"]) * res["ir"]exp(-2000*t)/10A source follows the same rule, and reads negative while it delivers:
res["v1"] * res["ie"]-exp(-1000*t)/10A Thévenin equivalent comes back with its four answers as attributes:
from symbulator import th
eq = th("e,1,0,20:r1,1,2,50:r2,2,0,150", "2", "0")
eq.vth, eq.z, eq.ino, eq.pmax(15, 75/2, 2/5, 3/2)The Evaluate and Solve cards
Once a circuit is solved, the app lets you write an expression in its answers, and solve an equation in them. Those are two functions, evaluate and solve, and they take the result of any analysis above.
from symbulator import evaluate, solve
res = dc("e1,1,0,vs:r1,1,2,1'k:r2,2,0,1'k")
evaluate(res, "v2/vs")1/2Evaluate in the app has a Conditions box, and here it is conditions. An equation there gives a name a value while the expression is worked out:
evaluate(res, "v2", conditions=["vs = 10"])5A voltage drop that the result does not hold is the difference of two node voltages, and it goes into an expression as one. The resistance of r, from its drop and its current, in TR:
evaluate(tr(rc), "(v1 - v2)/ir")1000The tools' own answers work the same way. A Thévenin result also answers to the load's irl, vrl and prl, in the variable load, and a matched load draws the maximum power:
evaluate(eq, "prl", conditions=["load = req"])3/2Solve is solve. It substitutes the answers first, solves for whatever is left, and returns a list of solutions, each a dictionary:
solve(res, ["v2 = 6"], ["vs"])[{'vs': 12}]conditions pins a symbol when it is an equation and filters the roots when it is a comparison, and real_only=True keeps real solutions only. A series circuit's resonance is where the source sees no reactance, with ω left as the symbol w:
res = ac("e,1,0,20:r,1,2,2:l,2,3,1'm:c,3,0,.4'u", "w")
solve(res, ["im(ze) = 0"], ["w"], conditions=["w > 0"], real_only=True)[{'w': 50000.0000000000}]A value the Define card gives is a condition here, in dc, ac, fd or tr as much as in evaluate.
Expert Mode
The three boxes of Expert Mode are the three keywords equations, unknowns and conditions, on any of dc, ac, fd and tr:
design = dc("e1,1,0,12:r1,1,2,4'k:r2,2,0,r_b",
equations=["v_2 = 6"], unknowns=["r_b"])
design["r_b"]4000Inside an equation, write an answer as the package stores it, with its underscore: v_2, p_jd1. The shorter spelling often works too, but a name such as re is SymPy's own function for the real part, and no rule of the package can tell the two apart. Symbols, Define and Expert Mode has Expert Mode.
Cell magics
%load_ext symbulator adds a cell magic for each analysis: %%dc, %%ac, %%fd and %%tr. A cell that starts with one is a circuit, an element to a line, exactly as the input card takes it:
%load_ext symbulator%%dc into=magic nodraw
e1,1,0,5
r1,1,2,1'k
r2,2,0,1'kThe cell draws the circuit and shows every answer, and into binds the result to a name:
magic["v2"]5/2Options go on the magic's line: omega=1000 for %%ac, rms, variables=v_2,i_r1 to limit a transient, into= and nodraw.
Plotting
SymPy plots a transient as it is, with Matplotlib behind it:
import sympy as sp
sp.plot(tr(rc)["v2"], (t, 0, 0.005),
xlabel="t (s)", ylabel="v2 (V)");bode_samples and time_samples return arrays for a frequency response or a time response, for Matplotlib to draw. The monograph's notebook below uses the first for the 1999 amplifier.
Notebooks to start from
Each is already executed, so you can read the answers before you run anything, and each opens in Google Colab. They are made from the app's own example files, and every answer in them has been compared with the app's.
| Notebook | What is in it |
|---|---|
| Quick start | The package in a few cells, from a circuit to a plot. |
| Claude's sampler | The app's twelve showcase entries, one of each kind of analysis. |
| A Baker's Dozen | Thirteen solved examples that look like an afternoon's work by hand. |
| The Manual's circuits | Every circuit of this Manual, run, with its printed answer beneath. |
| The monograph's exemplars | The exemplar circuits of The Internal Logic of Symbulator. |
| Alexander & Sadiku and Nilsson & Riedel | The two textbook samplers. |
The Course's own problems are there as well, one notebook to a lesson; the folder on GitHub has them all.
What stays in the app
The Numerical Solver is a page of the app and has no function in the package. SPICE has two, to_spice and from_spice, for the SPICE Translator's two directions. The schematic is draw, and to_svg returns it as text.