ahkab.circuit

Introduction

A circuit is described in the ahkab simulator by an instance of the Circuit class.

This class holds everything is needed to simulate the circuit, except the specification of the analyses to be performed.

To rewrite a netlist from a Circuit instance see the ahkab.printing module.

The Circuit

A circuit is derived from a list which contains all its elements.

Conceptually, every time an element is to be inserted in the circuit, two operations have to be performed:

  • The element must be appended to the Circuit instance.
  • Its connections should be ensure checking that the nodes the element refers to are indeed existing circuit nodes.

To simplify the operation of adding a component to a Circuit, the following convenience methods are provided to the user to add and remove most elements to the circuit:

Example:

mycircuit = circuit.Circuit(title="Example circuit", filename=None)
# no filename since there will be no deck associated with this circuit.
# get the ref node (gnd)
gnd = mycircuit.get_ground_node()
# add a node named n1 and a 600 ohm resistor connected between n1 and gnd
mycircuit.add_resistor(part_id="R1", n1="n1", n2=gnd, R=600)

Refer to the methods help for additional information.

Nodes

The nodes are internally stored in the following way: we assign to each node an internal ID, independetly from its external identifier used in the netlist. Those IDs are integers.

The simulator uses always the internal names. When the results are presented to the user, the internal node is not showed, the external identifier (or external node name) is printed instead.

This is done through:

my_circuit = Circuit()
...
[ init code ]
...
print "This is a node" + my_circuit.nodes_dict[int_node]

Internal only nodes

The number of internal only nodes (added automatically by the simulator) is held in Circuit.internal_nodes. That value shouldn’t be changed by hand.

Device models

Non-linear elements have their operation described by specialized routines held in their module.

They are stored in Circuit.models (of type dict), the following methods are provided to add and remove device models to a Circuit instance.

Reference

class Circuit(title, filename=None)[source]

The circuit class.

Parameters:

title : string
The circuit title.

filename : string, optional

Deprecated since version 0.09.

If the circuit instance corresponds to a netlist file on disk, set this to the netlist filename.

add_capacitor(part_id, n1, n2, value, ic=None)[source]

Adds a capacitor to the circuit.

The capacitor instance is added to the circuit elements and connected to the provided nodes. If the nodes are not found in the circuit, they are created and added as well.

Parameters:

part_id : string
The capacitor part_id (eg “C1”). The first letter is always C.
n1, n2 : string
The nodes to which the element is connected.
value : float
The capacitance value.
ic : float, optional
The initial condition, if any. See the simulation docs for how this affects the results.
add_cccs(part_id, n1, n2, source_id, value)[source]

Adds a current-controlled current source (CCCS) to the circuit

This method takes care that its nodes are added as well.

Parameters:

part_id : string
The cccs ID (eg 'F1'). The first letter is always 'F'.
n1, n2 : strings
The output port nodes, where the output current is forced. Eg. “outp”, “outm” or “out_a”, “out_b”.
source_id : string
The voltage source to be used to sense the current that drives the output. Eg. 'V1'.
value : float

The proportionality factor between input (\(I_s\)) and output (\(I_o\)) currents. Mathematically:

\[I_o = \alpha I_s\]

See also

ahkab.components.sources.FISource

add_ccvs(part_id, n1, n2, source_id, value)[source]

Adds a current-controlled voltage source (CCCS) to the circuit

This method takes care that its nodes are added as well.

Parameters:

part_id : string
The cccs ID (eg 'H1'). The first letter is always 'H'.
n1, n2 : strings
The output port nodes, where the output current is forced. Eg. “outp”, “outm” or “out_a”, “out_b”.
source_id : string
The voltage source to be used to sense the current that drives the output voltage. Eg. 'V1'.
value : float

The proportionality factor between the sense current \(I_s\) flowing into the source_id voltage source (input) and output voltage. Mathematically:

\[Vn_1 - Vn_2 = \alpha I_s\]

See also

ahkab.components.sources.EVSource, ahkab.components.sources.FISource

add_diode(part_id, n1, n2, model_label, models=None, Area=None, T=None, ic=None, off=False)[source]

Adds a diode to the circuit (also takes care that the nodes are added as well).

Parameters:

