Syrup_examples.mws
Syrup, a Symbolic Circuit Analyzer
Joseph Riel
joe.riel@incep.com
This Maple worksheet demonstrates the use and capabilities of
, a symbolic circuit analyzer for Maple.
Load Syrup
>
with(Syrup);
Resistor Divider
Analyzing this simple circuit illustrates the basics of using syrup. First, create the circuit deck. The deck may be in several formats; it may be an external file in standard SPICE format, a TEXT structure, or a string with embedded newline characters. In this tutorial all decks will be entered as strings. Newline characters are entered in a worksheet by using <shift><enter> or as \n.
>
divider :=
"Resistor Divider
V 1 0
R1 1 2
R2 2 0
.end":
As with SPICE, the first line is the title, it is ignored. Notice that none of the elements have been assigned values. SPICE would complain; syrup uses the name of an element as the default value. Now run syrup, specify a dc analysis and add an optional parameter that will be assigned the elements' currents.
>
syrup(divider, dc, 'curr');
Syrup/parsedeck: Analyzing SPICE deck "Resistor Divider" (ignoring this line)
Note that syrup prints the title of the deck. This helps you to detect the common error of omitting the title. If you enter an empty line for the title, nothing will be printed. Syrup returns the voltages of the two circuit nodes as equations, the syntax is
. Look at the currents.
>
curr;
The currents are also returned as equations, the syntax is similar to the voltages,
.
Wheatstone Bridge
The Wheatstone bridge, a classical electrical engineering circuit, has been used [1] to illustrate the use of Maple to solve an electric circuit. This example shows how syrup simplifies the analysis by eliminating the manual formulation of the equations. Notice that in the following circuit description, node names are not limited to integers, any unassigned Maple name is acceptable. The 0 node, as with SPICE, is reserved for ground.
>
bridge := "
V a 0
R1 a b
R2 a c
R3 b 0
R4 c 0
R5 b c
.end":
>
syrup(bridge, dc, 'curr');
We want to determine the value of R4 that makes the current through R5 zero. One way to solve this problem is to assign the set of current equations and then solve i[R5] for R4.
>
assign(curr):
>
solve(i[R5], {R4});
which is the result expected.
Capacitor Network
A popular SPICE tutorial [2] gives, as an exercise, a rather impressive looking network of capacitors and asks the reader to determine the effective capacitance between node 1 and ground. The method suggested, which simulates one once used in the lab, is to add a series inductor with a voltage source, locate the resonant frequency by performing an
analysis, and then determine the capacitance by using the relation
where
is the natural frequency at resonance. Let's use the same method with syrup. [There are better ways of doing this than creating a tank circuit.]
>
capnet := "
V a 0 1
L a 1
C1 1 3 2uF
C2 1 2 3uF
C3 2 3 1uF
C4 2 4 1.5uF
C5 3 4 2.5uF
C6 3 0 3.5uF
C7 4 0 0.5uF
.end":
This circuit is not be a valid SPICE deck because SPICE requires a dc path to ground at every node; syrup handles the analysis correctly. This behavior is useful but also imposes a certain rigor on the user; syrup does not not complain if elements are left dangling.
Perform an
analysis.
>
volt := syrup(capnet, ac);
>
assign(volt);
Syrup uses
to indicate complex frequency. Convert this to real frequency using the relation
.
>
v1(s) := eval(v[1], s=sqrt(-1)*omega);
At resonance,
. Evaluating the previous expression at that frequency we get
>
v1(omega0) := eval(v1(s), omega^2 = 1/L/Ceff);
Resonance occurs when the denominator goes to zero. Solving for
we get,
>
solve(denom(v1(omega0)), {Ceff});
In this example numeric values were assigned to most of the elements. To perform a symbolic analysis with a valid SPICE deck, use the optional parameter
. A symbolic analysis causes syrup to ignore any numeric values and use the default element value. Here's the same analysis performed symbolically.
>
syrup(capnet, ac, symbolic):
>
subs(%, s=sqrt(-1)*omega, v[1]):
>
subs(omega^2 = 1/L/Ceff, denom(%)):
>
solve(%, {Ceff}): simplify(%);
syrup: Symbolic analysis, numeric values will be ignored
Cascaded RC Circuit
>
DualRC := "
V 1 0
X1 1 2 rc
X2 2 3 rc
.subckt rc 1 2
R 1 2
C 2 0
.ends
.end":
>
deqs := syrup(DualRC, tran, 'curr');
Transient analyses use the the voltages across capacitors and currents through inductors as state variables. These elements may be assigned initial conditions using SPICE syntax; if initial conditions are not specified, as in this example, then they are assumed to be zero, this is different than SPICE, which uses the results of a dc analysis as the default initial conditions. The output of a transient analyses is a sequence of two sets, the first gives the differential equations and initial conditions, the second gives the state variables. This output can be passed directly to dsolve as shown below
.
>
dsol := dsolve(deqs);
>
eval(curr, dsol):
Suppose we need to calculate the total energy dissipated in the first resistor as the capacitors charge from 0 to V. Substitute the previous results into the current equations. Pick off the current through the resistor
>
iR := eval(i[R[X1]], %);
Integrate the power from 0 to infinity.
>
assume(R>0, C>0):
>
Energy := R*int(iR^2, t=0..infinity);
Nonlinear Resistor Divider
Syrup allows any valid Maple expression as a component value; node voltages and voltage source currents can be included in these expressions. Using this method theoretically allows one to model nonlinear components, however, doing so greatly increases the chance that Maple will be unable to solve the circuit. Don't expect an ac analysis to be meaningful since it implicitly assumes linear components. The following is an example of a resistor divider with the top resistor's value proportional to the square of the current through it.
>
test := "
V 1 0
R1 1 2 k*i[V]^2
R2 2 0
.end":
>
syrup(test, dc);
Semiconductors
Syrup does not provide built-in models for semiconductors, however, it does map elements that are SPICE semiconductors (those starting with the letters D, J, M, or Q) to subcircuit calls. The model of a semiconductor must be given as a subcircuit definition
Given the Ebers-Moll model [3] of an npn transistor, compute the forward current gain.
>
map(assume,[Is,aF,aR], positive):
>
semicon := "
Ib 0 2
Q 0 2 3 npn
Vcc 3 0
.subckt npn e b c
Vbe b e Vt*ln(i[Vbe]/Is+1)
Vbc b c Vt*ln(i[Vbc]/Is+1)
Feb e b Vbc aR
Fcb c b Vbe aF
.ends
.end":
>
syrup(semicon,dc,'curr');
>
Ic := eval(i[Vcc],curr):
>
hfe := diff(Ic,Ib):
For Vcc >> Vt, the usual case, the exponential goes to zero. The easiest way to compute this is to evaluate it when the exponential is zero.
>
eval(hfe, exp=0);
which is the expected result.
Biquad Filter Transfer Function
Syrup can be used to determine the transfer function of a circuit by performing an ac analysis. The following deck models an active bandpass filter, a biquad [4]. The op-amps are modeled as simple voltage controlled voltage sources.
>
biquad := `
Vin 1 0
Rg 1 2
X1 2 3 amp
Cf2 2 3
Rq 2 3
*Inverter
R1 3 4 1
R2 4 5 1
X2 4 5 amp
Rf1 5 6
Cf 6 7
X3 6 7 amp
RF2 7 2
.subckt amp negin vout
E1 vout 0 negin 0 -A
.ends
.end`:
>
volt := syrup(biquad, ac):
Node 3 is the output of the biquad. We are interested in the ideal case when the gain of the op-amp goes to infinity.
>
H := eval(v[3]/Vin, volt):
>
limit(H, A=infinity);
References
[1] T.C. Scott and M. Monagan: Maple in Education - Part II, Maple Technical Newsletter, MTN-1,1: pp. 71-72, (Spring 1994), Birkhauser.
[2] W. Banzhaf: "Computer-Aided Circuit Analysis Using SPICE", Prentice-Hall, New Jersey, pp. 74-75, (1989)
[3] J. J. Ebers and J. L. Moll, "Proceedings IRE," 42, 1761 (1954).
[4] D. Lancaster "Active-Filter Cookbook", Howard W. Sams & Co., Indianapolis, pp. 159-164, (1975).