Modules

Lcapy is a Python library for symbolic linear circuit and signal analysis.

Lcapy can analyse circuits described with netlists using modified nodal analysis. See lcapy.netlist

Alternatively, Lcapy can analyse networks and circuits formed by combining one, two, and three port networks. See lcapy.oneport

For detailed documentation see http://lcapy.readthedocs.io/en/latest

Copyright 2014–2022 Michael Hayes, UCECE

lcapy.show_version()

Show versions of Lcapy, SymPy, NumPy, MatplotLib, SciPy, and Python.

Circuit analysis

Circuit

This module provides circuit analysis using modified nodal analysis (MNA).

The circuit is described using netlists, similar to SPICE, but with arbitrary node names (except for the ground node which is labelled 0). The netlists can be loaded from a file or created at run-time. For example:

>>> from lcapy import Circuit
>>> cct = Circuit('''
V_s fred 0
R_a fred 1
R_b 1 0''')

Branch currents and branch voltage differences can be found using the component name as an attribute, for example,

>>> cct.V_s.V.pprint()
>>> cct.R_a.I.pprint()

Nodal voltages (with respect to the ground node) can be found using the node name or number as index, for example,

>>> cct['fred'].V.pprint()
>>> cct[1].V.pprint()

Copyright 2014–2023 Michael Hayes, UCECE

class lcapy.circuit.Circuit(filename=None, netlist=None, allow_anon=False, context=None)

Bases: Netlist, NetfileMixin

The Circuit class is used for describing networks using netlists. Despite the name, it does not require a closed path.

Here’s an example of using the Circuit class:

cct = Circuit(‘’’ V1 1 0 V; down R1 1 2 R; right C1 2 0_2 C; down W 0 0_2; right’’’)

The directions after the semicolon are hints for drawing the schematic and are ignored for the circuit analysis. The last net is a wire to make the schematic look nice; it is not needed for circuit analysis. Indeed the capacitor could be connected directly to nodes 2 and 0.

The nodes are usually numbers but can be any alphanumeric name including underscores. By default, nodes with underscores are not drawn.

The circuit components are also usually numbered but again they can be any alphanumeric name. They can also have anonymous names, as for the wire in the example. Internally they are enumerated sequentially for each component type: W#1, W#2, etc.

The circuit can be displayed using: >>> cct.draw()

The schematic can be saved to a file using: >>> cct.draw(‘schematic.pdf’)

The transform domain voltages across a component can be found using: >>> cct.V1.V

This is found using modified nodal analysis for each type of independent source in the circuit (AC, DC, transient, noise). Once this is performed, the results are cached until the network is modified.

The transform domain currents through a component can be found using: >>> cct.R1.I

The transform domain nodal voltages with respect to the ground node (0) can be found using: cct[2].V

The time domain voltages and currents are displayed using lowercase attributes v and i. For example, >>> cct.C1.v. This is equivalent to >>> cct.C1.V(t).

The impedance between nodes 2 and 0 can be found using: >>> Z = cct.impedance(2, 0)

The open-circuit voltage between nodes 2 and 0 can be found using: >>> Z = cct.Voc(2, 0)

The Thevenin equivalent circuit between nodes 2 and 0 can be found using: >>> thevenin = cct.thevenin(2, 0)

The s-domain model can be drawn using: >>> cct.s_model().draw()

Netlist

This module provides the Netlist class. It could be rolled into the Circuit class.

Copyright 2014–2023 Michael Hayes, UCECE

class lcapy.netlist.Netlist(filename=None, context=None, allow_anon=False)

Bases: NetlistOpsMixin, NetlistMixin, NetlistSimplifyMixin

This class handles a generic netlist with multiple sources. During analysis, subnetlists are created for each source kind (dc, ac, transient, etc). Since linearity is assumed, superposition is employed.

property Idict

Return dictionary of branch currents for each transform domain

property Vdict

Return dictionary of node voltages for each transform domain

ac(omega=None)

Return netlist for ac components of independent sources for angular frequency omega. If omega is undefined, the angular frequency omega0 is used.

See also: dc, transient, laplace.

ac_omega_list()

Return list of the angular frequencies of the sources in the netlist.

annotate(cpts, *args, **kwargs)

Annotate a particular component (or list of components) with specified schematic attributes and return new netlist.

For example: cct.annotate(‘R1’, color=’blue’) cct.annotate(‘R1’, ‘color=blue, dashed’) cct.annotate((‘U1’, ‘U2’), fill=’blue’)

See also highlight.

annotate_current(cpts, domainvar=None, flow=False, pos='')
annotate_currents(cpts=None, domainvar=None, flow=False, eng_format=True, evalf=True, num_digits=3, show_units=True, pos='')

Annotate specified list of component names cpts with current (or flow).

domainvar specifies the domain to calculate the voltages for (e.g., t for time-domain, s for Laplace-domain)

flow (default False) if True annotates current as a flow

eng_format (default True) if True use engineering format if the current is a number, e.g., 100, mV instead of 0.1, V

evalf (default True) if True prints floating point numbers as decimals otherwise they are shown as rationals

show_units (default True) if True applies the units(e.g., V for volts)

pos specifies where to position the labels(see docs)

annotate_node_voltages(nodes=None, domainvar=None, label_voltages=False, eng_format=True, evalf=True, num_digits=3, show_units=True, anchor='south west')

Create a new netlist with the node voltages annotated. This is useful for drawing a schematic with the node voltages shown. For example,

cct.annotate_node_voltages((1, 2, 3)).draw()

nodes is a list of the nodes to annotate or None for all.

domainvar specifies the domain to calculate the voltages for (e.g., t for time-domain, s for Laplace-domain)

label_voltages (default False) if True prefixes the annotation with V1 = for node 1, etc.

eng_format (default True) if True use engineering format if the voltage is a number, e.g., 100, mV instead of 0.1, V

evalf (default True) if True prints floating point numbers as decimals otherwise they are shown as rationals

num_digits (default 3) specfies the number of digits to print for floating point numbers

show_units (default True) if True applies the units(e.g., V for volts)

anchor (default ‘south west’) specifies the position of the voltage label

annotate_voltage(cpts, domainvar=None, pos='')
annotate_voltages(cpts=None, domainvar=None, eng_format=True, evalf=True, num_digits=3, show_units=True, pos='')

Annotate specified list of component names cpts with voltage.

domainvar specifies the domain to calculate the voltages for (e.g., t for time-domain, s for Laplace-domain)

pos specifies where to position the labels, see docs

eng_format (default True) if True use engineering format if the voltage is a number, e.g., 100, mV instead of 0.1, V

evalf (default True) if True prints floating point numbers as decimals otherwise they are shown as rationals

show_units (default True) if True applies the units(e.g., V for volts)

pos specifies where to position the labels(see docs)

apply_test_current_source(Np, Nm=None)

This copies the netlist, kills all the sources, and applies a Dirac delta test current source across the specified nodes. If the netlist is not connected to ground, the negative specified node is connected to ground. The new netlist is returned.

apply_test_voltage_source(Np, Nm=None)

This copies the netlist, kills all the sources, and applies a Dirac delta test voltage source across the specified nodes. If the netlist is not connected to ground, the negative specified node is connected to ground. The new netlist is returned.

branch_current_names()

Return ExprList of branch current names of the form i_cptname for the time-domain and of the form I_cptname othwerwise.

branch_currents()

Return ExprList of branch currents. Each element is a SuperpositionVoltage object.

If you want a vector of time-domain expressions use Vector(cct.branch_currents()(t)).

branch_voltage_names()

Return ExprList of branch voltage names of the form v_cptname for the time-domain and of the form V_cptname othwerwise.

branch_voltages()

Return ExprList of branch voltages. Each element is a SuperpositionVoltage object.

If you want a vector of time-domain expressions use Vector(cct.branch_voltages()(t)).

convert_IVP(t=0)

Remove switches from netlist and convert to an initial value problem. t is used to determine the state of the switches.

property cpts

Return list of component names.

dc()

Return netlist for dc components of independent sources.

See also: ac, transient, laplace.

describe()

Print a message describing how circuit is solved.

description()

Return a message describing how circuit is solved.

evidence_matrix()

Return the evidence matrix. This has a size NxM where N is the number of nodes and M is the number of branches.

An element is 1 for currents entering a node from a branch, -1 for currents leaving a node from a branch, and zero otherwise.

Note, each column sums to zero.

expand()

Expand the netlist, replacing complicated components with simpler components.

get_I(name, nowarn=False)

Current through component (time-domain)

get_Vd(Np, Nm=None, **kwargs)

Voltage drop between nodes (time-domain)

get_i(name)

Time-domain current through component

get_vd(Np, Nm=None)

Time-domain voltage drop between nodes

highlight(cpts, color='blue')

Highlight a particular component (or list of components) with specified color and return new netlist.

See also annotate.

initialize(cct, T=None)

Set the initial values for this netlist based on the values computed for netlist cct at specified time T.

Alternatively, set the initial values using a dictionary of values keyed by the component name.

property kinds

Return list of transform domain kinds required to analyse the netlist.

laplace()

Return netlist for Laplace representations of independent source values.

See also: dc, ac, transient.

loop_analysis()

Perform loop analysis for this netlist. This is cached.

This is currently an alias for mesh_analysis() and so only works for circuits with a planar topology.

matrix_equations(form='default', invert=False)

Return modified nodal analysis equations in matrix form.

Forms can be:

‘default’ ‘A y = b’ ‘b = A y’ ‘Ainv b = y’ ‘y = Ainv b’

If invert is True, evaluate the matrix inverse.

mesh_analysis()

Perform mesh analysis for this netlist. This is cached.

This is only applicable for circuits with a planar topology.

modified_nodal_analysis()

Perform modified nodal analysis for this netlist. This is cached.

nodal_analysis()

Perform nodal analysis for this netlist. This is cached.

noise_model(T='T')

“Create noise model where resistors are converted into a series combination of an ideal resistor and a noise voltage source.

noisy(*args, T='T')

Return a new circuit with the specified resistors in series with noise voltage sources

noisy_except(*args, T='T')

Return a new circuit with all but the specified resistors in series with noise voltage sources

open_circuit(cpt)

Apply open-circuit in series with component. Returns name of open circuit component.

property params

Return list of symbols used as arguments in the netlist.

remove(name)

Remove specified element by name or elements specified in list.

renumber(node_map=None)

Renumber nodes using specified node_map. If node_map not specified then a mapping is created.

replace(oldname, newname)

Replace component.

For example, b = a.replace(‘C’, ‘W’) c = a.replace(‘C1’, ‘C1 1 2’)

replace_switches(t=0, switchnames=None)

Replace specified switches with open-circuit or short-circuit for time at or after t. If switchnames is not specified, all switches are replaced.

replace_switches_before(t=0, switchnames=None)

Replace specified switches with open-circuit or short-circuit for time just before t. If switchnames is not specified, all switches are replaced.

save(filename)

Save netlist to file.

select(kind)

Return new netlist with transform domain kind selected for specified sources in sourcenames.

short_circuit(cpt)

Apply short-circuit across component. Returns name of voltage source component used as the short.

property sim

Generate simulation object.

property ss

Generate state-space representation. See also state_space()

property sub

Return dictionary of subnetlists keyed by transform domain kind. Note, the subnetlists are not created until a specific one is selected.

property subcircuits

Return dictionary of subnetlists keyed by transform domain kind. Note, the subnetlists are not created until a specific one is selected. The subcircuit keys are : ‘ivp’ for an initial value problem solved using Laplace methods, ‘s’ for transient analysis using Laplace methods, ‘dc’ for DC analysis, ‘time’ for time-domain analysis when there are no reactive components, ‘n*’ for noise-analysis (there is a subcircuit for each independent noise source), and omega (where omega is a number of expression specifying the angular frequency) for phasor analysis.

property super_nodes

Super nodes are nodes linked by voltage sources.

switching_times(tmax=1000000000000.0)

Return sorted list of the times that switches activate prior to tmax.

property symbols

Return dictionary of symbols defined in the netlist.

transient()

Return netlist for transient components of independent sources. Note, unlike the similar laplace method, dc and ac components are ignored.

See also: dc, ac, laplace.

property undefined_symbols

Netfile

This module provides the NetfileMixin class. This is used for Netlist and Schematic to parse a netlist file.

Copyright 2020–2023 Michael Hayes, UCECE

class lcapy.netfile.NetfileMixin

Bases: object

This parses netlist files for Netlist and Schematic.

add(string)

Add a component to the netlist. The general form is: ‘Name Np Nm args’ where Name is the component name, Np is the positive node, and Nm is the negative node.

A positive current is defined to flow from the positive node to the negative node.

This returns the added component.

last_added()

Return name of last added component.

netfile_add(pathname)

Add the nets from file with specified pathname

MNA

This module implements modified nodal analysis (MNA).

Copyright 2014–2023 Michael Hayes, UCECE

class lcapy.mna.Branchdict

Bases: ExprDict

class lcapy.mna.MNA(cct, solver_method)

Bases: object

This class performs modified nodal analysis (MNA) on a netlist of components. There are several variants:

1. DC analysis if all the independent sources are DC. The .V and .I methods return DC expressions with the dc assumption set.

2. AC analysis if all the independent sources are AC. The .V and .I methods return phasors.

3. Initial value Laplace analysis if an L or C has an explicit initial value. The .V and .I methods return s-domain expressions with no assumption sets; thus the time-domain results are only valid for t >= 0.

4. General Laplace analysis. If all the sources are causal and all the initial conditions are zero (explicitly or implicitly) then the time-domain results are causal.

  1. Noise analysis.

Note, it is assumed that the user of this class uses superposition to solve problems with mixed independent sources, such as DC and AC.

property A

Return A matrix for MNA

property B

Return B matrix for MNA

property C

Return C matrix for MNA

property D

Return D matrix for MNA

property E

Return E vector for MNA

property G

Return G matrix for MNA

property I

Return I vector for MNA

property Idict

Return dictionary of transform domain branch currents indexed by component name

property Vdict

Return dictionary of transform domain node voltages indexed by node name

property X

Return X vector (of unknowns) for MNA

property Z

Return Z vector for MNA

equations(inverse=False)

System of equations used to find the unknowns.

If inverse is True, evaluate the matrix inverse.

This is for compatibility and is deprecated. Use matrix_equations instead.

matrix_equations(form='default', invert=False)

System of equations used to find the unknowns.

Forms can be:

A y = b b = A y Ainv b = y y = Ainv b

If invert is True, evaluate the matrix inverse.

class lcapy.mna.Nodedict

Bases: ExprDict

Statespace

This module defines the StateSpace class for representing a linear continuous time-invariant system as a state-space model.

Copyright 2021–2023 Michael Hayes, UCECE

class lcapy.statespace.StateSpace(A, B, C, D, u=None, y=None, x=None, x0=None)

Bases: StateSpaceBase

Continuous-time linear time-invariant state space model.

property G

System transfer functions. For a SISO system, use G[0].

property H

X(s) / U(s)

property Lambda

Diagonal matrix of eigenvalues.

property M

Modal matrix (eigenvectors of A).

property P

Characteristic polynomial (aka system polynomial).

lambda(s) = |s * I - A|

property Phi

s-domain state transition matrix.

property U

Laplace transform of input vector.

property Wc

Controllability gramian matrix.

property Wo

Observability gramian matrix.

property Wr

Reachability gramian matrix.

property X

Laplace transform of state-variable vector.

property Y

Laplace transform of output vector.

characteristic_polynomial()

Characteristic polynomial (aka system polynomial).

lambda(s) = |s * I - A|

property controllability_gramian

Controllability gramian matrix.

discretize(method='bilinear', alpha=0.5)

Convert to a discrete-time state space approximation.

The default method is ‘bilinear’. Other methods are ‘forward_euler’, ‘backward_euler’, and ‘gbf’. The latter has a parameter alpha.

property dotx

Time derivative of state variable vector.

classmethod from_circuit(cct, node_voltages=None, branch_currents=None)
property g

System impulse responses.

generalized_bilinear_transform(alpha=0.5)
property h

ILT{X(s) / U(s)}

property observability_gramian

Observability gramian matrix.

output_equations()

System of output equations:

y(t) = C x(t) + D u(t)

where y is the output vector, x is the state vector and u is the input vector.

property phi

State transition matrix.

property reachability_gramian

Reachability gramian matrix. This is equivalent to the controllability gramian matrix for a linear time independent system.

state_equations()

System of first-order differential state equations:

dotx(t) = A x(t) + B u(t)

where x is the state vector and u is the input vector.

property u

Input vector.

property x

State variable vector.

property x0

State variable initial value vector.

property y

Output vector.

Loopanalysis

This module performs loop analysis. It is primarily for showing the equations rather than evaluating them.

Copyright 2019–2023 Michael Hayes, UCECE

class lcapy.loopanalysis.LoopAnalysis(cct)

Bases: object

This performs for loop analysis. Currently, it uses mesh analysis and so is only applicable to circuits with a planar topology.

The API is likely to change since different invocations find different current loops.

>>> from lcapy import Circuit, LoopAnalysis
>>> cct = Circuit('''
... V1 1 0 {u(t)}; down
... R1 1 2; right=2
... L1 2 3; down=2
... W1 0 3; right
... W 1 5; up
... W 2 6; up
... C1 5 6; right=2
...''')

To perform loop analysis in the time domain:

>>> la = LoopAnalysis(cct)

To display the equations found by applying KVL around each mesh:

>>> la.mesh_equations().pprint()

To display the system of equations (in matrix form) that needs to be solved:

>>> la.matrix_equations().pprint()

This only works for dc, ac, or laplace domains. For example,

>>> LoopAnalysis(cct.laplace()).matrix_equations().pprint()
property A

Return A matrix where A y = b.

property b

Return b vector where A y = b.

classmethod from_circuit(cct)
loops()

Return list of loops. Note, the loops can vary for different invocations of the LoopAnalysis class.

loops_by_cpt_name()

Return list of loops specified by cpt name.

matrix_equations(form='default', invert=False)

Return the equations in matrix form.

Forms can be:

‘default’ ‘A y = b’ ‘b = A y’ ‘Ainv b = y’ ‘y = Ainv b’

If invert is True, evaluate the matrix inverse.

mesh_currents()
mesh_equations()

Return mesh equations as a dict keyed by the mesh current.

mesh_equations_list()

Return mesh equations as a list.

property num_loops
pdb()

Enter the python debugger.

solve_laplace()

Determine the unknown voltages using Laplace transforms and return as a dict

property unknowns

Return tuple of the unknown voltages

property y

Return y vector where A y = b.

Nodalanalysis

This module performs nodal analysis. It is primarily for showing the equations rather than for evaluating them.

Copyright 2019–2022 Michael Hayes, UCECE

class lcapy.nodalanalysis.NodalAnalysis(cct, node_prefix='')

Bases: object

This is for nodal analysis.

>>> from lcapy import Circuit, NodalAnalysis
>>> cct = Circuit('''
... V1 1 0 {u(t)}; down
... R1 1 2; right=2
... L1 2 3; down=2
... W1 0 3; right
... W 1 5; up
... W 2 6; up
... C1 5 6; right=2
...''')

To perform nodal analysis in the Laplace domain:

>>> na = NodalAnalysis(cct.laplace())

To display the equations found by applying KCL at each node:

>>> na.nodal_equations().pprint()

To display the system of equations (in matrix form) that needs to be solved:

>>> na.matrix_equations().pprint()

This only works for dc, ac, or laplace domains. For example,

>>> NodalAnalysis(cct.laplace()).matrix_equations().pprint()
property A

Return A matrix where A y = b.

property b

Return b vector where A y = b.

equations_dict()

Return dictionary of equations keyed by node name.

classmethod from_circuit(cct, node_prefix='')
matrix_equations(form='default', invert=False)

Return the equations in matrix form.

Forms can be:

‘default’ ‘A y = b’ ‘b = A y’ ‘Ainv b = y’ ‘y = Ainv b’

If invert is True, evaluate the matrix inverse.

nodal_equations()

Return the equations found by applying KCL at each node. This is a directory of equations keyed by the node name.

property nodes
pdb()

Enter the python debugger.

solve_laplace()

Determine the unknown voltages using Laplace transforms and return as a dict

property unknowns

Return tuple of the unknown voltages

property y

Return y vector where A y = b.

Oneport

This module supports simple linear one-port networks based on the following ideal components:

V independent voltage source I independent current source R resistor C capacitor L inductor

These components are converted to s-domain models and so capacitor and inductor components can be specified with initial voltage and currents, respectively, to model transient responses.

One-ports can either be connected in series (+) or parallel (|) to create a new one-port.

Copyright 2014–2022 Michael Hayes, UCECE

class lcapy.oneport.C(Cval='C', v0=None, **kwargs)

Bases: OnePort

Capacitor

Capacitance Cval, initial voltage v0

current_equation(v, kind='t')

Return expression for current through component given applied voltage.

is_capacitor = True
voltage_equation(i, kind='t')

Return expression for voltage across component given applied current.

class lcapy.oneport.CPE(K, alpha=0.5, **kwargs)

Bases: OnePort

Constant phase element

This has an impedance 1 / (s**alpha * K). When alpha == 0, the CPE is equivalent to a resistor of resistance 1 / K. When alpha == 1, the CPE is equivalent to a capacitor of capacitance K.

When alpha == 0.5 (default), the CPE is a Warburg element.

The phase of the impedance is -pi * alpha / 2.

Note, when alpha is non-integral, the impedance cannot be represented as a rational function and so there are no poles or zeros. So don’t be suprised if Lcapy throws an occasional wobbly.

class lcapy.oneport.FerriteBead(Rs, Rp, Cp, Lp, **kwargs)

Bases: OnePort

Ferrite bead (lossy inductor)

This is modelled as a series resistor (Rs) connected to a parallel R, L, C network (Rp, Lp, Cp).

expand()
class lcapy.oneport.G(Gval='G', **kwargs)

Bases: OnePort

Conductor

current_equation(v, kind='t')

Return expression for current through component given applied voltage.

is_conductor = True
is_noiseless = False
voltage_equation(i, kind='t')

Return expression for voltage across component given applied current.

class lcapy.oneport.I(Ival='Is', **kwargs)

Bases: CurrentSourceBase

