Skip to content

Equivalent Circuit Fitting

pypalmsens.fitting.CircuitModel fits the equivalent circuit specified with the CDC descriptor code. Optional settings are fixing the value of a parameter, setting the min/max bounds for a parameter, specifying the frequency range to fit, limiting the number of iterations, delta error term or delta parameter term.

Example usage for fitting an equivalent circuit:

>>> import pypalmsens as ps

>>> measurements = ps.load_session_file('examples/Demo CV DPV EIS IS-C electrode.pssession')
>>> eis_data = measurements[2].eis_data[0]

>>> cdc = 'R(RC)'
>>> model = ps.fitting.CircuitModel(cdc=cdc)
>>> result = model.fit(eis_data)
>>> result
FitResult(cdc='R(RC)', parameters=[134.2601648341703, 11839.397430811792, 4.763069310462662e-07], error=[...], ...)

result is an instance of pypalmsens.fitting.FitResult, a dataclass with fit values, errors, and other fitting data:

>>> result.cdc
'R(RC)'

>>> result.parameters
[134.2601648341703, 11839.397430811792, 4.763069310462662e-07]

>>> result.error
[2.3519772735560074, 2.466430045381699, 2.7610107312609493]

>>> result.n_iter
19

>>> result.chisq
0.014493966401698677

>>> result.exit_code
'MinimumDeltaErrorTerm'

CircuitModel takes a single parameter, the circuit description code (CDC). Note that the code must be in all caps. For more information, see the CDC documentation.

You can pass result.parameters back to pypalmsens.fitting.CircuitModel.fit) to redo the fit from different starting parameters:

>>> model.fit(eis_data, parameters=result.parameters)
FitResult(cdc='R(RC)', parameters=[...], ...)

Parameters

If you want to tune the parameters, like fixing values or setting bounds, you can set them using the pypalmsens.fitting.Parameters class. model.default_parameters grabs the default parameters for the CDC.

These can be modified, for example:

>>> parameters = model.default_parameters()

>>> parameters[0].value = 123  # set starting value to 123
>>> parameters[0].fixed = True # fix this value
>>> parameters[1].min = 12  # set lower bound
>>> parameters[1].max = 34  # set upper bound

>>> model.fit(eis_data, parameters=parameters)
FitResult(cdc='R(RC)', parameters=[...], error=[...], ...)

Re-fit EIS data

If you have already fitted your data in PSTrace, you can redo the fit or use the values as starting parameters:

>>> model = ps.fitting.CircuitModel(cdc=eis_data.cdc)
>>> model.fit(eis_data, parameters=eis_data.cdc_values)
FitResult(cdc='R([RT]Q)', parameters=[...], error=[...], ...)

Plotting

If you have matplotlib installed, you can generate the plots from the result:

>>> result.plot_nyquist(eis_data)
<Figure size 640x480 with 1 Axes>

>>> result.plot_bode(eis_data)
<Figure size 640x480 with 2 Axes>

Nyquist plot in PyPalmSens Bode plot in PyPalmSens

Default values

This table shows the default values, the element types used in the system. Note that some element types have multiple values.

For more information on the formulas, please see the chapter "Equivalent Circuit Fitting" in the PSTrace user manual.

Element Value Min Max Units
Resistance (R) 1 × 10³ 1 × 10⁻⁶ 1 × 10¹² Ω
Capacitance (C) 10 × 10⁻⁹ 1 × 10⁻¹² 1 × 10⁻³ F
Inductance (L) 100 × 10⁻⁶ 1 × 10⁻¹² 1 × 10⁻³ H
Constant Phase Element (Q)
Y0 1 × 10⁻³ 1 × 10⁻¹² 1 × 10⁻³ T
Constant phase exponent n 1 0 1 σ
Warburg (W) 1 × 10³ 1 × 10⁻⁶ 1 × 10¹² σ
Warburg Open (T) / Short (O)
Warburg coefficient 1 × 10³ 1 × 10⁻⁶ 1 × 10¹² σ
B 1 1 × 10⁻¹² 1 × 10⁶ √s
Experimental parameter 0.5 0 1 φ
Gerischer (G)
Z0 1 × 10³ 1 × 10⁻⁶ 1 × 10¹² Z₀
k (reaction rate) 1 1 × 10⁻¹² 1 × 10⁶ s⁻¹
Bisquert Open (M) / Short (N)
Z pore 100 1 × 10⁻⁶ 1 × 10¹² Ω
Reaction resistance 10 × 10³ 1 × 10⁻⁶ 1 × 10¹² Ω
Pore diffusion CPE T 1 × 10⁻³ 1 × 10⁻¹² 1 × 10⁻³ T
Pore diffusion CPE n 1 0 1 Φ
Pore depth 1 0 1 × 10¹² L

Impedance.py

impedance.py is a popular Python package for analyzingelectrochemical impedance spectroscopy (EIS) data. It has a a straightforward, scikit-learn-like API for impedance analysis.

You can install impedance.py via pip install impedance.

For more information, see the documentation or source code on Github.

From an eis data set, it is trivial to create the frequency and impedance data (Z) for impedance.py using numpy:

import pypalmsens as ps
import numpy as np

measurement = ps.load_session_file('examples/Demo CV DPV EIS IS-C electrode.pssession')[2]

eis = measurement.eis_data[0]

F = np.array(eis.dataset['Frequency'])
Zre = np.array(eis.dataset['ZRe'])
Zim = np.array(eis.dataset['ZIm'])

Z = Zre - 1j * Zim

For example, to fit this circuit model:

Diagram of circuit model

We can use the circuit description: 'R0-p(R1-Wo1,CPE1)'. This is different from the CDC codes used by PalmSens. You can read about the available elements here.

The example below shows how to fit the circuit model to the data:

import matplotlib.pyplot as plt
from impedance.models.circuits import CustomCircuit
from impedance.visualization import plot_nyquist

circuit = 'R0-p(R1-Wo1,CPE1)'

initial_guess = [1000, 1000, 1000, 0.5, 1e-6, 1]

circuit = CustomCircuit(circuit, initial_guess=initial_guess)

ret = circuit.fit(F, Z)

print(ret)

Z_fit = circuit.predict(F)

fig, ax = plt.subplots()
plot_nyquist(Z, fmt='o', scale=10, ax=ax)
plot_nyquist(Z_fit, fmt='-', scale=10, ax=ax)

plt.legend(['Data', 'Fit'])
plt.show()

This results in the nyquist plot below:

Nyquist plot in impedance.py