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.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
- Returns
- 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
- Returns
- 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 atM = 3
and iterates up tomax_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
isNone
, then the automatic determination of RC elements is turned off and the solution is calculated formax_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.