Arbitrary current source

class lcapy.oneport.Iac(Ival, phi=0, omega=None, **kwargs)

Bases: CurrentSourceBase

AC current source.

property isc

Short-circuit time-domain current. This is the current flowing out of the positive node of the network, through a wire, and back to the negative node of the network.

netkeyword = 'ac'
class lcapy.oneport.Idc(Ival, **kwargs)

Bases: CurrentSourceBase

DC current source (note a DC current source of current i has an s domain current of i / s).

property isc

Short-circuit time-domain current. This is the current flowing out of the positive node of the network, through a wire, and back to the negative node of the network.

netkeyword = 'dc'
class lcapy.oneport.Inoise(Ival, nid=None, **kwargs)

Bases: CurrentSourceBase

Noise current source.

is_noisy = True
netkeyword = 'noise'
class lcapy.oneport.Istep(Ival, **kwargs)

Bases: CurrentSourceBase

Step current source (s domain current of i / s).

netkeyword = 'step'
class lcapy.oneport.L(Lval='L', i0=None, **kwargs)

Bases: OnePort

Inductor

Inductance Lval, initial current i0

current_equation(v, kind='t')

Return expression for current through component given applied voltage.

is_inductor = True
voltage_equation(i, kind='t')

Return expression for voltage across component given applied current.

class lcapy.oneport.NR(Rval='R', **kwargs)

Bases: R

Noiseless resistor

is_noiseless = True
class lcapy.oneport.Par(*args)

Bases: ParSer

Parallel class

property Isc

Short-circuit current. This is the current flowing out of the positive node of the network, through a wire, and back to the negative node of the network.

property admittance
property has_parallel_V
property height

Convert a string or number to a floating point number, if possible.

property impedance
is_parallel = True
property width

int([x]) -> integer int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by ‘+’ or ‘-’ and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal. >>> int(‘0b100’, base=0) 4

class lcapy.oneport.R(Rval='R', **kwargs)

Bases: OnePort

Resistor

current_equation(v, kind='t')

Return expression for current through component given applied voltage.

is_noiseless = False
is_resistor = True
voltage_equation(i, kind='t')

Return expression for voltage across component given applied current.

class lcapy.oneport.Ser(*args)

Bases: ParSer

Series class

property Voc

Open-circuit voltage.

property admittance
property has_series_I
property height

Convert a string or number to a floating point number, if possible.

property impedance
is_series = True
property width

int([x]) -> integer int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by ‘+’ or ‘-’ and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal. >>> int(‘0b100’, base=0) 4

class lcapy.oneport.V(Vval='V', **kwargs)

Bases: VoltageSourceBase

Arbitrary voltage source

class lcapy.oneport.Vac(V, phi=None, omega=None, **kwargs)

Bases: VoltageSourceBase

AC voltage source.

netkeyword = 'ac'
property voc

Open-circuit time-domain voltage.

class lcapy.oneport.Vdc(Vval, **kwargs)

Bases: VoltageSourceBase

DC voltage source (note a DC voltage source of voltage V has an s domain voltage of V / s).

netkeyword = 'dc'
property voc

Open-circuit time-domain voltage.

class lcapy.oneport.Vnoise(V, nid=None, **kwargs)

Bases: VoltageSourceBase

Noise voltage source.

is_noisy = True
netkeyword = 'noise'
class lcapy.oneport.Vstep(v, **kwargs)

Bases: VoltageSourceBase

Step voltage source (s domain voltage of v / s).

netkeyword = 'step'
class lcapy.oneport.Xtal(C0, R1, L1, C1, **kwargs)

Bases: OnePort

Crystal

This is modelled as a series R, L, C circuit in parallel with C0 (a Butterworth van Dyke model). Note, harmonic resonances are not modelled.

expand()
class lcapy.oneport.Y(Yval='Y', **kwargs)

Bases: OnePort

General admittance.

current_equation(v, kind='t')

Return expression for current through component given applied voltage.

voltage_equation(i, kind='t')

Return expression for voltage across component given applied current.

class lcapy.oneport.Z(Zval='Z', **kwargs)

Bases: OnePort

General impedance.

current_equation(v, kind='t')

Return expression for current through component given applied voltage.

voltage_equation(i, kind='t')

Return expression for voltage across component given applied current.

class lcapy.oneport.i(Ival, **kwargs)

Bases: CurrentSourceBase

Arbitrary t-domain current source

lcapy.oneport.ladder(*args, **kwargs)

Create a ladder oneport network with alternating series and shunt components. If an arg is None, the component is ignored.

ladder(R(1), C(2), R(3)) is equivalent to R(1) + (C(1) | R(3))

ladder(None, R(1), C(2), R(3)) is equivalent to R(1) | (C(1) + R(3))

lcapy.oneport.parallel(*args)

Create a parallel combination of a number of components. Args that are None are ignored. If there is only one non-None component, return that component.

class lcapy.oneport.sI(Ival, **kwargs)

Bases: CurrentSourceBase

Arbitrary s-domain current source

netkeyword = 's'
class lcapy.oneport.sV(Vval, **kwargs)

Bases: VoltageSourceBase

Arbitrary s-domain voltage source

netkeyword = 's'
lcapy.oneport.series(*args)

Create a series combination of a number of components. Args that are None are ignored. If there is only one non-None component, return that component.

class lcapy.oneport.v(vval, **kwargs)

Bases: VoltageSourceBase

Arbitrary t-domain voltage source

Expr

This module provides the Expr class. This attempts to create a consistent interface to SymPy’s expressions.

Copyright 2014–2023 Michael Hayes, UCECE

class lcapy.expr.UnevaluatedExpr(arg, **kwargs)

Bases: Expr

Expression that is not evaluated unless released.

Examples

>>> from sympy import UnevaluatedExpr
>>> from sympy.abc import x
>>> x*(1/x)
1
>>> x*UnevaluatedExpr(1/x)
x*1/x
default_assumptions = {}
doit(**hints)

Evaluate objects that are not evaluated by default like limits, integrals, sums and products. All objects of this kind will be evaluated recursively, unless some species were excluded via ‘hints’ or unless the ‘deep’ hint was set to ‘False’.

>>> from sympy import Integral
>>> from sympy.abc import x
>>> 2*Integral(x, x)
2*Integral(x, x)
>>> (2*Integral(x, x)).doit()
x**2
>>> (2*Integral(x, x)).doit(deep=False)
2*Integral(x, x)
lcapy.expr.deg(arg, **assumptions)

Set units to degrees. See also degrees() that converts radians to degrees.

lcapy.expr.equation(lhs, rhs, inputsym='x', outputsym='y', **assumptions)

Create an Lcapy equation.

This is an Lcapy expression of the form Eq(lhs, rhs). For example, e = equation(‘Y(s)’, ‘X(s) * 2 * s’)

The left hand side(lhs) and right hand side subexpressions can be obtained with the lhs and rhs attributes.

lcapy.expr.expr(arg, var=None, override=False, units=None, **assumptions)

Create Lcapy expression from arg.

If arg is an Expr it is returned, unless assumptions is specified.

If arg is a string:

If a t symbol is found in the string a TimeDomainExpression object is created. If a s symbol is found in the string a LaplaceDomainExpression object is created. If a f symbol is found in the string an FourierDomainExpression object is created. If an omega symbol is found in the string an AngularFourierDomainExpression object is created.

For example, v = expr(‘3 * exp(-t / tau) * u(t)’)

V = expr(‘5 * s’, causal=True)

If override is True, then create new symbol(s) even if previously defined by SymPy.

lcapy.expr.rad(arg, **assumptions)

Set units to radians. See also radians() that converts degrees to radians.

lcapy.expr.symbol(name, **assumptions)

Create Lcapy symbols from whitespace or comma delimited string of symbol names.

By default, symbols are assumed to be positive and real.

symbols(‘a b’, real=True) creates real symbols

symbols(‘a b’, complex=True) creates complex symbols

symbols(‘a b’, integer=True, positive=True) creates positive integer symbols

See also symbols.

lcapy.expr.symbols(names, **assumptions)

Create Lcapy symbols from whitespace or comma delimited string of symbol names. See also symbol.

Sexpr

This module provides the LaplaceDomainExpression class to represent s-domain (Laplace domain) expressions.

Copyright 2014–2023 Michael Hayes, UCECE

class lcapy.sexpr.LaplaceDomainExpression(val, **assumptions)

Bases: LaplaceDomain, Expr

s-domain expression or symbol.

ILT(zero_initial_conditions=None, **assumptions)

Attempt inverse Laplace transform.

If causal=True the response is zero for t < 0 and the result is multiplied by Heaviside(t) If ac=True or dc=True the result is extrapolated for t < 0. Otherwise the result is only known for t >= 0.

By default initial conditions are assumed to be zero. This can be controlled by zero_initial_conditions.

angular_fourier(**assumptions)

Convert to angular Fourier domain.

angular_frequency_response(**assumptions)

Convert to angular frequency response domain. Note, this is similar to the angular Fourier domain but not always.

as_expr()
backward_euler_transform()

Approximate s = ln(z) / dt

by s = (1 / dt) * (1 - z**-1). This is also known as the backward difference method.

See also discretize with regards to scaling of the result.

bilinear_transform()

Approximate s = ln(z) / dt

by s = (2 / dt) * (1 - z**-1) / (1 + z**-1)

This is also called Tustin’s method and is equivalent to the trapezoidal method.

See also discretize with regards to scaling of the result.

bode_plot(fvector=None, unwrap=True, var=None, strict=False, **kwargs)

Plot frequency response for a frequency-domain phasor as a Bode plot (but without the straight line approximations).

If var is None or f, fvector specifies the (linear) frequencies (in hertz) otherwise if var is omega, fvector specifies the angular frequencies (in radians).

If fvector is a tuple (f1, f2), it sets the frequency

limits. Since a logarithmic frequency scale is used, f1 must be greater than 0.

unwrap controls phase unwrapping (default True).

This method makes the assumption that the expression is causal. Note, the Bode plot does not exist for marginally stable and unstable systems since jw is outside the region of convergence.

delay(T)

Apply delay of T seconds by multiplying by exp(-s T).

differential_equation(inputsym='x', outputsym='y', normalize_a0=True)

Create differential equation from transfer function.

For example, >>> H = (s + 3) / (s**2 + 4) >>> H.differential_equation()

d d

y(t) + –(y(t)) = 4.x(t) + —(x(t))
dt 2

dt

discrete_frequency(method='bilinear', **assumptions)
discrete_time(method='bilinear', **assumptions)
discretize(method=None, alpha=0.5, scale=None)

Convert to a discrete-time approximation in the z-domain:

\(H(z) pprox K H_c(s)\)

where \(K\) is a scale factor.

Note, the default scaling is different for admittance, impedance, transfer function, or undefined expressions compared to voltage and current expressions.

The scaling is chosen so that the discrete-time voltage and current expressions have plots similar to the continuous-time forms. For example, with the impulse-invariance method for a continuous-time voltage signal \(v_c(t)\):

\(v[n] = v_c(n \Delta t)\)

However, for a transfer-function with a continuous-time impulse response \(h_c(t)\), then

\(h[n] = \Delta t h_c(n \Delta t)\).

This corrects the scaling when approximating a continuous-time convolution by a discrete-time convolution.

The default method is ‘bilinear’. Other methods are: ‘impulse-invariance’ ‘bilinear’, ‘tustin’, ‘trapezoidal’ ‘generalized-bilinear’, ‘gbf’ controlled by the parameter alpha, ‘euler’, ‘forward-diff’, ‘forward-euler’ ‘backward-diff’, ‘backward-euler’ ‘simpson’, ‘matched-Z’, ‘zero-pole-matching’

dlti_filter(method='bilinear', alpha=0.5)

Create DLTI filter using bilinear transform.

evaluate(svector=None)

Evaluate expression at arg. arg may be a scalar or a vector. The result is of type float or complex.

If arg is iterable, a NumPy array is returned.

There can be only one or fewer undefined variables in the expression. This is replaced by arg and then evaluated to obtain a result.

final_value()

Determine value at t = oo.

forward_euler_transform()

Approximate s = ln(z) / dt

by s = (1 / dt) * (1 - z**-1) / z**-1. This is also known as the forward difference method.

See also discretize with regards to scaling of the result.

fourier(**assumptions)

Convert to Fourier domain.

frequency_response(**assumptions)

Convert to frequency response domain. Note, this is similar to the Fourier domain but not always.

frequency_response_evaluate(fvector=None, var=None, **assumptions)
classmethod from_numer_denom(numer, denom)

Create a transfer function from lists of the coefficient for the numerator and denominator.

See also from_zeros_poles_gain, from_poles_residues.

classmethod from_poles_residues(poles, residues)

Create a transfer function from lists of poles and residues.

See also from_zeros_poles_gain, from_numer_denom.

classmethod from_zeros_poles_gain(zeros, poles, K=1)

Create a transfer function from lists of zeros and poles, and from a constant gain.

See also from_poles_residues, from_numer_denom.

generalized_bilinear_transform(alpha=0.5)

Approximate s = ln(z) / dt

by s = (1 / dt) * (1 - z**-1) / (alpha + (1 - alpha) * z**-1))

When alpha = 0 this is equivalent to the forward Euler (forward difference) method.

When alpha = 0.5 this is equivalent to the bilinear transform, aka, Tustin’s method or the trapezoidal method.

When alpha = 1 this is equivalent to the backward Euler (backward difference) method.

See also discretize with regards to scaling of the result.

impulse_invariance_transform()

This samples the impulse response and then calculates the Z-transform. It does not work if the impulse response has Dirac deltas, say for a transfer function that is a pure delay or is not-strictly proper.

The discrete-time and continuous-time impulse responses are identical at the sampling instants n * dt.

The data needs to be sampled many times the bandwidth to avoid aliasing.

See also bilinear_transform and matched_ztransform.

See also discretize with regards to scaling of the result.

impulse_response(tvector=None)

Evaluate transient (impulse) response.

inverse_laplace(zero_initial_conditions=None, **assumptions)

Attempt inverse Laplace transform.

If causal=True the response is zero for t < 0 and the result is multiplied by Heaviside(t) If ac=True or dc=True the result is extrapolated for t < 0. Otherwise the result is only known for t >= 0.

By default initial conditions are assumed to be zero. This can be controlled by zero_initial_conditions.

property jomega

Return expression with s = j omega.

laplace(**assumptions)

Convert to s-domain.

lti_filter(normalize_a0=True)

Create continuous-time linear time-invariant filter from continuous-time transfer function.

matched_ztransform()

Match poles and zeros of H(s) to approximate H(z).

If there are no zeros, this is equivalent to impulse_invariance.

See also bilinear_transform and impulse_invariance_transform.

See also discretize with regards to scaling of the result.

nichols_plot(fvector=None, var=None, **kwargs)

Plot frequency response for a frequency-domain phasor as a Nichols plot (dB versus phase). fvector specifies the frequencies. If it is a tuple (f1, f2), it sets the frequency limits.

npoints set the number of plotted points.

This method makes the assumption that the expression is causal.

norm_angular_fourier(**assumptions)

Convert to normalized angular Fourier domain.

norm_fourier(**assumptions)

Convert to normalized Fourier domain.

nyquist_plot(fvector=None, var=None, **kwargs)

Plot frequency response for a frequency-domain phasor as a Nyquist plot (imaginary part versus real part). fvector specifies the frequencies. If it is a tuple (f1, f2), it sets the frequency limits.

npoints set the number of plotted points.

The unit circle is shown by default. This can be disabled with unitcircle=False.

This method makes the assumption that the expression is causal.

phasor(**assumptions)

Convert to phasor domain.

phasor_ratio(**assumptions)

Convert to phasor ratio domain.

plot(**kwargs)

Plot pole-zero map.

kwargs include: axes - the plot axes to use otherwise a new figure is created xlabel - the x-axis label (default Re(s)) ylabel - the y-axis label (default Im(s)) xscale - the x-axis scaling yscale - the y-axis scaling pole_color – the color of the pole markers zero_color – the color of the zero markers in addition to those supported by the matplotlib plot command.

The plot axes are returned.

pole_zero_plot(**kwargs)

Plot pole-zero map.

post_initial_value()

Determine post-initial value at t = 0+.

response(xvector, tvector, method='bilinear', alpha=0.5)

Evaluate response to input signal xvector at times specified by tvector. This returns a NumPy array.

The default method is ‘bilinear’. Other methods are: ‘impulse-invariance’ ‘bilinear’, ‘tustin’, ‘trapezoidal’ ‘generalized-bilinear’, ‘gbf’ controlled by the parameter alpha ‘euler’, ‘forward-diff’, ‘forward-euler’ ‘backward-diff’, ‘backward-euler’.

See also discretize with regards to scaling of the result.

simpson_transform()

Approximate s = ln(z) / dt

by s = (3 / dt) * (z**2 - 1) / (z**2 + 4 * z + 1). This is more accurate than the other methods but doubles the system order and can produce unstable poles.

See also discretize with regards to scaling of the result.

property ss

Return state-space representation using controllable canonical form. For other forms, use state_space().

state_space(form='CCF')

Create state-space representation from transfer function. Note, state-space representations are not unique and are determined by the form argument. Currently this can be ‘CCF’ for the controllable canonical form, ‘OCF’ for the observable canonical form, or ‘DCF’ for the diagonal canonical form.

step_response(tvector=None)

Evaluate step response.

tdifferentiate()

Differentiate in t-domain (multiply by s).

time(**assumptions)

Convert to time domain.

If causal=True the response is zero for t < 0 and the result is multiplied by Heaviside(t) If ac=True or dc=True the result is extrapolated for t < 0. Otherwise the result is only known for t >= 0.

tintegrate()

Integrate in t-domain (divide by s).

transient_response(tvector=None)

Evaluate transient (impulse) response.

var = s
zdomain(**assumptions)
lcapy.sexpr.pr2tf(poles, residues, var=None)

Create a transfer function from lists of poles and residues.

lcapy.sexpr.sexpr(arg, **assumptions)

Create LaplaceDomainExpression object. If arg is ssym return s

lcapy.sexpr.tf(numer, denom=1, var=None)

Create a transfer function from lists of the coefficient for the numerator and denominator.

lcapy.sexpr.zp2tf(zeros, poles, K=1, var=None)

Create a transfer function from lists (or dictionaries) of zeros and poles, and from a constant gain.

Cexpr

This module provides the ConstantDomainExpression class to represent constant expressions.

Note there are two types: 1. ConstantTimeDomainExpression for signals 2. ConstantFrequencyResponseDomainExpression for transfer functions and immitances.

Note, impedance(3)(s) gives 3 but voltage(3)(s) gives 3 / s. Similarly, voltage(3)(t) gives 3 but impedance(3)(t) gives 3 * delta)(t)

Copyright 2014–2023 Michael Hayes, UCECE

class lcapy.cexpr.ConstantDomainExpression(val, **assumptions)

Bases: ConstantDomain, ConstantExpr

Constant real expression or symbol.

If symbols in the expression are known to be negative, use ConstantDomainExpression(expr, positive=False)

class lcapy.cexpr.ConstantFrequencyResponseDomainExpression(val, **assumptions)

Bases: ConstantFrequencyResponseDomain, ConstantExpr

This represents constant impedance, admittance, and transfer functions.

Note, impedance(3)(s) gives 3 but voltage(3)(s) gives 3 / s.

laplace(**assumptions)

Convert to Laplace domain representation.

phasor(omega=None, **assumptions)
time(**assumptions)

Convert to time domain.

class lcapy.cexpr.ConstantTimeDomainExpression(val, **assumptions)

Bases: ConstantTimeDomain, ConstantExpr

This represents constant voltage, current, voltage-squared, and current-squared signals.

Note, impedance(3)(s) gives 3 but voltage(3)(s) gives 3 / s.

phasor_ratio(omega=None, **assumptions)
lcapy.cexpr.cexpr(arg, frequency=False, **assumptions)

Create Lcapy constant expression from arg.

By default, arg is assumed to be positive. If symbols in the arg are known to be negative, use cexpr(arg, positive=False).

Texpr

This module provides the TimeDomainExpression class to represent time domain expressions.

Copyright 2014–2023 Michael Hayes, UCECE

class lcapy.texpr.TimeDomainExpression(val, **assumptions)

Bases: TimeDomain, Expr

t-domain expression or symbol.

FT(var=None, evaluate=True, **assumptions)

Attempt Fourier transform.

X(f) = int_{-infty} ^ {infty} x(t) exp(-j 2pi f t) dt.

LT(evaluate=True, zero_initial_conditions=None, **assumptions)

Determine one-sided Laplace transform with 0- as the lower limit.

By default initial conditions are assumed to be zero. This can be controlled by zero_initial_conditions.

This is an alias for laplace.

property abs

Return absolute value.

angular_fourier(evaluate=True, **assumptions)

Attempt angular Fourier transform.

angular_frequency_response(**assumptions)

Convert to angular frequency response domain. Note, this is similar to the angular Fourier domain but not always.

as_expr()
differential_equation(inputsym='x', outputsym='y')

Create differential equation from impulse response.

discrete_frequency(**assumptions)
discrete_time(**assumptions)
discretize(method=None, alpha=0.5)

Convert to a discrete-time approximation:

\(x(n) pprox K x(t)\)

where \(K\) is a scale factor.

The default method depends on the expression quantity. If the quantity is undefined, voltage, current, `voltagesquared, currentsquared, or power, the default method is impulse-invariance and there is no scaling. This uses:

: math: x[n] = x(n Delta t)

For other quantities, the default method is bilinear’, and the result is scaled by the sampling interval (`Delta t) as is common for the discrete-time impulse response of digital filters:

: math: h[n] = Delta t h_c(n Delta t)

The methods are: ‘impulse-invariance’ ‘bilinear’, ‘tustin’, ‘trapezoidal’ ‘generalized-bilinear’, ‘gbf’ controlled by the parameter alpha ‘euler’, ‘forward-diff’, ‘forward-euler’ ‘backward-diff’, ‘backward-euler’ ‘simpson’, ‘matched-Z’, ‘zero-pole-matching’. All the methods except impulse-invariance are applied in the Laplace domain so the result is unknown for n < 0 unless the expression is causal.

