Model Saving/Loading Example
This set of examples shows how to load and import template models in order to make setting up and reproducing circuit fits easier.
[1]:
# Load libraries
import impedance.preprocessing as preprocessing
import impedance.models.circuits as circuits
from impedance.visualization import plot_nyquist
import numpy as np
import matplotlib.pyplot as plt
[2]:
# Load data from the example EIS result
frequencies, Z = preprocessing.readCSV('../../../data/exampleData.csv')
# keep only the impedance data in the first quandrant
frequencies, Z = preprocessing.ignoreBelowX(frequencies, Z)
Example 1. Importing and Exporting Models
Call the circuit.save()
function to export the model to a human readable JSON file. The following code generates a test circuit and export it as a template. Here we are using an unfitted model as a template.
[3]:
test_circuit = circuits.CustomCircuit(initial_guess=[.01, .005, .1, .005, .1, .001, 200],
circuit='R0-p(R1,C1)-p(R2,C2)-Wo1')
print(test_circuit)
test_circuit.save('template_model.json')
Circuit string: R0-p(R1,C1)-p(R2,C2)-Wo1
Fit: False
Initial guesses:
R0 = 1.00e-02 [Ohm]
R1 = 5.00e-03 [Ohm]
C1 = 1.00e-01 [F]
R2 = 5.00e-03 [Ohm]
C2 = 1.00e-01 [F]
Wo1_0 = 1.00e-03 [Ohm]
Wo1_1 = 2.00e+02 [sec]
Call the model_io.model_import
function to import the model back as a template.
[4]:
loaded_template = circuits.CustomCircuit()
loaded_template.load('template_model.json')
print("Loaded Template")
print(loaded_template)
R0-p(R1,C1)-p(R2,C2)-Wo1
Loaded Template
Circuit string: R0-p(R1,C1)-p(R2,C2)-Wo1
Fit: False
Initial guesses:
R0 = 1.00e-02 [Ohm]
R1 = 5.00e-03 [Ohm]
C1 = 1.00e-01 [F]
R2 = 5.00e-03 [Ohm]
C2 = 1.00e-01 [F]
Wo1_0 = 1.00e-03 [Ohm]
Wo1_1 = 2.00e+02 [sec]
Example 2. Using imported template model to fit data
After the model has been imported as a template, it can be used as a starting point to fit data. This saves on needing to configure the initial parameters each time a fit is performed and to persist starting conditions across several fitting sessions.
[5]:
fig, ax = plt.subplots(figsize=(5,5))
f_pred = np.logspace(5,-2)
loaded_template.fit(frequencies, Z)
imported_circuit_init = loaded_template.predict(f_pred, use_initial = True)
imported_circuit_fit = loaded_template.predict(f_pred)
plot_nyquist(ax, Z)
plot_nyquist(ax, imported_circuit_init)
plot_nyquist(ax, imported_circuit_fit)
ax.legend(['Data', 'Loaded Template Initial', 'Loaded Template Fit'])
plt.show()
print(loaded_template)
Simulating circuit based on initial parameters
Circuit string: R0-p(R1,C1)-p(R2,C2)-Wo1
Fit: True
Initial guesses:
R0 = 1.00e-02 [Ohm]
R1 = 5.00e-03 [Ohm]
C1 = 1.00e-01 [F]
R2 = 5.00e-03 [Ohm]
C2 = 1.00e-01 [F]
Wo1_0 = 1.00e-03 [Ohm]
Wo1_1 = 2.00e+02 [sec]
Fit parameters:
R0 = 1.65e-02 (+/- 1.54e-04) [Ohm]
R1 = 8.77e-03 (+/- 1.89e-04) [Ohm]
C1 = 3.28e+00 (+/- 1.85e-01) [F]
R2 = 5.31e-03 (+/- 2.06e-04) [Ohm]
C2 = 2.32e-01 (+/- 1.90e-02) [F]
Wo1_0 = 6.37e-02 (+/- 2.03e-03) [Ohm]
Wo1_1 = 2.37e+02 (+/- 1.72e+01) [sec]
Example 3. Using fitted data as a starting point for new fits
Consider the case where a successful fit has been performed and a new set of EIS data is obtained which is similar to the first spectrum. It is useful to use the successfully fitted parameters as a starting point for subsequent fits.
[6]:
# Export the fitted model as a template
loaded_template.save('fitted_template.json')
Using the exported model’s fitted parameters, generate a new circuit using the fitted parameters as initial guesses by suppling the fitted_as_initial
parameter as True
.
[7]:
fitted_template = circuits.CustomCircuit()
fitted_template.load('fitted_template.json', fitted_as_initial=True)
print(fitted_template)
R0-p(R1,C1)-p(R2,C2)-Wo1
Circuit string: R0-p(R1,C1)-p(R2,C2)-Wo1
Fit: False
Initial guesses:
R0 = 1.65e-02 [Ohm]
R1 = 8.77e-03 [Ohm]
C1 = 3.28e+00 [F]
R2 = 5.31e-03 [Ohm]
C2 = 2.32e-01 [F]
Wo1_0 = 6.37e-02 [Ohm]
Wo1_1 = 2.37e+02 [sec]
Z2 is a similar impedance spectra that we can fit using the previous fitted parameters as starting points. It has been shifted by 5 mOhm in the real axis and the data has been scaled by 1.5x.
[8]:
Z2 = (0.005 + Z.real)*1.5 + 1.5j*Z.imag
[9]:
fig, ax = plt.subplots(figsize=(10,10))
f_pred = np.logspace(5,-2)
fitted_template.fit(frequencies, Z2)
imported_circuit_init = fitted_template.predict(f_pred, use_initial = True)
imported_circuit_fit = fitted_template.predict(f_pred)
plot_nyquist(ax, Z)
plot_nyquist(ax, Z2)
plot_nyquist(ax, imported_circuit_init)
plot_nyquist(ax, imported_circuit_fit)
ax.legend(['Original Data', 'Shifted Data', 'Template Initial', 'Loaded Template Fit'])
plt.show()
print(fitted_template)
Simulating circuit based on initial parameters
Circuit string: R0-p(R1,C1)-p(R2,C2)-Wo1
Fit: True
Initial guesses:
R0 = 1.65e-02 [Ohm]
R1 = 8.77e-03 [Ohm]
C1 = 3.28e+00 [F]
R2 = 5.31e-03 [Ohm]
C2 = 2.32e-01 [F]
Wo1_0 = 6.37e-02 [Ohm]
Wo1_1 = 2.37e+02 [sec]
Fit parameters:
R0 = 3.22e-02 (+/- 2.31e-04) [Ohm]
R1 = 1.31e-02 (+/- 2.84e-04) [Ohm]
C1 = 2.19e+00 (+/- 1.24e-01) [F]
R2 = 7.96e-03 (+/- 3.10e-04) [Ohm]
C2 = 1.55e-01 (+/- 1.26e-02) [F]
Wo1_0 = 9.56e-02 (+/- 3.05e-03) [Ohm]
Wo1_1 = 2.38e+02 (+/- 1.73e+01) [sec]