This document covers only how a circuit is represented after a netlist is parsed. This representation attempts to be independent of how the circuit is analyzed. Any specific analysis approach should be implemented separately in the analysis package.
The following example was originally taken from analyses/nodal.py. The objective of this code is to assign row/column numbers to all non-reference nodes and -1 to all reference nodes in a Circuit instance (ckt):
# make a list of all non-reference terminals in circuit
ckt.nD_termList = ckt.termDict.values() + ckt.get_internal_terms()
# get reference node (if any)
if ckt.has_term('gnd'):
ckt.nD_ref = ckt.get_term('gnd')
# remove ground node from terminal list
ckt.nD_termList.remove(ckt.nD_ref)
# remove ground node from terminal list
ckt.nD_termList.remove(ckt.nD_ref)
# For reference nodes assign -1
ckt.nD_ref.nD_namRC = -1
# Make a list of all elements
ckt.nD_elemList = ckt.elemDict.values()
# Set RC number of reference terminals to -1
for elem in ckt.nD_elemList:
if elem.localReference:
elem.connection[elem.localReference].nD_namRC = -1
# Assign a number (starting from 0) to all nodes.
for i, term in enumerate(ckt.nD_termList):
term.nD_namRC = i
The following example shows how to create and add devices from the point of view of a parser:
import circuit as cir
from devices import devClass
# Create circuit:
mainckt = cir.Circuit()
# Add elements with private model
# creates element type 'ind'
dev = devClass['ind']('Lchoke')
# override 'l' parameter value (otherwise default value is used)
dev.set_param('l', 1e-9)
# add to circuit
mainckt.add_elem(dev)
# connect to terminals 'vdd' and and 'drain', automatically created
mainckt.connect(dev, ['vdd', 'drain'])
# add element with shared (public) model: model 'my_nmos' is created
# if it is not already in circuit
m1 = devClass['mosacm']('mos1n')
mainckt.add_elem(m1, 'my_nmos')
# To later retrieve model
model = cir.get_model('my_nmos')
# if model not found returns None, use cir.add_model() if needed
# Subcircuits: create and add subcircuit instance
x1 = cir.Xsubckt('x1', 'LM741')
mainckt.add_subckt(x1)
# Connect subcircuit instance with cir.connect()
# Subcircuit definition: tl2 are the external connections
tl2 = ['vdd', 'vee', 'in', 'out']
amp1 = cir.SubCircuit('LM741', tl2)
# now you can treat amp1 as a regular circuit instance
dev = devClass['ind']('L2')
dev.override = [('l', 2e-9)]
amp1.add_elem(dev)
amp1.connect(dev, ['in', 'n1'])
Holds a circuit.
There are 2 global dictionaries defined at the class level:
Element, Xsubckt and (external) Terminal references are stored in dictionaries, empty by default:
Internal terminals must be accessed directly from the parent Element instance.
Ground node: terminals ‘0’ and ‘gnd’ are considered to be the same reference node. If a circuit does not contain a ground node then it is up to the user to set a reference.
Plot/Save requests are stored in lists: plotReqList/saveReqList
In the future we may implement topology checking utilities here.
Adds an element to a circuit.
If modelName is not given it is assumed that no global model will be used
Otherwise the model is retrieved (or created if necessary) and assigned to elem.dotModel. This model can be shared with other elements.
A check is made to make sure the instance name is unique
Adds a Xsubckt instance to circuit
This is slow for large circuits. Use for debugging to make sure that all elements and terminals have been added to the circuit. Also checks for floating terminals.
For now only works for unflattened circuits
Connect an Element (or subckt) instance to terminals
Terminals are specified by a list of terminal names (termList). If a terminal does not exist in the circuit it is created and added.
Important notes:
Element/subckt should be in circuit dictionary. No attempt to check this is made (use add_elem()).
Order in the adjacency list is important for Elements
For example, for a MOSFET the first node corresponds to the drain, the second to the gate, etc.
Returns a copy of an uninitialized circuit
newName is the circuit name for the copy
The elements in the copy point to the ParamSet of the original element (models are not cloned). Elements are shallow-copied, but terminal connections are re-generated.
Example:
ckt2 = ckt1.copy('ckt1copy')
If the circuit has been flattened, the copy does not include subcircuit instances, otherwise a shallow copy of subcircuit instances are generated.
Find a terminal (external/internal) by name
Returns terminal instance if found or raises CircuitError exception if not
Expand all subcircuit instances in place, assuming the circuit and subcircuits have not been initialized.
The flattened elements point to the ParamSet of the original element (models are not cloned). Elements are shallow-copied, but terminal connections are re-generated.
Returns a list with all non-reference internal terminals
Circuit must be initialized first. Note that the same effect can be achieved by directly polling the elements.
Returns a set with terminals to be plotted or saved
Set generated from all plot and save requests of the specified type.
Returns an external terminal instance with the given name.
A new instance is created if necessary
Convert all global stuff to netlist format
This includes: models, netlist variables and .options variables
Returns True if terminal present in circuit
To be used after all elements/terminals have been created. Can be called multiple times but only has an effect if self._initialized is False
Generates a ‘netlist-like’ description of the circuit
Disconnect and remove an element from a circuit. Internal terminals are also removed.
Removes a terminal from a circuit. Links are not removed, you must take care of that.
Used for exceptions raised in this module
Base class for circuit Elements.
Default flags are set here.
Create and connect one internal terminal
name: internal terminal name unit: internal variable unit
Returns internal terminal index
Create and connect one internal terminal to be used as local reference
Checks terminal connections
If numTerms is not zero, checks that the number of connected terminals is equal to numTerms. Raises an exception if they do not match.
Else sets numTerms = number of connected terminals
Disconnect any internal terms,
Normally used before calling process_params() for a second time or when an element is removed from circuit.
Disconnect a terminal from an element. Arguments are Element and Terminal instances.
Assumption is that if terminal is in element’s list, then the nodes are linked and element should be on terminal’s list. If nodes not connected an exception is raised.
Returns a list of internal terms (if any) excluding local references
General initialization function
Set the attribute values, check basic terminal connectivity and process parameters.
Returns True if paramName is valid and manually set
Output netlist-formatted string in netlist format
Nicely print parameter list and OP (if any) with values and units
Set parameters as attributes.
Priority is as follows: first manually set parameters, then manually set parameters in model (if any) and finally default values
Simple graph node base class (not circuit node)
Used for circuit Elements, subcircuits and terminals. Links are stored using lists.
Represent terminals that are internal to one Element instance
They only have one connection (the parent Element instance)
Return label for plots/tables in a formatted string
Holds a set of output variables requests
Output request consist in:
- Type of of request (type): dc, ac_*, tran, etc.
- List of variables (varlist): for external terminals, these are strings with terminal name. For internal terminals, a list with device and terminal names.
After initialization the circuit adds a list of terminals in the termlist attribute.
Almost identical to Circuit but adds support for external connections.
External subcircuit terminals have an additional attribute set: subCKTconnection. This attribute is set to the subcircuit’s connection number. Example:
.subckt inverter in out vplus vminus
in.subCKTconnection = 0
out.subCKTconnection = 1
vplus.subCKTconnection = 2
vminus.subCKTconnection = 3
The reference node (‘gnd’ or ‘0’) is global , i.e., a terminal named ‘gnd’ in a subcircuit is assumed to be connected to the same ground node in all other circuits/subcircuits. To avoid problems, the ground terminal can not be included in the external terminal list. One of the possible problems is short-circuiting a node to ground when a subcircuit is connected. Example of invalid code:
vdc:vcc 1 0 vdc=10V
vdc:vee 2 0 vdc=-10V
xamp1 1 2 in out amplifier
.subckt amplifier 1 gnd in out
res:rc 1 out r=5k
cap:cin in 2 c=1uF
bjt:q1 out 2 gnd type=npn
.ends
Possible solutions:
- Rename ‘gnd’ node in subcircuit to something else
- Remove ‘gnd’ node (implicitly connected to terminal ‘0’ in main circuit) from subcircuit external terminal list
Returns a copy of an uninitialized circuit
newName is the circuit name for the copy
Similar as Circuit.copy() but also takes care of subcircuit connections
Dump copy of circuit into target (for hierarchy flattening)
Subcircuit instances are ignored
Returns a list of subcircuit terminals
Ganerates a ‘netlist-like’ description of subcircuit.
Produces the same output as the Circuit class plus extra .subckt and .ends lines.
Represent circuit terminals (i.e., nodes)
This class should used only for ‘external’ terminals (i.e., terminals that appear in the netlist). See also InternalTerminal
Return label for plots/tables in a formatted string
Represent subcircuit instances (not definitions, use SubCircuit for those)
Convert to string in netlist format
Adds a public model (parameter set) to a circuit.
A check is made to make sure the instance name is unique
Used to get the circuit called ‘main’ weather it has been already created or not
Returns model reference if present in circuit, otherwise returns None.
Erases all existing circuits
Used mostly for debugging purposes
Handles sets of parameters used for Elements, Models and Analyses
Netlist variables are also handled here. They are stored in the ParamSet.netVar dictionary, accesible to all derived classes.
To reset parameters to netlist values, use the following:
obj.clean_attributes()
obj.set_attributes()
Provides ‘.model’ functionality (used for Elements)
Provides some extra functionality in addition to ParamSet methods
Output netlist-formatted string using pset definitions and attributes values from var
Set attributes not present in target with values in stored in self
Used for exceptions raised in this module
Handles a set of parameters with values.
Useful for devices, analyses and anything that accepts parameters.
Parameter definitions given in a dictionary with the following format:
paramDict = dict(
w = ('Channel width', 'm', float, 10e-6),
l = ('Channel length', 'm', float, 10e-6),
vt0 = ('Threshold Voltage', 'V', float, 0.532),
vsat = ('Velocity Saturation', 'm/s', float, 8e4),
tox = ('Oxide Thickness', 'm', float, 7.5e-9)
)
Delete parameter attributes
Returns a string with parameter information
If no parameter is specified all parameters are listed
Returns a string describing parameter named param
Returns a list with the names and values of ‘float’ attributes
This is handy for sensitivity calculation. Each item in the list is a tuple: (<name>, <value>)
The set is assumed to be already initialized. Values are taken directly from instance attributes.
Returns type if parameter exists
Returns True if paramName is valid and manually set
Briefly list parameter names
Output netlist-formatted string listing only non-default parameters
Reset to default state
Set attributes named after parameters in self.valueDict
Parameter values may refer to netlist variables. If a netlist variable is referenced but not defined, an exception is raised here.
If useDefaults is True, set defaults from self.paramDict
Set parameter given with paramName to value
Note that actual attribute is not set until set_attributes() is executed. A check is made to ensure the parameter name is valid.
If value type is a string and does not match with parameter type it is assumed that the value is a netlist variable name. The netlist variable may be assigned a value at a later time before set_attributes() is called.
Set all parameter values given in kwargs
Physical constants are from http://physics.nist.gov/cuu/Constants/
Usage example:
from globalVars import const, glVar
# Calculate thermal voltage (Vt) at default temperature
vt = const.k * glVar.temp / const.q
Important Note: The glVar name really refers to the variables in the .options line, not the netlist variables defined in .vars. Those are kept in a dictionary in ParamSet.
The devices package contains a library with device models. Device classes are imported into a dictionary. Keys are the device types. To create a new device use the following:
devices.devClass['devType']('instancename')
Example (from python):
from devices import devClass
# Create device instance
m1 = devClass['mosacm']('m1n')
Example (from netlist):
mosacm:m1n <nodes> <parameters>
Suppose the new model is implemented in a file named newmodel.py. Save this file in the devices directory and edit devices/__init__.py. Add your module name to netElemList as shown below:
# Regular 'netlist' elements must be listed here
netElemList = ['mosACM', 'resistor', 'capacitor', 'inductor', 'idc', 'vdc',
'diode', 'svdiode', 'mosEKV', 'bjt', 'svbjt', 'newelem']
That’s all!
UML diagrams generated using pyreverse (http://www.logilab.org/2560)