part_id : string
The diode ID (eg “D1”). The first letter is always D.
n1, n2 : string
the nodes to which the element is connected. eg. "in" or "out_a"
model_label : string
The diode model identifier. The model needs to be added first, then the elements using it.
models : dict, optional
List of available model instances. If not set or None, the circuit models will be used (recommended).
Area : float, optional
Scaled device area (optional, defaults to 1.0)
T : float, optional
Operating temperature (no temperature dependence yet)
ic : float, optional
Initial condition (not really implemented yet)
off : bool, optional
Consider the diode to be initially off.
add_inductor(part_id, n1, n2, value, ic=None)[source]

Adds an inductor to the circuit.

The inductor instance is added to the circuit elements and connected to the provided nodes. If the nodes are not found in the circuit, they are created and added as well.

Parameters:

part_id : string
The inductor part_id (eg “Lfilter”). The first letter is always L.
n1, n2 : string
The nodes to which the element is connected. Eg. "in" or "out_a".
value : float
The inductance value.
ic : float, optional
Initial condition, see simulation types for how this affects the results.
add_inductor_coupling(part_id, L1, L2, value)[source]

Add a coupling between two inductors.

Parameters:

part_id : string
The part ID for the inductor coupling device. Eg. 'K1', the first letter is always 'K'.
L1 : string
The part ID of the first inductor to be coupled.
L2 : string
The part ID of the second inductor to be coupled.
value : float
The k value of the mutual coupling coefficient. Its value must be greater than zero and lesser or equal to``1`` or instability ensues.
add_isource(part_id, n1, n2, dc_value, ac_value=0, function=None)[source]

Adds a current source to the circuit (also takes care that the nodes are added as well).

Parameters:

part_id : string
The current source ID (eg "IA" or "I3"). The first letter is always I.
n1, n2 : string
The nodes to which the element is connected, eg. "in" or "out1".
dc_value : float
DC current value.
ac_value :float, optional
AC current value, defaults to 0.
function : function, optional
Time function. See devices.py for built-in options.
add_model(model_type, model_label, model_parameters)[source]

Add a model to the available circuit models.

Parameters:

model_type : string
the model type (eg “ekv”). Right now, the possible values are: "mosq", "ekv", "diode", "sw".
model_label : string
a unique identifier for the model being added (eg. "nch1").
model_parameters: dict
a dictionary holding the parameters to be supplied to the model to instantiate it.
add_mos(part_id, nd, ng, ns, nb, w, l, model_label, models=None, m=1, n=1)[source]

Adds a mosfet to the circuit (also takes care that the nodes are added as well).

Parameters:

part_id : string
The mos part_id (eg “M1”). The first letter is always M.
nd : string
The drain node.
ng : string
The gate node.
ns : string
The source node.
nb : string
The bulk node.
w : float
The gate width.
l : float
The gate length.
model_label : string
The model identifier.
models : dict, optional
The circuit models.
m : int, optional
Shunt multiplier value. Defaults to 1.
n : int, optional
Series multiplier value, not always supported. Defaults to 1.
add_node(ext_name)[source]

Adds the supplied node to the circuit, if needed.

When a ‘normal’ (not the reference) node is added, a internal name (or label) is assigned to it.

The nodes labels are stored in Circuit.nodes_dict, as a dictionary of pairs like {int_node:ext_node}.

Those internal names are integers, by definition, and are generated starting from 1, then 2, 3, 4, 5... The integer 0 is reserved for the reference node (gnd), which is required for the circuit to be non-pathological and has ext_name=str(int_name)='0'.

Notice that this method doesn’t halt or print errors if the node is already been added previsiously. It simply returns the internal node name assigned to it.

Parameters:

ext_name : string
The unique identifier of the node.

Returns:

int_name : string
the unique internal ciecuit identifier of the node.
Raises:TypeError – if the parameter ext_name is not of “text” type (what that means exactly depends on which version of Python you are using.)
add_resistor(part_id, n1, n2, value)[source]

Adds a resistor to the circuit.

The resistor instance is added to the circuit elements and connected to the provided nodes. If the nodes are not found in the circuit, they are created and added as well.

Parameters:

part_id : string
the resistor part_id (eg “R1”). The first letter is replaced by an R
n1, n2 : string
the nodes to which the resistor is connected.
value : float,
The resistance between n1 and n2 in Ohm.
add_switch(part_id, n1, n2, sn1, sn2, ic, model_label, models=None)[source]

