EISFitpython is a Python package for Electrochemical Impedance Spectroscopy (EIS) analysis, optimized for temperature-dependent experiments and complex circuit models. It applies a unified chi-square optimization to fit multiple impedance datasets at once, preserving inter-parameter relationships and propagating uncertainties across the full temperature range.
Accurate modeling of temperature-dependent impedance demands consistent parameter evolution. EISFitpython delivers:
Standard EIS workflows fit each temperature in isolation, which can produce erratic parameter trends, biased activation-energy estimates, and incomplete error analysis. EISFitpython replaces this with a single global-local optimization:
- Concurrent Dataset Fitting
Reduces parameter inconsistency by optimizing all temperatures together. - Global Parameters
Keeps temperature-independent circuit elements constant across datasets. - Local Parameters
Allows temperature-dependent elements to adapt within physical constraints. - Error Propagation
Tracks uncertainty through every temperature step.
- Global-Local Parameter Classification
Automatically labels each circuit element as temperature-independent or temperature-dependent. - Unified Chi-Square Objective
Optimizes all datasets against one cost function for consistency. - Automated Classification
Detects and assigns global vs. local roles without manual intervention. - Statistical Validation
Computes confidence intervals and parameter correlations.
If you use this code in your research, please cite:
S. C. Adediwura, N. Mathew, J. Schmedt auf der Günne, J. Mater. Chem. A 12 (2024) 15847–15857.
https://doi.org/10.1039/d3ta06237f
Electrochemical Impedance Spectroscopy (EIS) is a powerful analytical technique that characterizes the electrical properties of materials and their interfaces with electronically conducting electrodes. The technique involves:
-
Signal Application:
$$E(t) = E_0\sin(\omega t)$$ -
System Response:
$$I(t) = I_0\sin(\omega t + \phi)$$ -
Impedance Calculation:
$$Z(\omega) = \frac{E(t)}{I(t)} = |Z|e^{j\phi} = Z' + jZ''$$
Where:
-
$\omega = 2\pi f$ is the angular frequency -
$\phi$ is the phase shift -
$|Z|$ is the impedance magnitude -
$Z'$ and$Z''$ are real and imaginary components
Electrochemical Impedance Spectroscopy (EIS) represents a non-linear system where impedance data must be fitted using complex non-linear least-squares (CNLS) analysis to extract meaningful physical parameters. The CNLS technique operates by minimizing a sum of squares function S, which quantifies the difference between experimental data and the theoretical model.
The sum of squares function for model fitting:
For EIS data over frequency range
Where:
-
$Z_i^\mathrm{EXP}$ and$Z_i^\mathrm{TH}$ represent experimental and theoretical impedance respectively - Re and Im denote real and imaginary components
-
$w_i$ and$w_i$ are weighting factors for real and imaginary components
The choice of weighting method significantly impacts the fitting quality. EISFitpython implements three established approaches:
-
Unit Weighting
$$w_i^\mathrm{RE} = w_i^\mathrm{IM} = 1$$ - Treats all data points equally
- May overemphasize larger impedance values
- Suitable for data with uniform uncertainties
-
Proportional Weighting
$$w_i^\mathrm{RE} = \frac{1}{(\mathrm{Re}Z_i)^2}, \quad w_i^\mathrm{IM} = \frac{1}{(\mathrm{Im}Z_i)^2}$$ - Assumes constant relative errors
- May overemphasize high and low-frequency regions
- Useful when uncertainties scale with impedance magnitude
-
Modulus Weighting
$$w_i= \frac{1}{|Z_i|^2}$$ - Balances contributions from small and large impedances
- Provides equal statistical weight to real and imaginary components
- Recommended for typical EIS measurements
- Python 3.9 or higher
- NumPy ≥ 1.19.0
- SciPy ≥ 1.6.0
- Matplotlib ≥ 3.3.0
- Pandas ≥ 1.2.0
Download the latest release from the GitHub Releases page, then install it with pip:
python -m pip install eisfitpython-<version>.tar.gz
# or, if you downloaded a wheel:
python -m pip install eisfitpython-<version>-py3-none-any.whl
pip install -r requirements.txt
Core module for defining and evaluating equivalent circuit models.
R
: Resistor (Z = R)C
: Capacitor (Z = 1/jωC)L
: Inductor (Z = jωL)Q
: Constant Phase Element (Z = 1/[Q(jω)ᵅ])W
: Warburg Element (Z = σω^(-1/2)(1-j))F
: Finite-length Warburg (Z = σ·tanh(√(jωτ))/√(jωτ))
- Series connections:
+
- Parallel connections:
|
- Nested circuits:
()
Example: "(R1|Q1)+(R2|Q2)"
represents a series combination of two parallel R-Q circuits.
-
compute_impedance(params, circuit_str, freqs)
- Calculates complex impedance for a given circuit
- Parameters: element values, circuit string, frequency points
-
Z_curve_fit(circuit_str)
- Generates fitting function for scipy.optimize.curve_fit
- Used internally by fitting routines
Handles importing and processing raw EIS data files with sophisticated data validation and preprocessing capabilities.
-
readNEISYS(filename)
- Reads NEISYS format spectrometer files
-
readTXT(filename)
/readCSV(filename)
- Supports multiple standard data formats:
- Three-column format: f, Z', Z"
- Supports multiple standard data formats:
-
trim_data(f, Z, fmin, fmax)
- Advanced frequency range filtering:
- Linear or logarithmic range selection
- Automatic endpoint adjustment
- Data density preservation
- Optional noise filtering
- Returns filtered f, Z arrays
- Example:
# Trim to specific frequency range f_trim, Z_trim = dt.trim_data(f, Z, fmin=1e-1, # 0.1 Hz fmax=1e6) # 1 MHz
- Advanced frequency range filtering:
-
get_eis_files(base_path, subfolder)
- Smart file handling:
- Recursive directory search
- Pattern matching for EIS data
- Automatic sorting by temperature
- Supports multiple file formats
- Temperature extraction from filenames
- Example:
# Get temperature-series files #if subfolder is not None files = dt.get_eis_files(base_path='base folder', subfolder='temp_series') #else files = dt.get_eis_files(base_path='basefolder')
- Smart file handling:
Core fitting and analysis functionality.
-
EISFit(f, Z, params, circuit, UB, LB, weight_mtd='M', method='lm', single_chi='No')
- Main fitting routine
- Supports multiple weighting methods:
- 'M': Modulus weighting (|Z|)
- 'P': Proportional weighting
- 'U': Unity (no weighting)
- Returns optimized parameters, errors, and fit statistics
-
full_EIS_report(f, Z, params, circuit, UB, LB, weight_mtd, method, single_chi, plot_type)
- Comprehensive analysis with parameter values and plots
- Generates Nyquist and/or Bode plots
- Calculates statistical metrics (χ², R², AICc)
-
plot_fit(f, Z, Z_fit, plot_type)
- Visualization of experimental and fitted data
- Supports Nyquist, Bode, or both plot types
- Automatic scaling of impedance units (Ω, kΩ, MΩ, GΩ)
Tools for analyzing multiple datasets, especially temperature-dependent studies.
-
Batch_fit(files, params, circuit, Temp, UB, LB, weight_mtd, method)
- Fits multiple datasets with same circuit model
- Handles temperature series data
- Generates combined plots and reports
-
plot_arrhenius(R_values, temp, diameter, thickness)
- Arrhenius plot generation
- Calculates activation energies
- Handles multiple components (bulk, grain boundary, etc.)
-
sigma_report(R, Rerr, l, con, T)
- Calculates conductivity and its uncertainty
- Accounts for geometric factors and measurement errors
- Reports temperature-dependent conductivity values with:
- Absolute conductivity (S/cm)
- Standard error
- Percent error
- Handles both single and multiple temperature points
-
C_eff(R, R_err, Q, Q_err, n, n_err, T)
- Calculates effective capacitance from CPE parameters
- Includes error propagation
- Useful for analyzing non-ideal capacitive behavior
Specialized tools for complex systems with shared parameters across multiple temperatures.
-
Single_chi_report(f, Z, params, Temp, circuit_str)
- Advanced fitting with global-local parameter handling:
- Global parameters remain constant across temperatures
- Local parameters vary with temperature
- Temperature-dependent parameter tracking
- Comprehensive error analysis including:
- Parameter correlations
- Standard errors
- Chi-square statistics
- Advanced fitting with global-local parameter handling:
-
flatten_params(params, circuit_str, N_sub)
- parameter management for complex fits
- Handles mixed global/local parameters:
- For global parameters: single value used across all temperatures
- For local parameters: array of values [T₁, T₂, ..., Tₙ]
- Automatic parameter validation and structure verification
- Example usage:
# Mixed global-local parameter structure params = ( [R1_T1, R1_T2, ..., R1_Tn], # Local R1 values Q1, # Global Q1 value n1, # Global n1 value [R2_T1, R2_T2, ..., R2_Tn] # Local R2 values )
-
Single_chi(f, *params, circuit_str, circuit_type)
- Core computation engine for impedance calculation
- Handles parameter distribution across temperature points
- Supports both fitting and prediction modes
- Automatically manages parameter structure based on temperature points
import EISFit_main as em
# Define a simple RC circuit
circuit = "(R1|C1)"
params = [100, 1e-6] # R = 100 Ω, C = 1 µF
freqs = np.logspace(-2, 6, 50) # 0.01 Hz to 1 MHz
# Generate simulated data
Z = em.predict_Z(freqs[0], freqs[-1], len(freqs), params, circuit)
# Import custom EIS modules
from EISFitpython import data_extraction as dt
# Load EIS data
# NEISYS spectrometer files
f, Z = dt.readNEISYS('my_data.txt')
#.txt file without headers and tab separated, three-column format: f, Z', Z"
f, Z = dt.readTXT('my_data.txt')
#.csv file without headers, three-column format: f, Z', Z"
f, Z = dt.readCSV('my_data.csv')
# Define circuit and initial parameters
circuit = "(R1|Q1)+R2"
params = [1e5, 1e-9, 0.8, 50] # R1, Q1, n1, R2
UB = [] # Upper bounds
LB = [] # Lower bounds
# Perform fitting
popt, perror = em.full_EIS_report(
f, Z, params, circuit,
UB=UB, LB=LB,
weight_mtd='M', # Modulus weighting
method='lm', # Levenberg-Marquardt algorithm
single_chi='No',
plot_type='both' # Generate both Nyquist and Bode plots
)
# Import custom EIS modules
from EISFitpython import data_extraction as dt
from EISFitpython import EIS_Batchfit as ebf
# Load multiple temperature datasets
#if subfolder is not None
files = dt.get_eis_files(base_path='base folder', subfolder='temp_series')
temps = np.array([25, 50, 75, 100]) # °C
# Equivalent circuit model
circuit_str = "(R1|Q1)+Q2"
# Initial parameter guesses for the circuit model
params = [R1, Q1,n1, Q2, n2]
# Perform batch fitting
fit_params, fit_errors = ebf.Batch_fit(
files, params, circuit, temps,
UB, LB, weight_mtd='M', method='lm'
)
# Generate Arrhenius plot
D = 1.3 # Sample diameter (cm)
L = 0.2 # Sample thickness (cm)
ebf.plot_arrhenius(fit_params[:,0], temps, D, L, labels='Bulk')
# Import custom EIS modules
from EISFitpython import data_extraction as dt
from EISFitpython import singlechi as sc
from EISFitpython import EISFit_main as em
from EISFitpython import EIS_Batchfit as ebf
import numpy as np
#%% Data Processing
# Get EIS data files
filenames=dt.get_eis_files(base_path='../EIS_Data', subfolder='temp_series')
# Extract frequency and impedance data from NEISYS spectrometer files
f, Z = dt.stack_NEISYS_files(filenames)
# Split data at 1MHz frequency point
sublist, _ = dt.split_array(f, Z=None, split_freq=np.max(f))
N_sub = len(sublist)
# Temperature points (in Celsius)
temps = np.array([140, 150, 160, 170, 180])
# Define parameters with temperature dependence
circuit = "(R1|Q1)+(R2|Q2)"
params = (
R1_values, # Array of R1 values for each temperature
Q1, # Global Q1 (temperature-independent) / local (temperature-dependent, i.e., ferroelectrics )
n1, # Global n1 (temperature-independent) / local (temperature-dependent, i.e., ferroelectrics )
R2_values, # Array of R2 values for each temperature
Q2, # Global/local Q2
n2 # Global/local n2
)
# Perform analysis
fit_params, fit_perror, Z_fit = sc.Single_chi_report(f, Z, params, Temp, circuit_str,weight_mtd='M')
The module handles complex parameter relationships:
- Resistance values (R) typically show temperature dependence
- CPE parameters (Q, n) often remain constant across temperatures
- Automatic handling of parameter interdependencies
- Built-in correlation analysis between parameters
-
Data Preparation:
- Use consistent file naming
- Maintain temperature series structure
- Use trim_data() for focused analysis
- Check frequency range coverage
-
Circuit Model Selection:
- Start simple, add complexity as needed
- Validate with physical meaning
- Check parameter uncertainties
-
Fitting Strategy:
- Use reasonable initial guesses
- Set appropriate parameter bounds
- Try different weighting methods
-
Temperature Analysis:
- Ensure consistent sample geometry
- Use proper temperature units
- Validate Arrhenius behavior
- Check activation energy
See Example_scripts/ directory for detailed examples:
- Example1-simulate.py: Circuit simulation
- Example2a-EISfit.py: Single temperature fitting
- Example3-Batchfit.py: Temperature series analysis
- Example4-Singlechi.py: Global-local optimization with one cost function
EISFitpython is distributed under the MIT License.
Sheyi Clement Adediwura (c) 2024