dlti_filter(method='bilinear')

Create DLTI filter using bilinear transform.

property energy

Return signal energy.

final_value()

Determine value at t = oo.

force_causal()

Remove the piecewise condition from the expression and multiply by Heaviside function. See also remove_condition.

fourier(var=None, evaluate=True, **assumptions)

Attempt Fourier transform. This is an alias for FT.

frequency_response(**assumptions)

Convert to frequency response domain. Note, this is similar to the Fourier domain but not always.

infer_assumptions()
initial_value()

Determine value at t = 0. See also pre_initial_value and post_initial_value

laplace(evaluate=True, zero_initial_conditions=None, **assumptions)

Determine one-sided Laplace transform with 0- as the lower limit.

By default initial conditions are assumed to be zero. This can be controlled by zero_initial_conditions.

This is an alias for LT.

norm_angular_fourier(evaluate=True, **assumptions)

Attempt normalized angular Fourier transform.

norm_fourier(evaluate=True, **assumptions)

Attempt normalized Fourier transform.

phasor(**assumptions)

Convert to phasor domain.

plot(t=None, **kwargs)

Plot the time waveform. If t is not specified, it defaults to the range(-0.2, 2). t can be a vector of specified instants, a tuple specifing the range, or a constant specifying the maximum value with the minimum value set to 0.

kwargs include: axes - the plot axes to use otherwise a new figure is created xlabel - the x-axis label ylabel - the y-axis label xscale - the x-axis scaling, say for plotting as ms yscale - the y-axis scaling, say for plotting mV plot_deltas - plot Dirac deltas as arrows in addition to those supported by the matplotlib plot command.

The plot axes are returned.

post_initial_value()

Determine value at t = 0+. See also pre_initial_value and initial_value

pre_initial_value()

Determine value at t = 0-. See also initial_value and post_initial_value

response(xvector, tvector, method='bilinear')

Evaluate response to input signal xvector at times tvector. This returns a NumPy array.

sample(tvector)

Return a discrete-time signal evaluated at time values specified by tvector. This returns a NumPy array.

time(**assumptions)
var = t
zdomain(**assumptions)
lcapy.texpr.texpr(arg, **assumptions)

Create TimeDomainExpression object. If arg is tsym return t

Fexpr

This module provides the FourierDomainExpression class to represent f-domain (Fourier domain) expressions.

Copyright 2014–2023 Michael Hayes, UCECE

class lcapy.fexpr.FourierDomainExpression(val, **assumptions)

Bases: FourierDomain, Expr

Fourier domain expression or symbol.

IDTFT(evaluate=True, **assumptions)

Convert to discrete-time domain using inverse discrete-time Fourier transform.

IFT(evaluate=True, **assumptions)

Convert to time domain. This is an alias for inverse_fourier.

angular_fourier(**assumptions)

Convert to angular Fourier domain.

angular_frequency_response(**assumptions)

Convert to angular frequency response domain.

as_expr()
bode_plot(fvector=None, unwrap=True, **kwargs)

Plot frequency response for a frequency-domain phasor as a Bode plot (but without the straight line approximations). fvector specifies the frequencies. If it is a tuple (f1, f2), it sets the frequency limits. Since a logarithmic frequency scale is used, f1 must be greater than 0.

unwrap controls phase unwrapping (default True).

For more info, see plot.

property energy

Return signal energy.

frequency_response(**assumptions)

Convert to frequency response domain.

inverse_fourier(evaluate=True, **assumptions)

Attempt inverse Fourier transform.

laplace(**assumptions)

Determine one-sided Laplace transform with 0- as the lower limit.

nichols_plot(fvector=None, log_frequency=True, **kwargs)

Plot frequency response as a Nichols plot (dB part versus phase). fvector specifies the frequencies. If it is a tuple (f1, f2), it sets the frequency limits as (f1, f2).

npoints set the number of plotted points.

norm_angular_fourier(**assumptions)

Convert to normalized angular Fourier domain.

norm_fourier(**assumptions)

Convert to normalized Fourier domain.

nyquist_plot(fvector=None, log_frequency=True, **kwargs)

Plot frequency response as a Nyquist plot (imaginary part versus real part). fvector specifies the frequencies. If it is a tuple (f1, f2), it sets the frequency limits as (f1, f2).

npoints set the number of plotted points.

The unit circle is shown by default. This can be disabled with unitcircle=False.

phasor(**assumptions)

Convert to phasor domain.

plot(fvector=None, plot_type=None, **kwargs)

Plot frequency response at values specified by fvector.

If fvector is a tuple, this sets the frequency limits.

plot_type - ‘dB-phase’, ‘dB-phase-degrees’, ‘mag-phase’, ‘mag-phase-degrees’, ‘real-imag’, ‘mag’, ‘phase’, ‘phase-degrees’, ‘real’, or ‘imag’.

The default plot_type for complex data is dB-phase.

kwargs include: axes - the plot axes to use otherwise a new figure is created xlabel - the x-axis label ylabel - the y-axis label ylabel2 - the second y-axis label if needed, say for mag and phase xscale - the x-axis scaling, say for plotting as ms yscale - the y-axis scaling, say for plotting mV norm - use normalized frequency dbmin - the smallest value to plot in dB (default -120) plot_deltas - plot Dirac deltas as arrows in addition to those supported by the matplotlib plot command.

The plot axes are returned. This is a tuple for magnitude/phase or real/imaginary plots.

There are many plotting options, see lcapy.plot and matplotlib.pyplot.plot.

For example:

V.plot(fvector, log_frequency=True) V.real.plot(fvector, color=’black’) V.phase.plot(fvector, color=’black’, linestyle=’–‘)

By default complex data is plotted as separate plots of magnitude (dB) and phase.

time(**assumptions)
var = f
lcapy.fexpr.fexpr(arg, **assumptions)

Create FourierDomainExpression object. If arg is fsym return f

Nexpr

This module provides the DiscreteTimeDomainExpression class to represent discrete-time expressions.

Copyright 2020–2023 Michael Hayes, UCECE

lcapy.nexpr.nexpr(arg, **assumptions)

Create nExpr object. If arg is nsym return n

Kexpr

This module provides the DiscreteFourierDomainExpression class to

represent k-domain (discrete Fourier domain) expressions.

Copyright 2020–2021 Michael Hayes, UCECE

lcapy.kexpr.kexpr(arg, **assumptions)

Create kExpr object. If arg is ksym return k

Zexpr

This module provides the ZDomainExpression class to represent z-domain expressions.

Copyright 2020–2022 Michael Hayes, UCECE

lcapy.zexpr.zexpr(arg, **assumptions)

Create ZDomainExpression object. If arg is zsym return z

Sequence

This module handles sequences.

Copyright 2020–2023 Michael Hayes, UCECE

class lcapy.sequence.Sequence(seq, ni=None, origin=None, evaluate=False, var=None, start_trunc=False, end_trunc=False)

Bases: ExprList, SeqDomain

DTFT(var=None, **assumptions)

Convert to Fourier domain using discrete time Fourier transform.

as_array()

Numerically evaluate and store as NumPy array.

as_impulses(var=None)

Convert to discrete-time signal in the form of a weighted sum of delayed impulses. For example, {1, 2, 3} -> ui[n] + 2 * ui[n - 1] + 3 * ui[n - 2]

convolve(h, mode='full')

Convolve with h.

copy()

Return a shallow copy of the list.

delay(m=0)

Return a new sequence delayed by an integer number of samples m. If m is negative, the sequence is advanced.

discrete_time_fourier_transform(var=None, **assumptions)

Convert to Fourier domain using discrete time Fourier transform.

evaluate(ni=None)

Evaluate expression at sequence indices specified by arg. arg may be a scalar or a vector. The result is of type float or complex. Zeroes are returned for indices outside the sequence extent.

If arg is iterable, a NumPy array is returned.

property expr

Convert sequence to an Lcapy expression.

property extent

Determine extent of the sequence.

For example, Sequence([1, 1]).extent = 2

Sequence([1, 0, 1]).extent = 3 Sequence([0, 1, 0, 1]).extent = 3

is_sequence = True
lfilter(b=None, a=None)

Implement digital filter specified by a transfer function. The transfer function is described by a vector b of coefficients for the numerator and an a vector of coefficients for the denominator.

If you would like the response with initial conditions see DTfilter.response().

For a FIR filter a = [1].

property origin

Return the element index for n == 0. This may raise a ValueError if the origin is not in the sequence.

plot(ni=None, **kwargs)

Plot the sequence. If ni is not specified, it defaults to the sequence indices. ni can be a vector of specified sequence indices, a tuple specifing the range, or a constant specifying the maximum value with the minimum value set to 0.

kwargs include: axes - the plot axes to use otherwise a new figure is created xlabel - the x-axis label ylabel - the y-axis label xscale - the x-axis scaling, say for plotting as ms yscale - the y-axis scaling, say for plotting mV in addition to those supported by the matplotlib plot command.

The plot axes are returned.

pretty(**kwargs)

Make pretty string.

prune()

Remove zeros from ends of sequence.

{0, 0, 1, 2, 3, 0} -> {1, 2, 3}

quantity = 'undefined'
property vals

Return the SymPy values as a list.

var = None
zeroextend()

Extend sequence by adding zeros so that the origin is included. This is used for printing.

zeropad(M)

Add M zeros to end of sequence:

For example, with M = 3

{1, 2, 3} -> {1, 2, 3, 0, 0, 0}

lcapy.sequence.parse_seq_str(s)

Omegaexpr

This module provides the AngularFourierDomainExpression class to represent omega-domain (angular frequency Fourier domain) expressions.

Copyright 2014–2022 Michael Hayes, UCECE

lcapy.omegaexpr.omegaexpr(arg, **assumptions)

Create AngularFourierDomainExpression object. If arg is omegasym return omega

Noiseexpr

This module provides the NoiseExpression class to represent noise expressions.

Copyright 2020–2022 Michael Hayes, UCECE

class lcapy.noiseexpr.NoiseExpression(val, **assumptions)

Bases: Expr

Frequency domain (one-sided) noise spectrum expression (amplitude spectral density).

This characterises a zero-mean Gaussian noise process.

When performing arithmetic on two noiseExpr expressions it is assumed that they are uncorrelated unless they have the same nid (noise indentifier). If the nid is not specified, a new one is created.

Uncorrelated noise expressions are added in quadrature (on a power basis). Thus (NoiseExpression(3) + NoiseExpression(4)).expr = 5 since 5 = sqrt(3**2 + 4**2)

NoiseExpression(3) != NoiseExpression(3) since they are different noise realisations albeit with the same properties. However, NoiseExpression(3).expr == NoiseExpression(3).expr. Similarly, NoiseExpression(3, nid=’n1’) == NoiseExpression(3, nid=’n1’) since they have the same noise identifier and thus have the same realisation.

Caution: The sum of two noise expressions generates a noise expression with a new nid. This can lead to unexpected results since noise expressions with different nids are assumed to be uncorrelated. For example, consider: a = NoiseExpression(3); b = NoiseExpression(4) a + b - b gives sqrt(41) and a + b - a gives sqrt(34).

This case is correctly handled by the Super class since each noise component is stored and considered separately.

(Voltage(a) + Voltage(b) - Voltage(b)).n gives 3 as expected.

asd()
autocorrelation()
fourier()
is_positive = True
is_real = True
laplace()
property nid
plot(fvector=None, **kwargs)

Plot frequency response at values specified by fvector.

There are many plotting options, see matplotlib.pyplot.plot.

For example:

V.plot(fvector, log_frequency=True) V.real.plot(fvector, color=’black’) V.phase.plot(fvector, color=’black’, linestyle=’–‘)

By default complex data is plotted as separate plots of magnitude (dB) and phase.

psd()
rms()

Calculate rms value.

sample(t, seed=None)

Return a sample function (realisation) of the noise process evaluated at time values specified by vector t. If t is an integer, this returns t samples.

subs(*args, **kwargs)

Substitute symbols in expression.

args is either: - two arguments, e.g. foo.subs(old, new) - one iterable argument, e.g. foo.subs(iterable). The iterable may be

o an iterable container with (old, new) pairs. In this case the

replacements are processed in the order given with successive patterns possibly affecting replacements already made.

o a dict or set whose key/value items correspond to old/new pairs.

The domain of the result can be coerced using domain argument.

time()

Phasor

This module provides the PhasorDomain and PhasorRatioDomain classes

to represent phasors and ratios of phasors for AC analysis.

A phasor represents the amplitude and phase for a single sinusoid. By default the angular frequency is omega_0 but it can be any number or symbol.

Phasors straddle the time and frequency domains and hence the confusing phasor classes.

A phasor is described by an amplitude and phase. There is also an implicit frequency. The amplitude and phase are usually functions of frequency. A phasor is useful to describe an AC voltage or current signal.

Lcapy considers V(jw) or I(jw) a generic phasor but V(3j) or I(3j) a specific phasor. Similarly, X(jw) is a generic phasor ratio and X(3j) is a specific phasor ratio, where X denotes an immittance or transfer function.

A ratio of two phasors (of the same frequency) is not a phasor. The ratio of two generic phasors is a frequency domain quantity. The frequency dependence is explicit. A phasor ratio is useful to describe an immittance or transfer function. These are frequency domain concepts. A phasor ratio can be inferred from the Laplace domain by substituting jomega (or jw) for s, where omega is the angular frequency of the phasor.

Copyright 2014–2023 Michael Hayes, UCECE

class lcapy.phasor.PhasorDomainExpression(val, **assumptions)

Bases: PhasorDomain, PhasorExpression

This is a phasor domain base class for voltages and currents.

angular_fourier(**assumptions)

Angular Fourier transform.

as_expr()
fourier(**assumptions)

Fourier transform.

classmethod from_constant(expr, omega=None, **assumptions)
classmethod from_time(expr, omega=None, **assumptions)
laplace(**assumptions)

Convert to Laplace domain representation.

plot(**kwargs)

Plot polar diagram.

time(**assumptions)

Convert to time domain representation.

class lcapy.phasor.PhasorRatioDomainExpression(val, **assumptions)

Bases: PhasorRatioDomain, PhasorExpression

This represents the ratio of two-phasors; for example an impedance, an admittance, or a transfer function.

angular_fourier(**assumptions)

Angular Fourier transform.

as_expr()
bode_plot(fvector=None, unwrap=True, **kwargs)

Plot frequency response for a frequency-domain phasor as a Bode plot (but without the straight line approximations). fvector specifies the frequencies. If it is a tuple (m1, m2), it sets the frequency limits as (10**m1, 10**m2).

unwrap controls phase unwrapping (default True).

property domain_label

str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to ‘strict’.

property domain_units

Expression representing multiplication operation for algebraic field.

Deprecated since version 1.7: Using arguments that aren’t subclasses of Expr in core operators (Mul, Add, and Pow) is deprecated. See non-expr-args-deprecated for details.

Every argument of Mul() must be Expr. Infix operator * on most scalar objects in SymPy calls this class.

Another use of Mul() is to represent the structure of abstract multiplication so that its arguments can be substituted to return different class. Refer to examples section for this.

Mul() evaluates the argument unless evaluate=False is passed. The evaluation logic includes:

  1. Flattening

    Mul(x, Mul(y, z)) -> Mul(x, y, z)

  2. Identity removing

    Mul(x, 1, y) -> Mul(x, y)

  3. Exponent collecting by .as_base_exp()

    Mul(x, x**2) -> Pow(x, 3)

  4. Term sorting

    Mul(y, x, 2) -> Mul(2, x, y)

Since multiplication can be vector space operation, arguments may have the different sympy.core.kind.Kind(). Kind of the resulting object is automatically inferred.

Examples

>>> from sympy import Mul
>>> from sympy.abc import x, y
>>> Mul(x, 1)
x
>>> Mul(x, x)
x**2

If evaluate=False is passed, result is not evaluated.

>>> Mul(1, 2, evaluate=False)
1*2
>>> Mul(x, x, evaluate=False)
x*x

Mul() also represents the general structure of multiplication operation.

>>> from sympy import MatrixSymbol
>>> A = MatrixSymbol('A', 2,2)
>>> expr = Mul(x,y).subs({y:A})
>>> expr
x*A
>>> type(expr)
<class 'sympy.matrices.expressions.matmul.MatMul'>

See Also

MatMul

fourier(**assumptions)

Fourier transform.

classmethod from_laplace(expr, **assumptions)
is_phasor_ratio_domain = True
is_transform_domain = True
laplace(**assumptions)

Convert to Laplace domain representation.

plot(fvector=None, **kwargs)

Plot frequency response.

If the dependent variable is omega, fvector specifies the angular frequencies. If it is a tuple, it sets the angular frequency limits.

If the dependent variable is f, fvector specifies the linear frequencies. If it is a tuple, it sets the linear frequency limits.

time(**assumptions)

Convert to time domain representation.

lcapy.phasor.phasor(arg, omega=None, **assumptions)

Create phasor.

If arg has the form A * cos(w * t + phi) the phasor A * exp(j * phi) of angular frequency w is returned.

If arg has the form A * sin(w * t + phi) the phasor A * exp(j * (phi - pi / 2)) of angular frequency w is returned.

If arg is a constant C, the phasor C is created with omega as the angular frequency (this defaults to ‘omega’ if not specified).

lcapy.phasor.phasor_ratio(arg, omega=None, **assumptions)

Create phasor ratio.

If arg is a constant C, the phasor ratio C is created with omega as the angular frequency (this defaults to ‘omega’ if not specified).

Matrix

This module implements the Lcapy Matrix class.

Copyright 2019–2023 Michael Hayes, UCECE

class lcapy.matrix.Matrix(*args, **kwargs)

Bases: MutableDenseMatrix

canonical()
property conj

Complex conjugate; for compatilibility with Expr, conj is an attribute.

det()

Computes the determinant of a matrix if M is a concrete matrix object otherwise return an expressions Determinant(M) if M is a MatrixSymbol or other expression.

Parameters

methodstring, optional

Specifies the algorithm used for computing the matrix determinant.

If the matrix is at most 3x3, a hard-coded formula is used and the specified method is ignored. Otherwise, it defaults to 'bareiss'.

Also, if the matrix is an upper or a lower triangular matrix, determinant is computed by simple multiplication of diagonal elements, and the specified method is ignored.

If it is set to 'domain-ge', then Gaussian elimination method will be used via using DomainMatrix.

If it is set to 'bareiss', Bareiss’ fraction-free algorithm will be used.

If it is set to 'berkowitz', Berkowitz’ algorithm will be used.

Otherwise, if it is set to 'lu', LU decomposition will be used.

Note

For backward compatibility, legacy keys like “bareis” and “det_lu” can still be used to indicate the corresponding methods. And the keys are also case-insensitive for now. However, it is suggested to use the precise keys for specifying the method.

iszerofuncFunctionType or None, optional

If it is set to None, it will be defaulted to _iszero if the method is set to 'bareiss', and _is_zero_after_expand_mul if the method is set to 'lu'.

It can also accept any user-specified zero testing function, if it is formatted as a function which accepts a single symbolic argument and returns True if it is tested as zero and False if it tested as non-zero, and also None if it is undecidable.

Returns

detBasic

Result of determinant.

Raises

ValueError

If unrecognized keys are given for method or iszerofunc.

NonSquareMatrixError

If attempted to calculate determinant from a non-square matrix.

Examples

>>> from sympy import Matrix, eye, det
>>> I3 = eye(3)
>>> det(I3)
1
>>> M = Matrix([[1, 2], [3, 4]])
>>> det(M)
-2
>>> det(M) == M.det()
True
>>> M.det(method="domain-ge")
-2
discretize(method=None, alpha=0.5, drop_dt=False)
evaluate(arg=None)

Evaluate matrix at arg. arg may be a scalar. The result is a NumPy float or complex array.

There can be only one or fewer undefined variables in the expression. This is replaced by arg and then evaluated to obtain a result.

property expr
inv(method='default')

Return the inverse of a matrix using the method indicated. Default for dense matrices is is Gauss elimination, default for sparse matrices is LDL.

Parameters

method : (‘GE’, ‘LU’, ‘ADJ’, ‘CH’, ‘LDL’)

iszerofuncfunction, optional

Zero-testing function to use.

try_block_diagbool, optional

If True then will try to form block diagonal matrices using the method get_diag_blocks(), invert these individually, and then reconstruct the full inverse matrix.

Examples

>>> from sympy import SparseMatrix, Matrix
>>> A = SparseMatrix([
... [ 2, -1,  0],
... [-1,  2, -1],
... [ 0,  0,  2]])
>>> A.inv('CH')
Matrix([
[2/3, 1/3, 1/6],
[1/3, 2/3, 1/3],
[  0,   0, 1/2]])
>>> A.inv(method='LDL') # use of 'method=' is optional
Matrix([
[2/3, 1/3, 1/6],
[1/3, 2/3, 1/3],
[  0,   0, 1/2]])
>>> A * _
Matrix([
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]])
>>> A = Matrix(A)
>>> A.inv('CH')
Matrix([
[2/3, 1/3, 1/6],
[1/3, 2/3, 1/3],
[  0,   0, 1/2]])
>>> A.inv('ADJ') == A.inv('GE') == A.inv('LU') == A.inv('CH') == A.inv('LDL') == A.inv('QR')
True

Notes

According to the method keyword, it calls the appropriate method:

GE …. inverse_GE(); default for dense matrices LU …. inverse_LU() ADJ … inverse_ADJ() CH … inverse_CH() LDL … inverse_LDL(); default for sparse matrices QR … inverse_QR()

Note, the GE and LU methods may require the matrix to be simplified before it is inverted in order to properly detect zeros during pivoting. In difficult cases a custom zero detection function can be provided by setting the iszerofunc argument to a function that should return True if its argument is zero. The ADJ routine computes the determinant and uses that to detect singular matrices in addition to testing for zeros on the diagonal.

See Also

inverse_ADJ inverse_GE inverse_LU inverse_CH inverse_LDL

Raises

ValueError

If the determinant of the matrix is zero.

property is_complex
latex(**kwargs)
next_timestep()
norm()

Return the Norm of a Matrix or Vector.

In the simplest case this is the geometric size of the vector Other norms can be specified by the ord parameter

ord

norm for matrices

norm for vectors

None