Adds a voltage-controlled or current-controlled switch to the circuit

This method also takes care that its nodes are added to the circuit as well, if necessary.

Notice:

  • Current-controlled switches are not yet implemented. If you try to add one, you’ll trigger an error. If you got a bit of time to spare, patches are welcome.
  • The switches part_id should begin with 'S' for voltage-controlled switches and with 'W' for current-controlled switches.
  • The actual behavior is set by the model. Make sure you supply a voltage-controlled switch model for a voltage-controlled switch and the appropriate type of model for the current-controlled switch. Mixing them up will go undetected.

Parameters:

part_id : string
the switch ID (eg "S1" - voltage-controlled - or "Wa" - current-controlled). The first letter is always S or W.
n1, n2 : string
the output port nodes, where the switch is connected. Eg. "out1", "out2" or "n_a", "n_b".
sn1, sn2 : string
The input port nodes, where the input voltage is read. Eg. “inp”, “inm” or “in_a”, “in_b”.
ic : boolean
The initial conditions for transient simulation. Not currently implemented!
model_label : string
The switch model identifier. The model needs to be added first, then the elements using it.
models : dict, optional
A dictionary assembled as (identifier:instance), containing all the available model instances. If not set or None, the circuit models will be used (recommended).
add_user_defined(module, label, param_dict)[source]

Adds a user defined element.

In order for this to work, you should write a module that supplies the elem class.

XXX WRITE DOC

add_vccs(part_id, n1, n2, sn1, sn2, value)[source]

Adds a voltage-controlled current source (VCCS) to the circuit

This method also takes care that its nodes are added as well.

Parameters:

part_id : string
The VCCS ID (eg "G1"). The first letter is always 'G'.
n1, n2 : string
The output port nodes, where the output current is forced. Eg. “outp”, “outm” or “out_a”, “out_b”. The passive convention is used as everywhere else in the simulator: a positive current flows into n1 and out of n2.
sn1, sn2 : string
The input port nodes, where the input voltage is sensed. Eg. “inp”, “inm” or “in_a”, “in_b”.
value : float

The proportionality factor between input and output voltages, which are related by the equality:

\[I_o = alpha * \left[V(inp) - V(inn)\right]\]
add_vcvs(part_id, n1, n2, sn1, sn2, value)[source]

Adds a voltage-controlled voltage source (vcvs) to the circuit

This method also takes care that its nodes are added as well.

Parameters:

part_id : string
The vcvs ID (eg “E1”). The first letter is always E.
n1, n2 : string
The output port nodes, where the output voltage is forced. Eg. “outp”, “outm” or “out_a”, “out_b”.
sn1, sn2 : string
The input port nodes, where the input voltage is read. Eg. “inp”, “inm” or “in_a”, “in_b”.
alpha : float

The proportionality factor between input and output voltages is given by the relationship:

\[V(out_p) - V(out_n) = \alpha \cdot (V(in_p) - V(in_n))\]
add_vsource(part_id, n1, n2, dc_value, ac_value=0, function=None)[source]

Adds a voltage source to the circuit (also takes care that the nodes are added as well).

Parameters:

part_id : string
The voltage source part_id (eg “VA”). The first letter is always V.
n1, n2 : string
The nodes to which the element is connected. Eg. "in" or "out_a".
dc_value : float
DC voltage value
ac_value : float, optional
AC voltage value, defaults to 0.
function : function, optional
Time function. See devices.py for built-in options.
create_node(name)[source]

Creates a new circuit node

If there is a node in the circuit with the same name, ValueError is raised.

Parameters:

name : string
the _unique_ identifier of the node.

Returns:

node : string
the _unique_ identifier of the node, to be used for subsequent element declarations, for example.
Raises:
  • ValueError – if a new node with the given id cannot be created, for example because a node with the same name already exists in the circuit. The only exception is the ground node, which has the reserved id '0', and for which this method won’t raise any exception.
  • TypeError – if the parameter name is not of “text” type (what that means exactly depends on which version of Python you are using.)
ext_node_to_int(ext_node)[source]

This function returns the integer id associated with an external node id.

Parameters:

ext_node : string
The external node id to be converted.

