Alkaline Electrolyte and Fe Impurity Effects on the Performance and Active-phase Structure of NiOOH Thin Films for OER Catalysis Applications
\newpage \maketitle \raggedbottom \tableofcontents
This document contains supporting figures, tables, images, and code for the work, “Alkaline electrolyte and Fe impurity effects on the performance and active-phase structure of NiOOH thin films for OER catalysis applications.” In particular, this document includes Python code for 1) fitting Gaussian functions to NiOOH Raman spectra and 2) the results of curve fitting for all NiOOH spectra analyzed for this manuscript. The code for fitting Gaussian functions to spectra data can be easily modified for the analysis of materials with similar Raman spectral signatures. In addition, this document contains Python code that generated all figures for this work.
The data files are also available as data.zip with the supporting information.
Figure ref:fig-s1 shows the results of LSV while switching the electrolyte between purified LiOH (0.1 M) and CsOH (0.1 M). A cation effect on catalytic performance was observed in purified electrolyte. Based on Figure ref:fig-s1, purified CsOH promoted OER current densities that were ≈100 % higher than OER current densities promoted by purified LiOH.
Figure ref:fig-s2 shows the results of LSV while switching the electrolyte between purified NaOH (0.1 M) and KOH (0.1 M). Based on Figure ref:fig-s2, a relatively small cation effect was observed in purified NaOH and KOH. KOH promoted slightly higher OER current densities than NaOH. The differences in catalytic performance between purified CsOH and LiOH were smaller than the differences in catalytic performance observed in Figure ref:fig-s1.
Figure ref:fig-s3 shows the results of LSV while switching the electrolyte between Fe-saturated LiOH (0.1 M) and CsOH (0.1 M). A cation effect on catalytic performance was observed in Fe-saturated electrolyte. Based on Figure ref:fig-s3, Fe-saturated CsOH promoted OER current densities that were ≈50 % higher than OER current densities promoted by Fe-saturated LiOH.
Figure ref:fig-s4 shows the results of LSV while switching the electrolyte between Fe-saturated NaOH (0.1 M) and KOH (0.1 M). A cation effect on catalyst performance was not observed between Fe-saturated NaOH and KOH. Most of the NaOH current densities (green) overlapped with the KOH current densities (black). Current densities likely diverged at overpotentials above ≈0.35 V due to differences in oxygen bubble coverage on the working electrode surface, which would impede the flow of current.
Figure ref:fig-s5 shows the results of LSV performed during Raman spectroscopy in purified LiOH (0.1 M) and CsOH (0.1 M). The corresponding Raman spectra are in Figure 3 (main text). Based on Figure ref:fig-s5, purified CsOH promoted OER current densities that were ≈50% higher than OER current densities promoted by purified LiOH. Spectra were collected at overpotentials of 240, 340, and 440 mV.
Figure ref:fig-s6 shows the results of LSV performed during Raman spectroscopy in Fe-saturated LiOH (0.1 M) and CsOH (0.1 M). The corresponding Raman spectra are in Figure 4 (main text). Based on Figure ref:fig-s6, Fe-saturated CsOH promoted OER current densities that were ≈50% higher than OER current densities promoted by Fe-saturated LiOH. Spectra were collected at overpotentials of 240, 340, and 440 mV.
Table ref:tab:s1 shows the results of a Tafel analysis performed on LSV curves in purified and Fe-saturated LiOH, NaOH, KOH, and CsOH. Error represents one standard deviation from mean Tafel slope.
Electrolyte | Tafel slope (mv/decade) |
---|---|
LiOH, purified | 56.95 \textpm \enspace 6.49 |
NaOH, purified | 61.66 \textpm \enspace 4.77 |
KOH, purified | 61.45 \textpm \enspace 2.70 |
CsOH, purified | 58.22 \textpm \enspace 8.74 |
LiOH, Fe-saturated | 21.39 \textpm \enspace 0.75 |
NaOH, Fe-saturated | 18.75 \textpm \enspace 1.09 |
KOH, Fe-saturated | 19.73 \textpm \enspace 0.96 |
CsOH, Fe-saturated | 21.57 \textpm \enspace 0.14 |
There was not a statistically significant difference between purified LiOH, NaOH, KOH, or CsOH; all Tafel slopes were ≈60 mV/decade. In addition, there was not a statistically significant difference between Fe-saturated LiOH, NaOH, KOH, or CsOH; all Tafel slopes were ≈20 mV/decade. Although these results do not provide much insight into the subtle differences in the current regimes, they clearly show that Fe had a significant effect on catalytic performance.
Figure ref:fig-s7 shows Raman spectra collected on Ni(OH)2 thin films at 300 mV (vs. Hg/HgO). These were same thin films used for the LSV/Raman spectroscopy experiments described in the main body of this report, except the films were in a reduced state (i.e. Ni(OH)2) and OER was not occurring. Figure ref:fig-s7 shows no sharp Raman peaks at ≈480 cm-1 and ≈560 cm-1 (as in Figures 3 and 4, main text), indicating that the film was Ni(OH)2 at an overpotential of 300 mV.
Below is an expression with four Gaussian terms that was fit to Raman spectra for NiOOH.An is amplitude (a.u.), Bn is mean peak position (cm-1), Cn is standard deviation (cm-1), x is Raman shift (cm-1), and y is Raman signal (a.u.). Subscripts n=1 and n=2 correspond to the two Gaussian curves fit to the peak at ≈480cm-1 and subscripts n=3 and n=4 correspond to the two Gaussian curves fit to the peak at ≈560 cm-1.
Below are initial guess, fitted, and calculated output parameters for fittings performed on all NiOOH Raman spectra for this manuscript. To call the curve fitting funtion, the following was typed (default settings included): dgaus2p(filename, cntr=(470, 560), amp1=(20, 20), amp2=(20, 20), std1=(10, 5), std2=(10, 5), datarange=None, output=False, step=4). Aside from the file name and step number, only default parameters that needed to be adjusted were included in the following code blocks. Python code for the “dgaus2p” function can be found in the Appendix below.
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-1-600mV.txt',
cntr=(480, 560),
amp1=(12, 12),
amp2=(5, 5),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-1-600mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-1-700mV.txt',
cntr=(480, 560),
amp1=(12, 12),
amp2=(5, 5),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-1-700mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-1-800mV.txt',
cntr=(480, 560),
amp1=(18, 18),
amp2=(8, 8),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-1-800mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-2-600mV.txt',
cntr=(480, 560),
amp1=(15, 15),
amp2=(8, 8),
output=True,
step=4)
# Print file containing input, fitted, and output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-2-600mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-2-700mV.txt',
cntr=(480, 560),
amp1=(12, 12),
amp2=(10, 10),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-2-700mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-2-800mV.txt',
cntr=(480, 560),
amp1=(15, 15),
amp2=(10, 10),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-2-800mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-3-600mV.txt',
cntr=(480, 560),
amp1=(20, 20),
amp2=(10, 10),
output=True,
step=4)
# Print file containing input, fitted, and output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-3-600mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-3-700mV.txt',
cntr=(480, 560),
amp1=(25, 25),
amp2=(15, 15),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-3-700mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-3-800mV.txt',
cntr=(480, 560),
amp1=(20, 20),
amp2=(15, 15),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Li-pure-3-800mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-1-600mV.txt',
cntr=(480, 560),
amp1=(20, 20),
amp2=(15, 15),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-1-600mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-1-700mV.txt',
cntr=(480, 560),
amp1=(25, 25),
amp2=(15, 15),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-1-700mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-1-800mV.txt',
cntr=(480, 560),
amp1=(25, 25),
amp2=(20, 20),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-1-800mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-2-600mV.txt',
cntr=(480, 560),
amp1=(20, 20),
amp2=(12, 12),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-2-600mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-2-700mV.txt',
cntr=(480, 560),
amp1=(20, 20),
amp2=(13, 13),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-2-700mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-2-800mV.txt',
cntr=(480, 560),
amp1=(22, 22),
amp2=(13, 13),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-2-800mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-3-600mV.txt',
cntr=(480, 560),
amp1=(15, 15),
amp2=(8, 8),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-3-600mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-3-700mV.txt',
cntr=(480, 560),
amp1=(20, 20),
amp2=(12, 12),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-3-700mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-3-800mV.txt',
cntr=(480, 560),
amp1=(20, 20),
amp2=(13, 13),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/purified/Ni-Cs-pure-3-800mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-1-600mV.txt',
cntr=(480, 560),
amp1=(12, 12),
amp2=(10, 10),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-1-600mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-1-700mV.txt',
cntr=(480, 560),
amp1=(15, 15),
amp2=(10, 10),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-1-700mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-1-800mV.txt',
cntr=(480, 560),
amp1=(17, 17),
amp2=(10, 10),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-1-800mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-2-600mV.txt',
cntr=(480, 560),
amp1=(12, 12),
amp2=(8, 8),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-2-600mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-2-700mV.txt',
cntr=(480, 560),
amp1=(12, 12),
amp2=(7, 7),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-2-700mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-2-800mV.txt',
cntr=(480, 560),
amp1=(12, 12),
amp2=(8, 8),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-2-800mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-3-600mV.txt',
cntr=(480, 560),
amp1=(12, 12),
amp2=(10, 10),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-3-600mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-3-700mV.txt',
cntr=(480, 560),
amp1=(10, 10),
amp2=(7, 7),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-3-700mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-3-800mV.txt',
cntr=(480, 560),
amp1=(12, 12),
amp2=(7, 7),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Li-Fe-3-800mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-1-600mV.txt',
cntr=(480, 560),
amp1=(8, 8),
amp2=(6, 6),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-1-600mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-1-700mV.txt',
cntr=(480, 560),
amp1=(10, 10),
amp2=(6, 6),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-1-700mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-1-800mV.txt',
cntr=(480, 560),
amp1=(10, 10),
amp2=(6, 6),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-1-800mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-2-600mV.txt',
cntr=(480, 560),
amp1=(12, 12),
amp2=(8, 8),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-2-600mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-2-700mV.txt',
cntr=(480, 560),
amp1=(12, 12),
amp2=(8, 8),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-2-700mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-2-800mV.txt',
cntr=(480, 560),
amp1=(12, 12),
amp2=(8, 8),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-2-800mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-3-600mV.txt',
cntr=(480, 560),
amp1=(12, 12),
amp2=(10, 10),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-3-600mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-3-700mV.txt',
cntr=(480, 560),
amp1=(15, 15),
amp2=(10, 10),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-3-700mV.fit', 'r') as f:
print f.read()
from ramantools import dgaus2p
dgaus2p('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-3-800mV.txt',
cntr=(480, 560),
amp1=(18, 18),
amp2=(12, 12),
output=True,
step=4)
# Print initial guess, fitted, and calculated output parameters
with open('./data/raman-spectra-for-fitting/iron-saturated/Ni-Cs-Fe-3-800mV.fit', 'r') as f:
print f.read()
Figure ref:fig-s8 shows the patterned three-electrode system (Pine Instruments) that was used for all experiments in this study. The Au working electrode is the yellow circle on the left side of the image. The Au counter electrode is the yellow area around the perimeter of the left side of the electrode. The Ag/AgCl reference electrode (RE) is the small, black circle on the left side of the image. An external Hg/HgO reference electrode was used instead of the Ag/AgCl reference electrode since all experiments were performed in alkaline electrolyte.
Figure ref:fig-s9 shows a top-view of the electrochemical cell used for the LSV electrolyte switching experiments. The patterned 3-electrode was connected to the white plug. The external Hg/HgO reference electrode is the clear plastic object with a black cap and white/blue tag.
Figure ref:fig-s10 shows a side-view of the electrochemical cell shown above. This image provides a better view of the working and counter electrodes.
Figure ref:fig-s11 shows the electrochemical cell mounted in the Raman spectroscopy system. This configuration was used to perform Raman spectroscopy during LSV. A laser beam was emitted from the black and blue objective above the electrode.
Figure ref:fig-s12 shows Ni(OH)2 in a polypropylene vial for electrolyte purification cite:trotochaud-2014-nickel-iron. Stock electrolyte soaked in Ni(OH)2 for at least 12 hours. The vial on the right shows electrolyte soaking in the adsorbent (i.e. Ni(OH)2). The vial on the left shows purified electrolyte after centrifugation, but before it was collected into a separate polypropylene vial for storage.
bibliographystyle:unsrt bibliography:references.bib
# Generate I vs. V figure
# LSV: LiOH, CsOH (purified)
import numpy as np
import matplotlib.pyplot as plt
import xlrd
# Open I vs. V data file
ex1 = xlrd.open_workbook('./data/lsv-data/lsv-li-cs-pure-10-08-mod.xlsx')
ex2 = xlrd.open_workbook('./data/lsv-data/lsv-li-cs-pure-10-03-mod.xlsx')
# LiOH
Li1 = ex1.sheet_by_index(0) # read data from Excel sheet
Li2 = ex1.sheet_by_index(1)
Li3 = ex1.sheet_by_index(2)
Li4 = ex1.sheet_by_index(3)
Li5 = ex2.sheet_by_index(0)
Li6 = ex2.sheet_by_index(1)
Li7 = ex2.sheet_by_index(2)
x = np.array(Li1.col_values(0)) - 0.365 # convert potential to overpotential (V)
LiI1 = np.array(Li1.col_values(1)) * 1000/0.0314159 # convert current (A) to current density (mA/cm2)
LiI2 = np.array(Li2.col_values(1)) * 1000/0.0314159
LiI3 = np.array(Li3.col_values(1)) * 1000/0.0314159
LiI4 = np.array(Li4.col_values(1)) * 1000/0.0314159
LiI5 = np.array(Li5.col_values(1)) * 1000/0.0314159
LiI6 = np.array(Li6.col_values(1)) * 1000/0.0314159
LiI7 = np.array(Li7.col_values(1)) * 1000/0.0314159
LiI = np.array([LiI2, LiI3, LiI4, LiI5, LiI6, LiI7])
# CsOH
Cs1 = ex1.sheet_by_index(4) # read data from Excel sheet
Cs2 = ex1.sheet_by_index(5)
Cs3 = ex1.sheet_by_index(6)
Cs4 = ex1.sheet_by_index(7)
Cs5 = ex2.sheet_by_index(3)
Cs6 = ex2.sheet_by_index(4)
Cs7 = ex2.sheet_by_index(5)
CsI1 = np.array(Cs1.col_values(1)) * 1000/0.0314159 # convert current (A) to current density (mA/cm2)
CsI2 = np.array(Cs2.col_values(1)) * 1000/0.0314159
CsI3 = np.array(Cs3.col_values(1)) * 1000/0.0314159
CsI4 = np.array(Cs4.col_values(1)) * 1000/0.0314159
CsI5 = np.array(Cs5.col_values(1)) * 1000/0.0314159
CsI6 = np.array(Cs6.col_values(1)) * 1000/0.0314159
CsI7 = np.array(Cs7.col_values(1)) * 1000/0.0314159
CsI = np.array([CsI2, CsI3, CsI4, CsI5, CsI6, CsI7])
# Calculate average current density
avgLiI = (LiI2 + LiI3 + LiI4 + LiI5 + LiI6 + LiI7) / 6
avgCsI = (CsI2 + CsI3 + CsI4 + CsI5 + CsI6 + CsI7) / 6
# Calculate standard deviation of specified data points
nth = 80 # interval for calculating std. dev.
stdLi, stdCs = [], []
for n in LiI.T[::-nth]:
stdLi.append(np.std(n))
stdLi = np.array(stdLi)
for n in CsI.T[::-nth]:
stdCs.append(np.std(n))
stdCs = np.array(stdCs)
xx = x[::-nth] # potentials where std. dev. calculated
# Generate and format figure
plt.figure(figsize=(3, 4))
plt.plot(x, avgCsI, 'r', label='CsOH') # voltage vs. avg. current density
plt.errorbar(xx, avgCsI[::-nth], yerr=stdCs, lw=0, elinewidth=1, color='r') # error bars
plt.plot(x, avgLiI, 'b', label='LiOH')
plt.errorbar(xx, avgLiI[::-nth], yerr=stdLi, lw=0, elinewidth=1, color='b')
plt.legend(loc='upper left', fontsize='11') # legend
plt.xlabel('Overpotential (V)') # x-axis label
plt.ylabel('Current Density (mA/cm$^{2}$)') # y-axis label
plt.axis([0.2, 0.6, -0.1, 3]) # x,y axis values
plt.tight_layout()
plt.xticks([0.2, 0.3, 0.4, 0.5, 0.6], [0.2, 0.3, 0.4, 0.5, 0.6])
# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
plt.savefig('./images/figures-supp-info/IvsV-Li-Cs-pure-10-08.{0}'.format(ext), dpi=300)
plt.show()
#Generate I vs. V figure
#LiOH, CsOH - purified
import numpy as np
import matplotlib.pyplot as plt
import xlrd
# Open I vs. V data file
ex1 = xlrd.open_workbook('./data/lsv-data/lsv-li-cs-iron-11-21.xlsx')
# LiOH
Li1 = ex1.sheet_by_index(0) # read data from Excel sheet
Li2 = ex1.sheet_by_index(1)
Li3 = ex1.sheet_by_index(2)
Li4 = ex1.sheet_by_index(3)
x = np.array(Li1.col_values(0)) - 0.365 # potential to overpotential (V)
LiI1 = np.array(Li1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
LiI2 = np.array(Li2.col_values(1)) * 1000/0.0314159
LiI3 = np.array(Li3.col_values(1)) * 1000/0.0314159
LiI4 = np.array(Li4.col_values(1)) * 1000/0.0314159
LiI = np.array([LiI1, LiI2, LiI3, LiI4])
# CsOH
Cs1 = ex1.sheet_by_index(4) # read data from Excel sheet
Cs2 = ex1.sheet_by_index(5)
Cs3 = ex1.sheet_by_index(6)
Cs4 = ex1.sheet_by_index(7)
CsI1 = np.array(Cs1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
CsI2 = np.array(Cs2.col_values(1)) * 1000/0.0314159
CsI3 = np.array(Cs3.col_values(1)) * 1000/0.0314159
CsI4 = np.array(Cs4.col_values(1)) * 1000/0.0314159
CsI = np.array([CsI1, CsI2, CsI3, CsI4])
# Calculate average current density
avgLiI = (LiI1 + LiI2 + LiI3 + LiI4) / 4
avgCsI = (CsI1 + CsI2 + CsI3 + CsI4) / 4
# Calculate standard deviation of specified data points
nth = 60 # interval for calculating std. dev.
stdLi, stdCs = [], []
for n in LiI.T[::-nth]:
stdLi.append(np.std(n))
stdLi = np.array(stdLi)
for n in CsI.T[::-nth]:
stdCs.append(np.std(n))
stdCs = np.array(stdCs)
xx = x[::-nth] # potentials where std. dev. calculated
# Generate and format figure
plt.figure(figsize=(3, 4))
plt.plot(x, avgCsI, 'r', label='CsOH') #plot voltage vs. avg. current density
plt.errorbar(xx, avgCsI[::-nth], yerr=stdCs, lw=0, elinewidth=1, color='r') # error bars
plt.plot(x, avgLiI, 'b', label='LiOH')
plt.errorbar(xx, avgLiI[::-nth], yerr=stdLi, lw=0, elinewidth=1, color='b')
plt.legend(loc='upper left', fontsize='11') # legend
plt.xlabel('Overpotential (V)') # x-axis label
plt.ylabel('Current Density (mA/cm$^{2}$)') # y-axis label
plt.axis([0.0, 0.5, -1, 25]) # x,y axis values
plt.tight_layout()
plt.xticks([0.0, 0.1, 0.2, 0.3, 0.4, 0.5], [0.0, 0.1, 0.2, 0.3, 0.4, 0.5])
# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
plt.savefig('./images/figures-supp-info/IvsV-Li-Cs-iron-11-21.{0}'.format(ext), dpi=300)
plt.show()
# Generate I vs. V figure
# LSV: LiOH, CsOH (purified)
import numpy as np
import matplotlib.pyplot as plt
import xlrd
# Open I vs. V data file
ex1 = xlrd.open_workbook('./data/lsv-data/lsv-na-k-pure-01-16.xlsx')
# NaOH
Na1 = ex1.sheet_by_index(0) # read data from Excel sheet
Na2 = ex1.sheet_by_index(1)
Na3 = ex1.sheet_by_index(2)
Na4 = ex1.sheet_by_index(3)
x = np.array(Na1.col_values(0)) - 0.365 # potential to overpotential (V)
NaI1 = np.array(Na1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
NaI2 = np.array(Na2.col_values(1)) * 1000/0.0314159
NaI3 = np.array(Na3.col_values(1)) * 1000/0.0314159
NaI4 = np.array(Na4.col_values(1)) * 1000/0.0314159
NaI = np.array([NaI2, NaI3, NaI4])
# KOH
K1 = ex1.sheet_by_index(4) # read data from Excel sheet
K2 = ex1.sheet_by_index(5)
K3 = ex1.sheet_by_index(6)
K4 = ex1.sheet_by_index(7)
KI1 = np.array(K1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
KI2 = np.array(K2.col_values(1)) * 1000/0.0314159
KI3 = np.array(K3.col_values(1)) * 1000/0.0314159
KI4 = np.array(K4.col_values(1)) * 1000/0.0314159
KI = np.array([KI2, KI3, KI4])
# Calculate average current density
avgNaI = (NaI2 + NaI3 + NaI4) / 3
avgKI = (KI2 + KI3 + KI4) / 3
# Calculate standard deviation of specified data points
nth = 70 # interval for calculating std. dev.
stdNa, stdK = [], []
for n in NaI.T[::-nth]:
stdNa.append(np.std(n))
stdNa = np.array(stdNa)
for n in KI.T[::-nth]:
stdK.append(np.std(n))
stdK = np.array(stdK)
xx = x[::-nth] # potentials where std. dev. calculated
# Generate and format figure
plt.figure(figsize=(3, 4))
plt.plot(x, avgKI, 'k', label='KOH') #plot voltage vs. avg. current density
plt.errorbar(xx, avgKI[::-nth], yerr=stdK, lw=0, elinewidth=1, color='k') # error bars
plt.plot(x, avgNaI, 'g', label='NaOH')
plt.errorbar(xx, avgNaI[::-nth], yerr=stdNa, lw=0, elinewidth=1, color='g')
plt.legend(loc='upper left', fontsize='11') # legend
plt.xlabel('Overpotential (V)') # x-axis label
plt.ylabel('Current Density (mA/cm$^{2}$)') # y-axis label
plt.axis([0.2, 0.6, -0.1, 2]) # x,y axis values
plt.tight_layout()
plt.xticks([0.2, 0.3, 0.4, 0.5, 0.6], [0.2, 0.3, 0.4, 0.5, 0.6])
# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
plt.savefig('./images/figures-supp-info/IvsV-Na-K-pure-01-16-15.{0}'.format(ext), dpi=300)
plt.show()
# Generate I vs. V figure
# LSV: NaOH, KOH (Fe-saturated)
import numpy as np
import matplotlib.pyplot as plt
import xlrd
# Open I vs. V data file
ex1 = xlrd.open_workbook('./data/lsv-data/lsv-na-k-iron-01-19.xlsx')
# NaOH
Na1 = ex1.sheet_by_index(0) # read data from Excel sheet
Na2 = ex1.sheet_by_index(1)
Na3 = ex1.sheet_by_index(2)
Na4 = ex1.sheet_by_index(3)
x = np.array(Na1.col_values(0)) - 0.365 # potential to overpotential (V)
NaI1 = np.array(Na1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
NaI2 = np.array(Na2.col_values(1)) * 1000/0.0314159
NaI3 = np.array(Na3.col_values(1)) * 1000/0.0314159
NaI4 = np.array(Na4.col_values(1)) * 1000/0.0314159
NaI = np.array([NaI2, NaI3, NaI4])
# KOH
K1 = ex1.sheet_by_index(4) # read data from Excel sheet
K2 = ex1.sheet_by_index(5)
K3 = ex1.sheet_by_index(6)
K4 = ex1.sheet_by_index(7)
KI1 = np.array(K1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
KI2 = np.array(K2.col_values(1)) * 1000/0.0314159
KI3 = np.array(K3.col_values(1)) * 1000/0.0314159
KI4 = np.array(K4.col_values(1)) * 1000/0.0314159
KI = np.array([KI2, KI3, KI4])
# Calculate average current density
avgNaI = (NaI2 + NaI3 + NaI4) / 3
avgKI = (KI2 + KI3 + KI4) / 3
# Calculate standard deviation of specified data points
nth = 70 # interval for calculating std. dev.
stdNa, stdK = [], []
for n in NaI.T[::-nth]:
stdNa.append(np.std(n))
stdNa = np.array(stdNa)
for n in KI.T[::-nth]:
stdK.append(np.std(n))
stdK = np.array(stdK)
xx = x[::-nth] # potentials where std. dev. calculated
# Generate and format figure
plt.figure(figsize=(3, 4))
plt.plot(x, avgKI, 'k', label='KOH') # voltage vs. avg. current density
plt.errorbar(xx, avgKI[::-nth], yerr=stdK, lw=0, elinewidth=1, color='k') # error bars
plt.plot(x, avgNaI, 'g', label='NaOH')
plt.errorbar(xx, avgNaI[::-nth], yerr=stdNa, lw=0, elinewidth=1, color='g')
plt.legend(loc='upper left', fontsize='11') # legend
plt.xlabel('Overpotential (V)') # x-axis label
plt.ylabel('Current Density (mA/cm$^{2}$)') # y-axis label
plt.axis([0.0, 0.5, -1, 30]) # x,y axis values
plt.tight_layout()
plt.xticks([0.0, 0.1, 0.2, 0.3, 0.4, 0.5], [0.0, 0.1, 0.2, 0.3, 0.4, 0.5])
# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
plt.savefig('./images/figures-supp-info/IvsV-Na-K-iron-01-19.{0}'.format(ext), dpi=300)
plt.show()
# Generate I vs. V figure
# LSV; LiOH, CsOH (purified)
import numpy as np
import matplotlib.pyplot as plt
import xlrd
# Open I vs. V data file
ex1 = xlrd.open_workbook('./data/lsv-data/lsv-li-cs-pure-10-08-mod.xlsx')
ex2 = xlrd.open_workbook('./data/lsv-data/lsv-li-cs-pure-10-03-mod.xlsx')
ex3 = xlrd.open_workbook('./data/lsv-data/lsv-na-k-pure-01-16.xlsx')
# LiOH
Li1 = ex1.sheet_by_index(0) # read data from Excel sheet
Li2 = ex1.sheet_by_index(1)
Li3 = ex1.sheet_by_index(2)
Li4 = ex1.sheet_by_index(3)
Li5 = ex2.sheet_by_index(0)
Li6 = ex2.sheet_by_index(1)
Li7 = ex2.sheet_by_index(2)
x = np.array(Li1.col_values(0)) - 0.365 # potential to overpotential (V)
LiI1 = np.array(Li1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
LiI2 = np.array(Li2.col_values(1)) * 1000/0.0314159
LiI3 = np.array(Li3.col_values(1)) * 1000/0.0314159
LiI4 = np.array(Li4.col_values(1)) * 1000/0.0314159
LiI5 = np.array(Li5.col_values(1)) * 1000/0.0314159
LiI6 = np.array(Li6.col_values(1)) * 1000/0.0314159
LiI7 = np.array(Li7.col_values(1)) * 1000/0.0314159
LiI = np.array([LiI2, LiI3, LiI4, LiI5, LiI6, LiI7])
# CsOH
Cs1 = ex1.sheet_by_index(4) # read data from Excel sheet
Cs2 = ex1.sheet_by_index(5)
Cs3 = ex1.sheet_by_index(6)
Cs4 = ex1.sheet_by_index(7)
Cs5 = ex2.sheet_by_index(3)
Cs6 = ex2.sheet_by_index(4)
Cs7 = ex2.sheet_by_index(5)
CsI1 = np.array(Cs1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
CsI2 = np.array(Cs2.col_values(1)) * 1000/0.0314159
CsI3 = np.array(Cs3.col_values(1)) * 1000/0.0314159
CsI4 = np.array(Cs4.col_values(1)) * 1000/0.0314159
CsI5 = np.array(Cs5.col_values(1)) * 1000/0.0314159
CsI6 = np.array(Cs6.col_values(1)) * 1000/0.0314159
CsI7 = np.array(Cs7.col_values(1)) * 1000/0.0314159
CsI = np.array([CsI2, CsI3, CsI4, CsI5, CsI6, CsI7])
# NaOH
Na1 = ex3.sheet_by_index(0) # read data from Excel sheet
Na2 = ex3.sheet_by_index(1)
Na3 = ex3.sheet_by_index(2)
Na4 = ex3.sheet_by_index(3)
x = np.array(Na1.col_values(0)) - 0.365 # potential to overpotential (V)
NaI1 = np.array(Na1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
NaI2 = np.array(Na2.col_values(1)) * 1000/0.0314159
NaI3 = np.array(Na3.col_values(1)) * 1000/0.0314159
NaI4 = np.array(Na4.col_values(1)) * 1000/0.0314159
NaI = np.array([NaI2, NaI3, NaI4])
# KOH
K1 = ex3.sheet_by_index(4) # read data from Excel sheet
K2 = ex3.sheet_by_index(5)
K3 = ex3.sheet_by_index(6)
K4 = ex3.sheet_by_index(7)
KI1 = np.array(K1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
KI2 = np.array(K2.col_values(1)) * 1000/0.0314159
KI3 = np.array(K3.col_values(1)) * 1000/0.0314159
KI4 = np.array(K4.col_values(1)) * 1000/0.0314159
KI = np.array([KI2, KI3, KI4])
# Calculate average current density
avgLiI = (LiI2 + LiI3 + LiI4 + LiI5 + LiI6 + LiI7) / 6
avgCsI = (CsI2 + CsI3 + CsI4 + CsI5 + CsI6 + CsI7) / 6
avgNaI = (NaI2 + NaI3 + NaI4) / 3
avgKI = (KI2 + KI3 + KI4) / 3
# Calculate standard deviation of specified data points
nth = 80 # interval for calculating std. dev.
stdLi, stdCs, stdNa, stdK = [], [], [], []
for n in LiI.T[::-nth]:
stdLi.append(np.std(n))
stdLi = np.array(stdLi)
for n in CsI.T[::-nth]:
stdCs.append(np.std(n))
stdCs = np.array(stdCs)
for n in NaI.T[::-nth]:
stdNa.append(np.std(n))
stdNa = np.array(stdNa)
for n in KI.T[::-nth]:
stdK.append(np.std(n))
stdK = np.array(stdK)
xx = x[::-nth]
# Generate and format figure
plt.figure(figsize=(3, 4))
plt.plot(x, avgCsI, 'r', label='CsOH')
plt.errorbar(xx, avgCsI[::-nth], yerr=stdCs, lw=0, elinewidth=1, color='r')
plt.plot(x, avgKI, 'k', label='KOH') #plot voltage vs. avg. current density
plt.errorbar(xx, avgKI[::-nth], yerr=stdK, lw=0, elinewidth=1, color='k') # error bars
plt.plot(x, avgNaI, 'g', label='NaOH')
plt.errorbar(xx, avgNaI[::-nth], yerr=stdNa, lw=0, elinewidth=1, color='g')
plt.plot(x, avgLiI, 'b', label='LiOH')
plt.errorbar(xx, avgLiI[::-nth], yerr=stdLi, lw=0, elinewidth=1, color='b')
plt.legend(loc='upper left', fontsize='11') # legend
plt.xlabel('Overpotential (V)') # x-axis label
plt.ylabel('Current Density (mA/cm$^{2}$)') # y-axis label
plt.axis([0.2, 0.6, -0.1, 3]) # x,y axis values
plt.tight_layout()
plt.xticks([0.2, 0.3, 0.4, 0.5, 0.6], [0.2, 0.3, 0.4, 0.5, 0.6])
# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
plt.savefig('./images/figures-main/IvsV-Na-K-Li-Cs-pure.{0}'.format(ext), dpi=300)
plt.show()
# Generate I vs. V figure
# LSV: LiOH, NaOH, KOH, CsOH (Fe-saturated)
import numpy as np
import matplotlib.pyplot as plt
import xlrd
# Open I vs. V data file
ex1 = xlrd.open_workbook('./data/lsv-data/lsv-li-cs-iron-11-21.xlsx')
ex2 = xlrd.open_workbook('./data/lsv-data/lsv-na-k-iron-01-19.xlsx')
# LiOH
Li1 = ex1.sheet_by_index(0) # read data from Excel sheet
Li2 = ex1.sheet_by_index(1)
Li3 = ex1.sheet_by_index(2)
Li4 = ex1.sheet_by_index(3)
x = np.array(Li1.col_values(0)) - 0.365 # potential to overpotential (V)
LiI1 = np.array(Li1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
LiI2 = np.array(Li2.col_values(1)) * 1000/0.0314159
LiI3 = np.array(Li3.col_values(1)) * 1000/0.0314159
LiI4 = np.array(Li4.col_values(1)) * 1000/0.0314159
LiI = np.array([LiI1, LiI2, LiI3, LiI4])
# CsOH
Cs1 = ex1.sheet_by_index(4) # read data from Excel sheet
Cs2 = ex1.sheet_by_index(5)
Cs3 = ex1.sheet_by_index(6)
Cs4 = ex1.sheet_by_index(7)
CsI1 = np.array(Cs1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
CsI2 = np.array(Cs2.col_values(1)) * 1000/0.0314159
CsI3 = np.array(Cs3.col_values(1)) * 1000/0.0314159
CsI4 = np.array(Cs4.col_values(1)) * 1000/0.0314159
CsI = np.array([CsI1, CsI2, CsI3, CsI4])
# NaOH
Na1 = ex2.sheet_by_index(0) # read data from Excel sheet
Na2 = ex2.sheet_by_index(1)
Na3 = ex2.sheet_by_index(2)
Na4 = ex2.sheet_by_index(3)
x = np.array(Na1.col_values(0)) - 0.365 # potential to overpotential (V)
NaI1 = np.array(Na1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
NaI2 = np.array(Na2.col_values(1)) * 1000/0.0314159
NaI3 = np.array(Na3.col_values(1)) * 1000/0.0314159
NaI4 = np.array(Na4.col_values(1)) * 1000/0.0314159
NaI = np.array([NaI2, NaI3, NaI4])
# KOH
K1 = ex2.sheet_by_index(4) # read data from Excel sheet
K2 = ex2.sheet_by_index(5)
K3 = ex2.sheet_by_index(6)
K4 = ex2.sheet_by_index(7)
KI1 = np.array(K1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
KI2 = np.array(K2.col_values(1)) * 1000/0.0314159
KI3 = np.array(K3.col_values(1)) * 1000/0.0314159
KI4 = np.array(K4.col_values(1)) * 1000/0.0314159
KI = np.array([KI2, KI3, KI4])
# Calculate average current density
avgLiI = (LiI1 + LiI2 + LiI3 + LiI4) / 4
avgCsI = (CsI1 + CsI2 + CsI3 + CsI4) / 4
avgNaI = (NaI2 + NaI3 + NaI4) / 3
avgKI = (KI2 + KI3 + KI4) / 3
# Calculate standard deviation of specified data points
nth = 80 # interval for calculating std. dev.
stdLi, stdCs, stdNa, stdK = [], [], [], []
for n in LiI.T[::-nth]:
stdLi.append(np.std(n))
stdLi = np.array(stdLi)
for n in CsI.T[::-nth]:
stdCs.append(np.std(n))
stdCs = np.array(stdCs)
for n in NaI.T[::-nth]:
stdNa.append(np.std(n))
stdNa = np.array(stdNa)
for n in KI.T[::-nth]:
stdK.append(np.std(n))
stdK = np.array(stdK)
xx = x[::-nth]
# Generate and format figure
plt.figure(figsize=(3, 4))
plt.plot(x, avgKI, 'k', label='KOH') #plot voltage vs. avg. current density
plt.errorbar(xx, avgKI[::-nth], yerr=stdK, lw=0, elinewidth=1, color='k') # error bars
plt.plot(x, avgNaI, 'g', label='NaOH')
plt.errorbar(xx, avgNaI[::-nth], yerr=stdNa, lw=0, elinewidth=1, color='g')
plt.plot(x, avgCsI, 'r', label='CsOH')
plt.errorbar(xx, avgCsI[::-nth], yerr=stdCs, lw=0, elinewidth=1, color='r')
plt.plot(x, avgLiI, 'b', label='LiOH')
plt.errorbar(xx, avgLiI[::-nth], yerr=stdLi, lw=0, elinewidth=1, color='b')
plt.legend(loc='upper left', fontsize='11') # legend
plt.xlabel('Overpotential (V)') # x-axis label
plt.ylabel('Current Density (mA/cm$^{2}$)') # y-axis label
plt.axis([0.0, 0.6, -1, 30]) # x,y axis values
plt.tight_layout()
plt.xticks([0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6], [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6])
# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
plt.savefig('./images/figures-main/IvsV-Na-K-Li-Cs-iron.{0}'.format(ext), dpi=300)
plt.show()
# Generate I vs. V figure
# LSV during Raman spectroscopy: LiOH, CsOH (purified)
import numpy as np
import matplotlib.pyplot as plt
import xlrd
# Open I vs. V data file
ex1 = xlrd.open_workbook('./data/lsv-data/lsv-raman-li-cs-pure-10-31.xlsx')
# LiOH
Li1 = ex1.sheet_by_index(0) # read data from Excel sheet
Li2 = ex1.sheet_by_index(1)
Li3 = ex1.sheet_by_index(2)
Li4 = ex1.sheet_by_index(3)
x = np.array(Li1.col_values(0)) - 0.365 # potential to overpotential (V)
LiI1 = np.array(Li1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
LiI2 = np.array(Li2.col_values(1)) * 1000/0.0314159
LiI3 = np.array(Li3.col_values(1)) * 1000/0.0314159
LiI4 = np.array(Li4.col_values(1)) * 1000/0.0314159
LiI = np.array([LiI2, LiI3, LiI4])
# CsOH
Cs1 = ex1.sheet_by_index(4) # read data from Excel sheet
Cs2 = ex1.sheet_by_index(5)
Cs3 = ex1.sheet_by_index(6)
Cs4 = ex1.sheet_by_index(7)
#CsV1 = np.array(Cs1.col_values(0)) - 0.365 # potential to overpotential (V)
CsI1 = np.array(Cs1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
CsI2 = np.array(Cs2.col_values(1)) * 1000/0.0314159
CsI3 = np.array(Cs3.col_values(1)) * 1000/0.0314159
CsI4 = np.array(Cs4.col_values(1)) * 1000/0.0314159
CsI = np.array([CsI2, CsI3, CsI4])
# Calculate average current density
avgLiI = (LiI2 + LiI3 + LiI4) / 3
avgCsI = (CsI2 + CsI3 + CsI4) / 3
# Calculate standard deviation of specified data points
nth = 80 # interval for calculating std. dev.
stdLi, stdCs = [], []
for n in LiI.T[::-nth]:
stdLi.append(np.std(n))
stdLi = np.array(stdLi)
for n in CsI.T[::-nth]:
stdCs.append(np.std(n))
stdCs = np.array(stdCs)
xx = x[::-nth] # potentials where std. dev. calculated
# Generate and format figure
plt.figure(figsize=(3, 4))
plt.plot(x, avgCsI, 'r', label='CsOH') # plot voltage vs. avg. current density
plt.errorbar(xx, avgCsI[::-nth], yerr=stdCs, lw=0, elinewidth=1, color='r') # error bars
plt.plot(x, avgLiI, 'b', label='LiOH')
plt.errorbar(xx, avgLiI[::-nth], yerr=stdLi, lw=0, elinewidth=1, color='b')
plt.legend(loc='upper left', fontsize='11') # legend
plt.xlabel('Overpotential (V)') # x-axis label
plt.ylabel('Current Density (mA/cm$^{2}$)') # y-axis label
plt.axis([0.2, 0.6, -0.1, 8]) # x,y axis values
plt.tight_layout()
plt.xticks([0.2, 0.3, 0.4, 0.5, 0.6], [0.2, 0.3, 0.4, 0.5, 0.6])
# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
plt.savefig('./images/figures-supp-info/IvsV-Raman-Li-Cs-pure-10-31.{0}'.format(ext), dpi=300)
plt.show()
# Generate I vs. V figure
# LSV during Raman spectroscopy: LiOH, CsOH (Fe-saturated)
import numpy as np
import matplotlib.pyplot as plt
import xlrd
# Open I vs. V data file
ex1 = xlrd.open_workbook('./data/lsv-data/lsv-raman-li-cs-iron-11-19.xlsx')
# LiOH
Li1 = ex1.sheet_by_index(0) # read data from Excel sheet
Li2 = ex1.sheet_by_index(1)
Li3 = ex1.sheet_by_index(2)
Li4 = ex1.sheet_by_index(3)
x = np.array(Li1.col_values(0)) - 0.365 # potential to overpotential (V)
LiI1 = np.array(Li1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
LiI2 = np.array(Li2.col_values(1)) * 1000/0.0314159
LiI3 = np.array(Li3.col_values(1)) * 1000/0.0314159
LiI4 = np.array(Li4.col_values(1)) * 1000/0.0314159
LiI = np.array([LiI1, LiI3, LiI4])
# CsOH
Cs1 = ex1.sheet_by_index(4) # read data from Excel sheet
Cs2 = ex1.sheet_by_index(5)
Cs3 = ex1.sheet_by_index(6)
Cs4 = ex1.sheet_by_index(7)
CsI1 = np.array(Cs1.col_values(1)) * 1000/0.0314159 # current (A) to current density (mA/cm2)
CsI2 = np.array(Cs2.col_values(1)) * 1000/0.0314159
CsI3 = np.array(Cs3.col_values(1)) * 1000/0.0314159
CsI4 = np.array(Cs4.col_values(1)) * 1000/0.0314159
CsI = np.array([CsI1, CsI2, CsI3, CsI4])
# Calculate average current density
avgLiI = (LiI1 + LiI3 + LiI4) / 3
avgCsI = (LiI1 + CsI2 + CsI3 + CsI4) / 4
# Calculate standard deviation of specified data points
nth = 80 # interval for calculating std. dev.
stdLi, stdCs = [], []
for n in LiI.T[::-nth]:
stdLi.append(np.std(n))
stdLi = np.array(stdLi)
for n in CsI.T[::-nth]:
stdCs.append(np.std(n))
stdCs = np.array(stdCs)
xx = x[::-nth]
# Generate and format figure
plt.figure(figsize=(3, 4))
plt.plot(x, avgCsI, 'r', label='CsOH') # plot voltage vs. avg. current density
plt.errorbar(xx, avgCsI[::-nth], yerr=stdCs, lw=0, elinewidth=1, color='r') # error bars
plt.plot(x, avgLiI, 'b', label='LiOH')
plt.errorbar(xx, avgLiI[::-nth], yerr=stdLi, lw=0, elinewidth=1, color='b')
plt.legend(loc='upper left', fontsize='11') # legend
plt.xlabel('Overpotential (V)') # x-axis label
plt.ylabel('Current Density (mA/cm$^{2}$)') # y-axis label
plt.axis([0.0, 0.6, -1, 16]) # x,y axis values
plt.tight_layout()
plt.xticks([0.0, 0.2, 0.4, 0.6], [0.0, 0.2, 0.4, 0.6])
# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
plt.savefig('./images/figures-supp-info/IvsV-Raman-Li-Cs-iron-11-19.{0}'.format(ext), dpi=300)
plt.show()
Below is a Python function for fitting Gaussian distributions to Raman spectra of NiOOH thin films. This function was called in other Python code blocks within this Supporting Information file. See section #sec-fitting.
import numpy as np
import matplotlib.pyplot as plt
from scipy.special import erf
from scipy.optimize import curve_fit
import os
def dgaus2p(filename,
cntr=(470.0, 560.0),
amp1=(20.0, 20.0),
amp2=(20.0, 20.0),
std1=(10.0, 5.0),
std2=(10.0, 5.0),
datarange=None,
output=False,
step=4):
"""Fitting Raman spectra data using the two Gaussian functions
This function fits two double Gaussian fits for Raman peaks
with overlapping tails.
Parameters
----------
filename : str
The name of the file containing the data to be analyzed. Data is
read in using the numpy.loadtxt function. Data should be separated
into two rows, the first being the wavenumber, the second being
signal intensity.
cntr : list, optional
Initial starting point for the center of each peak in wavenumbers.
A float in the list for each peak.
amp1 : list, optional
Initial starting point for the amplitude of the frist Gaussian.
A float in the list for each peak.
amp2 : list, optional
Initial starting point for the amplitude of the second Gaussian.
A float in the list for each peak.
std1 : list, optional
Initial starting point for the standard deviation of the frist
Gaussian. A float in the list for each peak.
std2 : list, optional
Initial starting point for the standard deviation of the second
Gaussian. A float in the list for each peak.
datarange : list, optional
This is a list of two floats specifying the range of wavenumbers
you want to analyze from the data file. Takes the entire range of
data by default.
output : bool , optional
Whether or not the function returns an output .fit file.
step : 1, 2, 3, or 4 : optional
Specifies which step of the fitting process the user is working on:
step = 1: Fittings the baseline (figure produced)
step = 2: Choosing initial guess for peaks (figure produced)
step = 3: Evaluate the fit (figure produced)
step = 4: View and save the final figure (no figure)
Returns
-------
results : array
An array of: [center peak 1, center peak 2,
height peak 1, height peak 2,
area peak 1, area peak 2,
baseline slope, baseline intercept]
fiterror : array
An array of the fitting errors for: [center peak 1, center peak 2,
height peak 1, height peak 2]
popt : array
An array of the optimized fitting parameters as output from the
scipy.optimize.curve_fit function:
Peak # : 1 2
[cntr[0], cntr[1], # Peak center
amp1[0], amp1[1], # Amplitude of Gaussian 1
amp2[0], amp2[1], # Amplitude of Gaussian 2
std1[0], std1[1], # Standard deviation of Gaussian 1
std2[0], std2[1]) # Standard deviation of Gaussian 2
parguess : array
An array of the initial fitting parameters:
Peak # : 1 2
[cntr[0], cntr[1], # Peak center
amp1[0], amp1[1], # Amplitude of Gaussian 1
amp2[0], amp2[1], # Amplitude of Gaussian 2
std1[0], std1[1], # Standard deviation of Gaussian 1
std2[0], std2[1]) # Standard deviation of Gaussian 2
See Also
--------
scipy.special.erf
scipy.optimize.curve_fit
"""
# This unpacks the data from the text file.
S, I = np.loadtxt(filename, usecols=(0, 1), unpack=True)
if datarange == None:
datarange = [min(S), max(S)]
# Define the low and high regions for baseline sampling
dx = 80.
low = datarange[0] + dx
high = datarange[1] - dx
# Seperate the data points to be used for fitting the baseline
xbl = np.append(S[(S < low)], S[(S > high)])
ybl = np.append(I[(S < low)], I[(S > high)])
# Fits a line to the base line points
blpars = np.polyfit(xbl, ybl, 1)
blfit = np.poly1d(blpars)
if step != 1 and step != 2 and step != 3 and step != 4:
print 'Set step = 1, 2, 3, or 4 to continue'
# Step 1: Choose low and high values for a satisfactory baseline
if step == 1:
plt.figure()
plt.plot(S, I, label='data')
plt.plot(S, blfit(S), 'r-', lw=2, label='base line')
plt.xlabel('Raman shift (cm$^{-1}$)')
plt.ylabel('Intensity (counts)')
plt.legend(loc='best')
plt.show()
print 'When you are satisfied with the fit of the base line, set step = 2'
exit()
# Subtracts the baseline from the intensities
I -= blfit(S)
# Gaussians will only be fit the the data not used for the baseline
nS = S[(S > low) & (S < high)]
nI = I[(S > low) & (S < high)]
# These are functions which define the types of fit which you could implement
# Currently, the code only utilizes Gaussians
# ----------------------------------------------------------------------
def gaussian(x, pars):
A = pars[0] # amplitude
mu = pars[1] # means
sig = pars[2] # std dev
return A * np.exp((-(x - mu)**2.) / ((2*sig)**2.))
def sum_gaussian(x, *p):
g1 = gaussian(x, [p[2], p[0], p[6]])
g2 = gaussian(x, [p[3], p[0], p[7]])
g3 = gaussian(x, [p[4], p[1], p[8]])
g4 = gaussian(x, [p[5], p[1], p[9]])
return g1 + g2 + g3 + g4
# ----------------------------------------------------------------------
# These are initial guesses of the tuning parameters for the Gaussian fits.
# Peak # : 1 2
parguess = (cntr[0], cntr[1], # Peak center
amp1[0], amp1[1], # Amplitude of Gaussian 1
amp2[0], amp2[1], # Amplitude of Gaussian 2
std1[0], std1[1], # Standard deviation of Gaussian 1
std2[0], std2[1]) # Standard deviation of Gaussian 2
# Step 2: Fitting the curves to the data
if step == 2:
plt.figure()
plt.plot(nS, nI, 'b-', label='Data')
plt.plot(S, sum_gaussian(S, *parguess), 'g--', lw=3, label='Initial guess')
plt.xlim(datarange[0], datarange[1])
plt.ylim(0, max(nI) + 2)
plt.xlabel('Raman shift (cm$^{-1}$)')
plt.ylabel('Intensity (counts)')
plt.legend(loc='best')
plt.show()
print 'Once the initial guess looks reasonable, set step = 3'
exit()
# This is a multivaraible curve fitting program which attempts to optimize the fitting parameters
popt, pcov = curve_fit(sum_gaussian, S, I, parguess)
peak1 = gaussian(S, [popt[2], popt[0], popt[6]]) + gaussian(S, [popt[3], popt[0], popt[7]])
peak2 = gaussian(S, [popt[4], popt[1], popt[8]]) + gaussian(S, [popt[5], popt[1], popt[9]])
# Step 3: Evaluate the fit
if step == 3:
plt.figure()
plt.plot(nS, nI, 'b-', label='Data')
plt.plot(S, sum_gaussian(S, *popt), 'r-', lw=3, label='Final Fit')
plt.plot(S, peak1, 'm-', lw=3, label='Fit for peak 1')
plt.plot(S, gaussian(S, [popt[4], popt[1], popt[8]]) + gaussian(S, [popt[5], popt[1], popt[9]]),
'c-', lw=3, label='Fit for peak 2')
plt.xlim(low, high)
plt.ylim(0, max(nI) + 2)
plt.xlabel('Raman shift (cm$^{-1}$)')
plt.ylabel('Intensity (counts)')
plt.legend(loc='best')
plt.show()
print 'When you are satisfied with the peak fit, set step = 3'
print 'else, return to step 2 and choose new fitting parameters'
exit()
# Step 4: A summary of the resulting fit
if step == 4:
ypeak1 = popt[2] + popt[3] + blfit(popt[0])
ypeak2 = popt[4] + popt[5] + blfit(popt[1])
area1 = -np.trapz(S, peak1)
area2 = -np.trapz(S, peak2)
savefile = filename.rstrip('txt')
perr = np.sqrt(np.diag(pcov))
pk1err = np.sqrt(perr[2]**2. + perr[3]**2 + 2 * pcov[2][3])
pk2err = np.sqrt(perr[4]**2. + perr[5]**2 + 2 * pcov[4][5])
results = np.array([popt[0], popt[1],
ypeak1, ypeak2,
area1, area2,
blpars[0], blpars[1]])
fiterror = np.array([perr[0], perr[1],
pk1err, pk2err])
if output:
savefile = savefile + 'fit'
f = 'Initial guess parameters:\n'
f += '=========================\n'
f += ' Peak 1, Peak 2\n'
f += 'Peak center = {0:1.1f}, {1:1.2f}\n'.format(cntr[0], cntr[1])
f += 'Amplitude fit 1 = {0:1.1f}, {1:1.2f}\n'.format(amp1[0], amp1[1])
f += 'Amplitude fit 2 = {0:1.1f}, {1:1.2f}\n'.format(amp2[0], amp2[1])
f += 'Standard dev. fit 1 = {0:1.1f}, {1:1.1f}\n'.format(std1[0], std1[1])
f += 'Standard dev. fit 2 = {0:1.1f}, {1:1.1f}\n'.format(std2[0], std2[1])
f += '\nBaseline parameters:\n'
f += '===================\n'
f += 'Slope = {0:1.2f}\n'.format(blpars[0])
f += 'Intercept = {0:1.2f}\n'.format(blpars[1])
f += '\nFitted parameters:\n'
f += '==================\n'
f += ' Peak 1, Peak 2\n'
f += 'Peak center = {0:1.2f}, {1:1.2f}\n'.format(popt[0], popt[1])
f += 'Amplitude fit 1 = {0:1.2f}, {1:1.2f}\n'.format(popt[2], popt[3])
f += 'Amplitude fit 2 = {0:1.2f}, {1:1.2f}\n'.format(popt[4], popt[5])
f += 'Standard dev. fit 1 = {0:1.2f}, {1:1.2f}\n'.format(popt[6], popt[7])
f += 'Standard dev. fit 2 = {0:1.2f}, {1:1.2f}\n'.format(popt[8], popt[9])
f += '\nCalculation output:\n'
f += '======================\n'
f += 'Mean peak 1 = {0:1.1f} $\pm$ {1:1.2f}\n'.format(popt[0], perr[0])
f += 'Mean peak 2 = {0:1.1f} $\pm$ {1:1.2f}\n'.format(popt[1], perr[1])
f += 'Height peak 1 = {0:1.1f} $\pm$ {1:1.2f}\n'.format(ypeak1, pk1err)
f += 'Height peak 2 = {0:1.1f} $\pm$ {1:1.2f}\n'.format(ypeak2, pk2err)
f += 'Area peak 1 = {0:1.1f}\n'.format(area1)
f += 'Area peak 2 = {0:1.1f}'.format(area2)
fl = open(savefile, 'w')
fl.write(f)
fl.close()
return results, fiterror, popt, parguess
import numpy as np
import matplotlib.pyplot as plt
from ramantools import dgaus2p
# Put the name of your data files here
data_file_name = ['./data/raman-spectra-for-figs/purified/Ni-Li-pure-3-600mV.txt',
'./data/raman-spectra-for-figs/purified/Ni-Li-pure-3-700mV.txt',
'./data/raman-spectra-for-figs/purified/Ni-Li-pure-3-800mV.txt',
'./data/raman-spectra-for-figs/purified/Ni-Cs-pure-1-600mV.txt',
'./data/raman-spectra-for-figs/purified/Ni-Cs-pure-1-700mV.txt',
'./data/raman-spectra-for-figs/purified/Ni-Cs-pure-2-800mV.txt']
def Gaussian(x, pars):
A = pars[0] # amplitude
mu = pars[1] # means
sig = pars[2] # std dev
return A * np.exp((-(x - mu)**2.) / ((2*sig)**2.))
def sum_gaussian(x, pars):
p = pars
g1 = Gaussian(x, [p[2], p[0], p[6]])
g2 = Gaussian(x, [p[3], p[0], p[7]])
g3 = Gaussian(x, [p[4], p[1], p[8]])
g4 = Gaussian(x, [p[5], p[1], p[9]])
return g1 + g2 + g3 + g4
# Line will begin at offset from 0.
offset = [0, 30, 60,
100, 130, 160] # Adjust y-position of Raman spectra
labels = ['240 mV', '340 mV', '440 mV',
'240 mV', '340 mV', '440 mV']
cl = ['b', 'b', 'b',
'k', 'k', 'k']
plt.figure(figsize=(3, 5))
for i, f in enumerate(data_file_name):
# get fitting parameters
R, E, P, ip = dgaus2p(f)
# get Raman data
S, I = np.loadtxt(f, usecols=(0, 1), unpack=True)
# reproduce fit to raw data
bl = np.poly1d([R[-2], R[-1]])
F = sum_gaussian(S, list(P)) + bl(S)
# plot the fit and the data
plt.plot(S, I + offset[i], color=cl[i])
plt.plot(S, F + offset[i], 'r-', lw=2)
# Labels for curve
# (x-position, y-position, alignment, alignment)
plt.text(649, I[-1] + offset[i] + 15,
labels[i],
horizontalalignment='right',
verticalalignment='bottom',
fontsize='10')
# Add guild lines to peak center (only for one fit)
if i == 0:
ctr1, ctr2 = P[0], P[1] # cm^-1
plt.plot([ctr1, ctr1], [0, 300], 'k-')
plt.plot([ctr2, ctr2], [0, 300], 'k-')
# Remove tick marks from y-axis
plt.tick_params(axis='y',
which='both',
left='off',
right='off',
labelleft='off')
plt.xlim(400, 650)
plt.ylim(0, 230)
plt.xlabel('Raman shift (cm$^{-1}$)')
plt.ylabel('Intensity (a.u.)')
plt.tight_layout()
# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
plt.savefig('./images/figures-main/raman-combined-pure-10-31-14.{0}'.format(ext), dpi=300)
plt.show()
# Generate figures of Raman spectra
# Ni(OH)2
import matplotlib.pyplot as plt
import xlrd
# open raman spectra data file
ex1 = xlrd.open_workbook('./data/raman-spectra-for-figs/NiOH2-Raman-spectra.xlsx')
# Raman shift vs. Intensity
Li_pure = ex1.sheet_by_index(0) # read data from Excel sheet
Cs_pure = ex1.sheet_by_index(1)
Li_iron = ex1.sheet_by_index(2)
Cs_iron = ex1.sheet_by_index(3)
# Purified electrolyte
Li_rs_pure = Li_pure.col_values(0) # Raman shift
Li_int_pure = Li_pure.col_values(1) # intensity (a.u.)
Cs_rs_pure = Cs_pure.col_values(0) # Raman shift
Cs_int_pure = Cs_pure.col_values(1) # intensity (a.u.)
# Fe-saturated electrolyte
Li_rs_iron = Li_iron.col_values(0) # Raman shift
Li_int_iron = Li_iron.col_values(1) # intensity (a.u.)
Cs_rs_iron = Cs_iron.col_values(0) # Raman shift
Cs_int_iron = Cs_iron.col_values(1) # intensity (a.u.)
# Plotting the above lists will yield ugly figures, since there are so many data points.
# Need to snip out enough useful data.
# Empty lists for data modifications
Li_rs_pure_m = []
Li_int_pure_m = []
Cs_rs_pure_m = []
Cs_int_pure_m = []
Li_rs_iron_m = []
Li_int_iron_m = []
Cs_rs_iron_m = []
Cs_int_iron_m = []
# Snip out some raw data before plotting
snip = range(0, len(Li_rs_pure), 5) # all lists in code have same length
for i in snip:
Li_rs_pure_m.append(Li_rs_pure[i]) # append useful data to new list
Li_int_pure_m.append(Li_int_pure[i] - 5) # append and shift spectra
Cs_rs_pure_m.append(Cs_rs_pure[i])
Cs_int_pure_m.append(Cs_int_pure[i]+6)
Li_rs_iron_m.append(Li_rs_iron[i])
Li_int_iron_m.append(Li_int_iron[i]+ 10)
Cs_rs_iron_m.append(Cs_rs_iron[i])
Cs_int_iron_m.append(Cs_int_iron[i] + 35)
# Create and format figure
plt.figure(figsize=(3, 4))
plt.plot(Li_rs_pure_m, Li_int_pure_m, 'b', label = 'LiOH, purified') # LiOH, purified
plt.plot(Cs_rs_pure_m, Cs_int_pure_m, 'r', label = 'CsOH, purified') # CsOH, purified
plt.plot(Li_rs_iron_m, Li_int_iron_m, 'g', label = 'LiOH, Fe saturated') # LiOH, Fe saturated
plt.plot(Cs_rs_iron_m, Cs_int_iron_m, 'k', label = 'CsOH, Fe saturated') # CsOH, Fe saturated
# Spectra labels
# (x-position, y-position, label, alignment, alignment)
plt.text(540, 13, 'LiOH, purified', horizontalalignment='left', verticalalignment='bottom', fontsize='10')
plt.text(540, 30, 'CsOH, purified', horizontalalignment='left', verticalalignment='bottom', fontsize='10')
plt.text(540, 51, 'LiOH, Fe sat.', horizontalalignment='left', verticalalignment='bottom', fontsize='10')
plt.text(540, 69, 'CsOH, Fe sat.', horizontalalignment='left', verticalalignment='bottom', fontsize='10')
# Make y-axis text invisible
frame = plt.gca()
frame.axes.get_yaxis().set_ticks([])
plt.xlabel('Raman shift cm$^{-1}$')
plt.ylabel('Intensity (a.u.)')
plt.axis([250, 750, 0, 80])
plt.tight_layout()
# Save image with various extentions
for ext in ['eps', 'pdf', 'png']:
plt.savefig('./images/figures-supp-info/raman-nioh2-pure-iron.{0}'.format(ext), dpi=300)
plt.show()