impedanceR
- an R package for simulating impedance spectra of equivalent circuits
This package contains a suite of functions for calculating and simulating electrical or electrochemical impedance spectra using the R programming language. The package contains functions for simulating the most common equivalent circuit elements, some convenient functions for constructing the circuits themselves, and other useful utility functions.
I used early versions of this code throughout my introduction to EIS pages to simulate equivalent circuits and create the interactive components of those pages.
For those interested, I have now released this code as a more convenient R package on GitHub, which also contains some improved functionality and additional equivalent circuit elements. This page gives some basic instructions on installation and usage.
You will need R and the devtools
package installed. I also recommend RStudio and the tidyverse
suite of add-on packages for working with data - I will use this in my examples. (The impedanceR
package also requires magrittr
which provides the pipe (%>%
) operator).
You can consult the R documentation (i.e., by using ?functionname
) for more information on each specific function.
The following equivalent circuit elements and the arguments (i.e., parameters they take) are as follows:
Z_R(R)
- resistor
Z_C(C, omega)
- capacitor
Z_L(L, omega)
- inductor
Z_Q(L, n, omega)
- constant phase element
Z_W(sigma, omega)
- Warburg element
Z_FLW(Z0, tau, omega)
- Finite Length (“short”) Warburg element (FLW)
Z_FSW(Z0, tau, omega)
- Finite Space (“open”) Warburg element (FSW)
Z_G(Z0, k, omega)
- Infinite length Gerischer element
Z_FLG(Z0, k, tau, omega)
- Finite length Gerischer element
trans_line(R, U, n)
- transmission line
para()
- for adding any number of circuit elements in parallel
omega_range()
- for calculating a range of angular frequency values (necessary for all circuit elements, except resistors)
Z_to_df()
- convert a complex vector to a data.frame
of real and imaginary values
All of the equivalent circuit elements (except the resistor) take a vector of angular frequency values (omega
, that is, the frequency data points to be simulated) as an argument, and all output a vector of complex numbers as a result.
All the elements in the circuit need to use the same omega
values, so it is simplest to define these as its own variable at the start, using the omega_range
function:
This creates a set of values for angular frequency from 1 Hz to 10 kHz, with 12 points per decade of frequency.
Equivalent circuits can be calculated by mathematically adding them in series (with the +
operator) or in parallel (with the provided para()
function). Let’s consider a circuit with two parallel RC elements in series with each other:
We can check that the variable a
has the right form:
cplx [1:61] 25-0.3i 25-0.3i 25-0.4i ...
And this is the expected result - a vector of complex numbers. The provided Z_to_df()
function converts this to a data frame:
Re Im 1 24.99684 -0.2528585 2 24.99536 -0.3063226 3 24.99320 -0.3710783 4 24.99002 -0.4495006 5 24.98535 -0.5444561
And we can plot this (using, by convention, the negative imaginary part). If using ggplot2
, use the coord_fixed()
option to make sure that the axes are proportional!
We can also create Bode plots, but this requires adding the omega
variable (or frequency, which is omega
divided by 2π) to the data frame. I find the easiest way is to use gather()
from the dplyr
package:
and so forth.
One feature I will highlight in particular is the possibility to simulate transmission line style circuits, which are useful for example in modelling porous electrodes.
The basic function trans_line()
takes the form:
where in the equivalent circuit below, R
is the value of each individual resistor in one of the rails of the transmission line, U
is any other equivalent circuit unit which shorts the two rails together, and n
is the total number of R-U units linked together. The opposite rail has zero resistance (this is a limitation currently, I’m afraid).
So for example, we can simulate the classic de Levie transmission line as discussed in my page on diffusion resistance, where U is just a capacitor:
So now we are calculating the impedance of a transmission line where each resistor has a value of 2 Ω, the U
unit is a capacitor with a capacitance of 1 µF, and the total transmission line is 40 units long. If we plot this, we get:
And this result has the same shape as the finite space Warburg (FSW) element, where the Z0 parameter is equal to the sum of all the resistors in the rail.
Here’s a more complicated example. Let’s imagine a more complicated model where the U
unit in the transmission line is a modified Randles circuit (this is the sort of thing we might consider as a model for a battery electrode, for example). In 13 lines, I can simulate this equivalent circuit for several different lengths of transmission line, and make a basic plot of the data.
Give it a try! Any questions, feel free to contact me or ask in the comments below.
comments powered by Disqus