Schematics

Introduction

High quality schematics can be generated from a netlist using Circuitikz for LaTeX diagrams. This is much easier than writing Circuitikz commands directly in LaTeX.

A semi-automatic component placement is used with hints required to designate component orientation and explicit wires to link nodes of the same potential but with different coordinates.

Here’s an example:
>>> from lcapy import Circuit
>>> cct = Circuit("""
... V 1 0 {V(s)}; down
... R 1 2; right
... C 2 _0_2; down
... W 0 _0_2; right"")
>>> cct.draw('schematic.pdf')

Note, the orientation hints are appended to the netlist strings with a semicolon delimiter. The drawing direction is with respect to the first node. The component W is a wire. Node names starting with an underscore are not drawn.

The image generated by this netlist is:

_images/schematic.png
Here’s another example, this time loading the netlist from a file:
>>> from lcapy import Circuit
>>> cct = Circuit('voltage-divider.sch')
>>> cct.draw('voltage-divider.pdf')

Here are the contents of the file ‘voltage-divider.sch’:

Vi 1 0_1; down
R1 1 2; right, size=1.5
R2 2 0; down
P1 2_2 0_2; down, v=V_o
W 2 2_2; right
W 0_1 0; right
W 0 0_2; right

Here, P1 defines a port. This is shown as a pair of open blobs. The wires do not need unique names.

_images/voltage-divider.png

Component orientation

Lcapy uses a semi-automated component layout. Each component requires a specified orientation: up, down, left, or right. In addition, attributes can be added to override color, size, etc.

The drawing direction provides a constraint. For example, the nodes of components with a vertical orientation have the same x coordinate, whereas nodes of horizontal components have the same y coordinate.

The component orientation is specified by a rotation angle. This angle is degrees anticlockwise with zero degrees being along the positive x axis. For example,

>>> cct.add('D1 1 2; rotate=45')

The component orientation can also be specified by a direction keyword. Note, this rotates the component:

  • right (0 degrees)
  • left (180 degrees)
  • up (90 degrees)
  • down (-90 degrees)

For example:

D1 1 2;right
_images/Dright.png
D1 1 2;down
_images/Ddown.png

Note, the drawing direction is from the positive node to the negative node.

Here’s an example of how to draw a diode bridge:

D1 2 1; rotate=225, size=1.5
D2 3 2; rotate=-45, size=1.5
D3 3 4; rotate=225, size=1.5
D4 4 1; rotate=-45, size=1.5
_images/Dbridge.png

Most components can be mirrored about the x-axis using the mirror or flipud attributes and mirrored about the y axis with the invert or fliplr attribute. For example, to switch the order of the inverting and non-inverting inputs of an opamp use:

>>> cct.add('E1 1 2 opamp 3 0; right, mirror')

Note, the mirroring is performed before rotations are applied. Opamps also have a mirrorinputs option that switches the inverting and non-inverting inputs pwithout mirroring the entire component.

Here’s an example of using invert to mirror a D flip-flop in the y-axis, compared to rotating the flip-flop:

U1 dff
U2 dff; fliplr
U3 dff; left
O U1.mid U2.mid; right=2
O U2.mid U3.mid; right=2
_images/fliplr1.png

Component size

By default each component has a minimum size of 1. This can be stretched to satisfy a node constraint. The minimum size is specified using the size keyword, for example:

>>> cct.add('R1 1 2; right, size=2')

The size argument is used as a scale factor for the component node spacing. The size can also be specified by adding a value to the left, right, up, or down arguments. For example:

>>> cct.add('R1 1 2; right=2')

Here’s a comparison of resistors of different sizes.

R1 1 2; right
R2 2 3; right=2
R3 3 4; right=3
;help_lines=1
_images/resistors1.png

By default, a component with size 1 has its nodes spaced by 2 units. This can be changed using the node_spacing option of the schematic. For example,

R1 1 2; right
R2 2 3; right=2
R3 3 4; right=3
;node_spacing=1.5, help_lines=1
_images/resistors2.png

Be default, a component has a length of 1.5 units. This can be changed using the cpt_size option of the schematic. For example,

R1 1 2; right
R2 2 3; right=2
R3 3 4; right=3
;cpt_size=1, help_lines=1
_images/resistors3.png
R1 1 2; right
R2 2 3; right=2
R3 3 4; right=3
;cpt_size=1, node_spacing=1, help_lines=1
_images/resistors4.png

The size of components can scaled with the scale attribute:

R1 1 2; right
R2 2 3; right=2, scale=2
R3 3 4; right=3, scale=3
;help_lines=1
_images/resistors6.png

The overall schematic can be scaled with the scale option of the schematic:

R1 1 2; right
R2 2 3; right=2
R3 3 4; right=3
;scale=0.5, help_lines=1
_images/resistors5.png

Nodes

Nodes are shown by a blob. By default, only the primary nodes (those not starting with an underscore) are shown by default. This is equivalent to:

>>> cct.draw(draw_nodes='primary')

All nodes can be drawn using:

>>> cct.draw(draw_nodes='all')

Only the nodes where there are more than two branches can be drawn using:

>>> cct.draw(draw_nodes='connections')

No nodes can be drawn using:

>>> cct.draw(draw_nodes=False)

By default, only the primary nodes are labelled. All nodes can be labelled (this is useful for debugging) using:

>>> cct.draw(label_nodes='all')

No nodes can be labelled using:

>>> cct.draw(label_nodes=False)

Only nodes starting with a letter can be labelled using:

>>> cct.draw(label_nodes='alpha')

In this case nodes with names such as in and out will be displayed but not numeric node names.

These options can be stored with the schematic netlist, for example:

C1 1 0 100e-12; down, size=1.5, v={5\,kV}
R1 1 6 1500; right
R2 2 4 1e12; down
C2 3 5 5e-9; down
W 2 3; right
W 0 4; right
W 4 5; right
SW 6 2 no; right, l=, size=1.5
; draw_nodes=connections, label_nodes=False, label_ids=False

Node names

Circuit nodes are usually identified by a number. They can be given arbitrary names provided they do not contain a period (.). By default, nodes with names starting with an underscore are not drawn. The name can contain an underscore to denote a subscript or a caret to denote a superscript. For example, T_123.

Node names starting with a period are a short-hand notation. For example:

R1 1 .2; right
C1 R1.2 3; right

is short-hand for:

R1 1 R1.2; right
C1 R1.2 3; right

Node names not starting with an underscore are considered primary nodes. Node names starting with an underscore are considered secondary nodes (usually they are at the same potential as a primary node and do not need to be labelled). For backward compatibility, nodes with names that contain an underscore and start with a digit are considered secondary.

Node names can also refer to pins of shape and chip components. For example:

U1 regulator; right
W  1 U1.in; right
W  U1.gnd 0; down

Components

Only linear, time-invariant, components can be analyzed by Lcapy. However, many others can be drawn.

Batteries

BAT1 1 2; right, l=default
BAT2 2 3; right, kind=cell1, l=cell1
; label_nodes=false, draw_nodes=connections

_images/batteries.png

Crystals

XT1 1 2; right
_images/XT1.png

Constant phase elements (CPE)

CPE1 1 0; right
_images/CPE1.png

Diodes

Diodes can be drawn but not simulated. A standard diode is described using:

Dname Np Nm

Different kinds of diodes can be specified by the kind option, for example,

D1 1 2; right, l=diode
D2 2 3; right, kind=schottky, l=schottky
D3 3 4; right, kind=led, l=led
D4 4 5; right, kind=zener, l=zener
D5 5 6; right, kind=zzener, l=zzener
D6 6 7; right, kind=tunnel, l=tunnel
D7 7 8; right, kind=photo, l=photo
_images/diodes.png

The drawn style is controlled by the style option, for example,

D1 1 2; right, l=empty
D2 2 3; right, style=full, l=full
D3 3 4; right, style=stroke, l=stroke

_images/diodes2.png

Ferrite beads

FB1 1 2; right
_images/FB1.png

Gyrators

GY1 1 2 3 4 R; right
_images/GY1.png

Integrated circuits

ICs can be drawn but not simulated. Here’s an example:

; draw_nodes=connections, help_lines=1
U1 chip2121; right=2, l={MCU}, pinlabels={r1=PIO1,r2=PIO2}
W U1.vdd VDD; implicit, up=0.2, l=3V3
W U1.vss 0; implicit, down=0.7, l=0V
R1 U1.r2 1; right
D1 1 3 led; down
W 3 0; down=0.1, implicit, l=0V
R2 U1.r1 2; right
W 2 5; right
D2 5 4 led; down
W 4 0; down=0.1, implicit, l=0V
_images/ic1.png

In this example, the chip2121 keyword specifies a block with two pins on the left, one on the bottom, two on the right, and one at the top. The component has pre-defined pinnames, l1, l2, vss, r2, r1, and vdd; these can be modified. Since the pin names start with a dot the associated node names are prefixed by the name of the chip, for example, U1.out1.

The supported chips are:
  • chip1313
  • chip2121
  • chip2222
  • chip3131
  • chip3333
  • chip4141
  • buffer
  • inverter
  • regulator
  • adc
  • dac
  • dff
  • jkff
  • rslatch
  • fdopamp
  • inamp
  • isoamp
  • opamp
  • mux21
  • mux41
  • mux42
_images/Uchip1313.png _images/Uchip2121.png _images/Uchip2222.png _images/Uchip3131.png _images/Uchip3333.png _images/Uchip4141.png _images/Uregulator.png _images/Uadc.png _images/Udac.png _images/Uopamp.png _images/Uinamp.png _images/Ufdopamp.png _images/Uisoamp.png _images/Umux21.png _images/Umux41.png _images/Umux42.png _images/Udff.png _images/Ujkff.png _images/Urslatch.png _images/Uinverter.png _images/Ubuffer.png

Chips are subclassed from the shape class and thus the pins can be labelled, renamed, etc. For example:

U1 chip2222; right, pindefs={sda=b1,scl=b2}, pinlabels={sda=SDA,scl=SCL}, pinnodes=all, pinnames=all
_images/pindefs1.png

Meters

Here’s an example using a voltmeter and an ammeter:

BAT 1 0 7.2; down=1.5, l={7.2\,V}
AM 1 2; right=1.5
R 2 3; down
W 0 3; right
W 2 2_1; right
W 3 3_1; right
VM 2_1 3_1; down
_images/meters2.png

Miscellanous components

Miscellaneous Circuitikz bipole components can be drawn using a MISC component. For example,

MISC1 1 2; right, kind=thermistor, l=thermistor
MISC2 2 3; right, kind=memristor, l=memresistor

_images/misc.png

See the Circuitikz manual for bipole components that can be drawn.

Opamps

Opamps can be drawn using the opamp argument to a VCCS. For example:

E 1 0 opamp 2 3 A; right
;help_lines=1
_images/opamp1.png

The size can be controlled with the scale and size options. The positions of the inverting and non-inverting inputs can be flipped with the mirror option.

E 1 0 opamp 2 3 A; right, scale=0.75, size=0.75
;help_lines=1
_images/opamp2.png
E 1 0 opamp 2 3 A; right, scale=0.75
;help_lines=1
_images/opamp3.png
E 1 0 opamp 2 3 A; right, scale=0.5
;help_lines=1
_images/opamp4.png

Fully differential opamps can be drawn in a similar manner using the fdopamp argument to a VCCS. For example:

E1 1 0 fdopamp 2 3 A; right
;help_lines=1
_images/fdopamp1.png

Opamps and fully differential opamps have additional pins that can be connected:

_images/opamps.png _images/fdopamps.png

Opamps and fully differential opamps can also be drawn without the wires using the integrated circuit syntax. However, these cannot be analysed electrically. For example:

U1 opamp; right
U2 fdopamp; right
W U1.out U2.in+; right
_images/Uopamp1.png

Here are the named connections:

_images/Uopamps.png _images/Ufdopamps.png

Potentiometers

RV1 1 2 3; right
; label_nodes=all
_images/RV1.png

Alternatively, a variable resistor can be defined using:

R 1 2; variable
_images/RV2.png

Switches

Switches can be drawn but they are ignored for analysis since they make the circuit time-varying.

The general format is:

SWname Np Nm nc|no|push

Here’s an example:

SW1 1 2 no; right
SW2 2 3 nc; right
SW3 3 4 push; right
SW4 4 5 6 spdt; right
_images/switches.png

Switches can be mirrored and inverted, for example:

SW1 1 2 no; right
SW2 2 3 no; right, mirror
SW3 3 4 no; right, mirror, invert
SW4 4 5 no; right, invert
_images/switches2.png

Transformers

TF1 1 2 3 4; right
_images/TF1.png
TF1 1 2 3 4 core; right
_images/TFcore1.png
TF1 1 2 3 4 tap _5 _6; right
W 5 _5; right=0.5
W _6 6; right=0.5
_images/TFtap1.png
TF1 1 2 3 4 tapcore _5 _6; right
W 5 _5; right=0.5
W _6 6; right=0.5
_images/TFtapcore1.png

Transistors

Transistors (BJT, JFET, and MOSFET) can be drawn but not analyzed. Both are added to the netlist using a syntax similar to that of SPICE. A BJT is described using:

Qname NC NB NE npn|pnp

where NC, NB, and NE denote the collector, base, and emitter nodes. A MOSFET is described using:

Mname ND NG NS nmos|pmos

where ND, NG, and NS denote the drain, gate, and source nodes.

A JFET is described using:

Jname ND NG NS njf|pjf

where ND, NG, and NS denote the drain, gate, and source nodes.

Here’s an example:

Q1 1 2 3 npn; up
Q2 5 4 3 pnp; up
M1 5 6 7 nmos; up
M2 9 8 7 pmos; up
J1 9 10 11 njf; up
J2 13 12 11 pjf; up
_images/transistors.png

Transmission lines

A transmission line is a two-port device. Here’s an example:

U1 buffer; right
TL1 1 2 U1.out 4; right=2, scale=2, l={50\,$\Omega$}
R 1 2; down
W U1.vdd 9; up=0.1, implicit, l=Vdd
W U1.vss 11; down
W 11 4; right=0.5
W 11 10; down=0.1, implicit, l=Vss
W 5 U1.in; right=0.5
;draw_nodes=connections
_images/tline3.png

The ground wires can be removed using the nowires attribute:

U1 buffer; right
TL1 1 2 U1.out 4; right=2, scale=2, l={50\,$\Omega$}, nowires
W 5 U1.in; right=0.5
;draw_nodes=connections
_images/tline5.png

Mechanical components

Springs, dampers (dashpots), and masses are oneport components for modelling mechanical systems, for example,

k 1 2; right
r 2 3; right
m 3 0; right
_images/massspringdamper1.png

Wires

Wires are useful for schematic formatting, for example,

W 1 2; right

Here an anonymous wire is created since it has no identifier.

The line style of wires can be changed, such as dashed or dotted (see Line styles).

Wires can be implicitly added using the offset attribute. Here’s an example to draw two parallel resistors:

R1 1 2; right, offset=0.25
R2 1 2; right, offset=-0.25
; draw_nodes=connections, label_nodes=none
_images/parallel.png

Stepped wires

Stepped wires can be drawn using the steps attribute. For example:

O 1 2; right=2, rotate=-45
W 1 2; steps=-|, free
_images/steppedwire1.png
O 1 2; right=2, rotate=-45
W 1 2; steps=|-|-, free
_images/steppedwire2.png

In these examples, the free attribute is used so that the wire places no constraints on the node positions. Thus the size and rotate attributes are ignored. The open-circuit component is used to fix the node locations.

The - character represents a horizontal step and the | character represents a vertical step. The shape of the line is controlled by the step pattern. For example –|- represents two steps horizontally, one step vertically, and then one step horizontally. A number before the - or | symbol specifies the number of repeats of the step. For example, steps=-4|- is equivalent to steps=-||||-.

If the step pattern is not specified, a default step pattern -| is chosen if the horizontal extent is longer than the vertical extent and |- is chosen otherwise. For example,

O 1 2; right=2, rotate=-45
W 1 2; steps, free
_images/steppedwire0.png

Arrows

Arrows can be drawn on wires using the startarrow and endarrow attributes. There are many arrow styles, see the tikz manual. For example,

W 1 2; right, endarrow=tri
W 2 3; right, endarrow=otri
W 3 4; right, startarrow=open triangle 90, endarrow=open triangle 90
W 4 5; right, startarrow=stealth, endarrow=stealth
; help_lines=1, draw_nodes=none
_images/arrows.png

Implicit wires

Implicit wires are commonly employed for power supply and ground connections. They have one of the following attributes:

  • implicit equivalent to signal ground
  • sground signal ground
  • ground earth ground
  • cground chassis ground
  • nground noiseless ground
  • pground protected ground
  • rground reference ground
  • vcc positive power supply (voltage to collectors)
  • vdd positive power supply (voltage to drains ;-)
  • vee negative power supply (voltage to emitters)
  • vss negative power supply (voltage to sources)

Here are some ground examples:

# signal ground
W 1 01; down=0.2, sground
W 1 2; right
# earth ground
W 2 02; down=0.2, ground
W 2 3; right
# chassis ground
W 3 03; down=0.2, cground
W 3 4; right
# noiseless ground
W 4 04; down=0.2, nground
W 4 5; right
# protected ground
W 5 05; down=0.2, pground
W 5 6; right
# reference ground
W 6 06; down=0.2, rground
_images/grounds.png

Here are some power supply examples:

R 1 2; right
W 1 1u; up=0.2, vcc
W 2 2d; down=0.2, vss
_images/supplies.png

Connections

These are similar to implicit wires but are useful for denoting an off-sheet connection or an IC pin. They have one of the attributes:

  • input input connection
  • output output connection
  • bidir bidirectional connection
  • pad generic connection

For example:

W 1 2; right=0.2, input, l=input, fill=blue!50
W 3 4; right=0.2, output, l=output
W 5 6; right=0.2, bidir, l=bidir
W 7 8; right=0.2, pad, l=pad
O 1 3; right
O 3 5; right
O 5 7; right
; label_nodes=none


_images/connections1.png

The sizes of the pads can be controlled with the width and aspect attributes.

For example:

W 1 2; right=0.2, input, l=PA0, fill=blue!50
W 3 4; right=0.2, input=1.25, l=PA0
W 5 6; right=0.2, input=1.25, l=PA0, aspect=1.25
W 7 8; right=0.2, input, l=PA0, aspect=0.8
O 1 3; right=1.5
O 3 5; right=1.5
O 5 7; right=1.5
; label_nodes=none


_images/connections2.png

Cables

The kind of cable is specified with the kind attribute. This can be coax, twinax, twistedpair, shieldedtwistedpair, or tline (transmission line). The default is coax. Note, this component is experimental and the syntax may change.

_images/cable.png

Here are some examples:

Cable1; right=2, dashed, kind=coax
W 1 Cable1.in; right=0.5
W Cable1.out 2; right=0.5
_images/cable-coax.png
Cable1; right=2, dashed, kind=twinax
W 1+ Cable1.in+; right=0.5
W 1- Cable1.in-; right=0.5
W Cable1.out+ 2+; right=0.5
W Cable1.out- 2-; right=0.5
_images/cable-twinax.png
Cable1; right=2, dashed, kind=shieldedtwistedpair
W 1+ Cable1.in+; right=0.5
W 1- Cable1.in-; right=0.5
W Cable1.out+ 2+; right=0.5
W Cable1.out- 2-; right=0.5
_images/cable-tp.png
Cable1; right=2, dashed, kind=twistedpair
W 1+ Cable1.in+; right=0.5
W 1- Cable1.in-; right=0.5
W Cable1.out+ 2+; right=0.5
W Cable1.out- 2-; right=0.5
_images/cable-utp.png
Cable1; right=2, kind=tline
W 1 Cable1.in; right=0.5
W Cable1.out 2; right=0.5
_images/cable-tline.png
Cable1; right=4, dashed, kind=coax
W 1 Cable1.in; right=0.5
W Cable1.out 2; right=0.5
# Provide electrical connection
W Cable1.in Cable1.out; free, invisible
W Cable1.ognd 10; down=0.5
Cin Cable1.mid Cable1.b; down=0.2, dashed, scale=0.6, l=
W 2 3; right=1.5
W 3 11; right=0.5
W 3 4; down=0.5
W 5 6; down=0.5
W 6 7; left
W 7 10; up=0.5
R 10 8; right
E 8 0 opamp 4 5 A; left=0.5, mirror, scale=0.5
; label_nodes=none, draw_nodes=connections

_images/guard1.png

Block diagrams

Block diagrams can be constructed with the following components:
  • TF transfer function
  • SPpp, SPpm, SPppp, SPpmm, SPppm summing points
  • MX mixer
  • box rectangular box
  • circle circle (or ellipse)

Here’s an example showing negative feedback:

W 1 14; right=0.5, endarrow=tri, l=V{in}
SP1 pm 14 9 13; right, l={}
W 13 10; endarrow=tri, l=Vd
TR1 10 11 A; right=1.5, l=Open-loop gain (A)
W 11 2; right, l=V{out}
W 2 3; down
TR2 8 12 B; left=1.5, l=Attenuator $\beta$
W 3 8; left, endarrow=tri
W 12 4; left
W 4 9; up, endarrow=tri
W 2 5; right=0.5, endarrow=tri
; draw_nodes=false, label_nodes=false
_images/negative-feedback3.png

Here’s a more complicated example for a causal system:

S1 box; right=1.9, aspect=2.1, draw=white, l={Transfer function\\$H(s)$}
S2 box; right=1.9, aspect=2.1, draw=white, l={Impulse response\\$h(t)$}
S3 box; right=1.9, aspect=2.1, draw=white, l={Frequency response\\$H(\mathrm{j}2\pi f)$ or $H(f)$}
S4 box; right, l={$\mathcal{L}^{-1}\left\{.\right\}$}
S5 box; right, l={$\mathcal{F}\left\{.\right\}$}
S6 box; right, l={$s=\mathrm{j}2\pi f$}
W S1.e S4.w; right=0.4, startarrow=tri, endarrow=tri, color=blue
W S4.e S2.w; right=0.4, startarrow=tri, endarrow=tri, color=black!70!green
W S2.s 4; down, color=black!70!green
W 4 S5.e; left=0.4, endarrow=tri, color=black!70!green
W S5.w S3.e; left=0.4, startarrow=tri, endarrow=tri, color=purple
W S1.s S6.n; down=0.4, endarrow=tri, color=blue
W S6.s S3.n; down=0.4, endarrow=tri, color=purple
O S4.mid S5.mid; down=1.3
; label_nodes=alpha, draw_nodes=none, label_ids=false

_images/LTFT.png

Summing points

There are a number of summing point varieties: SPpp, SPpm, SPppp, SPpmm, SPppm. The p suffix stands for plus, the m suffix stands for minus. The other variations can be generated using the mirror attribute.

Here’s an example:

SP1 pp ._1 ._2 ._3; down
W 1 SP1._1; down=0.5, endarrow=tri
W 2 SP1._2; right=0.5, endarrow=tri
W SP1._3 3; down=0.5, endarrow=tri
; draw_nodes=false
_images/SP4.png

Mixers

Here’s a example of a mixer:

MX1 ._1 ._2 ._3; right
W MX1._1 1; right=0.5, endarrow=tri
W 2 MX1._2; right=0.5, endarrow=tri
W 3 MX1._3; up=0.5, endarrow=tri
_images/MX1.png

Shapes

Shapes include box, circle, ellipse, triangle.

box, circle, ellipse, and triangle shapes have default anchor nodes based on the centre (c) and sixteen directions of the compass: n, nne, ne, ene, e, ese, se, sse, s, ssw, sw, wsw, w, wnw, nw, nww.

_images/Sbox2.png _images/Scircle2.png _images/Striangle2.png

The aspect ratio of box, circle, and triangle can be controlled with the aspect attribute.

Here’s an example of their use:

W x 1; right
W 1 S1.w; right=0.5, endarrow=tri
S1 box; right=0.5, l=$z^{-1}$
S2 circle; right=0.5, l=$\times$
S3 circle; right=0.5, l=$\times$
S4 circle; right=0.5, l=$+$
W S1.e 2; right=0.5
W 3 S4.w; right=1.25, endarrow=tri
W 1 S2.n; down
W S2.s 3; down
W a0 S2.w; right=0.5, endarrow=tri
W 2 S3.n; down, endarrow=tri
W S3.s S4.n; down, endarrow=tri
W a1 S3.w; right=0.5, endarrow=tri
W S4.e y; right=0.5, endarrow=tri
# Align multipliers
O S2.w S3.w; right
; draw_nodes=false, label_nodes=alpha
_images/fir5.png

triangle is an equilateral triangle. Its shape can be changed with the aspect attribute. It has anchors n, e, s, w, c, c1, c2, c3,

The label of a shape can be replaced by an image, using the image keyword. For example,

S1 box; right=4, image=cmos1.png

Each shape has a number of predefined connection pins. Associated with each pin is an optional label.

The pinlabels option can be specified as:
  • all : the default labels for all the pins are shown
  • connected : the default labels for all the connected pins are shown
  • none : none of the default labels are shown
  • {pin1:label1, pin2:label2, …} : the labels are specified for the named pins.
The names of the pins can be drawn using the pinnames option. This has a syntax:
  • all : the pin names for all the pins are shown
  • connected : the pin names for all the connected pins are shown
  • none : none of the pin names are shown
  • {pin1, pin2, …} : the specified pin names are shown.
The nodes of the pins can be drawn using the pinnodes option. This has a syntax:
  • all : the pin nodes for all the pins are shown
  • connected : the pin nodes for all the connected pins are shown
  • none : none of the pin nodes are shown
  • {pin1, pin2, …} : the specified pin nodes are shown.
The pin names can be redefined by the pindefs option. This has a syntax:
  • pindefs={new1=old1, new2=old2, …}

Annotation

Nodes can be annotated using the A net. For example,

R 1 2; right
A1 1; l=hello, anchor=north
A2 2; l=world, anchor=west
; label_nodes=false
_images/annotate1.png

Schematics can be annotated using additional tikz commands in the netlist. These are delimited by a line starting with two semicolons, for example:

C1 1 0 100e-12;down
R1 1 6 1500;right
R2 2 4 1e12;down
C2 3 5 5e-12;down
W 2 3;right
W 0 4;right
W 4 5;right
SW 6 2 no;right, l=
;draw_nodes=connections, label_nodes=False, label_ids=False
;;\node[blue,draw,dashed,inner sep=5mm,anchor=north, fit=(1) (6) (0), label=Human body model] {};
;;\node[blue,draw,dashed,inner sep=5mm, fit=(2) (3) (4) (5), label=CMOS input model]{};

This example draws dashed boxes around the nodes 0, 1, and 6 and 2, 3, 4, and 5:

_images/fit1.png

Alternatively, the boxes can be fit around named components, for example:

;;\node[blue,draw,dashed,inner sep=5mm, fit=(R2) (C2), label=CMOS input model]{};

When referring to an anchor of a component it is necessary to use @ instead of ., for example, U1@tl instead of U1.tl. Here’s an example:

U1 chip3333; right, l={MCU}, pinlabels={vss,vdd}
R1 1 1a; down
V_DD 1a 0; down
L1 1 2; right=1
L2 0 0_2; right
W 2 5; right=0.5
W 0_2 0_5; right=0.5
Cbulk 5 0_5; down=2, kind=electrolytic
L3 5 6; right
L4 0_5 0_6; right
W 6 3; right=0.5
W 0_6 0_3; right=0.5
L5 3 4; right, color=blue
L6 0_3 0_4; right, color=blue
W 4 U1.vdd; down=0.25, color=blue
W 0_4 U1.vss; up=0.25, color=blue
Clocal 6 0_6; down, color=blue
; label_nodes=none, draw_nodes=connections, label_values=false, label_ids=false
;;\node[blue,draw,dashed,inner sep=8mm, fit=(Cbulk) (U1@tl) (U1@br), label=PCB]{};
_images/fit3.png

Styles

Three component styles are supported: american (default), british, and european. The style is set by a style argument to the draw method or by a schematic option. For example,

Vi 1 0_1; down
Rs 1 2; right=1.5
C 2 0; down
W 0_1 0; right
W 0 0_2; right
Rin 2_2 0_2; down, v=V_{in}
W 2 2_2; right
E1 3 0_3 2 0 A; down, l=A V_{in}
Rout 3 4; right=1.5
RL 4 0_4; down, v=V_o
W 0_2 0_3; size=1.2
W 0_3 0_4
P1 4 0_4; down
; style=european
_images/lpf1-buffer-loaded3.png

Colors

By default the components are drawn in black. This can be overridden with the color attribute, for example:

>>> cct.add('R1 1 2; right, color=blue')

Line styles

The line style of wires can be changed using the tikz attributes, dashed, dotted, thick, ultra thick, line width, densely dotted, loosely dashed and many others. For example,

W 1 2; right
W 2 3; right, dashed
W 3 4; right, dotted
W 4 5; right, thick
W 5 6; right, ultra thick
W 6 7; right, ultra thick, dashed
W 7 8; right, line width=4pt
; help_lines=1
_images/wirestyles.png

Labels

Each component has a component identifier label and a value label. These can be augmented by explicit voltage, current, and flow labels.

  • l=label – component label
  • i=label – current label
  • v=label – voltage label
  • f=label – flow label

The label name can be displayed using LaTeX math mode by enclosing the name between dollar signs. Thus superscripts and subscripts can be employed. For example,

>>> cct.add('R1 1 2; right, i=$I_1$, v=$V_{R_1}$')

The component and voltage label positions can be controlled with the ^ and _ attrbutes. The ^ attribute positions the label above the component and the _ attribute positions the label below the component. For example,

R1 1 2; right=1.5, l=A
R2 2 3; right=1.5, l_=B
R3 3 4; right=1.5, l^=C
; label_nodes=none, draw_nodes=none
_images/labels1.png
R1 1 2; right=1.5, v=V_1, l=
R2 2 3; right=1.5, v^=V_2, l=
R3 3 4; right=1.5, v_=V_3, l=
; label_nodes=none, draw_nodes=none
_images/voltage_labels1.png

The current and flow labels have additional < and > attributes to specify the flow direction. If these come before the ^ and _ attributes, the label is positioned at the start of the component otherwise it is positioned at the end of the component.

Here are some examples of current and flow label positioning:

R1 1 2; right=1.5, i=I, l=
R2 2 3; right=1.5, i>^=I, l=$>\wedge$
R3 3 4; right=1.5, i>_=I, l=$>\_$
R4 4 5; right=1.5, i^>=I, l=$\wedge>$
R5 5 6; right=1.5, i_>=I, l=$\_>$
R6 6 7; right=1.5, i<^=-I, l=$<\wedge$
R7 7 8; right=1.5, i<_=-I, l=$<\_$
R8 8 9; right=1.5, i^<=-I, l=$\wedge<$
R9 9 10; right=1.5, i_<=-I, l=$\_<$
; label_nodes=none, draw_nodes=none
_images/current_labels1.png
R1 2 1; left=1.5, i=I, l=
R2 3 2; left=1.5, i>^=I, l=$>\wedge$
R3 4 3; left=1.5, i>_=I, l=$>\_$
R4 5 4; left=1.5, i^>=I, l=$\wedge>$
R5 6 5; left=1.5, i_>=I, l=$\_>$
R6 7 6; left=1.5, i<^=-I, l=$<\wedge$
R7 8 7; left=1.5, i<_=-I, l=$<\_$
R8 9 8; left=1.5, i^<=-I, l=$\wedge<$
R9 10 9; left=1.5, i_<=-I, l=$\_<$
; label_nodes=none, draw_nodes=none
_images/current_labels2.png
R1 1 2; right=1.5, f=I, l=
R2 2 3; right=1.5, f>^=I, l=$>\wedge$
R3 3 4; right=1.5, f>_=I, l=$>\_$
R4 4 5; right=1.5, f^>=I, l=$\wedge>$
R5 5 6; right=1.5, f_>=I, l=$\_>$
R6 6 7; right=1.5, f<^=-I, l=$<\wedge$
R7 7 8; right=1.5, f<_=-I, l=$<\_$
R8 8 9; right=1.5, f^<=-I, l=$\wedge<$
R9 9 10; right=1.5, f_<=-I, l=$\_<$
; label_nodes=none, draw_nodes=none
_images/flow_labels1.png

By default, if a component has a value label it is displayed, otherwise the component identifier is displayed. Both can be displayed using:

>>> cct.draw(label_ids=True, label_values=True)

Schematic options are separated using a comma. If you need a comma, say in a label, enclose the field in braces. For example:

>>> C1 1 0 100e-12; down, size=1.5, v={5\,kV}

Math-mode labels need to be enclosed in $…$. There is an experimental feature that is activated when the label starts with a single un-matched $. In this case, Lcapy tries to generate a nice LaTeX label. For example, words in sub- and superscripts are converted into a roman font using mathrm. This feature is also activated if the label is not enclosed in $…$ but includes an ^ or _.

Voltage labels can be annotated between pairs of nodes using an open-circuit component. For example,

>>> O1 1 0; down, v=V_1

Component attributes

  • size: scale factor for distance between component’s nodes
  • scale: scale factor for length of component
  • rotate: angle in degrees to rotate component anti-clockwise
  • mirror: mirror component in x-axis (opamps, transistors)
  • mirrorinputs: mirror inputs for opamps
  • invisible: connect to the other components but do not draw
  • ignore: do not connect to the other components and do not draw (this is useful for simulating multiple mutual inductances but where it it is too hard to show them on a schematic)
  • free: place no constraints on the node positions; this is useful for stepped wires. With this attribute the size and rotate attributes are ignored.
  • color: component color
  • variable: for variable resistors, inductors, and capacitors
  • kind: electrolytic, polar, or variable for capacitors; variable for inductors
  • fixed: do not stretch
  • aspect: set aspect ratio for boxes
  • pins: define pin labels for ICs
  • anchors: specify which anchors to show
  • offset: distance to orthogonally offset component (useful for parallel components)

Here’s an example using the variable attribute:

V 1 0 ac; down=1.5
L 1 2; right=1.5, variable
R 2 3; down, variable
W 0 3; right
W 2 2_1; right
W 3 3_1; right
C 2_1 3_1; down, variable
_images/variable1.png

Here’s an example using the kind attribute to specify the type of capacitor.

C 1 2; right
Celectrolytic 2 3; right, kind=electrolytic
Cpolar 3 4; right, kind=polar
Cvariable 4 5; right, kind=variable
; label_nodes=false, draw_nodes=connections

_images/capacitors.png

Schematic attributes

  • node_spacing: scale factor for distance between component nodes (default 2).
  • cpt_size: length of component (default 1.5).
  • scale: scale factor (default 1).
  • help_lines: spacing between help lines (default 0 to disable).
  • draw_nodes: specifies which nodes to draw (default primary). Its argument can either be all, connections (nodes that connect at least two components), none, or primary (node names not starting with an underscore).
  • label_nodes: specifies which nodes to label (default primary). Its argument can either be all, alpha (node names starting with a letter), none, or primary (node names not starting with an underscore).
  • label_ids: specifies whether component ids are drawn (default true).
  • label_values: specifies whether component values are drawn (default true).
  • style: specifies the component style. This is either american, british, or european (default american).
  • dpi: dots per inch (default 150) when converting to a PNG file (as used for displaying Jupyter notebooks). This will change the displayed size of the schematic on the screen.

Schematic attributes apply to the whole schematic. They can be specified by starting a netlist with a semicolon, for example,

;help_lines=1, draw_nodes=connections

The schematic attributes can be overridden using arguments to the draw method. For example,

>>> sch.draw(draw_nodes='alpha')

Includes

Large schematics can be composed by including smaller schematics using the .include directive, for example:

.include part1.sch
.include part2.sch

Each of the smaller schematics can be included into their own namespace to avoid conflicts, for example:

.include LC1.sch as s1
.include LC1.sch as s2
W s1.2 s2.1; right=0.1
W s1.3 s2.0; right=0.1

Namespaces

Hierarchical namespaces are supported, for example:

a.R1 1 2; right
b.R1 1 2; right

This creates two resistors: a.R1 with nodes a.1 and a.2 and b.R1 with nodes b.1 and a.2. They can be joined using:

W a.2 b.1; right

When node names start with a dot, they are defined relative to the name of the component, for example:

R1 .p .m; right
W 1 R1.p; right
W R1.m 2; right

Examples

Inverting opamp amplifier

P1 1 0_1; down
R1 1 2; right
R2 2_1 3_1; right
E1 3_2 0_3 opamp 2_0 2 A; mirror
W 0_1 0; right
W 2_0 0; down
W 3_2 3; right
W 0 0_3; right
P2 3 0_3; down
W 2_1 2; down
W 3_1 3_2; down
; draw_nodes=connections
_images/opamp-inverting-amplifier.png

Non-Inverting opamp amplifier

P1 1 0_1; down
W 2_1 2; down
R1 2 0; down
R2 2 3_1; right
W 3_2 3_1; down
E1 3_2 0_3 opamp 1_1 2_1 A;
W 0_1 0; right
W 3_2 3; right
W 0 0_3; right
P2 3 0_3; down
W 1 1_1; right
_images/opamp-noninverting-amplifier.png

Inverting opamp integrator

P1 1 0_1; down
R 1 2; right
C 2_1 3_1; right
E1 3_2 0_3 opamp 2_0 2 A; mirror
W 0_1 0; right
W 2_0 0; down
W 3_2 3; right
W 0 0_3; right
P2 3 0_3; down
W 2_1 2; down
W 3_1 3_2; down
_images/opamp-inverting-integrator.png

CMOS inverter

M1 3_c 2_p Vdd pmos P; right
M2 3_c 2_n 0 nmos N; right
W 2_p 2_c; down=0.5
W 2_c 2_n; down=0.5
W in 2_c; right
W 3_c out; right
P1 in 0_2; down
P2 out 0_3; down
W 0_2 0;right
W 0 0_3;right
_images/cmos1.png

Diode bridge

D1 1 2; left=1.5
D2 3 4; right
D3 1 4; down=1.5
D4 3 2; up
_images/D4.png

Labelled circuit

V1 1 0 step; down
R1 1 2; left=2, i=I_1, v=V_{R_1}
R2 1 3; right=2, i=I_2, v=V_{R_2}
L1 2 0_1; down=2, i=I_1, v=V_{L_1}
L2 3 0_3; down=2, i=I_2, v=V_{L_2}
W 0 0_3; right
W 0 0_1; left
_images/VRL2.png

Loaded opamp model

Vi 1 0_1; down=1.3
Rs 1 2; right=1.5
C 2 0; down
W 0_1 0; right
W 0 0_2; right
Rin 2_2 0_2; down, v=V_{in}
W 2 2_2; right
E1 3 0_3 2 0 A; down, l=A V_{in}
Rout 3 4; right=1.5
RL 4 0_4; down=1.3, v=V_o
W 0_2 0_3; size=1.2
W 0_3 0_4
P1 4 0_4; down
; draw_nodes=connected
_images/lpf1-buffer-loaded2.png

Sallen Key filter

P 1 0; down, v=v_{in}(t)
R1 1 2; right
R2 2 3; right
C1 2 4; up
C2 3 9; down
W 4 5; right
W 5 6; right
W 6 7; down=0
W 7 8; right=0.5
E 7 0 opamp 3 11 A; right, mirror, scale=0.75, size=0.75
W 5 11; down=0.5
P 8 10; down, v^=v_{out}(t)
W 0 9; right
W 9 10; right
;draw_nodes=connections, label_nodes=False, help_lines=1
_images/sallen-key-lpf1.png

CMOS back-drive

U1 inverter; right=2, l={}
U2 inverter; right=2, l={}
W U1.out U2.in; right=1, color=red
W U1.vss 4_2; down=0.3, implicit, l=0V
W U2.vss 4_3; down=0.3, implicit, l=0V
W U1.vdd 3_2; up=0.3, implicit, l=V_{DD1}, color=red
W U2.vdd 3_3; up=0.3, implicit, l=V_{DD2}, color=red
W U2.in 7_1; right=0.25, dashed, fixed, color=red
D1 7_1 6_1; up=0.25, scale=0.5, l=, color=red
D2 6_2 7_1; up=0.25, scale=0.5, l=
W 6_1 U2.vdd; right=0.6, dashed, color=red
W 6_2 U2.vss; right=0.6, dashed
M1 1 2 3 pmos; right=0.25, scale=0.25, l={}, color=red
M2 1 4 5 nmos; right=0.25, scale=0.25, l={}
W 3 3_1; up=0.0, color=red
W 3_1 U1.vdd; right=0.2, dashed, color=red
W 5 5_1; down=0.0
W 5_1 U1.vss; right=0.2, dashed
W 1 U1.out; right, dashed, color=red
;draw_nodes=connections,label_nodes=false,thickness=2

_images/cmos-backdrive2.png

Pierce oscillator

U1 inverter; right
W 5 U1.in; right=0.5
W U1.out 6; right=0.5
W 6 9; right=0.5
R1 7 8; right
W 5 1; down=0.75
W 6 2; down=0.75
W 5 7; up=0.75
W 6 8; up=0.75
XT1 1 2; right
C1  1 4; down=0.8
C2  2 3; down=0.8
W 4 0; down=0.1, implicit, l=GND
W 3 0; down=0.1, implicit, l=GND
; draw_nodes=connections, label_nodes=False
_images/pierce-oscillator.png

Accelerometer

In this example, a dashed wire connects the electrical and mechanical grounds for simulation.

Pm1 1 0_1; down, v=f_1
W 1 0_1; down, dashed
Pm2 2 0_2; down, v=f_2
W 2 0_2; down, dashed
Lm1 1 3; right=3, i>^=u_1
Lm2 3 2; right=3, i^<=u_2
Rm 3 4; down
Cm 4 5; down
TF 5 6 9 0 k; right
W 6 0_6; down
W 0_1 0_10; right
W 0_10 0_6; right, free
W 0_6 0_2; right

Pe 7 0_7; down, v=v
W 7 8; right=0.5, i=i
W 0_7 0_8; right=0.5
W 8 9; right
W 0_8 0; right
C0 8 0_8; down
W 0 0_10; down, dashed
; label_nodes=none, draw_nodes=connections
_images/accelerometer1.png

Customisation

Circuitikz commands (indeed any TikZ/PGF macros) can be embedded in a netlist. Here’s an example that embeds a circuitikz command to change the inductor style:

L1 1 2; right
;; \ctikzset{inductor=cute}
L2 2 3; right
_images/L1.png

File formats

Lcapy uses the filename extension to determine the file format to produce. This must be one of tex, schtex, pgf, png, svg, or pdf. The pgf format is useful for including schematics into LaTeX documents. The tex, schtex, and pgf extension generates a standalone LaTeX file. If no filename is specified, the schematic is displayed on the screen.

By default, the png format is used for interactive drawing. However, being a bit-mapped image, the quality is poor. First, LaTeX is used to create a temporary pdf file; this is then converted to png format. Several strategies are tried to do the conversion:

  1. ghostscript
  2. ImageMagick convert (By default pdf conversions are disabled. On a Linux system edit /etc/ImageMagick-6/policy.xml to enable this conversion.)
  3. pdftoppm (this does a poor job with thin lines)

When using a Jupyter notebook, the svg format can be used with draw(svg=True). However, Jupyter has problems loading multiple svg files.

schtex

schtex is a Python script that will generate a schematic from a netlist file. For example, here’s how a png file can be generated:

>>> schtex Dbridge.sch Dbridge.png

The generated stand-alone LaTeX file can be obtained using:

>>> schtex Dbridge.sch Dbridge.tex

If you wish to include the schematic into a LaTeX file use:

>>> schtex Dbridge.sch Dbridge.pgf

and then include the file with \input{Dbridge.pgf}.

schtex has many command line options to configure the drawing. These override the options specified in the netlist file. For example:

>>> schtex --draw_nodes=connections --label_nodes=false --cpt-size=1 --help_lines=1 Dbridge.sch Dbridge.pdf

One useful option is to renumber the nodes in a netlist. For example,

>>> schtex --renumber='10:1, 11:2' infile.sch outfile.sch

This will choose small integers for the node numbers, honoring the provided mapping. Equipotential nodes will be distinguished using enumerated subscripts, e.g., 1_1, 1_2, 1_3 etc.

Schematics in LaTeX

Here’s an example of how to include an Lcapy schematic in a LaTeX document.

\documentclass[a4paper, 12pt]{article}
\usepackage{circuitikz}

\begin{document}

\begin{figure}
  \centering
  \input{pic4.pgf}
  \caption{RLC network.}
\end{figure}

\end{document}

A PDF file can be produced using:

$ schtex pic4.sch pic4.pgf
$ pdflatex pic4-demo

Drawing tips

Lcapy uses a semi-automated approach to component layout. For each component it needs its orientation and size. By default the size is 1. This is the minimum distance between its nodes (for a one-port device). If the component can be stretched, Lcapy will increase but never decrease this distance.

The x and y positions of nodes are computed independently using a graph. An error can occur if components have the wrong orientation since this makes the graph inconsistent. Unfortunately, it is not trivial to find the offending component so it is best to draw a schematic incrementally and to test it as you go. A sketch on a piece of paper showing the nodes is useful.

Problems can occur using components, such as integrated circuits and opamps, that cannot be stretched. Usually this is due to a conflict between constraints. A solution is to reduce the size of the component if it can be stretched, such as a wire or resistor. Sometimes it is necessary to add a short interconnecting wire.

The stretching of components can be prevented by specifying the fixed attribute.

Additional constraints can be supplied by using an open-circuit to align components.

Grid lines can be added to a schematic using some Tikz markup. For example:

;;\draw[help lines] (0,0) grid [xstep=0.1, ystep=0.1] (10,5);

Unfortunately, the drawing quality depends on the installed version of circuitikz due to slight tweakings of component sizes.