Returns:

int_node : int
The internal node associated.
find_vde(index)[source]

Finds a voltage-defined element from its MNA KVL index

Parameters:

index : int
The element index in the KVL equations.

Returns:

e : circuit element (an instance of a subclass of Component)
The element corresponding to index.
Raises:IndexError – if no element corresponds to such an index.
find_vde_index(elem_or_id, verbose=3)[source]

Finds a voltage-defined element MNA index.

Parameters:

elem_or_id : string or circuit element
You may pass as first element, alternatively, either the part_id of the element whose index is being requested (eg. ‘V1’) or the element itself. Notice the part_id includes both the id letter (eg. ‘V’) and the description (eg. ‘1’).
verbose : int
The verbosity level, from 0 (silent) to 6 (debug).

Returns:

indx : int
The index.
Raises:ValueError – if no such element is in the circuit.
get_elem_by_name(part_id)[source]

Get a circuit element from its part_id value.

If no matching element is found, the method returns None. This may change in the future.

Parameters:

part_id : string
The part_id of the element

Returns:

elem : circuit element
Depending whether a matching element was found or not.
Raises:ValueError – if the element is not found.
get_ground_node()[source]

Returns the reference node, AKA GND.

get_locked_nodes()[source]

Get all nodes connected to non-linear elements.

This list is meant to be passed to dc_solve or mdn_solver to be used in get_td to evaluate the damping coefficient in a Newton-Rhapson iteration.

Returns:

locked_nodes : list
A list of internal nodes.
get_nodes_number()[source]

Returns the number of nodes in the circuit

has_duplicate_elem()[source]

Self-check for duplicate elements.

No circuit should ever have duplicate elements (ie elements with the same part_id).

Returns:

chk : boolean
The result of the check.
int_node_to_ext(int_node)[source]

This function returns the string id associated with the integer internal node id int_node.

Parameters:

int_node : int
The internal node id to be converted.

Returns:

ext_node : string
the string id associated with int_node.
is_int_node_internal_only(int_node)[source]

Check whether an internal node is an “internal only node” or not.

Parameters:

int_node : int
The internal only node to be checked.

Returns:

chk : boolean
The result of the check.
Raises:TypeError – if the supplied node is not an int. Typically this happens when the method is called with an external name.
is_nonlinear()[source]

Check whether the circuit is non-linear or not.

Returns:

chk : boolean
The result of the check.
new_internal_node()[source]

Generate implicit internal nodes.

Some devices are made of a group of other devices, connected by “internal only” nodes, which have the prefix 'INT' and the simulator treats specially, hiding them from the user if not explicitly asked about them.

This method generates the external names for such nodes and inserts them in the circuit.

Returns:

ext_node : string
The corresponding external node id.
remove_elem(elem_or_id)[source]

Removes an element from the circuit and takes care that no “orphan” nodes are left.

Note

Support for removing elements is experimental.

Parameters:

elem_or_id : string or circuit element
You may pass as first element, alternatively, either the part_id of the element to be removed or the element itself.

The method will also take care of purging from the circuit nodes that are left orphan, ie with no elements connected.

Raises:ValueError – if no such element is found in the circuit.
remove_model(model_label)[source]

Remove a model from the available models.

Parameters:

model_label : string
the unique identifier corresponding to the model being removed.

Note

This method currently silently ignores models that are not defined.

exception CircuitError[source]

General circuit assembly exception.

exception ModelError[source]

Model not found exception.

exception NodeNotFoundError[source]

Circuit Node exception.

is_elem_voltage_defined(elem)[source]

Check if an element needs its own KCL equation

Parameters:

elem : Component
The element to be checked.

Returns:

chk : bool
True if elem is a voltage source, an inductor, a voltage-controlled voltage source or a current-controlled voltage source. False otherwise.
class subckt(name, code, connected_nodes_list)[source]

This class holds the necessary information about a circuit.

An instance of this class is returned by:

ahkab.netlist_parser.parse_sub_declaration()

Parameters:

name : string
The subcircuit definition label.
code : string
The netlist code that can be instantiated have a circuit instance.
connected_nodes_list : list
A list of nodes that are used in the circuit and that are meant to be connected to the external circuit.

Notice that in the current implementation, the GND node (0) is always global.