Frobenius norm

2-norm

‘fro’

Frobenius norm

  • does not exist

inf

maximum row sum

max(abs(x))

-inf

min(abs(x))

1

maximum column sum

as below

-1

as below

2

2-norm (largest sing. value)

as below

-2

smallest singular value

as below

other

  • does not exist

sum(abs(x)**ord)**(1./ord)

Examples

>>> from sympy import Matrix, Symbol, trigsimp, cos, sin, oo
>>> x = Symbol('x', real=True)
>>> v = Matrix([cos(x), sin(x)])
>>> trigsimp( v.norm() )
1
>>> v.norm(10)
(sin(x)**10 + cos(x)**10)**(1/10)
>>> A = Matrix([[1, 1], [1, 1]])
>>> A.norm(1) # maximum sum of absolute values of A is 2
2
>>> A.norm(2) # Spectral norm (max of |Ax|/|x| under 2-vector-norm)
2
>>> A.norm(-2) # Inverse spectral norm (smallest singular value)
0
>>> A.norm() # Frobenius Norm
2
>>> A.norm(oo) # Infinity Norm
2
>>> Matrix([1, -2]).norm(oo)
2
>>> Matrix([-1, 2]).norm(-oo)
1

See Also

normalized

property numpy

Return NumPy array; not a NumPy matrix.

pdb()

Enter the python debugger.

pprint()
replace(query, value, map=False, simultaneous=True, exact=None)

Replaces Function F in Matrix entries with Function G.

Examples

>>> from sympy import symbols, Function, Matrix
>>> F, G = symbols('F, G', cls=Function)
>>> M = Matrix(2, 2, lambda i, j: F(i+j)) ; M
Matrix([
[F(0), F(1)],
[F(1), F(2)]])
>>> N = M.replace(F,G)
>>> N
Matrix([
[G(0), G(1)],
[G(1), G(2)]])
rewrite(*args, **hints)
simplify()

Simplify the elements of the matrix.

subs(*args, **kwargs)

Substitute variables in expression, see sympy.subs for usage.

property symbols
property sympy
lcapy.matrix.matrix(mat)

Create Lcapy Matrix from a SymPy Matrix.

If a t symbol is found in an element a tMatrix object is created. If a s symbol is found in an element an sMatrix object is created.

lcapy.matrix.matrix_inverse(M, method='default')
lcapy.matrix.matrix_solve(M, b, method='default')
lcapy.matrix.msympify(expr)

Smatrix

This module implements the LaplaceDomainMatrix class for a matrix of Laplace-domain expressions.

Copyright 2019–2023 Michael Hayes, UCECE

class lcapy.smatrix.LaplaceDomainAdmittanceMatrix(*args, **kwargs)

Bases: LaplaceDomainMatrix

class LaplaceDomainAdmittance(val, **assumptions)

Bases: AdmittanceMixin, LaplaceDomainExpression

Angular frequency-domain admittance (units S).

class lcapy.smatrix.LaplaceDomainCurrentMatrix(*args, **kwargs)

Bases: LaplaceDomainMatrix

class LaplaceDomainCurrent(val, **assumptions)

Bases: CurrentMixin, LaplaceDomainExpression

Angular frequency-domain current (units A/Hz).

class lcapy.smatrix.LaplaceDomainImpedanceMatrix(*args, **kwargs)

Bases: LaplaceDomainMatrix

class LaplaceDomainImpedance(val, **assumptions)

Bases: ImpedanceMixin, LaplaceDomainExpression

Angular frequency-domain impedance (units ohm).

class lcapy.smatrix.LaplaceDomainMatrix(*args, **kwargs)

Bases: Matrix

ILT(**assumptions)
class LaplaceDomainExpression(val, **assumptions)

Bases: LaplaceDomain, Expr

s-domain expression or symbol.

ILT(zero_initial_conditions=None, **assumptions)

Attempt inverse Laplace transform.

If causal=True the response is zero for t < 0 and the result is multiplied by Heaviside(t) If ac=True or dc=True the result is extrapolated for t < 0. Otherwise the result is only known for t >= 0.

By default initial conditions are assumed to be zero. This can be controlled by zero_initial_conditions.

angular_fourier(**assumptions)

Convert to angular Fourier domain.

angular_frequency_response(**assumptions)

Convert to angular frequency response domain. Note, this is similar to the angular Fourier domain but not always.

as_expr()
backward_euler_transform()

Approximate s = ln(z) / dt

by s = (1 / dt) * (1 - z**-1). This is also known as the backward difference method.

See also discretize with regards to scaling of the result.

bilinear_transform()

Approximate s = ln(z) / dt

by s = (2 / dt) * (1 - z**-1) / (1 + z**-1)

This is also called Tustin’s method and is equivalent to the trapezoidal method.

See also discretize with regards to scaling of the result.

bode_plot(fvector=None, unwrap=True, var=None, strict=False, **kwargs)

Plot frequency response for a frequency-domain phasor as a Bode plot (but without the straight line approximations).

If var is None or f, fvector specifies the (linear) frequencies (in hertz) otherwise if var is omega, fvector specifies the angular frequencies (in radians).

If fvector is a tuple (f1, f2), it sets the frequency

limits. Since a logarithmic frequency scale is used, f1 must be greater than 0.

unwrap controls phase unwrapping (default True).

This method makes the assumption that the expression is causal. Note, the Bode plot does not exist for marginally stable and unstable systems since jw is outside the region of convergence.

delay(T)

Apply delay of T seconds by multiplying by exp(-s T).

differential_equation(inputsym='x', outputsym='y', normalize_a0=True)

Create differential equation from transfer function.

For example, >>> H = (s + 3) / (s**2 + 4) >>> H.differential_equation()

d d

y(t) + –(y(t)) = 4.x(t) + —(x(t))
dt 2

dt

discrete_frequency(method='bilinear', **assumptions)
discrete_time(method='bilinear', **assumptions)
discretize(method=None, alpha=0.5, scale=None)

Convert to a discrete-time approximation in the z-domain:

\(H(z) pprox K H_c(s)\)

where \(K\) is a scale factor.

Note, the default scaling is different for admittance, impedance, transfer function, or undefined expressions compared to voltage and current expressions.

The scaling is chosen so that the discrete-time voltage and current expressions have plots similar to the continuous-time forms. For example, with the impulse-invariance method for a continuous-time voltage signal \(v_c(t)\):

\(v[n] = v_c(n \Delta t)\)

However, for a transfer-function with a continuous-time impulse response \(h_c(t)\), then

\(h[n] = \Delta t h_c(n \Delta t)\).

This corrects the scaling when approximating a continuous-time convolution by a discrete-time convolution.

The default method is ‘bilinear’. Other methods are: ‘impulse-invariance’ ‘bilinear’, ‘tustin’, ‘trapezoidal’ ‘generalized-bilinear’, ‘gbf’ controlled by the parameter alpha, ‘euler’, ‘forward-diff’, ‘forward-euler’ ‘backward-diff’, ‘backward-euler’ ‘simpson’, ‘matched-Z’, ‘zero-pole-matching’

dlti_filter(method='bilinear', alpha=0.5)

Create DLTI filter using bilinear transform.

evaluate(svector=None)

Evaluate expression at arg. arg may be a scalar or a vector. The result is of type float or complex.

If arg is iterable, a NumPy array is returned.

There can be only one or fewer undefined variables in the expression. This is replaced by arg and then evaluated to obtain a result.

final_value()

Determine value at t = oo.

forward_euler_transform()

Approximate s = ln(z) / dt

by s = (1 / dt) * (1 - z**-1) / z**-1. This is also known as the forward difference method.

See also discretize with regards to scaling of the result.

fourier(**assumptions)

Convert to Fourier domain.

frequency_response(**assumptions)

Convert to frequency response domain. Note, this is similar to the Fourier domain but not always.

frequency_response_evaluate(fvector=None, var=None, **assumptions)
classmethod from_numer_denom(numer, denom)

Create a transfer function from lists of the coefficient for the numerator and denominator.

See also from_zeros_poles_gain, from_poles_residues.

classmethod from_poles_residues(poles, residues)

Create a transfer function from lists of poles and residues.

See also from_zeros_poles_gain, from_numer_denom.

classmethod from_zeros_poles_gain(zeros, poles, K=1)

Create a transfer function from lists of zeros and poles, and from a constant gain.

See also from_poles_residues, from_numer_denom.

generalized_bilinear_transform(alpha=0.5)

Approximate s = ln(z) / dt

by s = (1 / dt) * (1 - z**-1) / (alpha + (1 - alpha) * z**-1))

When alpha = 0 this is equivalent to the forward Euler (forward difference) method.

When alpha = 0.5 this is equivalent to the bilinear transform, aka, Tustin’s method or the trapezoidal method.

When alpha = 1 this is equivalent to the backward Euler (backward difference) method.

See also discretize with regards to scaling of the result.

impulse_invariance_transform()

This samples the impulse response and then calculates the Z-transform. It does not work if the impulse response has Dirac deltas, say for a transfer function that is a pure delay or is not-strictly proper.

The discrete-time and continuous-time impulse responses are identical at the sampling instants n * dt.

The data needs to be sampled many times the bandwidth to avoid aliasing.

See also bilinear_transform and matched_ztransform.

See also discretize with regards to scaling of the result.

impulse_response(tvector=None)

Evaluate transient (impulse) response.

inverse_laplace(zero_initial_conditions=None, **assumptions)

Attempt inverse Laplace transform.

If causal=True the response is zero for t < 0 and the result is multiplied by Heaviside(t) If ac=True or dc=True the result is extrapolated for t < 0. Otherwise the result is only known for t >= 0.

By default initial conditions are assumed to be zero. This can be controlled by zero_initial_conditions.

property jomega

Return expression with s = j omega.

laplace(**assumptions)

Convert to s-domain.

lti_filter(normalize_a0=True)

Create continuous-time linear time-invariant filter from continuous-time transfer function.

matched_ztransform()

Match poles and zeros of H(s) to approximate H(z).

If there are no zeros, this is equivalent to impulse_invariance.

See also bilinear_transform and impulse_invariance_transform.

See also discretize with regards to scaling of the result.

nichols_plot(fvector=None, var=None, **kwargs)

Plot frequency response for a frequency-domain phasor as a Nichols plot (dB versus phase). fvector specifies the frequencies. If it is a tuple (f1, f2), it sets the frequency limits.

npoints set the number of plotted points.

This method makes the assumption that the expression is causal.

norm_angular_fourier(**assumptions)

Convert to normalized angular Fourier domain.

norm_fourier(**assumptions)

Convert to normalized Fourier domain.

nyquist_plot(fvector=None, var=None, **kwargs)

Plot frequency response for a frequency-domain phasor as a Nyquist plot (imaginary part versus real part). fvector specifies the frequencies. If it is a tuple (f1, f2), it sets the frequency limits.

npoints set the number of plotted points.

The unit circle is shown by default. This can be disabled with unitcircle=False.

This method makes the assumption that the expression is causal.

phasor(**assumptions)

Convert to phasor domain.

phasor_ratio(**assumptions)

Convert to phasor ratio domain.

plot(**kwargs)

Plot pole-zero map.

kwargs include: axes - the plot axes to use otherwise a new figure is created xlabel - the x-axis label (default Re(s)) ylabel - the y-axis label (default Im(s)) xscale - the x-axis scaling yscale - the y-axis scaling pole_color – the color of the pole markers zero_color – the color of the zero markers in addition to those supported by the matplotlib plot command.

The plot axes are returned.

pole_zero_plot(**kwargs)

Plot pole-zero map.

post_initial_value()

Determine post-initial value at t = 0+.

response(xvector, tvector, method='bilinear', alpha=0.5)

Evaluate response to input signal xvector at times specified by tvector. This returns a NumPy array.

The default method is ‘bilinear’. Other methods are: ‘impulse-invariance’ ‘bilinear’, ‘tustin’, ‘trapezoidal’ ‘generalized-bilinear’, ‘gbf’ controlled by the parameter alpha ‘euler’, ‘forward-diff’, ‘forward-euler’ ‘backward-diff’, ‘backward-euler’.

See also discretize with regards to scaling of the result.

simpson_transform()

Approximate s = ln(z) / dt

by s = (3 / dt) * (z**2 - 1) / (z**2 + 4 * z + 1). This is more accurate than the other methods but doubles the system order and can produce unstable poles.

See also discretize with regards to scaling of the result.

property ss

Return state-space representation using controllable canonical form. For other forms, use state_space().

state_space(form='CCF')

Create state-space representation from transfer function. Note, state-space representations are not unique and are determined by the form argument. Currently this can be ‘CCF’ for the controllable canonical form, ‘OCF’ for the observable canonical form, or ‘DCF’ for the diagonal canonical form.

step_response(tvector=None)

Evaluate step response.

tdifferentiate()

Differentiate in t-domain (multiply by s).

time(**assumptions)

Convert to time domain.

If causal=True the response is zero for t < 0 and the result is multiplied by Heaviside(t) If ac=True or dc=True the result is extrapolated for t < 0. Otherwise the result is only known for t >= 0.

tintegrate()

Integrate in t-domain (divide by s).

transient_response(tvector=None)

Evaluate transient (impulse) response.

var = s
zdomain(**assumptions)
class lcapy.smatrix.LaplaceDomainVoltageMatrix(*args, **kwargs)

Bases: LaplaceDomainMatrix

class LaplaceDomainVoltage(val, **assumptions)

Bases: VoltageMixin, LaplaceDomainExpression

Angular frequency-domain voltage (units V/Hz).

Tmatrix

This module implements the TimeDomainMatrix class for a matrix of time-domain expressions.

Copyright 2019–2021 Michael Hayes, UCECE

class lcapy.tmatrix.TimeDomainMatrix(*args, **kwargs)

Bases: Matrix

LT()
class TimeDomainExpression(val, **assumptions)

Bases: TimeDomain, Expr

t-domain expression or symbol.

FT(var=None, evaluate=True, **assumptions)

Attempt Fourier transform.

X(f) = int_{-infty} ^ {infty} x(t) exp(-j 2pi f t) dt.

LT(evaluate=True, zero_initial_conditions=None, **assumptions)

Determine one-sided Laplace transform with 0- as the lower limit.

By default initial conditions are assumed to be zero. This can be controlled by zero_initial_conditions.

This is an alias for laplace.

property abs

Return absolute value.

angular_fourier(evaluate=True, **assumptions)

Attempt angular Fourier transform.

angular_frequency_response(**assumptions)

Convert to angular frequency response domain. Note, this is similar to the angular Fourier domain but not always.

as_expr()
differential_equation(inputsym='x', outputsym='y')

Create differential equation from impulse response.

discrete_frequency(**assumptions)
discrete_time(**assumptions)
discretize(method=None, alpha=0.5)

Convert to a discrete-time approximation:

\(x(n) pprox K x(t)\)

where \(K\) is a scale factor.

The default method depends on the expression quantity. If the quantity is undefined, voltage, current, `voltagesquared, currentsquared, or power, the default method is impulse-invariance and there is no scaling. This uses:

: math: x[n] = x(n Delta t)

For other quantities, the default method is bilinear’, and the result is scaled by the sampling interval (`Delta t) as is common for the discrete-time impulse response of digital filters:

: math: h[n] = Delta t h_c(n Delta t)

The methods are: ‘impulse-invariance’ ‘bilinear’, ‘tustin’, ‘trapezoidal’ ‘generalized-bilinear’, ‘gbf’ controlled by the parameter alpha ‘euler’, ‘forward-diff’, ‘forward-euler’ ‘backward-diff’, ‘backward-euler’ ‘simpson’, ‘matched-Z’, ‘zero-pole-matching’. All the methods except impulse-invariance are applied in the Laplace domain so the result is unknown for n < 0 unless the expression is causal.

dlti_filter(method='bilinear')

Create DLTI filter using bilinear transform.

property energy

Return signal energy.

final_value()

Determine value at t = oo.

force_causal()

Remove the piecewise condition from the expression and multiply by Heaviside function. See also remove_condition.

fourier(var=None, evaluate=True, **assumptions)

Attempt Fourier transform. This is an alias for FT.

frequency_response(**assumptions)

Convert to frequency response domain. Note, this is similar to the Fourier domain but not always.

infer_assumptions()
initial_value()

Determine value at t = 0. See also pre_initial_value and post_initial_value

laplace(evaluate=True, zero_initial_conditions=None, **assumptions)

Determine one-sided Laplace transform with 0- as the lower limit.

By default initial conditions are assumed to be zero. This can be controlled by zero_initial_conditions.

This is an alias for LT.

norm_angular_fourier(evaluate=True, **assumptions)

Attempt normalized angular Fourier transform.

norm_fourier(evaluate=True, **assumptions)

Attempt normalized Fourier transform.

phasor(**assumptions)

Convert to phasor domain.

plot(t=None, **kwargs)

Plot the time waveform. If t is not specified, it defaults to the range(-0.2, 2). t can be a vector of specified instants, a tuple specifing the range, or a constant specifying the maximum value with the minimum value set to 0.

kwargs include: axes - the plot axes to use otherwise a new figure is created xlabel - the x-axis label ylabel - the y-axis label xscale - the x-axis scaling, say for plotting as ms yscale - the y-axis scaling, say for plotting mV plot_deltas - plot Dirac deltas as arrows in addition to those supported by the matplotlib plot command.

The plot axes are returned.

post_initial_value()

Determine value at t = 0+. See also pre_initial_value and initial_value

pre_initial_value()

Determine value at t = 0-. See also initial_value and post_initial_value

response(xvector, tvector, method='bilinear')

Evaluate response to input signal xvector at times tvector. This returns a NumPy array.

sample(tvector)

Return a discrete-time signal evaluated at time values specified by tvector. This returns a NumPy array.

time(**assumptions)
var = t
zdomain(**assumptions)

Network

Copyright 2014–2022 Michael Hayes, UCECE

class lcapy.network.Network

Bases: object

This is the base class for network objects.

property analysis
property cct

Convert a Network object into a Circuit object.

circuit()

Convert a Network object into a Circuit object.

cpt_type = ''
describe()

Print a message describing how network is solved.

draw(filename=None, layout='horizontal', form=None, evalf=False, **kwargs)

Draw schematic of network.

filename specifies the name of the file to produce. If None, the schematic is displayed on the screen.

Note, if using Jupyter, then need to first issue command %matplotlib inline

layout is either ‘horizontal’, ‘vertical’, or ‘ladder’.

evalf can be False or an integer specifying the number of decimal places used to evaluate floats.

kwargs include:

label_ids: True to show component ids label_values: True to display component values draw_nodes: True to show all nodes, False to show no nodes,

‘primary’ to show primary nodes, ‘connections’ to show nodes that connect more than two components, ‘all’ to show all nodes

label_nodes: True to label all nodes, False to label no nodes,

‘primary’ to label primary nodes, ‘alpha’ to label nodes starting with a letter, ‘pins’ to label nodes that are pins on a chip, ‘all’ to label all nodes

style: ‘american’, ‘british’, or ‘european’ scale: schematic scale factor, default 1.0 node_spacing: spacing between component nodes, default 2.0 cpt_size: size of a component, default 1.5 dpi: dots per inch for png files help_lines: distance between lines in grid, default 0.0 (disabled) debug: True to display debug information

property has_ac
property has_dc
has_ic = None
property has_transient
property initial_value_problem
property is_IVP
property is_ac
is_capacitor = False
property is_causal
is_conductor = False
is_current_source = False
property is_dc
is_inductor = False
is_noiseless = True
is_parallel = False
is_resistor = False
is_series = False
is_voltage_source = False
property kinds

Return list of transform domain kinds.

kwargs = {}
latex(**kwargs)
netkeyword = ''
netlist(layout='horizontal', evalf=None)

Create a netlist.

layout can be ‘horizontal’, ‘vertical’, or ‘ladder’.

evalf can be False or an integer specifying the number of decimal places used to evaluate floats.

noisy(T='T')

Create noisy network model by replacing resistances with a series combination of a resistance and a noise voltage source.

property params

Return list of symbols used as arguments in the network.

pdb()

Enter the python debugger.

pprint()
pretty(**kwargs)
sch(layout='horizontal', evalf=False)

Convert a Network object into a Schematic object.

simplify()
subs(subs_dict)

Substitute values using dictionary of substitutions.

For example, b = a.subs({‘R1’: 1e3, ‘R2’: 9e3})

property symbols

Return dictionary of symbols defined in the network.

transform(form='cauerI')

Transform the network impedance into an alternative form. The transformation is performed using network synthesis of the network’s impedance (note, this ignores the sources). form includes: cauerI, cauerII, fosterI, fosterII.

Note some methods generate networks with negative value components.

zeroic = True

Voltage

This module provides voltage support.

Copyright 2020–2023 Michael Hayes, UCECE

lcapy.voltage.Vname(name, kind, cache=False)
lcapy.voltage.Vtype(kind)
lcapy.voltage.noisevoltage(arg, **assumptions)

Create a new noise voltage with specified amplitude spectral density.

lcapy.voltage.phasorvoltage(arg, omega=None, **assumptions)
lcapy.voltage.voltage(arg, **assumptions)

Current

This module provides current support.

Copyright 2020–2023 Michael Hayes, UCECE

lcapy.current.Iname(name, kind, cache=False)
lcapy.current.Itype(kind)
lcapy.current.current(arg, **assumptions)
lcapy.current.current_sign(I, is_source)

Manipulate the sign of the current according to the current sign convention specified by state.current_sign_convention.

lcapy.current.noisecurrent(arg, **assumptions)

Create a new noise current with specified amplitude spectral density.

lcapy.current.phasorcurrent(arg, omega=None, **assumptions)

Super

This module provides the SuperpositionDomainExpression class. It is the base class for Current and Voltage. It represents voltages and currents as a superposition in different transform domains.

Copyright 2019–2023 Michael Hayes, UCECE

class lcapy.super.Superposition(*args, **kwargs)

Bases: SuperpositionDomain, ExprDict

This class represents a superposition of different signal types, DC, AC, transient, and noise.

The time-domain representation is returned with the time method, V.time(), or with the notation V(t). This does not include the noise component.

The Laplace representation is returned with the laplace method, V.laplace() or with the notation V(s). This does not include the noise component.

