Validation¶

Interpreting EIS data fundamentally relies on the the system conforming to conditions of causality, linearity, and stability. For an example of how the adherence to the Kramers-Kronig relations, see the Validation Example Jupyter Notebook

Lin-KK method¶

Validating your data with the lin-KK model requires fitting an optimal number of RC-elements and analysis of the residual errors.

impedance.validation.calc_mu(Rs)[source]

Calculates mu for use in LinKK

impedance.validation.eval_linKK(elements, ts, f)[source]

Builds a circuit of RC elements to be used in LinKK

impedance.validation.fit_linKK(f, ts, M, Z, fit_type='real', add_cap=False)[source]

Fits the linKK model using linear regression

Parameters: f: np.ndarray measured frequencies ts: np.ndarray logarithmically spaced time constants of RC elements M: int the number of RC elements Z: np.ndarray of complex numbers measured impedances fit_type: str selects which components of data are fit (‘real’, ‘imag’, or ‘complex’) add_cap: bool option to add a serial capacitance that helps validate data with no low-frequency intercept elements: np.ndarray values of fit $$R_k$$ in RC elements and series $$R_0$$, L, and optionally C. mu: np.float under- or over-fitting measure

Notes

Since we have a system of equations, $$Ax ~= b$$, that’s linear wrt $$R_k$$, we can fit the model by calculating the pseudo-inverse of A. $$Ax$$ is our model fit, $$\hat{Z}$$, and $$b$$ is the normalized real or imaginary component of the impedance data, $$Re(Z)/|Z|$$ or $$Im(Z)/|Z|$$, respectively.

$$\hat{Z} = R_0 + \sum^M_{k=1}(R_k / |Z|(1 + j * w * \tau_k))$$. $$x$$ is an (M+1) $$\times$$ 1 matrix where the first row contains $$R_0$$ and subsequent rows contain $$R_k$$ values. A is an N $$\times$$ (M+1) matrix, where N is the number of data points, and M is the number of RC elements.

Examples

Fitting the real part of data, the first column of A contains values of $$\frac{1}{|Z|}$$, the second column contains $$Re(1 / |Z| (1 + j * w * \tau_1))$$, the third contains $$Re(1 / |Z| (1 + j * w * \tau_2))$$ and so on. The $$R_k$$ values within the x matrix are found using numpy.linalg.pinv when fit_type = ‘real’ or ‘imag’. When fit_type = ‘complex’ the coefficients are found “manually” using $$r = ||A'x - b'||^2 + ||A''x - b'||^2$$ according to Eq 14 of Schonleber [1].

[1] Schönleber, M. et al. A Method for Improving the Robustness of linear Kramers-Kronig Validity Tests. Electrochimica Acta 131, 20–27 (2014) doi: 10.1016/j.electacta.2014.01.034.

impedance.validation.get_tc_distribution(f, M)[source]

Returns the distribution of time constants for the linKK method

impedance.validation.linKK(f, Z, c=0.85, max_M=50, fit_type='real', add_cap=False)[source]

A method for implementing the Lin-KK test for validating linearity [1]

Parameters: f: np.ndarray measured frequencies Z: np.ndarray of complex numbers measured impedances c: np.float cutoff for mu max_M: int the maximum number of RC elements fit_type: str selects which components of data are fit (‘real’, ‘imag’, or ‘complex’) add_cap: bool option to add a serial capacitance that helps validate data with no low-frequency intercept M: int number of RC elements used mu: np.float under- or over-fitting measure Z_fit: np.ndarray of complex numbers impedance of fit at input frequencies resids_real: np.ndarray real component of the residuals of the fit at input frequencies resids_imag: np.ndarray imaginary component of the residuals of the fit at input frequencies

Notes

The lin-KK method from Schönleber et al. [1] is a quick test for checking the validity of EIS data. The validity of an impedance spectrum is analyzed by its reproducibility by a Kramers-Kronig (KK) compliant equivalent circuit. In particular, the model used in the lin-KK test is an ohmic resistor, $$R_{Ohm}$$, and $$M$$ RC elements.

$\hat Z = R_{Ohm} + \sum_{k=1}^{M} \frac{R_k}{1 + j \omega \tau_k}$

The $$M$$ time constants, $$\tau_k$$, are distributed logarithmically,

$\tau_1 = \frac{1}{\omega_{max}} ; \tau_M = \frac{1}{\omega_{min}} ; \tau_k = 10^{\log{(\tau_{min}) + \frac{k-1}{M-1}\log{{( \frac{\tau_{max}}{\tau_{min}}}})}}$

and are not fit during the test (only $$R_{Ohm}$$ and $$R_{k}$$ are free parameters).

In order to prevent under- or over-fitting, Schönleber et al. propose using the ratio of positive resistor mass to negative resistor mass as a metric for finding the optimal number of RC elements.

$\mu = 1 - \frac{\sum_{R_k \ge 0} |R_k|}{\sum_{R_k < 0} |R_k|}$

The argument c defines the cutoff value for $$\mu$$. The algorithm starts at M = 3 and iterates up to max_M until a $$\mu < c$$ is reached. The default of 0.85 is simply a heuristic value based off of the experience of Schönleber et al., but a lower value may give better results.

If the argument c is None, then the automatic determination of RC elements is turned off and the solution is calculated for max_M RC elements. This manual mode should be used with caution as under- and over-fitting should be avoided.

[1] Schönleber, M. et al. A Method for Improving the Robustness of linear Kramers-Kronig Validity Tests. Electrochimica Acta 131, 20–27 (2014) doi: 10.1016/j.electacta.2014.01.034.

impedance.validation.residuals_linKK(elements, ts, Z, f, residuals='real')[source]

Calculates the residual between the data and a LinKK fit