Circuit models 101

In this notebook, we will explore the basics of circuit models in AutoEIS. We will start by importing the necessary libraries.

[1]:
import numpy as np
import autoeis as ae
ae.visualization.set_plot_style()

Circuit representation

In AutoEIS, circuits are represented as strings. Please refer to circuit notation for the syntax of the circuit string. Now, let’s create a sample circuit string:

[2]:
circuit = "R1-[P2,R3]-C4-[[R5,C6],[L7,R8]]-R2"

We can visualize the circuit model using the draw_circuit function, which requires the lcapy package to be installed, and a working LaTeX installation. See here for more details.

[3]:
x = ae.visualization.draw_circuit(circuit)
Suggestion: add a constraint between nodes (25, 27) and (28, 26) for vertical graph
../_images/examples_circuit_basics_5_1.png

Querying circuit strings

Once you have the circuit string, you can run different queries on it. We’re not going to explore all of available queries here, but we’ll show you a few of the most common ones. To see the full list of available queries, check out the API reference.

To get the list of components in the circuit, you can use the get_component_labels function:

[4]:
ae.parser.get_component_labels(circuit)
[4]:
['R1', 'P2', 'R3', 'C4', 'R5', 'C6', 'L7', 'R8', 'R2']

(The impedance of) Each component is represented by one or more parameters. To get the list of parameters that fully describe the circuit, use the get_parameter_labels function:

[5]:
ae.parser.get_parameter_labels(circuit)
[5]:
['R1', 'P2w', 'P2n', 'R3', 'C4', 'R5', 'C6', 'L7', 'R8', 'R2']

Note that components and parameters are not the same, despite the fact that for single-parameter components they’re represented by the same string. For instance, R1 is both a parameter and a component, but P2 is a component, which is described by the parameters P2w and P2n.

You can also validate the circuit using the validate_circuit function in case you’re not sure if the circuit is valid:

[6]:
ae.parser.validate_circuit(circuit)
[6]:
True

Let’s try to validate an invalid circuit string:

[7]:
ae.parser.validate_circuit("R1-[R2,P3]-R1")
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
Cell In[7], line 1
----> 1 ae.parser.validate_circuit("R1-[R2,P3]-R1")

File ~/work/AutoEIS/AutoEIS/src/autoeis/parser.py:56, in validate_circuit(circuit)
     54 components = get_component_labels(circuit)
     55 duplicates = [e for e in components if components.count(e) > 1]
---> 56 assert not duplicates, f"Duplicate elements found: {set(duplicates)}"
     57 # Test circuit is not empty
     58 assert len(circuit) > 0, "Circuit string is empty."

AssertionError: Duplicate elements found: {'R1'}

Another useful query is to compare two circuits to see if they are structurally equivalent. For instance, one would expect that R1-R2 and R2-R1 and R5-R0 are equivalent, i.e., neither the order of appearance of the components nor the labels matter. This is useful for filtering out duplicate circuits, which may (and will) arise during circuit generation using evolutionary algorithms. You can do this using the are_circuits_equivalent function:

[8]:
circuit1 = "R1-[P2,R3]-C4"
circuit2 = "C4-R1-[R3,P2]"
circuit3 = "C0-R5-[R9,P0]"

assert ae.utils.are_circuits_equivalent(circuit1, circuit2)
assert ae.utils.are_circuits_equivalent(circuit1, circuit3)

Evaluating circuit strings

Once you have a valid circuit string, you can calculate the EIS spectra of the circuit model by evaluating it at the frequency range of interest. To do this, you need to convert the circuit string to a function using the generate_circuit_fn function:

[9]:
circuit_fn = ae.utils.generate_circuit_fn(circuit)

Now, let’s calculate the EIS spectra for a few frequencies. For this, we also need to pass the parameters of the circuit model, for which we can use random values:

[10]:
freq = np.logspace(-3, 3, 10)
num_params = ae.parser.count_parameters(circuit)
p = np.random.rand(num_params)
Z = circuit_fn(freq, p)
Z
[10]:
array([1.21883079-2.24443252e+02j, 1.2175161 -4.83386010e+01j,
       1.2507572 -1.03434596e+01j, 1.38312962-2.19648084e+00j,
       1.37171398-5.63043052e-01j, 1.19447804-2.53134306e-01j,
       1.07605597-9.78569732e-02j, 1.03376487-4.21266919e-02j,
       1.01152567-2.01285355e-02j, 1.0002327 -9.77043145e-03j])