Noise components with different noise identifiers are stored separately, keyed by the noise identifier. They are ignored by the laplace() and time() methods.

The total noise can be accessed with the .n attribute. This sums each of the noise components in quadrature since they are independent.

For example, consider V = Voltage(‘cos(3 * t) + exp(-4 * t) + 5’)

str(V(t)) gives ‘cos(3*t) + 5 + exp(-4*t)’

str(V(s)) gives ‘s/(9*(s**2/9 + 1)) + 1/(4*(s/4 + 1)) + 5/s’

V.dc gives 5

V.ac gives {3: 1}

V.s gives 1/(s + 4)

property abs

Return the magnitude if phasor.

property ac

Return the AC components.

ac_keys()

Return list of keys for all ac components.

add(value)

Add a value into the superposition.

angular_fourier(**assumptions)

Convert to angular Fourier domain.

asd()
canonical()
property dc

Return the DC component.

decompose()

Decompose into a new representation in the transform domains.

decompose_to_domain(expr, kind)
final_value()

Determine value at t = oo.

force_time()
fourier(**assumptions)

Convert to Fourier domain.

frequency_response(fvector=None)

Convert to frequency domain and evaluate response if frequency vector specified.

has(subexpr)

Test whether the sub-expression is contained. For example, V.has(exp(t)) V.has(t)

property has_ac

True if there is an AC component.

property has_dc

True if there is a DC component.

property has_noisy

True if there is a noise component.

property has_s_transient

True if have transient component defined in the s-domain.

has_symbol(sym)

Test if have symbol. For example, V.has_symbol(‘a’) V.has_symbol(t)

property has_t_transient

True if have transient component defined in the time-domain.

property has_transient

True if have transient component.

initial_value()

Determine value at t = 0. See also pre_initial_value and post_initial_value

property is_ac

True if only has AC components.

property is_causal
property is_dc

True if only has a DC component.

property is_noisy

True if only has noise components.

property is_phasor_domain

True if has single AC component.

property is_s_transient

True if only has s-domain transient component.

property is_superposition
property is_t_transient

True if only has t-domain transient component.

property is_transient

True if only has transient component(s). Note, should not have both t and s components.

laplace(**assumptions)

Convert to s-domain.

latex(**kwargs)

Latex

limit(var, value, dir='+')

Determine limit of expression(var) at var = value. If dir == ‘+’ search from right else if dir == ‘-’ search from left.

property magnitude

Return the magnitude if phasor.

property n
netval(kind)
property noise

Return the total noise.

noise_keys()

Return list of keys for all noise components.

property omega

Return angular frequency if phasor.

oneport()

Create oneport component.

property phase

Return the phase if phasor.

phasor(**kwargs)

Return phasor if have a single AC component otherwise raise error.

post_initial_value()

Determine value at t = 0+. See also pre_initial_value and initial_value

pprint()

Pretty print

pre_initial_value()

Determine value at t = 0-. See also initial_value and post_initial_value

psd()
rms()
property s

Return the s-domain representation of the transient component. This is not the full s-domain representation as returned by the laplace method V.laplace() or V(s).

This attribute may be deprecated due to possible confusion.

select(kind)

Select a component of the signal representation by kind where: ‘super’ : the entire superposition ‘time’ : the time domain representation (equivalent to self.time()) ‘laplace’ : the laplace domain representation (equivalent to self.laplace()) ‘ivp’ : the s-domain representation (equivalent to self.laplace()) ‘dc’ : the DC component omega : the AC component with angular frequency omega ‘s’ : the transient component in the s-domain ‘n’ : the noise component ‘t’ : the time-domain transient component (this may or may not

include the DC and AC components).

simplify()

Simplify each element but not the keys.

subs(*args, **kwargs)

Substitute symbols in the expression.

args is either: - two arguments, e.g. foo.subs(old, new) - one iterable argument, e.g. foo.subs(iterable). The iterable may be

o an iterable container with (old, new) pairs. In this case the

replacements are processed in the order given with successive patterns possibly affecting replacements already made.

o a dict or set whose key/value items correspond to old/new pairs.

The domain of the result can be coerced using domain argument.

property symbols

Return dictionary of symbols in the expression keyed by name.

time(**assumptions)

Convert to time domain.

transform(arg, **assumptions)

Transform into a different domain.

property transient

Return the transient component.

transient_response(tvector=None)

Evaluate transient (impulse) response.

property units

Return the units of the expression. However, since this is a superposition, units are not defined. Instead, it is necessary to transform to a specific domain. For example, using V(s).

Admittance

This module provides admittance support.

Copyright 2019–2022 Michael Hayes, UCECE

lcapy.admittance.admittance(arg, causal=True, **assumptions)

Create an admittance class for the specified admittance.

Y(omega) = G(omega) + j * B(omega)

where G is the conductance and B is the susceptance.

Admittance is the reciprocal of impedance:

Z(omega) = 1 / Y(omega)

Impedance

This module provides impedance support.

Copyright 2019–2022 Michael Hayes, UCECE

lcapy.impedance.impedance(arg, causal=True, **assumptions)

Create an impedance class for the specified impedance.

Z(omega) = R(omega) + j * X(omega)

where G is the conductance and B is the susceptance.

Impedance is the reciprocal of admittance:

Z(omega) = 1 / Y(omega)

Functions

This module wraps SymPy functions and provides a few others. The underlying SymPy function is obtained with the sympy attribute.

Copyright 2014–2023 Michael Hayes, UCECE

Symbols

This module defines special symbols f, s, t, and omega.

Copyright 2014–2021 Michael Hayes, UCECE

Mnacpts

This module defines the components for modified nodal analysis. The components are defined at the bottom of this file.

Copyright 2015–2023 Michael Hayes, UCECE

Laplace

This module provides support for Laplace transforms. It acts as a quantity for SymPy’s Laplace transform. It calculates the unilateral Laplace transform using:

F(s) = lim_{t_0 ightarrow 0} int_{-t_0}^{infty} f(t) e^{-s t} dt

In comparison, SymPy uses:

F(s) = int_{0}^{infty} f(t) e^{-s t} dt

The latter gives 0.5 for the Laplace transform of DiracDelta(t) whereas the former version gives 1. Note, SymPy is inconsistent in that it gives DiracDelta(t) for the inverse Laplace transform of 1.

Another difference with this implementation is that it will transform undefined functions such as v(t) to V(s).

These functions are for internal use by Lcapy.

Copyright 2016–2023 Michael Hayes, UCECE

lcapy.laplace.LT(expr, t, s, evaluate=True, **kwargs)

Compute unilateral Laplace transform of expr with lower limit 0-.

lcapy.laplace.laplace_transform(expr, t, s, evaluate=True, **kwargs)

Compute unilateral Laplace transform of expr with lower limit 0-.

Fourier

This module provides support for Fourier transforms. It calculates the bilateral Fourier transform using:

S(f) = int_{-infty}^{infty} s(t) e^{-j * 2 * pi * t} dt

It also allows functions that strictly do not have a Fourier transform by using Dirac deltas. For example, a, cos(a * t), sin(a * t), exp(j * a * t).

Copyright 2016–2023 Michael Hayes, UCECE

lcapy.fourier.FT(expr, t, f, **kwargs)

Compute bilateral Fourier transform of expr.

Undefined functions such as v(t) are converted to V(f)

This also handles some expressions that do not really have a Fourier transform, such as a, cos(a * t), sin(a * t), exp(I * a * t).

Ztransform

This module provides support for z transforms.

Copyright 2020–2023 Michael Hayes, UCECE

lcapy.ztransform.ZT(expr, n, z, evaluate=True, **kwargs)

Compute unilateral Z-Transform transform of expr with lower limit 0.

Undefined functions such as v[n] are converted to V(z).

Transform

This module performs transformations between domains.

Copyright 2018–2022 Michael Hayes, UCECE

lcapy.transform.call(expr, arg, **assumptions)
lcapy.transform.select(expr, kind)
lcapy.transform.transform(expr, arg, **assumptions)

If arg is a domain variable perform domain transformation, otherwise perform substitution.

Note (1 / s)(omega) will fail since 1 / s is assumed not to be causal and so the Fourier transform is unknown. However, impedance(1 / s)(omega) will work since an impedance is assumed to be causal. Alternatively, use (1 / s)(omega, causal=True).

Transforming from s->jomega is fast since it just requires a substitution of s with jomega.

Transforming from s->omega, s->Omega, s->f, or s->F can be slow since this requires a inverse Laplace transform followed by a Fourier transform. However, if the expression is causal and the expression is lossy when s is replaced by jw, the result can be found by substituting jw or 2 * 2 * pi * f for s. This does not apply for an expression such as Z = 1 / (s * C).

Plot

This module performs plotting using matplotlib.

Copyright 2014–2022 Michael Hayes, UCECE

lcapy.plot.make_axes(figsize=None, axes=None, **kwargs)
lcapy.plot.parse_range(frange, zero=0.1, positive=False)
lcapy.plot.plot_angular_bode(obj, f, **kwargs)

This is a helper function for a Bode plot. It is better to use the bode_plot() method of an AngularFourierDomainExpression.

lcapy.plot.plot_angular_frequency(obj, omega, plot_type=None, **kwargs)

This is a helper function for a frequency response plot. It is better to use the plot() method of an AngularFourierDomainExpression.

lcapy.plot.plot_bode(obj, f, **kwargs)

This is a helper function for a Bode plot. It is better to use the bode_plot() method of a FourierDomainExpression.

lcapy.plot.plot_deltas(ax, t, deltas, var, plot_type='real', color='k')
lcapy.plot.plot_frequency(obj, f, plot_type=None, **kwargs)

This is a helper function for a frequency response plot. It is better to use the plot() method of a FourierDomainExpression.

lcapy.plot.plot_nichols(obj, f, norm=False, **kwargs)

This is a helper function for a Nichols plot. It is better to use the nichols_plot() method of a LaplaceDomainExpression.

lcapy.plot.plot_nyquist(obj, f, norm=False, **kwargs)

This is a helper function for a Nyquist plot. It is better to use the nyquist_plot() method of a LaplaceDomainExpression.

lcapy.plot.plot_phasor(obj, **kwargs)

This is a helper function for a phasor plot. It is better to use the plot() method of a PhasorDomainExpression.

lcapy.plot.plot_pole_zero(obj, **kwargs)

This is a helper function for a pole zero plot. It is better to use the plot() method of a LaplaceDomainExpression.

lcapy.plot.plot_sequence(obj, ni, plot_type=None, polar=False, **kwargs)

This is a helper function for a stem (lollipop) plot. It is better to use the plot() method of a DiscreteTimeDomainExpression.

lcapy.plot.plot_sequence_polar(obj, ni=(-10, 10), **kwargs)
lcapy.plot.plot_time(obj, t, plot_type=None, **kwargs)

This is a helper function for a time plot. It is better to use the plot() method of a TimeDomainExpression.

lcapy.plot.plotit(ax, obj, f, V, plot_type=None, deltas=None, log_magnitude=False, log_frequency=False, norm=False, dbmin=-120, dbmax=None, unwrap=False, **kwargs)

Acdc

This module provides the CausalChecker, ACChecker, and DCChecker classes as used by the is_causal, is_ac, and is_dc functions.

Copyright 2020–2023 Michael Hayes, UCECE

class lcapy.acdc.ACChecker(expr, var)

Bases: object

This looks for real ac signals; it does not work for complex ac signals.

class lcapy.acdc.CausalChecker(expr, var)

Bases: object

class lcapy.acdc.DCChecker(expr, var)

Bases: object

lcapy.acdc.is_ac(expr, var)
lcapy.acdc.is_causal(expr, var)
lcapy.acdc.is_dc(expr, var)

Ratfun

This module provides support for rational functions.

Copyright 2016–2022 Michael Hayes, UCECE

class lcapy.ratfun.Pole(expr, n, damping=None)

Bases: object

property conj
conjugate()
class lcapy.ratfun.Ratfun(expr, var)

Bases: object

property Apoly
property Bpoly
property Ddegree

Return the degree (order) of the denominator of a rational function. Note zero has a degree of -inf.

property Ndegree

Return the degree (order) of the numerator of a rational function. Note zero has a degree of -inf.

ZPK(combine_conjugates=False)

Convert to zero-pole-gain (ZPK) form.

See also canonical, general, standard, timeconst, and partfrac

as_B_A_delay_undef()
as_QMA()

Decompose expression into Q, M, A, delay, undef where

expression = (Q + M / A) * exp(-delay * var) * undef

as_QRF(combine_conjugates=False, damping=None, method=None)

Decompose expression into Q, R, F, delay, undef where

expression = (Q + sum_n r_n / f_n) * exp(-delay * var) * undef

as_QRF_old(combine_conjugates=False, damping=None)

Decompose expression into Q, R, F, delay, undef where

expression = (Q + sum_n r_n / f_n) * exp(-delay * var) * undef

as_QRPO(damping=None, method=None)

Decompose expression into Q, R, P, O, delay, undef where

expression = (Q + sum_n r_n / (var - p_n)**o_n) * exp(-delay * var) * undef

method can be ‘sub’ (substitution method, the default) or ‘ec’ (equating cofficients method).

as_ZPK()

Decompose expression into zeros, poles, gain, undef where

