impedance: fitting electrochemical impedance spectra

Code author: Ueli Sauter, Peter Kraus

Including functions relevant for Electrochemical Impedance Spectroscopy (EIS): evaluation of an equivalent circuit as well as the fitting of the circuit to data (calc_circuit() and fit_circuit()), and an interpolation function to find the lowest_real_impedance() in the data.

Functions

calc_circuit(freq, circuit, parameters[, output])

Calculates the complex impedance \(\text{Re}(Z)\) and \(-\text{Im}(Z)\) of the prescribed equivalent circuit as a function of frequency \(f\).

fit_circuit(real, imag, freq, circuit, ...)

Fits an equivalent circuit to the frequency-resolved EIS data.

lowest_real_impedance(real, imag[, ...])

A function that finds and interpolates the lowest \(\text{Re}(Z)\) value at which the complex impedance \(Z = \text{Re}(Z) - j \text{Im}(Z)\) is a real number (i.e. \(\text{Im}(Z) \approx 0\)).

Note

The functions in this module expect the whole EIS trace as input - the \(\text{Re}(Z)\), \(-\text{Im}(Z)\) and \(f\) are expected to be pint.Quantity containing an np.ndarray (or similar list-like object), which is then processed to a (set of) scalar values. This means that for processing time resolved data, the functions in this module have to be called on each timestep individually.

dgpost.transform.impedance.fit_circuit(real: Quantity, imag: Quantity, freq: Quantity, circuit: str, initial_values: dict[str, float], fit_bounds: dict[str, tuple[float, float]] = None, fit_constants: list[str] = None, ignore_neg_res: bool = True, upper_freq: float = inf, lower_freq: float = 0, repeat: int = 1, output: str = 'fit_circuit') dict[str, int | str | Quantity]

Fits an equivalent circuit to the frequency-resolved EIS data.

For the fitting an equivalent circuit is needed, defined as a str. The circuit may be composed of multiple circuit elements. To combine elements in a series a dash (-) is used. Elements in parallel are wrapped by p( , ). An element is defined by an identifier (usually letters) followed by a digit. Already implemented elements are located in the circuit_utils.circuit_components module:

Name

Symbol

Parameters

Bounds

Units

Resistor

R

R

(1e-6, 1e6)

Ω

Capacitance

C

C

(1e-20, 1)

F

Constant Phase Element

CPE

CPE_Q

(1e-20, 1)

Ω⁻¹sᵃ

CPE_a

(0, 1)

Warburg element

W

W

(0, 1e10)

Ω⁻¹s¹ᐟ²

Warburg short element

Ws

Ws_R

(0, 1e10)

Ω

Ws_T

(1e-10, 1e10)

s

Warburg open element

Wo

Wo_R

(0, 1e10)

Ω

Wo_T

(1e-10, 1e10)

s

Additionally an initial guess for the fitting parameters is needed. The initial guess is given as a dict where each key is the parameter name and the corresponding value is the initial value for the circuit.

The bounds of each parameter can be customized by the fit_bounds parameter. This parameter is a dict, where each key is the parameter name and the value consists of a tuple for the lower and upper bound (lb, ub).

To hold a parameter constant, add the name of the parameter to a list and pass it as fit_constants

Parameters:
  • real – A pint.Quantity object containing the real part of the impedance data, \(\text{Re}(Z)\). The unit of the provided gets converted to ‘Ω’.

  • imag – A pint.Quantity object containing the imaginary part of the impedance data, \(-\text{Im}(Z)\). The unit of the provided gets converted to ‘Ω’.

  • freq – A pint.Quantity object containing the frequency \(f\) of the impedance data. The unit of the provided data should gets converted to ‘Hz’.

  • circuit – A str description of the equivalent circuit.

  • initial_values – A dict with the initial (guess) values. Structure: {“param name”: value, … }

  • output – A str prefix

  • fit_bounds – Custom bounds for a parameter if default bounds are not wanted Structure: {“param name”: (lower bound, upper bound), …} Default is ‘’None’’

  • fit_constants – list of parameters which should stay constant during fitting Structure: [“param name”, …] Default is ‘’None’’

  • ignore_neg_res – ignores impedance values with a negative real part

  • upper_freq – upper frequency bound to be considered for fitting

  • lower_freq – lower frequency bound to be considered for fitting

  • repeat – how many times fit_routine gets called

Returns:

A tuple containing two dicts.
  • parameters, contains all the values of the parameters accessible by their names

  • units, contains all the units of the parameters accessible by their names

Return type:

(parameters, units)

dgpost.transform.impedance.calc_circuit(freq: Quantity, circuit: str, parameters: dict[str, float], output: str = 'calc_circuit') tuple[dict[str, float], dict[str, str]]

Calculates the complex impedance \(\text{Re}(Z)\) and \(-\text{Im}(Z)\) of the prescribed equivalent circuit as a function of frequency \(f\).

Parameters:
  • freq – A pint.Quantity containing the frequencies \(f\) at which the equivalent circuit is to be evaluated. The provided data should be in “Hz”.

  • circuit – A str description of the equivalent circuit. For more details see fit_circuit().

  • parameters – A dict containing the values defining the equivalent circuit. Structure: {“param name”: value, … }

  • output – A str prefix for the Re(Z) and -Im(Z) values calculated in this function. Defaults to "calc_circuit".

Returns:

retvals – A dictionary containing the pint.Quantity arrays with the output-prefixed \(\text{Re}(Z)\) and \(-\text{Im}(Z)\) as keys.

Return type:

dict[str, pint.Quantity]

dgpost.transform.impedance.lowest_real_impedance(real: Quantity, imag: Quantity, threshold: float = 0.0, output: str = 'min Re(Z)') dict[str, int | str | Quantity]

A function that finds and interpolates the lowest \(\text{Re}(Z)\) value at which the complex impedance \(Z = \text{Re}(Z) - j \text{Im}(Z)\) is a real number (i.e. \(\text{Im}(Z) \approx 0\)). If the impedance does not cross the real-zero axis, the \(\text{Re}(Z)\) at which the \(\text{abs}(\text{Im}(Z))\) is the smallest is returned.

Parameters:
  • real – A pint.Quantity object containing the real part of the impedance data, \(\text{Re}(Z)\). The units of real and imag are assumed to match.

  • imag – A pint.Quantity object containing the imaginary part of the impedance data, \(-\text{Im}(Z)\). The units of real and imag are assumed to match.

  • output – A str name for the output column, defaults to "min Re(Z)".

Returns:

retvals – A dictionary containing the pint.Quantity values of the real impedances with the output as keys.

Return type:

dict[str, pint.Quantity]