expression = K * (prod_n (var - z_n) / (prod_n (var - p_n)) * undef

canonical(factor_const=True)

Convert rational function to canonical form; this is like general form but with a unity highest power of denominator. For example,

(5 * s**2 + 5 * s + 5) / (s**2 + 4)

If factor_const is True, factor constants from numerator, for example,

5 * (s**2 + s + 1) / (s**2 + 4)

See also general, partfrac, standard, timeconst, and ZPK

coeffs()
property degree

Return the degree (order) of the rational function.

This the maximum of the numerator and denominator degrees. Note zero has a degree of -inf.

expandcanonical()

Expand in terms for different powers with each term expressed in canonical form.

general()

Convert rational function to general form.

See also canonical, partfrac, standard, timeconst, and ZPK

property is_strictly_proper

Return True if the degree of the dominator is greater than the degree of the numerator.

partfrac(combine_conjugates=False, damping=None, method=None)

Convert rational function into partial fraction form.

If combine_conjugates is True then the pair of partial fractions for complex conjugate poles are combined.

See also canonical, standard, general, timeconst, and ZPK

poles(damping=None)

Return poles of expression as a list of Pole objects. Note this may not find all the poles.

Poles at infinity are not returned. There will be p - q poles at infinity for a rational function with a numerator of degree p and a denominator of degree q.

residue(pole, poles)

Determine residue for given pole.

residues(combine_conjugates=False, damping=None)

Return residues of partial fraction expansion.

This is not much use without the corresponding poles. It is better to use as_QRF.

roots()

Return roots of expression as a dictionary Note this may not find them all.

standard()

Convert rational function into mixed fraction form.

This is the sum of strictly proper rational function and a polynomial.

See also canonical, general, partfrac, timeconst, and ZPK

timeconst()

Convert rational function to time constant form with unity lowest power of denominator.

See also canonical, general, partfrac, standard, and ZPK

zeros()

Return zeroes of expression as a dictionary Note this may not find them all.

Zeros at infinity are not returned. There will be q - p zeros at infinity for a rational function with a numerator of degree p and a denominator of degree q.

lcapy.ratfun.as_B_A_delay_undef(expr, var)
lcapy.ratfun.as_numer_denom(expr, var)
lcapy.ratfun.polyroots(poly, var)

Return roots of polynomial poly for variable var.

lcapy.ratfun.roots(expr, var)

Return roots of expression expr for variable var.

Schematics

Schematic

This module performs schematic drawing using circuitikz from a netlist:

>>> from lcapy import Schematic
>>> sch = Schematic('''
... P1 1 0.1; down
... R1 3 1; right
... L1 2 3; right
... C1 3 0; down
... P2 2 0.2; down
... W 0 0.1; right
... W 0.2 0.2; right''')
>>> sch.draw()

Copyright 2014–2023 Michael Hayes, UCECE

class lcapy.schematic.Schematic(filename=None, allow_anon=False, **kwargs)

Bases: NetfileMixin

add(string)

Add a component to the netlist. The general form is: ‘Name Np Nm args’ where Np is the positive node and Nm is the negative node.

A positive current is defined to flow from the positive node to the negative node.

draw(filename=None, **kwargs)

filename specifies the name of the file to produce. If None, the schematic is displayed on the screen.

Note, if using Jupyter, then need to first issue command %matplotlib inline

kwargs include:

‘label_ids’: True to show component ids ‘label_values’: True to display component values ‘annotate_values’: True to display component values as separate label ‘draw_nodes’: True to show all nodes,

False or ‘none’ to show no nodes, ‘primary’ to show primary nodes, ‘connections’ to show nodes that connect more than two components, ‘all’ to show all nodes

‘label_nodes’: True to label all nodes,

False or ‘none’ to label no nodes, ‘primary’ to label primary nodes (nodes without an underscore), ‘alpha’ to label nodes starting with a letter, ‘pins’ to label nodes that are pins on a chip, ‘all’ to label all nodes,

‘anchor’: where to position node label (default south east) ‘include’: name of file to include before begin{document} ‘style’: ‘american’, ‘british’, or ‘european’ ‘scale’: schematic scale factor, default 1.0 ‘node_spacing’: spacing between component nodes, default 2.0 ‘cpt_size’: size of a component, default 1.5 ‘dpi’: dots per inch for png files, default 300 ‘help_lines’: distance between lines in grid, default 0 (disabled) ‘debug’: non-zero to display debug information

make_graphs(debug=0, **kwargs)
netfile_add(filename)

Add the nets from file with specified filename

netlist()

Return the current netlist

pdb()

Enter the python debugger.

tikz_draw(filename, **kwargs)

Schemcpts

This module defines and draws the schematic components using circuitikz. The components are defined at the bottom of this file.

Copyright 2015–2023 Michael Hayes, UCECE

class lcapy.schemcpts.A(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Unipole

Annotation.

tikz_cpt = ''
class lcapy.schemcpts.ANT(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Unipole

Antenna

can_invert = True
can_mirror = True
kinds = {'rx': 'rxantenna', 'tx': 'txantenna'}
tikz_cpt = 'antenna'
class lcapy.schemcpts.BAT(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Battery

kinds = {'cell1': 'battery1'}
tikz_cpt = 'battery'
class lcapy.schemcpts.BJT(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Transistor

aliases = {'base': 'b', 'collector': 'c', 'emitter': 'e'}
inpins = {'b': ('lx', 0.55, 0.5), 'c': ('lx', 0, 0), 'e': ('lx', 0, 1)}
ippins = {'b': ('lx', 0.55, 0.5), 'c': ('lx', 0, 1), 'e': ('lx', 0, 0)}
kinds = {'Lnigbt': 'Lnigbt', 'Lnigbt-bodydiode': 'Lnigbt-bodydiode', 'Lpigbt': 'Lpigbt', 'Lpigbt-bodydiode': 'Lpigbt-bodydiode', 'bodydiode': '-bodydiode', 'nigbt': 'nigbt', 'nigbt-bodydiode': 'nigbt-bodydiode', 'npn': 'npn', 'pigbt': 'pigbt', 'pigbt-bodydiode': 'pigbt-bodydiode', 'pnp': 'pnp'}
node_pinnames = ('e', 'b', 'c')
npins = {'b': ('lx', 0, 0.5), 'c': ('lx', 0.55, 0), 'e': ('lx', 0.55, 1)}
ppins = {'b': ('lx', 0, 0.5), 'c': ('lx', 0.55, 1), 'e': ('lx', 0.55, 0)}
class lcapy.schemcpts.BL(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Block

kinds = {'acdc': 'sacdc', 'adc': 'adc', 'allpass': 'allpass', 'amp': 'amp', 'bandpass': 'bandpass', 'bandstop': 'bandstop', 'dac': 'dac', 'dcac': 'sdcac', 'dcdc': 'sdcdc', 'detector': 'detector', 'dsp': 'dsp', 'fft': 'fft', 'highpass': 'highpass', 'highpass2': 'highpass2', 'lowpass': 'lowpass', 'lowpass2': 'lowpass2', 'phaseshifter': 'phaseshifter', 'piattenuator': 'piattenuator', 'tattenuator': 'tattenuator', 'twoport': 'twoport', 'twoportsplit': 'twoportsplit', 'vamp': 'vamp', 'vco': 'vco', 'vphaseshifter': 'vphaseshifter', 'vpiattenuator': 'vpiattenuator', 'vtattenuator': 'vtattenuator'}
tikz_cpt = 'twoport'
class lcapy.schemcpts.Bipole(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: StretchyCpt

aliases = {'n': '-', 'p': '+'}
can_invert = True
can_mirror = True
can_scale = True
draw(**kwargs)
label_make(label_pos='', **kwargs)
node_pinnames = ('+', '-')
pins = {'+': ('lx', -0.5, 0), '-': ('rx', 0.5, 0)}
class lcapy.schemcpts.Box(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Shape

pins = {'e': ('r', 0.5, 0), 'ene': ('r', 0.5, 0.25), 'ese': ('r', 0.5, -0.25), 'n': ('t', 0, 0.5), 'ne': ('t', 0.5, 0.5), 'nne': ('t', 0.25, 0.5), 'nnw': ('t', -0.25, 0.5), 'nw': ('t', -0.5, 0.5), 's': ('b', 0, -0.5), 'se': ('b', 0.5, -0.5), 'sse': ('b', 0.25, -0.5), 'ssw': ('b', -0.25, -0.5), 'sw': ('b', -0.5, -0.5), 'w': ('l', -0.5, 0), 'wnw': ('l', -0.5, 0.25), 'wsw': ('l', -0.5, -0.25)}
shape = 'rectangle'
class lcapy.schemcpts.Box12(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Shape

pins = {'e': ('r', 0.5, 0), 'ene': ('r', 0.5, 0.25), 'ese': ('r', 0.5, -0.25), 'n': ('t', 0, 0.5), 'nne': ('t', 0.25, 0.5), 'nnw': ('t', -0.25, 0.5), 's': ('b', 0, -0.5), 'sse': ('b', 0.25, -0.5), 'ssw': ('b', -0.25, -0.5), 'w': ('l', -0.5, 0), 'wnw': ('l', -0.5, 0.25), 'wsw': ('l', -0.5, -0.25)}
shape = 'rectangle'
class lcapy.schemcpts.Box2(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Shape

Square box, A rectangle is created by defining aspect.

pins = {'e': ('r', 0.5, 0), 'w': ('l', -0.5, 0)}
shape = 'rectangle'
class lcapy.schemcpts.Box4(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Shape

pins = {'e': ('r', 0.5, 0), 'n': ('t', 0, 0.5), 's': ('b', 0, -0.5), 'w': ('l', -0.5, 0)}
shape = 'rectangle'
class lcapy.schemcpts.C(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Capacitor

kinds = {'curved': 'cC', 'electrolytic': 'eC', 'ferroelectric': 'ferrocap', 'polar': 'cC', 'sensor': 'sC', 'tunable': 'vC, tunable end arrow={Bar}', 'variable': 'vC'}
tikz_cpt = 'C'
class lcapy.schemcpts.CCS(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Current controlled source

node_pinnames = ('+', '-', '', '')
class lcapy.schemcpts.CPE(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Constant phase element

draw(**kwargs)
class lcapy.schemcpts.Cable(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Shape

a = 0.3
auxiliary = {'bl': ('l', -0.5, -0.5), 'br': ('r', 0.5, -0.5), 'in': ('l', -0.5, 0), 'in+': ('l', -0.5, 0.3), 'in-': ('l', -0.5, -0.3), 'mid': ('c', 0.0, 0.0), 'out': ('r', 0.5, 0), 'out+': ('r', 0.5, 0.3), 'out-': ('r', 0.5, -0.3), 'tl': ('l', -0.5, 0.5), 'top': ('t', 0, 0.5), 'tr': ('r', 0.5, 0.5)}
default_aspect = 4
draw(**kwargs)
pins = {'b': ('c', 0, -0.5), 'ignd': ('l', -0.5, -0.5), 'ognd': ('r', 0.46, -0.5), 't': ('c', 0, 0.5)}
class lcapy.schemcpts.Chip(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Shape

General purpose chip

default_width = 2.0
do_transpose = True
draw(**kwargs)
property path
class lcapy.schemcpts.Circle(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Ellipse

shape = 'circle'
class lcapy.schemcpts.Circle2(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Shape

Circle

pins = {'e': ('r', 0.5, 0), 'w': ('l', -0.5, 0)}
shape = 'circle'
class lcapy.schemcpts.Circle4(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Shape

pins = {'e': ('r', 0.5, 0), 'n': ('t', 0, 0.5), 's': ('b', 0, -0.5), 'w': ('l', -0.5, 0)}
shape = 'circle'
class lcapy.schemcpts.Cpt(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: object

R(angle_offset=0)

Return rotation matrix

aliases = {}
anchor_opt(thing, default=None)
property angle

Return rotation angle

annotate(pos, label, dargs=None, bold=False)
annotation_keys = ('a', 'a_', 'a^')
property annotation_str
args_str(**kwargs)
property aspect
autoground(autoground)
auxiliary = {}
boolattr(opt)
can_invert = False
can_mirror = False
can_rotate = True
can_scale = False
can_stretch = True
check()

Check schematic options and return True if component is to be drawn

check_nodes()
connection_keys = ('input', 'output', 'bidir', 'pad')
property coords
current_keys = ('i', 'i_', 'i^', 'i_>', 'i_<', 'i^>', 'i^<', 'i>_', 'i<_', 'i>^', 'i<^', 'i>', 'i<', 'ir')
property current_str
default_aspect = 1.0
default_pins = ()
default_width = 1.0
directive = False
do_transpose = False
property down
draw(**kwargs)
draw_connection(n, kind)

Draw connection and label.

draw_cpt(pos1, pos2, cpt='', args='', dargs='')

Create a string to draw a circuitikz component cpt between positions pos1 and pos2. args is a list or string of the component options; dargs is a list or string of the draw options.

The general form of the generated string is:

draw[dargs] (pos1) to [cpt, args] (pos2);

draw_cptnode(pos, cpt='', args='', dargs='', label='')

Create a string to draw a tikz node containing a circuitikz component cpt at position pos. args is a list or string of the node options; dargs is a list or string of the draw options. label is an optional label.

The general form of the generated string is:

draw[dargs] (pos) node[cpt, args] {label};

draw_implicit(n, kind, draw_nodes)

Draw implicit connection and label.

draw_implicit_norotate(n, kind, draw_nodes)

Draw implicit connection and label with no rotation.

draw_implicit_rotate(n, kind, draw_nodes)

Draw implicit connection and label with rotation.

draw_label(pos, keys=None, default=True, **kwargs)

Draw label for component that does not have a circuitikz label.

draw_node(n, draw_nodes, dargs)

Draw a node symbol. This also draws the node label for implicit and connection nodes.

draw_node_label(node, label_nodes, anchor, dargs=None)
draw_node_labels(**kwargs)
draw_nodes(**kwargs)
property draw_nodes_opt
draw_path(points, style='', join='--', closed=False, dargs=None)
draw_pinlabel(node)
draw_pinname(node)
draw_pins()
draw_stepped_wire(pos1, steps, dargs=None, startarrow='', endarrow='', style='')
draw_wire(pos1, pos2, dargs=None, startarrow='', endarrow='', style='')

Create a string to draw a circuitikz wire between positions pos1 and pos2. dargs is a list or string of the draw options.

The general form of the generated string is:

draw[-, dargs] (pos1) to (pos2);

property drawn_nodes

Nodes that are drawn

fakepin(pinname)

Return True if pinname is a fake pin

find_ref_node_names()

Determine which nodes are referenced for this component.

property fixed
property fliplr
property flipud
flow_keys = ('f', 'f_', 'f^', 'f_>', 'f_<', 'f^>', 'f^<', 'f>_', 'f<_', 'f>^', 'f<^', 'f>', 'f<')
property flow_str
property free
ground_keys = ('ground', 'sground', 'rground', 'cground', 'nground', 'pground', '0V')
property h

Normalized height

property horizontal
property ignore
implicit_key(opts)
implicit_keys = ('implicit', 'ground', 'sground', 'rground', 'cground', 'nground', 'pground', '0V', 'vcc', 'vdd', 'vee', 'vss')
inner_label_keys = ('t',)
property inner_label_str
property invert
property invisible
property kind
kinds = {}
label(keys=None, default=True, **kwargs)
label_keys = ('l', 'l_', 'l^')
property label_nodes_opt
label_opt_keys = ('label_values', 'label_ids', 'annotate_values')
property label_str
property label_str_list
label_tweak(label, xscale, yscale, angle)
property left
midpoint(node1, node2)
property mirror
property mirrorinputs
misc_keys = ('left', 'right', 'up', 'down', 'rotate', 'size', 'mirror', 'invert', 'scale', 'invisible', 'variable', 'fixed', 'aspect', 'pins', 'image', 'offset', 'pinlabels', 'pinnames', 'pinnodes', 'pindefs', 'outside', 'pinmap', 'kind', 'wire', 'ignore', 'style', 'nosim', 'nowires', 'nolabels', 'steps', 'free', 'fliplr', 'flipud', 'nodots', 'draw_nodes', 'label_nodes', 'nodraw', 'mirrorinputs', 'autoground', 'xoffset', 'yoffset', 'anchor', 'def', 'nodes')
node(pinname)

Return node by pinname

node_opts()
node_pinnames = ()
node_special_keys = ('label', 'l', 'anchor')
property nodes

Nodes used to draw the element.

property nodots
property nodraw
property nolabels
property nowires
property offset
opts_str(choices)

Format voltage, current, or label string as a key-value pair

opts_str_list(choices)

Format voltage, current, or label string as a key-value pair and return list of strings

parse_nodes()
parse_pindefs()
pinpos(pinname)

Return pinpos by pinname

pins = {}
place = True
process_attribute_nodes()

Process nodes specified as attributes. For example, R1 1 2; .n.vss

process_implicit_nodes()

Parse implicit nodes.

process_nodes(nodes, draw_pin=False, add_pinname=False)
required_auxiliary = ('mid',)
property required_node_names

Subset of node_names. This filters out nodes that are not drawn. For example, the ground node of an Eopamp is not drawn.

property required_pins
property right
property s

Sanitised name

property scale
property scales
setup()
shape_scale = 1.0
property size

Component size between its nodes

special_keys = ('v', 'v_', 'v^', 'v_>', 'v_<', 'v^>', 'v^<', 'v<', 'v>', 'i', 'i_', 'i^', 'i_>', 'i_<', 'i^>', 'i^<', 'i>_', 'i<_', 'i>^', 'i<^', 'i>', 'i<', 'ir', 'f', 'f_', 'f^', 'f_>', 'f_<', 'f^>', 'f^<', 'f>_', 'f<_', 'f>^', 'f<^', 'f>', 'f<', 'l', 'l_', 'l^', 't', 'a', 'a_', 'a^', 'left', 'right', 'up', 'down', 'rotate', 'size', 'mirror', 'invert', 'scale', 'invisible', 'variable', 'fixed', 'aspect', 'pins', 'image', 'offset', 'pinlabels', 'pinnames', 'pinnodes', 'pindefs', 'outside', 'pinmap', 'kind', 'wire', 'ignore', 'style', 'nosim', 'nowires', 'nolabels', 'steps', 'free', 'fliplr', 'flipud', 'nodots', 'draw_nodes', 'label_nodes', 'nodraw', 'mirrorinputs', 'autoground', 'xoffset', 'yoffset', 'anchor', 'def', 'nodes', 'implicit', 'ground', 'sground', 'rground', 'cground', 'nground', 'pground', '0V', 'vcc', 'vdd', 'vee', 'vss', 'label_values', 'label_ids', 'annotate_values', 'input', 'output', 'bidir', 'pad')
property steps
property stretch
property style
styles = {}
supply_keys = ('vcc', 'vdd', 'vee', 'vss')
supply_negative_keys = ('vee', 'vss')
supply_positive_keys = ('vcc', 'vdd')
property tcoords

Transformed coordinates for each of the nodes

tf(centre, offset, angle_offset=0.0, scale=None)

Transform coordinate.

property up
property variable
property vertical
voltage_keys = ('v', 'v_', 'v^', 'v_>', 'v_<', 'v^>', 'v^<', 'v<', 'v>')
property voltage_str
property w

Normalized width

property wire
property xoffset
property xvals
property yoffset
property yvals
class lcapy.schemcpts.D(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Diode

kinds = {'bidirectional': 'biD', 'laser': 'lasD', 'led': 'leD', 'photo': 'pD', 'schottky': 'sD', 'tunnel': 'tD', 'tvs': 'tvsDo', 'varcap': 'VC', 'zener': 'zD', 'zzener': 'zzD'}
styles = {'empty': '', 'full': '*', 'stroke': '-'}
tikz_cpt = 'D'
class lcapy.schemcpts.Eamp(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Amplifier.

can_scale = True
default_width = 1.0
do_transpose = False
draw(**kwargs)
node_pinnames = ('out', '', 'in', '')
pinlabels = {'vdd': 'VDD', 'vss': 'VSS'}
pins = {'in': ('lx', -1.25, 0.0), 'out': ('rx', 1.25, 0.0), 'r+': ('l', -0.85, 0.25), 'r-': ('l', -0.85, -0.25), 'ref': ('b', 0.45, -0.245), 'vdd': ('t', 0, 0.5), 'vdd2': ('t', -0.45, 0.755), 'vss': ('b', 0, -0.5), 'vss2': ('b', -0.45, -0.755)}
class lcapy.schemcpts.Efdopamp(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

This is for a fully differential opamp created with the E netlist type. See also Ufdopamp for a fully differential opamp created with the U netlist type.

can_mirror = True
can_scale = True
default_width = 1.0
do_transpose = False
draw(**kwargs)
node_pinnames = ('out+', 'out-', 'in+', 'in-', 'ocm')
npins = {'in+': ('l', -1.25, -0.5), 'in-': ('l', -1.25, 0.5), 'ocm': ('l', -0.85, 0), 'out+': ('r', 0.85, 0.5), 'out-': ('r', 0.85, -0.5), 'r+': ('l', -0.85, -0.25), 'r-': ('l', -0.85, 0.25), 'vdd': ('t', -0.25, 0.645), 'vss': ('b', -0.25, -0.645)}
pinlabels = {'vdd': 'VDD', 'vss': 'VSS'}
property pins

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s

(key, value) pairs

dict(iterable) -> new dictionary initialized as if via:

d = {} for k, v in iterable:

d[k] = v

dict(**kwargs) -> new dictionary initialized with the name=value pairs

in the keyword argument list. For example: dict(one=1, two=2)

ppins = {'in+': ('l', -1.25, 0.5), 'in-': ('l', -1.25, -0.5), 'ocm': ('l', -0.85, 0), 'out+': ('r', 0.85, -0.5), 'out-': ('r', 0.85, 0.5), 'r+': ('l', -0.85, 0.25), 'r-': ('l', -0.85, -0.25), 'vdd': ('t', -0.25, 0.645), 'vss': ('b', -0.25, -0.645)}
class lcapy.schemcpts.Einamp(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Eopamp

Instrumentation amplifier created with E netlist type. See also Uinamp for an instrumentation amplifier created with the U netlist type.

auxiliary = {'bl': ('l', -0.5, -0.5), 'br': ('r', 0.5, -0.5), 'lin+': ('c', -0.375, 0.3), 'lin-': ('c', -0.375, -0.3), 'mid': ('c', 0.0, 0.0), 'tl': ('l', -0.5, 0.5), 'top': ('t', 0, 0.5), 'tr': ('r', 0.5, 0.5)}
can_mirror = True
can_scale = True
default_width = 1.0
do_transpose = False
node_pinnames = ('out', 'ref', 'in+', 'in-', 'r+', 'r-')
class lcapy.schemcpts.Ellipse(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Shape

pins = {'e': ('r', 0.5, 0), 'ene': ('r', 0.4619, 0.1913), 'ese': ('r', 0.4619, -0.1913), 'n': ('t', 0, 0.5), 'ne': ('r', 0.3536, 0.35365), 'nne': ('t', 0.1913, 0.4619), 'nnw': ('t', -0.1913, 0.4619), 'nw': ('t', -0.3536, 0.3536), 's': ('b', 0, -0.5), 'se': ('r', 0.3536, -0.3536), 'sse': ('b', 0.1913, -0.4619), 'ssw': ('b', -0.1913, -0.4619), 'sw': ('b', -0.3536, -0.3536), 'w': ('l', -0.5, 0), 'wnw': ('l', -0.4619, 0.1913), 'wsw': ('l', -0.4619, -0.1913)}
shape = 'ellipse'
class lcapy.schemcpts.Eopamp(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

This is for an opamp created with the E netlist type as used for simulation.

can_mirror = True
can_scale = True
default_width = 1.0
do_transpose = False
draw(**kwargs)
node_pinnames = ('out', '', 'in+', 'in-')
npins = {'in+': ('lx', -1.25, -0.5), 'in-': ('lx', -1.25, 0.5), 'out': ('rx', 1.25, 0.0), 'r+': ('l', -0.85, -0.25), 'r-': ('l', -0.85, 0.25), 'ref': ('b', 0.45, -0.245), 'vdd': ('t', 0, 0.5), 'vdd2': ('t', -0.45, 0.755), 'vss': ('b', 0, -0.5), 'vss2': ('b', -0.45, -0.755)}
pinlabels = {'vdd': 'VDD', 'vss': 'VSS'}
property pins

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s

(key, value) pairs

dict(iterable) -> new dictionary initialized as if via:

d = {} for k, v in iterable:

d[k] = v

dict(**kwargs) -> new dictionary initialized with the name=value pairs

in the keyword argument list. For example: dict(one=1, two=2)

ppins = {'in+': ('lx', -1.25, 0.5), 'in-': ('lx', -1.25, -0.5), 'out': ('rx', 1.25, 0.0), 'r+': ('l', -0.85, 0.25), 'r-': ('l', -0.85, -0.25), 'ref': ('b', 0.45, -0.245), 'vdd': ('t', 0, 0.5), 'vdd2': ('t', -0.45, 0.755), 'vss': ('b', 0, -0.5), 'vss2': ('b', -0.45, -0.755)}
class lcapy.schemcpts.FB(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Ferrite bead

draw(**kwargs)
class lcapy.schemcpts.FixedCpt(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Cpt

can_stretch = False
property centre
tf(centre, offset, angle_offset=0.0, scale=None)

Transform coordinate.

class lcapy.schemcpts.Flipflop(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

default_width = 1.0
class lcapy.schemcpts.Gate2(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

can_invert = False
can_mirror = False
can_scale = True
draw(**kwargs)
pins = {'in1': ('l', -0.6, 0.15), 'in2': ('l', -0.6, -0.15), 'out': ('r', 0.55, 0)}
class lcapy.schemcpts.Gyrator(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: FixedCpt

draw(**kwargs)
node_pinnames = ('out+', 'out-', 'in+', 'in-')
pins = {'in+': ('lx', 0, 1), 'in-': ('lx', 0, 0), 'out+': ('rx', 1, 1), 'out-': ('rx', 1, 0)}
class lcapy.schemcpts.I(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Current source

kinds = {'ac': 'sI', 'dc': 'I', 'noise': 'nI', 'square': 'sqI', 'step': 'I', 'triangle': 'tI'}
tikz_cpt = 'I'
class lcapy.schemcpts.JFET(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Transistor

aliases = {'drain': 'd', 'gate': 'g', 'source': 's'}
inpins = {'d': ('lx', 0, 1), 'g': ('lx', 0.55, 0.355), 's': ('lx', 0, 0)}
ippins = {'d': ('lx', 0, 0), 'g': ('lx', 0.55, 0.645), 's': ('lx', 0, 1)}
node_pinnames = ('d', 'g', 's')
npins = {'d': ('lx', 0.55, 1), 'g': ('lx', 0, 0.355), 's': ('lx', 0.55, 0)}
ppins = {'d': ('lx', 0.55, 0), 'g': ('lx', 0, 0.645), 's': ('lx', 0.55, 1)}
class lcapy.schemcpts.K(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: TF1

Mutual coupling

property coords
property nodes

Nodes used to draw the element.

property scales
class lcapy.schemcpts.L(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Inductor

kinds = {'choke': 'cute choke', 'sensor': 'sL', 'tunable': 'vL, tunable end arrow={Bar}', 'twolineschoke': 'cute choke, twolineschoke', 'variable': 'vL'}
tikz_cpt = 'L'
class lcapy.schemcpts.MOSFET(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Transistor

aliases = {'drain': 'd', 'gate': 'g', 'source': 's'}
inpins = {'d': ('lx', 0, 1), 'g': ('lx', 0.55, 0.5), 's': ('lx', 0, 0)}
inpins2 = {'d': ('lx', 0, 1), 'g': ('lx', 0.55, 0.355), 's': ('lx', 0, 0)}
ippins = {'d': ('lx', 0, 0), 'g': ('lx', 0.55, 0.5), 's': ('lx', 0, 1)}
ippins2 = {'d': ('lx', 0, 0), 'g': ('lx', 0.55, 0.645), 's': ('lx', 0, 1)}
kinds = {'hemt': 'hemt', 'nfet': 'nfet', 'nfet-bodydiode': 'nfet-bodydiode', 'nfetd': 'nfetd', 'nfetd-bodydiode': 'nfetd-bodydiode', 'nigfetd': 'nigfetd', 'nigfetd-bodydiode': 'nigfetd-bodydiode', 'nigfete': 'nfigete', 'nigfete-bodydiode': 'nfigete-bodydiode', 'nigfetebulk': 'nigfetebulk', 'nmos': 'nmos', 'nmosd': 'nmosd', 'pfet': 'pfet', 'pfet-bodydiode': 'pfet-bodydiode', 'pfetd': 'pfetd', 'pfetd-bodydiode': 'pfetd-bodydiode', 'pigfetd': 'pigfetd', 'pigfetd-bodydiode': 'pigfetd-bodydiode', 'pigfete': 'pigfete', 'pigfete-bodydiode': 'pigfete-bodydiode', 'pigfetebulk': 'pigfetebulk', 'pmos': 'pmos', 'pmosd': 'pmosd'}
node_pinnames = ('d', 'g', 's')
npins = {'d': ('lx', 0.55, 1), 'g': ('lx', 0, 0.5), 's': ('lx', 0.55, 0)}
npins2 = {'d': ('lx', 0.55, 1), 'g': ('lx', 0, 0.355), 's': ('lx', 0.55, 0)}
ppins = {'d': ('lx', 0.55, 0), 'g': ('lx', 0, 0.5), 's': ('lx', 0.55, 1)}
ppins2 = {'d': ('lx', 0.55, 0), 'g': ('lx', 0, 0.645), 's': ('lx', 0.55, 1)}
class lcapy.schemcpts.MT(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Motor

draw(**kwargs)
class lcapy.schemcpts.MX(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: FixedCpt

Mixer

can_scale = True
draw(**kwargs)
node_pinnames = ('in1', 'in2', 'out')
pins = {'in1': ('lx', 0.25, 0.25), 'in2': ('lx', -0.25, 0.25), 'out': ('rx', 0, 0)}
class lcapy.schemcpts.Mux(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Multiplexer

property path
class lcapy.schemcpts.Potentiometer(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Potentiometer Np, Nm, No

aliases = {'+': 'p', '-': 'n'}
can_stretch = False
node_pinnames = ('p', 'n', 'wiper')
pins = {'n': ('rx', 1, 0), 'p': ('rx', 0, 0), 'wiper': ('lx', 0.5, 0.3)}
class lcapy.schemcpts.R(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Resistor

kinds = {'tunable': 'vR, tunable end arrow = {Bar}', 'variable': 'vR'}
tikz_cpt = 'R'
class lcapy.schemcpts.REL(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Reluctance

kinds = {'tunable': 'vR, tunable end arrow = {Bar}', 'variable': 'vR'}
tikz_cpt = 'R'
class lcapy.schemcpts.SP(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: FixedCpt

Summing point

can_mirror = True
can_scale = True
draw(**kwargs)
node_pinnames = ('in1', 'in2', 'out', 'in3')
npins = {'in1': ('lx', -0.25, 0), 'in2': ('tx', 0, 0.25), 'in3': ('bx', 0, -0.25), 'out': ('rx', 0.25, 0)}
property pins

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s

(key, value) pairs

dict(iterable) -> new dictionary initialized as if via:

d = {} for k, v in iterable:

d[k] = v

dict(**kwargs) -> new dictionary initialized with the name=value pairs

in the keyword argument list. For example: dict(one=1, two=2)

ppins = {'in1': ('lx', -0.25, 0), 'in2': ('bx', 0, -0.25), 'in3': ('tx', 0, 0.25), 'out': ('rx', 0.25, 0)}
class lcapy.schemcpts.SP3(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: SP

Summing point

node_pinnames = ('in1', 'in2', 'out')
npins = {'in1': ('lx', -0.25, 0), 'in2': ('tx', 0, 0.25), 'out': ('rx', 0.25, 0)}
property pins

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s

(key, value) pairs

dict(iterable) -> new dictionary initialized as if via:

d = {} for k, v in iterable:

d[k] = v

dict(**kwargs) -> new dictionary initialized with the name=value pairs

in the keyword argument list. For example: dict(one=1, two=2)

ppins = {'in1': ('lx', -0.25, 0), 'in2': ('bx', 0, -0.25), 'out': ('rx', 0.25, 0)}
class lcapy.schemcpts.SPDT(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: FixedCpt

SPDT switch

aliases = {'+': 'p', '-': 'n'}
can_invert = True
can_mirror = True
draw(**kwargs)
node_pinnames = ('p', 'n', 'common')
npins = {'common': ('lx', 0, 0), 'n': ('rx', 0, 0.338), 'p': ('lx', 0.632, 0.169)}
property pins

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s

(key, value) pairs

dict(iterable) -> new dictionary initialized as if via:

d = {} for k, v in iterable:

d[k] = v

dict(**kwargs) -> new dictionary initialized with the name=value pairs

in the keyword argument list. For example: dict(one=1, two=2)

ppins = {'common': ('lx', 0.632, 0), 'n': ('rx', 0.632, 0.338), 'p': ('lx', 0, 0.169)}
class lcapy.schemcpts.SPpm(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: SP3

Summing point

labels = '+-'
class lcapy.schemcpts.SPpmm(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: SP

Summing point

labels = '+--'
class lcapy.schemcpts.SPpp(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: SP3

Summing point

labels = '++'
class lcapy.schemcpts.SPppm(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: SP

Summing point

labels = '++-'
class lcapy.schemcpts.SPppp(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: SP

Summing point

labels = '+++'
class lcapy.schemcpts.Shape(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: FixedCpt

General purpose shape

auxiliary = {'bl': ('l', -0.5, -0.5), 'br': ('r', 0.5, -0.5), 'mid': ('c', 0.0, 0.0), 'tl': ('l', -0.5, 0.5), 'top': ('t', 0, 0.5), 'tr': ('r', 0.5, 0.5)}
can_invert = True
can_mirror = True
default_aspect = 1.0
draw(**kwargs)
property height
parse_pindefs()
parse_pinlabels()
parse_pinnames()
parse_pinnodes()
pinlabels = {}
pinpos_rotate(pinpos, angle)

Rotate pinpos by multiple of 90 degrees. pinpos is either ‘l’, ‘t’, ‘r’, ‘b’.

process_implicit_nodes()

Parse implicit nodes.

process_pinlabels()
process_pinnames()
process_pinnodes()
setup()
property width
class lcapy.schemcpts.StretchyCpt(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Cpt

can_stretch = True
xtf(centre, offset, angle_offset=0.0)

Transform x coordinate.

class lcapy.schemcpts.TF1(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: FixedCpt

Transformer

can_scale = True
default_aspect = 0.8
draw(link=True, **kwargs)
misc = {'label': (0, 0.48), 'link': (0, 0.15), 'pdot': (-0.30000000000000004, 0.34), 'sdot': (0.30000000000000004, 0.34)}
node_pinnames = ('s+', 's-', 'p+', 'p-')
pins = {'p+': ('lx', 0, 1), 'p-': ('lx', 0, 0), 's+': ('rx', 0.8, 1), 's-': ('rx', 0.8, 0)}
w = 0.8
class lcapy.schemcpts.TFtap(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: TF1

Transformer

draw(**kwargs)
property drawn_nodes

Nodes that are drawn

node_pinnames = ('s+', 's-', 'p+', 'p-', 'ptap', 'stap')
pins = {'p+': ('lx', 0, 1), 'p-': ('lx', 0, 0), 'ptap': ('lx', 0, 0.5), 's+': ('rx', 0.8, 1), 's-': ('rx', 0.8, 0), 'stap': ('rx', 0.8, 0.5)}
w = 0.8
class lcapy.schemcpts.TL(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: StretchyCpt

Transmission line

aliases = {'in+': 'in1', 'in-': 'in2', 'out+': 'out1', 'out-': 'out2'}
can_scale = True
draw(**kwargs)
property drawn_nodes

Nodes that are drawn

node_pinnames = ('out1', 'out2', 'in1', 'in2')
pins = {'in1': ('lx', 0, 0.5), 'in2': ('lx', 0, 0), 'out1': ('rx', 1, 0.5), 'out2': ('rx', 1, 0)}
w = 1
class lcapy.schemcpts.TR(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Box2

Transfer function

default_aspect = 1.5
default_width = 1.5
node_pinnames = ('w', 'e')
class lcapy.schemcpts.Transformer(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: TF1

draw(**kwargs)
class lcapy.schemcpts.Transistor(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: FixedCpt

can_invert = True
can_mirror = True
can_scale = True
draw(**kwargs)
property pins

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s

(key, value) pairs

dict(iterable) -> new dictionary initialized as if via:

d = {} for k, v in iterable:

d[k] = v

dict(**kwargs) -> new dictionary initialized with the name=value pairs

in the keyword argument list. For example: dict(one=1, two=2)

class lcapy.schemcpts.Triangle(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Shape

Equilateral triangle. The triangle shape can be altered by defining aspect.

auxiliary = {'bl': ('l', -0.5, -0.2887), 'br': ('r', 0.5, -0.2887), 'mid': ('c', 0.0, 0.0), 'tl': ('l', -0.5, 0.5774), 'top': ('t', 0, 0.5774), 'tr': ('r', 0.5, 0.5774)}
draw(**kwargs)
pins = {'e': ('r', 0.5, -0.2887), 'ene': ('r', 0.375, -0.075), 'ese': ('b', 0.375, -0.2887), 'n': ('t', 0.0, 0.5774), 'ne': ('r', 0.25, 0.14435), 'nne': ('r', 0.125, 0.355), 'nnw': ('l', -0.125, 0.355), 'nw': ('l', -0.25, 0.14435), 's': ('b', 0.0, -0.2887), 'se': ('b', 0.25, -0.2887), 'sse': ('b', 0.125, -0.2887), 'ssw': ('b', -0.125, -0.2887), 'sw': ('b', -0.25, -0.2887), 'w': ('l', -0.5, -0.2887), 'wnw': ('l', -0.375, -0.075), 'wsw': ('b', -0.375, -0.2887)}
required_auxiliary = ('top', 'bl', 'br', 'mid')
shape = 'triangle'
class lcapy.schemcpts.Triode(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: FixedCpt

aliases = {'anode': 'a', 'cathode': 'k', 'grid': 'g'}
draw(**kwargs)
node_pinnames = ('a', 'g', 'k')
pins = {'a': ('l', 0.75, 0), 'g': ('l', 0.25, 0.5), 'k': ('l', -0.25, 0)}
class lcapy.schemcpts.TwoPort(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Shape

Two-port

auxiliary = {'bl': ('l', -0.5, -0.5), 'br': ('r', 0.5, -0.5), 'ene': ('l', 0.5, 0.375), 'ese': ('l', 0.5, -0.375), 'mid': ('c', 0.0, 0.0), 'tl': ('l', -0.5, 0.5), 'top': ('t', 0, 0.5), 'tr': ('r', 0.5, 0.5), 'wnw': ('l', -0.5, 0.375), 'wsw': ('l', -0.5, -0.375)}
default_aspect = 1
default_width = 1
draw(**kwargs)
n = 0.75
node_pinnames = ('out+', 'out-', 'in+', 'in-')
p = 0.375
pins = {'e': ('r', 0.5, 0), 'in+': ('lx', -0.75, 0.375), 'in-': ('lx', -0.75, -0.375), 'n': ('t', 0, 0.5), 'nne': ('t', 0.375, 0.5), 'nnw': ('t', -0.375, 0.5), 'out+': ('rx', 0.75, 0.375), 'out-': ('rx', 0.75, -0.375), 's': ('b', 0, -0.5), 'sse': ('b', 0.375, -0.5), 'ssw': ('b', -0.375, -0.5), 'w': ('l', -0.5, 0)}
required_auxiliary = ('wnw', 'wsw', 'ene', 'ese', 'mid')
shape = 'rectangle'
shape_scale = 1.3333333333333333
x = 0.5
class lcapy.schemcpts.Uadc(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

ADC

property path
pinlabels = {'avdd': 'AVDD', 'avss': 'AVSS', 'clk': '>', 'data': 'DATA', 'dvdd': 'DVDD', 'dvss': 'DVSS', 'fs': 'FS', 'vdd': 'VDD', 'vref+': 'VREF+', 'vref-': 'VREF-', 'vss': 'VSS'}
pins = {'avdd': ('t', -0.1, 0.5), 'avss': ('b', -0.1, -0.5), 'clk': ('r', 0.5, -0.25), 'data': ('r', 0.5, 0), 'dvdd': ('t', 0.3, 0.5), 'dvss': ('b', 0.3, -0.5), 'fs': ('r', 0.5, 0.25), 'in': ('l', -0.5, 0), 'in+': ('l', -0.4375, 0.125), 'in-': ('l', -0.4375, -0.125), 'vdd': ('t', 0.1, 0.5), 'vref+': ('l', -0.375, 0.25), 'vref-': ('l', -0.375, -0.25), 'vss': ('b', 0.1, -0.5)}
class lcapy.schemcpts.Uand(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Gate2

kind = 'and'
class lcapy.schemcpts.Ubuffer(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Buffer with power supplies

default_width = 1.0
property path
pinlabels = {'en': 'E', 'vdd': 'VDD', 'vss': 'VSS'}
pins = {'en': ('b', -0.25, -0.375), 'in': ('l', -0.5, 0), 'out': ('r', 0.5, 0), 'vdd': ('t', 0, 0.25), 'vdd1': ('t', -0.25, 0.375), 'vdd2': ('t', 0.25, 0.125), 'vss': ('b', 0, -0.25)}
class lcapy.schemcpts.Uchip1313(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Chip of size 1 3 1 3

aliases = {'in': 'l1', 'out': 'r1', 'vdd': 't2', 'vss': 'b2'}
pins = {'b1': ('b', -0.25, -0.5), 'b2': ('b', 0, -0.5), 'b3': ('b', 0.25, -0.5), 'l1': ('l', -0.5, 0), 'r1': ('r', 0.5, 0), 't1': ('t', -0.25, 0.5), 't2': ('t', 0, 0.5), 't3': ('t', 0.25, 0.5)}
class lcapy.schemcpts.Uchip2121(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Chip of size 2 1 2 1

aliases = {'vdd': 't1', 'vss': 'b1'}
pinlabels = {'vdd': 'VDD', 'vss': 'VSS'}
pins = {'b1': ('b', 0, -0.5), 'l1': ('l', -0.5, 0.25), 'l2': ('l', -0.5, -0.25), 'r1': ('r', 0.5, 0.25), 'r2': ('r', 0.5, -0.25), 't1': ('t', 0, 0.5)}
class lcapy.schemcpts.Uchip2222(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Chip of size 2 2 2 2

pins = {'b1': ('b', -0.25, -0.5), 'b2': ('b', 0.25, -0.5), 'l1': ('l', -0.5, 0.25), 'l2': ('l', -0.5, -0.25), 'r1': ('r', 0.5, 0.25), 'r2': ('r', 0.5, -0.25), 't1': ('t', -0.25, 0.5), 't2': ('t', 0.25, 0.5)}
class lcapy.schemcpts.Uchip3131(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Chip of size 3 1 3 1

aliases = {'vdd': 't1', 'vss': 'b1'}
property path
pinlabels = {'vdd': 'VDD', 'vss': 'VSS'}
pins = {'b1': ('b', 0.0, -0.5), 'l1': ('l', -0.5, 0.25), 'l2': ('l', -0.5, 0), 'l3': ('l', -0.5, -0.25), 'r1': ('r', 0.5, 0.25), 'r2': ('r', 0.5, 0), 'r3': ('r', 0.5, -0.25), 't1': ('t', 0.0, 0.5)}
class lcapy.schemcpts.Uchip3333(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Chip of size 3 3 3 3

aliases = {'vdd': 't2', 'vss': 'b2'}
property path
pinlabels = {'vdd': 'VDD', 'vss': 'VSS'}
pins = {'b1': ('b', -0.25, -0.5), 'b2': ('b', 0.0, -0.5), 'b3': ('b', 0.25, -0.5), 'l1': ('l', -0.5, 0.25), 'l2': ('l', -0.5, 0), 'l3': ('l', -0.5, -0.25), 'r1': ('r', 0.5, 0.25), 'r2': ('r', 0.5, 0), 'r3': ('r', 0.5, -0.25), 't1': ('t', -0.25, 0.5), 't2': ('t', 0.0, 0.5), 't3': ('t', 0.25, 0.5)}
class lcapy.schemcpts.Uchip4141(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Chip of size 4 1 4 1

aliases = {'vdd': 't1', 'vss': 'b1'}
pins = {'b1': ('b', 0.0, -0.5), 'l1': ('l', -0.5, 0.375), 'l2': ('l', -0.5, 0.125), 'l3': ('l', -0.5, -0.125), 'l4': ('l', -0.5, -0.375), 'r1': ('r', 0.5, 0.375), 'r2': ('r', 0.5, 0.125), 'r3': ('r', 0.5, -0.125), 'r4': ('r', 0.5, -0.375), 't1': ('t', 0.0, 0.5)}
class lcapy.schemcpts.Uchip4444(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Chip of size 4 4 4 4

pins = {'b1': ('b', -0.375, -0.5), 'b2': ('b', -0.125, -0.5), 'b3': ('b', 0.125, -0.5), 'b4': ('b', 0.375, -0.5), 'l1': ('l', -0.5, 0.375), 'l2': ('l', -0.5, 0.125), 'l3': ('l', -0.5, -0.125), 'l4': ('l', -0.5, -0.375), 'r1': ('r', 0.5, 0.375), 'r2': ('r', 0.5, 0.125), 'r3': ('r', 0.5, -0.125), 'r4': ('r', 0.5, -0.375), 't1': ('t', -0.375, 0.5), 't2': ('t', -0.125, 0.5), 't3': ('t', 0.125, 0.5), 't4': ('t', 0.375, 0.5)}
class lcapy.schemcpts.Uchip5555(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Chip of size 5 5 5 5

pins = {'b1': ('b', -0.4, -0.5), 'b2': ('b', -0.2, -0.5), 'b3': ('b', 0.0, -0.5), 'b4': ('b', 0.2, -0.5), 'b5': ('b', 0.4, -0.5), 'l1': ('l', -0.5, 0.4), 'l2': ('l', -0.5, 0.2), 'l3': ('l', -0.5, 0.0), 'l4': ('l', -0.5, -0.2), 'l5': ('l', -0.5, -0.4), 'r1': ('r', 0.5, 0.4), 'r2': ('r', 0.5, 0.2), 'r3': ('r', 0.5, 0.0), 'r4': ('r', 0.5, -0.2), 'r5': ('r', 0.5, -0.4), 't1': ('t', -0.4, 0.5), 't2': ('t', -0.2, 0.5), 't3': ('t', 0, 0.5), 't4': ('t', 0.2, 0.5), 't5': ('t', 0.4, 0.5)}
class lcapy.schemcpts.Uchip6666(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Chip of size 6 6 6 6

pins = {'b1': ('b', -0.375, -0.5), 'b2': ('b', -0.225, -0.5), 'b3': ('b', -0.075, -0.5), 'b4': ('b', 0.075, -0.5), 'b5': ('b', 0.225, -0.5), 'b6': ('b', 0.375, -0.5), 'l1': ('l', -0.5, 0.375), 'l2': ('l', -0.5, 0.225), 'l3': ('l', -0.5, 0.075), 'l4': ('l', -0.5, -0.075), 'l5': ('l', -0.5, -0.225), 'l6': ('l', -0.5, -0.375), 'r1': ('r', 0.5, 0.375), 'r2': ('r', 0.5, 0.225), 'r3': ('r', 0.5, 0.075), 'r4': ('r', 0.5, -0.075), 'r5': ('r', 0.5, -0.225), 'r6': ('r', 0.5, -0.375), 't1': ('t', -0.375, 0.5), 't2': ('t', -0.225, 0.5), 't3': ('t', -0.075, 0.5), 't4': ('t', 0.075, 0.5), 't5': ('t', 0.225, 0.5), 't6': ('t', 0.357, 0.5)}
class lcapy.schemcpts.Uchip7777(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Chip of size 7 7 7 7

pins = {'b1': ('b', -0.375, -0.5), 'b2': ('b', -0.25, -0.5), 'b3': ('b', -0.125, -0.5), 'b4': ('b', 0.0, -0.5), 'b5': ('b', 0.125, -0.5), 'b6': ('b', 0.25, -0.5), 'b7': ('b', 0.375, -0.5), 'l1': ('l', -0.5, 0.375), 'l2': ('l', -0.5, 0.25), 'l3': ('l', -0.5, 0.125), 'l4': ('l', -0.5, 0.0), 'l5': ('l', -0.5, -0.125), 'l6': ('l', -0.5, -0.25), 'l7': ('l', -0.5, -0.375), 'r1': ('r', 0.5, 0.375), 'r2': ('r', 0.5, 0.25), 'r3': ('r', 0.5, 0.125), 'r4': ('r', 0.5, 0.0), 'r5': ('r', 0.5, -0.125), 'r6': ('r', 0.5, -0.25), 'r7': ('r', 0.5, -0.375), 't1': ('t', -0.375, 0.5), 't2': ('t', -0.25, 0.5), 't3': ('t', -0.125, 0.5), 't4': ('t', 0.0, 0.5), 't5': ('t', 0.125, 0.5), 't6': ('t', 0.25, 0.5), 't7': ('t', 0.375, 0.5)}
class lcapy.schemcpts.Uchip8181(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Chip of size 8 1 8 1

aliases = {'vdd': 't1', 'vss': 'b1'}
pins = {'b1': ('b', 0.0, -0.5), 'l1': ('l', -0.5, 0.4375), 'l2': ('l', -0.5, 0.3125), 'l3': ('l', -0.5, 0.1875), 'l4': ('l', -0.5, 0.0625), 'l5': ('l', -0.5, -0.0625), 'l6': ('l', -0.5, -0.1875), 'l7': ('l', -0.5, -0.3125), 'l8': ('l', -0.5, -0.4375), 'r1': ('r', 0.5, 0.4375), 'r2': ('r', 0.5, 0.3125), 'r3': ('r', 0.5, 0.1875), 'r4': ('r', 0.5, 0.0625), 'r5': ('r', 0.5, -0.0625), 'r6': ('r', 0.5, -0.1875), 'r7': ('r', 0.5, -0.3125), 'r8': ('r', 0.5, -0.4375), 't1': ('t', 0.0, 0.5)}
class lcapy.schemcpts.Uchip8888(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Chip of size 8 8 8 8

pins = {'b1': ('b', -0.4375, -0.5), 'b2': ('b', -0.3125, -0.5), 'b3': ('b', -0.1875, -0.5), 'b4': ('b', -0.0625, -0.5), 'b5': ('b', 0.0625, -0.5), 'b6': ('b', 0.1875, -0.5), 'b7': ('b', 0.3125, -0.5), 'b8': ('b', 0.4375, -0.5), 'l1': ('l', -0.5, 0.4375), 'l2': ('l', -0.5, 0.3125), 'l3': ('l', -0.5, 0.1875), 'l4': ('l', -0.5, 0.0625), 'l5': ('l', -0.5, -0.0625), 'l6': ('l', -0.5, -0.1875), 'l7': ('l', -0.5, -0.3125), 'l8': ('l', -0.5, -0.4375), 'r1': ('r', 0.5, 0.4375), 'r2': ('r', 0.5, 0.3125), 'r3': ('r', 0.5, 0.1875), 'r4': ('r', 0.5, 0.0625), 'r5': ('r', 0.5, -0.0625), 'r6': ('r', 0.5, -0.1875), 'r7': ('r', 0.5, -0.3125), 'r8': ('r', 0.5, -0.4375), 't1': ('t', -0.4375, 0.5), 't2': ('t', -0.3125, 0.5), 't3': ('t', -0.1875, 0.5), 't4': ('t', -0.0625, 0.5), 't5': ('t', 0.0625, 0.5), 't6': ('t', 0.1875, 0.5), 't7': ('t', 0.3125, 0.5), 't8': ('t', 0.4375, 0.5)}
class lcapy.schemcpts.Udac(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

DAC

property path
pinlabels = {'avdd': 'AVDD', 'avss': 'AVSS', 'clk': '>', 'data': 'DATA', 'dvdd': 'DVDD', 'dvss': 'DVSS', 'fs': 'FS', 'vdd': 'VDD', 'vref+': 'VREF+', 'vref-': 'VREF-', 'vss': 'VSS'}
pins = {'avdd': ('t', 0.1, 0.5), 'avss': ('b', 0.1, -0.5), 'clk': ('l', -0.5, -0.25), 'data': ('l', -0.5, 0), 'dvdd': ('t', -0.3, 0.5), 'dvss': ('b', -0.3, -0.5), 'fs': ('l', -0.5, 0.25), 'out': ('r', 0.5, 0), 'out+': ('r', 0.4375, 0.125), 'out-': ('r', 0.4375, -0.125), 'vdd': ('t', -0.1, 0.5), 'vref+': ('r', 0.375, 0.25), 'vref-': ('r', 0.375, -0.25), 'vss': ('b', -0.1, -0.5)}
class lcapy.schemcpts.Udff(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Flipflop

D flip-flop

default_pins = ('d', 'clk', 'q')
pinlabels = {'/q': '$\\overline{\\mathrm{Q}}$', 'clk': '>', 'd': 'D', 'q': 'Q', 'vdd': 'VDD', 'vss': 'VSS'}
pins = {'/q': ('r', 0.5, -0.25), 'clk': ('l', -0.5, 0), 'd': ('l', -0.5, 0.25), 'q': ('r', 0.5, 0.25), 'vdd': ('t', 0.0, 0.5), 'vss': ('b', 0.0, -0.5)}
class lcapy.schemcpts.Udiffamp(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Differential amplifier. It is not automatically annotated with + and - symbols for inputs. This can be achieved using pinlabels={in+, in-}.

default_width = 1.0
property path
pinlabels = {'in+': '$+$', 'in-': '$-$', 'vdd': 'VDD', 'vss': 'VSS'}
pins = {'in+': ('l', -0.5, 0.25), 'in-': ('l', -0.5, -0.25), 'out': ('r', 0.5, 0), 'vdd': ('t', 0, 0.25), 'vss': ('b', 0, -0.25)}
class lcapy.schemcpts.Udiffdriver(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Differential driver with power supplies

default_width = 1.0
draw(**kwargs)
property path
pinlabels = {'en': 'E', 'vdd': 'VDD', 'vss': 'VSS'}
pins = {'en': ('b', -0.3, -0.4), 'in': ('l', -0.5, 0), 'out+': ('r', -0.02, 0.25), 'out-': ('r', 0.1, -0.25), 'vdd': ('t', 0, 0.22), 'vss': ('b', -0.15, -0.3)}
class lcapy.schemcpts.Ufdopamp(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

This is for a fully differential opamp created with the U netlist type. It has no wires. See also Efdopamp for a fully differential opamp created with the E netlist type.

auxiliary = {'bl': ('l', -0.5, -0.5), 'br': ('r', 0.5, -0.5), 'lin+': ('c', -0.375, 0.2), 'lin-': ('c', -0.375, -0.2), 'lout+': ('c', 0, -0.17), 'lout-': ('c', 0, 0.17), 'mid': ('c', 0.0, 0.0), 'tl': ('l', -0.5, 0.5), 'top': ('t', 0, 0.5), 'tr': ('r', 0.5, 0.5)}
can_mirror = True
draw(**kwargs)
npins = {'in+': ('l', -0.5, -0.2), 'in-': ('l', -0.5, 0.2), 'ocm': ('l', -0.5, 0), 'out+': ('r', 0.1, 0.2), 'out-': ('r', 0.1, -0.2), 'vdd': ('t', -0.1, 0.3), 'vss': ('b', -0.1, -0.3)}
property path
pinlabels = {'vdd': 'VDD', 'vss': 'VSS'}
property pins

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s

(key, value) pairs

dict(iterable) -> new dictionary initialized as if via:

d = {} for k, v in iterable:

d[k] = v

dict(**kwargs) -> new dictionary initialized with the name=value pairs

in the keyword argument list. For example: dict(one=1, two=2)

ppins = {'in+': ('l', -0.5, 0.2), 'in-': ('l', -0.5, -0.2), 'ocm': ('l', -0.5, 0), 'out+': ('r', 0.1, -0.2), 'out-': ('r', 0.1, 0.2), 'vdd': ('t', -0.1, 0.3), 'vss': ('b', -0.1, -0.3)}
required_auxiliary = ('lin+', 'lin-', 'lout+', 'lout-', 'mid')
class lcapy.schemcpts.Uinamp(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Uopamp

Instrumentation amplifier created with U netlist type.

auxiliary = {'bl': ('l', -0.5, -0.5), 'br': ('r', 0.5, -0.5), 'lin+': ('c', -0.375, 0.3), 'lin-': ('c', -0.375, -0.3), 'mid': ('c', 0.0, 0.0), 'tl': ('l', -0.5, 0.5), 'top': ('t', 0, 0.5), 'tr': ('r', 0.5, 0.5)}
can_mirror = True
npins = {'in+': ('l', -0.5, -0.3), 'in-': ('l', -0.5, 0.3), 'out': ('r', 0.5, 0.0), 'r+': ('l', -0.5, -0.2), 'r-': ('l', -0.5, 0.2), 'ref': ('b', 0.225, -0.135), 'vdd': ('t', 0, 0.25), 'vdd2': ('t', -0.225, 0.365), 'vss': ('b', 0, -0.25), 'vss2': ('b', -0.225, -0.365)}
ppins = {'in+': ('l', -0.5, 0.3), 'in-': ('l', -0.5, -0.3), 'out': ('r', 0.5, 0.0), 'r+': ('l', -0.5, 0.2), 'r-': ('l', -0.5, -0.2), 'ref': ('b', 0.225, -0.135), 'vdd': ('t', 0, 0.25), 'vdd2': ('t', -0.225, 0.365), 'vss': ('b', 0, -0.25), 'vss2': ('b', -0.225, -0.365)}
class lcapy.schemcpts.Uinverter(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Inverter with power supplies

default_width = 1.0
draw(**kwargs)
property path
pinlabels = {'en': 'E', 'vdd': 'VDD', 'vss': 'VSS'}
pins = {'en': ('b', -0.25, -0.37), 'in': ('l', -0.5, 0), 'out': ('r', 0.5, 0), 'vdd': ('t', 0, 0.22), 'vss': ('b', 0, -0.22)}
class lcapy.schemcpts.Uisoamp(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Ufdopamp

Isolated amplifier created with U netlist type.

auxiliary = {'bl': ('l', -0.5, -0.5), 'br': ('r', 0.5, -0.5), 'lin+': ('c', -0.4, 0.2), 'lin-': ('c', -0.4, -0.2), 'lout+': ('c', 0.1, 0.12), 'lout-': ('c', 0.1, -0.12), 'mid': ('c', 0.0, 0.0), 'tl': ('l', -0.5, 0.5), 'top': ('t', 0, 0.5), 'tr': ('r', 0.5, 0.5)}
property path
pins = {'in': ('l', -0.5, 0.0), 'in+': ('l', -0.5, 0.2), 'in-': ('l', -0.5, -0.2), 'out': ('r', 0.5, 0), 'out+': ('r', 0.2, 0.15), 'out-': ('r', 0.2, -0.15), 'vdd1': ('t', -0.3, 0.4), 'vdd2': ('t', 0.0, 0.25), 'vss1': ('b', -0.3, -0.4), 'vss2': ('b', 0.0, -0.25)}
class lcapy.schemcpts.Ujkff(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Flipflop

JK flip-flop

default_pins = ('j', 'k', 'clk', 'q')
pinlabels = {'/q': '$\\overline{\\mathrm{Q}}$', 'clk': '>', 'j': 'J', 'k': 'K', 'q': 'Q', 'vdd': 'VDD', 'vss': 'VSS'}
pins = {'/q': ('r', 0.5, -0.25), 'clk': ('l', -0.5, 0), 'j': ('l', -0.5, 0.25), 'k': ('l', -0.5, -0.25), 'q': ('r', 0.5, 0.25), 'vdd': ('t', 0.0, 0.5), 'vss': ('b', 0.0, -0.5)}
class lcapy.schemcpts.Umux21(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Mux

Multiplexer 2 to 1

pins = {'b': ('b', 0, -0.375), 'l1': ('l', -0.25, 0.25), 'l2': ('l', -0.25, -0.25), 'r': ('r', 0.25, 0.0), 't': ('t', 0, 0.375)}
class lcapy.schemcpts.Umux41(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Mux

Multiplexer 4 to 1

pins = {'b1': ('b', -0.125, -0.4375), 'b2': ('b', 0.125, -0.3125), 'l1': ('l', -0.25, 0.375), 'l2': ('l', -0.25, 0.125), 'l3': ('l', -0.25, -0.125), 'l4': ('l', -0.25, -0.375), 'r': ('r', 0.25, 0), 't1': ('t', -0.125, 0.4375), 't2': ('t', 0.125, 0.3125)}
class lcapy.schemcpts.Umux42(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Mux

Multiplexer 4 to 2

pins = {'b1': ('b', -0.125, -0.4375), 'b2': ('b', 0.125, -0.3125), 'l1': ('l', -0.25, 0.375), 'l2': ('l', -0.25, 0.125), 'l3': ('l', -0.25, -0.125), 'l4': ('l', -0.25, -0.375), 'r1': ('r', 0.25, 0.125), 'r2': ('r', 0.25, -0.125), 't1': ('t', -0.125, 0.4375), 't2': ('t', 0.125, 0.3125)}
class lcapy.schemcpts.Unand(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Gate2

kind = 'nand'
class lcapy.schemcpts.Unipole(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Cpt

aliases = {'p': '+'}
draw(**kwargs)
node_pinnames = ('+',)
pins = {'+': ('lx', 0, 0)}
place = False
class lcapy.schemcpts.Unor(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Gate2

kind = 'nor'
class lcapy.schemcpts.Uopamp(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

This is for an opamp created with the U netlist type. It has no wires. See also Opamp for an opamp created with the E netlist type.

auxiliary = {'bl': ('l', -0.5, -0.5), 'br': ('r', 0.5, -0.5), 'lin+': ('c', -0.375, 0.25), 'lin-': ('c', -0.375, -0.25), 'mid': ('c', 0.0, 0.0), 'tl': ('l', -0.5, 0.5), 'top': ('t', 0, 0.5), 'tr': ('r', 0.5, 0.5)}
can_mirror = True
draw(**kwargs)
npins = {'in+': ('l', -0.5, -0.25), 'in-': ('l', -0.5, 0.25), 'out': ('r', 0.5, 0.0), 'r+': ('l', -0.5, -0.125), 'r-': ('l', -0.5, 0.125), 'ref': ('b', 0.225, -0.135), 'vdd': ('t', 0, 0.25), 'vdd2': ('t', -0.225, 0.365), 'vss': ('b', 0, -0.25), 'vss2': ('b', -0.225, -0.365)}
property path
pinlabels = {'vdd': 'VDD', 'vss': 'VSS'}
property pins

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s

(key, value) pairs

dict(iterable) -> new dictionary initialized as if via:

d = {} for k, v in iterable:

d[k] = v

dict(**kwargs) -> new dictionary initialized with the name=value pairs

in the keyword argument list. For example: dict(one=1, two=2)

ppins = {'in+': ('l', -0.5, 0.25), 'in-': ('l', -0.5, -0.25), 'out': ('r', 0.5, 0.0), 'r+': ('l', -0.5, 0.125), 'r-': ('l', -0.5, -0.125), 'ref': ('b', 0.225, -0.135), 'vdd': ('t', 0, 0.25), 'vdd2': ('t', -0.225, 0.365), 'vss': ('b', 0, -0.25), 'vss2': ('b', -0.225, -0.365)}
required_auxiliary = ('lin+', 'lin-', 'mid')
class lcapy.schemcpts.Uor(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Gate2

kind = 'or'
class lcapy.schemcpts.Uregulator(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Chip

Voltage regulator

default_aspect = 1.3333333333333333
pinlabels = {'en': 'E', 'gnd': 'GND'}
pins = {'en': ('b', -0.25, -0.5), 'gnd': ('b', 0, -0.5), 'in': ('l', -0.5, 0), 'out': ('r', 0.5, 0)}
class lcapy.schemcpts.Urslatch(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Flipflop

RS latch

default_pins = ('r', 's', 'q')
pinlabels = {'/q': '$\\overline{\\mathrm{Q}}$', 'q': 'Q', 'r': 'R', 's': 'S', 'vdd': 'VDD', 'vss': 'VSS'}
pins = {'/q': ('r', 0.5, -0.25), 'q': ('r', 0.5, 0.25), 'r': ('l', -0.5, 0.25), 's': ('l', -0.5, -0.25), 'vdd': ('t', 0.0, 0.5), 'vss': ('b', 0.0, -0.5)}
class lcapy.schemcpts.Uxnor(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Gate2

kind = 'xnor'
class lcapy.schemcpts.Uxor(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Gate2

kind = 'xor'
class lcapy.schemcpts.V(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Voltage source

kinds = {'ac': 'sV', 'dc': 'V', 'noise': 'nV', 'square': 'sqV', 'step': 'V', 'triangle': 'tV'}
tikz_cpt = 'V'
class lcapy.schemcpts.VCS(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Voltage controlled source

node_pinnames = ('+', '-', '', '')
class lcapy.schemcpts.Wire(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

draw(**kwargs)
class lcapy.schemcpts.XX(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Cpt

directive = True
draw(**kwargs)
process_opts_nodes()
class lcapy.schemcpts.Y(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Admittance

kinds = {'sensor': 'european resistive sensor', 'tunable': 'variable european resistor, tunable end arrow = {Bar}', 'variable': 'variable european resistor'}
tikz_cpt = 'generic'
class lcapy.schemcpts.Z(sch, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, keyword, *args)

Bases: Bipole

Impedance

kinds = {'sensor': 'european resistive sensor', 'tunable': 'variable european resistor, tunable end arrow = {Bar}', 'variable': 'variable european resistor'}
tikz_cpt = 'generic'
lcapy.schemcpts.anchor_choose(pinpos, outside=False)
lcapy.schemcpts.anchor_map(anchor)
lcapy.schemcpts.angle_choose(pinpos)
lcapy.schemcpts.arrow_map(name)
lcapy.schemcpts.check_boolean(value)
lcapy.schemcpts.defcpt(name, base, docstring, cpt=None)
lcapy.schemcpts.make(classname, parent, namespace, name, cpt_type, cpt_id, string, opts_string, node_names, *args)

Schemgraph

This module provides classes for schematic layout.

Copyright 2014–2021 Michael Hayes, UCECE

class lcapy.schemgraph.Gedge(cpt, from_gnode, to_gnode, size, stretch=False)

Bases: object

Edge between common nodes

property name
class lcapy.schemgraph.Gnode(name)

Bases: object

Drawing node

add_fedge(edge)
add_redge(edge)
property fmt_name
property pos
class lcapy.schemgraph.Graph(name, nodes, debug=False)

Bases: dict

Drawing graph

add(cpt, n1, n2, size, stretch)

Add cpt between nodes n1 and n2 to the graph

add_edges(cpt, gnode1, gnode2, size, stretch)
add_node(n)
add_start_nodes()

Nodes without forward edges are connected to the end node. Nodes without reverse edges are connected to the start node.

property all_nodes
assign_fixed(unknown)

Assign node positions to nodes with fixed edge lengths to nodes with known positions. Iterate until no more changes. This stage is not needed but provides a minor optimisation.

assign_fixed1(gnode)
assign_longest(path, unknown)
assign_stretchy(unknown)

Use a worklist algorithm to assign nodes with unknown positions that are connected via stretchable edges to the known nodes.

assign_stretchy1(gnode, unknown)
check_positions()
dot(filename=None, stage=None, tweak_node_label=True)

Generate directed graph using graphviz notation

Make nodes n1 and n2 share common gnode

longest_path(from_gnode, to_gnode)

Find longest path through DAG from from_gnode to to_gnode or to a gnode with a known position.

makepath(from_gnode)
property nodes
path_to_closest_known(from_gnode, forward=True)

Find path through DAG to the closest node with a known pos.

prune()

Remove redundant paths from graph. If there are two parallel stretchy edges, the longest is chosen.

solve(stage=None)

Solve graph assigning gnode positions.

stage 0 — do nothing stage 1 — prune redundant edges stage 2 — add start/end nodes and assign gnode positions on longest path stage 3 — assign gnode positions with fixed positions to known gnodes stage 4 — assign all gnode positions

suggest_edges()
class lcapy.schemgraph.GraphPath(iterable=(), /)

Bases: list

This is a list of edges defining a path through a graph.

property dist
from_dist(match_node)
property from_gnode
property gnodes

Return list of nodes along path including end nodes.

on(match_node)
property stretches
to_dist(match_node)
property to_gnode

Schemmisc

This module provides miscellaneous support for schematic drawing.

Copyright 2014–2023 Michael Hayes, UCECE

class lcapy.schemmisc.Pos(x, y=0)

Bases: object

norm()
property xy
class lcapy.schemmisc.Steps(string, pos1, pos2)

Bases: object

General

Config

This module contains configuration information.

Copyright 2019–2021 Michael Hayes, UCECE

Grammar

This module defines a grammar for SPICE-like netlists.

Copyright 2015–2023 Michael Hayes, UCECE

Parser

This module performs parsing of SPICE-like netlists. It uses a custom parser rather than lex/yacc to give better error messages.

Copyright 2015–2023 Michael Hayes, UCECE

class lcapy.parser.Arg(param, name)

Bases: object

assign(value)
class lcapy.parser.Args(iterable=(), /)

Bases: list

index(name)

Return first index of value.

Raises ValueError if the value is not present.

class lcapy.parser.Param(paramstr, paramdict)

Bases: object

class lcapy.parser.ParamDef(name, base, comment)

Bases: object

is_valid(string)
class lcapy.parser.Parser(cpts, grammar, allow_anon=False)

Bases: object

parse(string, namespace='', parent=None)

Parse string and create object

class lcapy.parser.Rule(cpt_type, classname, fields, params, comment, pos)

Bases: object

extract_args(string, fields, name, default_value)
extract_nodes(string, fields, name, namespace)

Extract the node names and prepend namespace

process(string, fields, name, namespace, default_value)
syntax_error(error, string)
lcapy.parser.split(s, delimiters)

Split string by specified delimiters but not if a delimiter is within curly brackets {} or “”.

Printing

This module provides printing support.

Copyright 2014–2022 Michael Hayes, UCECE

lcapy.printing.pprint(expr, **kwargs)

Pretty print an expression.

If have non-interactive shell a latex string is returned.

Latex

This module provides the Latex class for formatting values and labels.

Copyright 2020–2023 Michael Hayes, UCECE

class lcapy.latex.Latex(string)

Bases: object

greek(s)

Replace alpha with lpha, etc.

mathrm(s)

Place words in sub- or super-scripts inside a mathrm. For example: V_{rms} -> V_{mathrm{rms}}

lcapy.latex.latex_format_label(s)
lcapy.latex.latex_format_node_label(s)
lcapy.latex.latex_str(string)

Context

This module provides the Context class that maintains the context for a Circuit.

Copyright 2014–2022 Michael Hayes, UCECE

class lcapy.context.Context

Bases: object

State

This module provides the State class that maintains the global state, such as the symbol context.

Copyright 2014–2022 Michael Hayes, UCECE

class lcapy.state.State

Bases: object

This maintains Lcapy’s state, such as the defined symbols, and behaviour.

loose_units (default True) allows constants to be added to quantities show_units (default False) prints the units after an expression canonical_units (default True) converts units to canonical form, e.g., V / A is shown as ohms. ‘printing.abbreviate_units` (default True) prints V rather than volts ‘printing.order` (default none) controls the order that symbols in an expression are printed.

property abbreviate_units
new_context()
restore_context()
switch_context(context)
lcapy.state.validate(value, message)

System

This module wraps system dependent programs for pdf generation, etc.

Copyright 2014–2021 Michael Hayes, UCECE

class lcapy.system.LatexRunner(debug=False)

Bases: object

cleanup(tex_filename, wanted_filename='')
extract_circuitikz_version(tex_filename)
find_circuitikz_version()
run(tex_filename)
class lcapy.system.PDFConverter(debug=False)

Bases: object

to_png(pdf_filename, png_filename, dpi=300, method=None)
to_png_convert(pdf_filename, png_filename, dpi=300)
to_png_ghostscript(pdf_filename, png_filename, dpi=300)
to_png_pdftoppm(pdf_filename, png_filename, dpi=300)
to_svg(pdf_filename, svg_filename)
lcapy.system.checkexe(command, debug=False)
lcapy.system.hasexe(program)
lcapy.system.run(command, stderr=-3, stdout=-3, shell=False, debug=False)
lcapy.system.run_dot(dotfilename, filename)
lcapy.system.tmpfilename(suffix='', dirname=None)
lcapy.system.which(program)

Units

This module provides the Units class for simplification of units. It should be rolled into SymPy. It can perform simplification of units, e.g., volts / amperes -> ohms.

Copyright 2020–2021 Michael Hayes, UCECE

class lcapy.units.Units(unit_system='SI')

Bases: object

as_value_unit(expr)
simplify(expr)
simplify_units(unit)
lcapy.units.as_value_unit(expr)

Utils

This module provides common utility functions.

Copyright 2021–2022 Michael Hayes, UCECE

lcapy.utils.as_N_D(expr, var, monic_denominator=False, use_sympy=False)
lcapy.utils.as_sum(expr, var)
lcapy.utils.as_sum_terms(expr, var)
lcapy.utils.expand_functions(expr, var)
lcapy.utils.factor_const(expr, var)

Extract constant factor from expression and return tuple of constant and the rest of the expression.

For example a * r(var) returns a, r(var).

If have a polynomial expression, the leading coefficient is returned as the constant, for example: 2 * s + 4 returns 2, s + 2.

lcapy.utils.factor_expr(expr, factor)

Extract factor from expression or None if expression does not have factor.

lcapy.utils.isiterable(arg)
lcapy.utils.merge_common(lists)
lcapy.utils.pair_conjugates(poles_dict)

Return dictionary of conjugate pole pairs and a dictionary of the remaining single poles.

lcapy.utils.remove_images(expr, var, dt, m1=0, m2=0)
lcapy.utils.scale_shift(expr, var)
lcapy.utils.separate_dirac_delta(expr)

Separate Dirac delta terms from expression.

lcapy.utils.similarity_shift(expr, var)

Rewrite foo(a * t + b) as foo(t) and return a, b.

lcapy.utils.split_dirac_delta(expr)

Return expression as a list of terms. The first term has no DiracDeltas, the second term collates the DiracDeltas, the third term collates derivatives of DiracDeltas, etc.

For example, u(t) + DiractDelta(t, 1) returns [u(t), 0, DiracDelta(t, 1)]

lcapy.utils.split_parens(s, delimiter=',')

Split a string by delimiter except if in ()

lcapy.utils.term_const(expr, var)

Extract constant term from expression and return tuple of constant and the rest of the expression.