From e2d013bed4242ff8728de56d01b9e3eb784d3e24 Mon Sep 17 00:00:00 2001 From: wbessler Date: Mon, 6 May 2019 10:44:00 +0200 Subject: [PATCH 1/4] Improved lithium-ion battery cti file and Matlab example Extended and clarified comments, corrected density data, improved functionality --- data/inputs/lithium_ion_battery.cti | 259 +++++++++++++++++---------- samples/matlab/lithium_ion_battery.m | 53 +++--- 2 files changed, 190 insertions(+), 122 deletions(-) diff --git a/data/inputs/lithium_ion_battery.cti b/data/inputs/lithium_ion_battery.cti index b02c152ec4..748e02d150 100644 --- a/data/inputs/lithium_ion_battery.cti +++ b/data/inputs/lithium_ion_battery.cti @@ -1,21 +1,30 @@ -#===================================================================================== +#============================================================================== # Cantera input file for an LCO/graphite lithium-ion battery +# +# This file includes a full set of thermodynamic and kinetic parameters of a +# lithium-ion battery, in particular: +# - Active materials: LiCoO2 (LCO) and LiC6 (graphite) +# - Organic electrolyte: EC/PC with 1M LiPF6 +# - Interfaces: LCO/electrolyte and LiC6/electrolyte +# - Charge-transfer reactions at the two interfaces +# +# A MATLAB example using this file for simulating a discharge curve is +# samples/matlab/lithium_ion_battery.m +# # Reference: # M. Mayur, S. DeCaluwe, B. L. Kee, W. G. Bessler, "Modeling # thermodynamics and kinetics of intercalation phases for lithium-ion -# batteries in Cantera", Computer Physics Communications -#===================================================================================== +# batteries in Cantera", under review at Electrochimica Acta. +#============================================================================== - -#===================================================================================== +#============================================================================== # Bulk phases -#===================================================================================== - -#------------------------------------------------------------------ +#============================================================================== +#------------------------------------------------------------------------------ # Graphite (anode) -# Thermodynamic data based on half-cell measurements by K. Kumaresan et al., J. Electrochem. Soc. 155, A164-A171 (2008) -# Density: 5031.67 kg/m3 - used to calculate species molar volume as molecular weight (MW)/density -#------------------------------------------------------------------ +# Thermodynamic data based on half-cell measurements by K. Kumaresan et al., +# J. Electrochem. Soc. 155, A164-A171 (2008) +#------------------------------------------------------------------------------ BinarySolutionTabulatedThermo( name = "anode", elements = "Li C", @@ -48,26 +57,11 @@ BinarySolutionTabulatedThermo( 1.92885E+01, 1.92876E+01, 1.92837E+01, 1.92769E+01, 1.92850E+01, 1.93100E+01, 1.93514E+01], "J/mol/K"))) -# Lithium intercalated in graphite, MW: 79.0070 g/mol -species( - name = "Li[anode]", - atoms = "Li:1 C:6", - thermo = const_cp(h0 = (0, 'kJ/mol'), s0 = (0.0, 'J/mol/K')), # these are dummy entries because the values are taken from the table - standardState = constantIncompressible(molarVolume = (79.0070/5.0317, 'cm3/gmol'))) - -# Vacancy in graphite, MW: 72.0660 g/mol. Note this species includes the carbon host matrix. -species( - name = "V[anode]", - atoms = "C:6", - thermo = const_cp(h0 = (0.0, 'kJ/mol'), s0 = (0.0, 'J/mol/K')), # values are set to 0 because this is the reference species for this phase - standardState = constantIncompressible(molarVolume = (72.0660/5.0317, 'cm3/gmol'))) - - -#------------------------------------------------------------------ +#------------------------------------------------------------------------------ # Lithium cobalt oxide (cathode) -# Thermodynamic data based on half-cell measurements by K. Kumaresan et al., J. Electrochem. Soc. 155, A164-A171 (2008) -# Density: 2292 kg/m3 - used to calculate species molar volume as molecular weight (MW)/density -#------------------------------------------------------------------ +# Thermodynamic data based on half-cell measurements by K. Kumaresan et al., +# J. Electrochem. Soc. 155, A164-A171 (2008) +#------------------------------------------------------------------------------ BinarySolutionTabulatedThermo( name = "cathode", elements = "Li Co O", @@ -100,24 +94,21 @@ BinarySolutionTabulatedThermo( -5.39817E+01, -5.45468E+01, -5.48125E+01, -5.51520E+01, -5.54526E+01, -5.52961E+01, -5.50219E+01, -5.46653E+01, -5.42305E+01], "J/mol/K"))) -# Lithium cobalt oxide, MW: 97.8730 g/mol -species( - name = "Li[cathode]", - atoms = "Li:1 Co:1 O:2", - thermo = const_cp(h0 = (0.0, 'kJ/mol'), s0 = (0.0, 'J/mol/K')), # these are dummy entries because the values are taken from the table - standardState = constantIncompressible(molarVolume = (97.8730/2.292, 'cm3/gmol'))) - -# Vacancy in the cobalt oxide, MW: 90.9320 g/mol. Note this species includes the host matrix. -species( - name = "V[cathode]", - atoms = "Co:1 O:2", - thermo = const_cp(h0 = (0.0, 'kJ/mol'), s0 = (0.0, 'J/mol/K')), # values are set to 0 because this is the reference species for this phase - standardState = constantIncompressible(molarVolume = (90.9320/2.292, 'cm3/gmol'))) - +#------------------------------------------------------------------------------ +# Carbonate based electrolyte +# Solvent: Ethylene carbonate:Propylene carbonate (1:1 v/v) +# Salt: 1M LiPF6 +#------------------------------------------------------------------------------ +IdealSolidSolution( + name = "electrolyte", + elements = "Li P F C H O E", + species = "C3H4O3[elyt] C4H6O3[elyt] Li+[elyt] PF6-[elyt]", + initial_state = state(mole_fractions = 'C3H4O3[elyt]:0.47901 C4H6O3[elyt]:0.37563 Li+[elyt]:0.07268 PF6-[elyt]:0.07268'), + standard_concentration = "unity") -#------------------------------------------------------------------ +#------------------------------------------------------------------------------ # Electron conductor -#------------------------------------------------------------------ +#------------------------------------------------------------------------------ metal( name = "electron", elements = "E", @@ -125,90 +116,172 @@ metal( density = (1.0, 'kg/m3'), # dummy entry initial_state = state( mole_fractions = "electron:1.0")) -# Electron, MW: 0.000545 g/mol + +#============================================================================== +# Species +#============================================================================== +#------------------------------------------------------------------------------ +# Lithium intercalated in graphite, MW: 79.0070 g/mol. +# Note this species includes the carbon host matrix. +# Molar enthalpy and entropy are set to 0 because the values given in the +# BinarySolidSolutionTabulatedThermo class are used. +# Density of graphite: 2270 kg/m3 (W. M. Haynes et al, CRC Handbook of Chemistry +# and Physics, 94th edition, CRC press, Boca Raton, London, New York, 2013) +# (used to calculate species molar volume as molecular weight (MW)/density). +#------------------------------------------------------------------------------ species( - name = "electron", - atoms = "E:1", - thermo = const_cp(h0 = (0.0, 'kJ/mol'), s0 = (0.0, 'J/mol/K'))) # dummy entries because chemical potential is set to zero for a "metal" phase + name = "Li[anode]", + atoms = "Li:1 C:6", + thermo = const_cp(h0 = (0.0, 'kJ/mol'), s0 = (0.0, 'J/mol/K')), + standardState = constantIncompressible(molarVolume = (79.0070/2.270, 'cm3/mol'))) +#------------------------------------------------------------------------------ +# Vacancy in graphite, MW: 72.0660 g/mol. +# Note this species includes the carbon host matrix. +# Molar enthalpy and entropy are set to 0 because this is the reference species +# for this phase. +# Density of graphite: 2270 kg/m3 (W. M. Haynes et al, CRC Handbook of Chemistry +# and Physics, 94th edition, CRC press, Boca Raton, London, New York, 2013) +# (used to calculate species molar volume as molecular weight (MW)/density). +#------------------------------------------------------------------------------ +species( + name = "V[anode]", + atoms = "C:6", + thermo = const_cp(h0 = (0.0, 'kJ/mol'), s0 = (0.0, 'J/mol/K')), + standardState = constantIncompressible(molarVolume = (72.0660/2.270, 'cm3/mol'))) +#------------------------------------------------------------------------------ +# Lithium cobalt oxide, MW: 97.8730 g/mol. +# Note this species includes the cobalt oxide host matrix. +# Molar enthalpy and entropy are set to 0 because the values given in the +# BinarySolidSolutionTabulatedThermo class are used. +# Density of LCO: 4790 kg/m3 (E.J. Cheng et al., J. Asian Ceramic Soc. 5, 113, +# 2017) (used to calculate species molar volume as molecular weight/density). +#------------------------------------------------------------------------------ +species( + name = "Li[cathode]", + atoms = "Li:1 Co:1 O:2", + thermo = const_cp(h0 = (0.0, 'kJ/mol'), s0 = (0.0, 'J/mol/K')), + standardState = constantIncompressible(molarVolume = (97.8730/4.790, 'cm3/mol'))) -#-------------------------------------------------------------------- -# Carbonate based electrolyte -# Solvent: Ethylene carbonate:Propylene carbonate (1:1 v/v) -# Salt: 1M LiPF6 -# Density: 1260.0 kg/m3 - used to calculate species molar volume as molecular weight (MW)/density -#-------------------------------------------------------------------- -IdealSolidSolution( - name = "electrolyte", - elements = "Li P F C H O E", - species = "C3H4O3[elyt] C4H6O3[elyt] Li+[elyt] PF6-[elyt]", - initial_state = state(pressure = OneAtm, mole_fractions = 'C3H4O3[elyt]:0.47901 C4H6O3[elyt]:0.37563 Li+[elyt]:0.07268 PF6-[elyt]:0.07268'), - standard_concentration = "unity") +#------------------------------------------------------------------------------ +# Vacancy in the cobalt oxide, MW: 90.9320 g/mol. +# Note this species includes the cobalt oxide host matrix. +# Molar enthalpy and entropy are set to 0 because this is the reference species +# for this phase. +# Density of LCO: 4790 kg/m3 (E.J. Cheng et al., J. Asian Ceramic Soc. 5, 113, +# 2017) (used to calculate species molar volume as molecular weight/density). +#------------------------------------------------------------------------------ +species( + name = "V[cathode]", + atoms = "Co:1 O:2", + thermo = const_cp(h0 = (0.0, 'kJ/mol'), s0 = (0.0, 'J/mol/K')), + standardState = constantIncompressible(molarVolume = (90.9320/4.790, 'cm3/mol'))) +#------------------------------------------------------------------------------ # Ethylene carbonate, MW: 88.0630 g/mol +# Density of electrolyte: 1260 kg/m3 (used to calculate species molar volume +# as molecular weight (MW)/density) +# Molar enthalpy and entropy set to zero (dummy entries as this species does +# not participate in chemical reactions) +#------------------------------------------------------------------------------ species( name = "C3H4O3[elyt]", atoms = "C:3 H:4 O:3", - thermo = const_cp(h0 =(0.0, 'J/mol'), s0 = (0.0, 'J/mol/K')), # Dummy entries as this species does not participate in chemical reactions - standardState = constantIncompressible(molarVolume = (88.0630/1.260, 'cm3/gmol'))) + thermo = const_cp(h0 =(0.0, 'J/mol'), s0 = (0.0, 'J/mol/K')), + standardState = constantIncompressible(molarVolume = (88.0630/1.260, 'cm3/mol'))) +#------------------------------------------------------------------------------ # Propylene carbonate, MW: 102.0898 g/mol +# Density of electrolyte: 1260.0 kg/m3 (used to calculate species molar volume +# as molecular weight (MW)/density) +# Molar enthalpy and entropy set to zero (dummy entries as this species does +# not participate in chemical reactions) +#------------------------------------------------------------------------------ species( name = "C4H6O3[elyt]", atoms = "C:4 H:6 O:3", - thermo = const_cp(h0 =(0.0, 'J/mol'), s0 = (0.0, 'J/mol/K')), # Dummy entries as this species does not participate in chemical reactions - standardState = constantIncompressible(molarVolume = (102.0898/1.260, 'cm3/gmol'))) + thermo = const_cp(h0 =(0.0, 'J/mol'), s0 = (0.0, 'J/mol/K')), + standardState = constantIncompressible(molarVolume = (102.0898/1.260, 'cm3/mol'))) +#------------------------------------------------------------------------------ # Lithium ion, MW: 6.940455 g/mol +# Density of electrolyte: 1260.0 kg/m3 (used to calculate species molar volume +# as molecular weight (MW)/density) +# Molar enthalpy and entropy taken from Li+(aq) from P. Atkins "Physical +# Chemistry", Wiley-VCH (2006) +#------------------------------------------------------------------------------ species( name = "Li+[elyt]", atoms = "Li:1 E:-1", - thermo = const_cp(h0 = (-278.49, 'kJ/mol'), s0 = (13.4, 'J/mol/K')), # Li+(aq) from P. Atkins "Physical Chemistry", Wiley-VCH (2006) - standardState = constantIncompressible(molarVolume = (6.940455/1.260, 'cm3/gmol'))) + thermo = const_cp(h0 = (-278.49, 'kJ/mol'), s0 = (13.4, 'J/mol/K')), + standardState = constantIncompressible(molarVolume = (6.940455/1.260, 'cm3/mol'))) +#------------------------------------------------------------------------------ # Hexafluorophosphate ion, MW: 144.964745 g/mol +# Density of electrolyte: 1260.0 kg/m3 (used to calculate species molar volume +# as molecular weight (MW)/density) +# Molar enthalpy and entropy set to zero (dummy entries as this species does +# not participate in chemical reactions) +#------------------------------------------------------------------------------ species( name = "PF6-[elyt]", atoms = "P:1 F:6 E:1", - thermo = const_cp(h0 = (0.0, 'J/mol'), s0 = (0.0, 'J/mol/K')), # Dummy entries as this species does not participate in chemical reactions - standardState = constantIncompressible(molarVolume = (144.964745/1.260, 'cm3/gmol'))) + thermo = const_cp(h0 = (0.0, 'J/mol'), s0 = (0.0, 'J/mol/K')), + standardState = constantIncompressible(molarVolume = (144.964745/1.260, 'cm3/mol'))) +#------------------------------------------------------------------------------ +# Electron, MW: 0.000545 g/mol +# Molar enthalpy and entropy set to zero (dummy entries because chemical +# potential is set to zero for a "metal" phase) +#------------------------------------------------------------------------------ +species( + name = "electron", + atoms = "E:1", + thermo = const_cp(h0 = (0.0, 'kJ/mol'), s0 = (0.0, 'J/mol/K'))) +#------------------------------------------------------------------------------ +# Dummy species (needed for defining the interfaces) +#------------------------------------------------------------------------------ +species( + name = "(dummy)", + atoms = "", + thermo = const_cp(h0 = (0.0, 'kJ/mol'), s0 = (0.0, 'J/mol/K'))) -#===================================================================================== -# Interfaces for electrochemical reactions -#===================================================================================== -#-------------------------------------------------------------------- -# Anode reaction -#-------------------------------------------------------------------- +#============================================================================== +# Interfaces for electrochemical reactions +#============================================================================== +#------------------------------------------------------------------------------ +# Graphite/electrolyte interface +# Species and site density are dummy entries (as we do not consider surface- +# adsorbed species) +#------------------------------------------------------------------------------ ideal_interface( name = "edge_anode_electrolyte", phases = "anode electron electrolyte", reactions = "anode_*", - elements = "Li E C", - species = "(dummy)", # dummy entry for global kinetics - site_density = (1.0e-2, 'mol/cm2')) # dummy entry for global kinetics - -edge_reaction("Li[anode] <=> Li+[elyt] + V[anode] + electron", [4, 0.0, (0, 'kJ/mol')], rate_coeff_type = "exchangecurrentdensity", beta = 0.5,id="anode_reaction") + species = "(dummy)", + site_density = (1.0e-2, 'mol/cm2')) - -#-------------------------------------------------------------------- -# Cathode reaction -#-------------------------------------------------------------------- +#------------------------------------------------------------------------------ +# LCO/electrolyte interface +# Species and site density are dummy entries (as we do not consider surface- +# adsorbed species) +#------------------------------------------------------------------------------ ideal_interface( name = "edge_cathode_electrolyte", phases = "cathode electron electrolyte", reactions = "cathode_*", - elements = "Li E Co O", - species = "(dummy)", # dummy entry for global kinetics - site_density = (1.0e-2, 'mol/cm2')) # dummy entry for global kinetics + species = "(dummy)", + site_density = (1.0e-2, 'mol/cm2')) + +#============================================================================== +# Electrochemical reactions +#============================================================================== + +# Use Butler-Volmer kinetics (rate_coeff_type = "exchangecurrentdensity"). +edge_reaction("Li[anode] <=> Li+[elyt] + V[anode] + electron", [4, 0.0, (0, 'kJ/mol')], rate_coeff_type = "exchangecurrentdensity", beta = 0.5,id="anode_reaction") edge_reaction("Li+[elyt] + V[cathode] + electron <=> Li[cathode]", [100, 0.0, (0, 'kJ/mol')], rate_coeff_type = "exchangecurrentdensity", beta = 0.5,id="cathode_reaction") -# Dummy species -species( - name = "(dummy)", - atoms = "", - thermo = const_cp(h0 = (0.0, 'kJ/mol'), s0 = (0.0, 'J/mol/K'))) diff --git a/samples/matlab/lithium_ion_battery.m b/samples/matlab/lithium_ion_battery.m index 0113cf4859..cdd849dd42 100644 --- a/samples/matlab/lithium_ion_battery.m +++ b/samples/matlab/lithium_ion_battery.m @@ -15,13 +15,7 @@ % M. Mayur, S. DeCaluwe, B. L. Kee, W. G. Bessler, "Modeling % thermodynamics and kinetics of intercalation phases for lithium-ion % batteries in Cantera", under review at Electrochimica Acta. - -% For the sake of simplicity, we're going to assume that the anode and -% cathode capacities are perfectly balanced (i.e. if the cathode lithium -% content is X percent of it's max possible (i.e. its capacity), then we -% will assume that the anode is at 1-X percent. Without loss of -% generality, we will define the anode composition: - +% % The routine below returns the cell voltage (in Volt) of a lithium-ion % cell for a given cell current and active material lithium stoichiometries. % @@ -32,18 +26,16 @@ % - externally-applied current I_app [A] % - electrolyte resistance R_elyt [Ohm] -X_Li_an = [0.005:0.025:0.995]; -X_Li_ca = 1 - X_Li_an; -I_app = 0; -R_elyt = 0; -T = 300; -P = oneatm; - -global F -% Parameters +% Input parameters +SOC = 0:0.02:1; % [-] Input state of charge (0...1) +X_Li_an = (0.75-0.01)*SOC+0.01; % anode balancing +X_Li_ca = (0.99-0.49)*(1-SOC)+0.49; % cathode balancing +I_app = 0; % [A] Externally-applied current +R_elyt = 0; % [Ohm] Electrolyte resistance +T = 300; % [K] Temperature +P = oneatm; % [Pa] Pressure inputCTI = 'lithium_ion_battery.cti'; % cantera input file name -F = 96485; % Faraday's constant [C/mol] S_ca = 1.1167; % [m^2] Cathode total active material surface area S_an = 0.7824; % [m^2] Anode total active material surface area @@ -56,14 +48,16 @@ cathode_interface = Interface(inputCTI, 'edge_cathode_electrolyte', cathode, elde, elyt); % Set the temperatures and pressures of all phases -phases = [anode elde elyt cathode]; -for ph = phases - set(ph,'T',T,'P',P); -end +set(anode,'T',T,'P',P); +set(cathode,'T',T,'P',P); +set(elde,'T',T,'P',P); +set(elyt,'T',T,'P',P); +set(anode_interface,'T',T,'P',P); +set(cathode_interface,'T',T,'P',P); % Calculate cell voltage, separately for each entry of the input vectors -E_cell = zeros(length(X_Li_ca),1); -for i = 1:length(X_Li_ca) +E_cell = zeros(length(SOC),1); +for i = 1:length(SOC) % Set anode electrode potential to 0 phi_s_an = 0; @@ -80,11 +74,12 @@ E_cell(i) = phi_s_ca - phi_s_an; end -% Let's plot the cell voltage, as a function of the cathode stoichiometry: -plot(X_Li_ca,E_cell,'linewidth',2.5) +% Let's plot the cell voltage, as a function of the state of charge: +figure(1); +plot(SOC*100,E_cell,'linewidth',2.5) ylim([2.5,4.3]) -xlabel('Li Fraction in Cathode') -ylabel('Cell potential [V]') +xlabel('State of charge / %') +ylabel('Cell voltage / V') set(gca,'fontsize',14) @@ -107,7 +102,7 @@ r = rop_net(anode_interface).*1e3; % [mol/m2/s] % Calculate the current - anCurr = r*F*S_an*1; + anCurr = r*96485*S_an*1; % F = 96485 C/mol Faraday's constant end % This function returns the Cantera calculated cathode current (in A) @@ -126,5 +121,5 @@ r = rop_net(cathode_interface).*1e3; % [mol/m2/s] % Calculate the current - caCurr = r*F*S_ca*(-1); + caCurr = r*96485*S_ca*(-1); % F = 96485 C/mol Faraday's constant end From d2eb66c42b2e0776f99a272296f9076601ee5144 Mon Sep 17 00:00:00 2001 From: wbessler Date: Tue, 25 Jun 2019 08:29:38 +0200 Subject: [PATCH 2/4] Further improved Li-ion battery example MATLAB example: better comments, faster calculation, consistent signs; CTI file: thermally-activated kinetics --- data/inputs/lithium_ion_battery.cti | 12 +++- samples/matlab/lithium_ion_battery.m | 100 +++++++++++++++------------ 2 files changed, 63 insertions(+), 49 deletions(-) diff --git a/data/inputs/lithium_ion_battery.cti b/data/inputs/lithium_ion_battery.cti index 748e02d150..2521a117c1 100644 --- a/data/inputs/lithium_ion_battery.cti +++ b/data/inputs/lithium_ion_battery.cti @@ -279,9 +279,15 @@ ideal_interface( #============================================================================== # Electrochemical reactions +# +# We use Butler-Volmer kinetics by setting rate_coeff_type = "exchangecurrentdensity". +# The preexponential factors and activation energies are converted from +# Guo et al., J. Electrochem. Soc. 158, A122 (2011) #============================================================================== -# Use Butler-Volmer kinetics (rate_coeff_type = "exchangecurrentdensity"). -edge_reaction("Li[anode] <=> Li+[elyt] + V[anode] + electron", [4, 0.0, (0, 'kJ/mol')], rate_coeff_type = "exchangecurrentdensity", beta = 0.5,id="anode_reaction") -edge_reaction("Li+[elyt] + V[cathode] + electron <=> Li[cathode]", [100, 0.0, (0, 'kJ/mol')], rate_coeff_type = "exchangecurrentdensity", beta = 0.5,id="cathode_reaction") +# Graphite/electrolyte interface +edge_reaction("Li+[elyt] + V[anode] + electron <=> Li[anode]", [2.028e4, 0.0, (20, 'kJ/mol')], rate_coeff_type = "exchangecurrentdensity", beta = 0.5,id="anode_reaction") + +# LCO/electrolyte interface +edge_reaction("Li+[elyt] + V[cathode] + electron <=> Li[cathode]", [5.629e11, 0.0, (58, 'kJ/mol')], rate_coeff_type = "exchangecurrentdensity", beta = 0.5,id="cathode_reaction") diff --git a/samples/matlab/lithium_ion_battery.m b/samples/matlab/lithium_ion_battery.m index cdd849dd42..9edf293c86 100644 --- a/samples/matlab/lithium_ion_battery.m +++ b/samples/matlab/lithium_ion_battery.m @@ -1,44 +1,53 @@ -% This example file calculates the open-circuit voltage for a lithium-ion -% battery over a range of compositions. +% This example file calculates the cell voltage of a lithium-ion % battery +% at given temperature, pressure, current, and range of state of charge (SOC). % % The thermodynamics are based on a graphite anode and a LiCoO2 cathode, % modeled using the 'BinarySolutionTabulatedThermo' class. +% Further required cell parameters are the electrolyte ionic resistance, the +% stoichiometry ranges of the active materials (electrode balancing), and the +% surface area of the active materials. % -% Note that the function 'E_cell' below has even greater capabilities than -% what we use, here. It calculates the steady state cell voltage, at a -% given composition and cell current, for a given electrolyte ionic -% resistance. This functionality is presented in greater detail in the +% The functionality of this example is presented in greater detail in the % reference (which also describes the derivation of the % BinarySolutionTabulatedThermo class): % % Reference: -% M. Mayur, S. DeCaluwe, B. L. Kee, W. G. Bessler, "Modeling -% thermodynamics and kinetics of intercalation phases for lithium-ion -% batteries in Cantera", under review at Electrochimica Acta. -% -% The routine below returns the cell voltage (in Volt) of a lithium-ion -% cell for a given cell current and active material lithium stoichiometries. -% -% Input: -% - stoichiometries X_Li_ca and X_Li_an [-] (can be vectors) -% - temperature T [K] -% - pressure P [Pa] -% - externally-applied current I_app [A] -% - electrolyte resistance R_elyt [Ohm] - - -% Input parameters -SOC = 0:0.02:1; % [-] Input state of charge (0...1) -X_Li_an = (0.75-0.01)*SOC+0.01; % anode balancing -X_Li_ca = (0.99-0.49)*(1-SOC)+0.49; % cathode balancing -I_app = 0; % [A] Externally-applied current -R_elyt = 0; % [Ohm] Electrolyte resistance -T = 300; % [K] Temperature +% M. Mayur, S. DeCaluwe, B. L. Kee, W. G. Bessler, "Modeling and simulation of +% the thermodynamics of lithium-ion battery intercalation materials in an +% open-source software", under review at Electrochimica Acta (2019). + +% ----------------------------------------------------------------------------- +% Input +% ----------------------------------------------------------------------------- + +% Operation parameters +SOC = 0:0.02:1; % [-] Input state of charge (0...1) (can be a vector) +I_app = -1; % [A] Externally-applied current, negative for discharge +T = 293; % [K] Temperature P = oneatm; % [Pa] Pressure -inputCTI = 'lithium_ion_battery.cti'; % cantera input file name + +% Cell properties +inputCTI = 'lithium_ion_battery.cti'; % Cantera input file name +R_elyt = 0.0384; % [Ohm] Electrolyte resistance S_ca = 1.1167; % [m^2] Cathode total active material surface area S_an = 0.7824; % [m^2] Anode total active material surface area +% Electrode balancing: The "balancing" of the electrodes relates the chemical +% composition (lithium mole fraction in the active materials) to the macroscopic +% cell-level state of charge. +X_Li_an_0 = 0.01; % [-] anode Li mole fraction at SOC = 0 % +X_Li_an_1 = 0.75; % [-] anode Li mole fraction at SOC = 100 % +X_Li_ca_0 = 0.99; % [-] cathode Li mole fraction at SOC = 0 % +X_Li_ca_1 = 0.49; % [-] cathode Li mole fraction at SOC = 100 % + +% ----------------------------------------------------------------------------- +% Calculations +% ----------------------------------------------------------------------------- + +% Calculate mole fractions from SOC +X_Li_an = (X_Li_an_1-X_Li_an_0)*SOC+X_Li_an_0; % anode balancing +X_Li_ca = (X_Li_ca_0-X_Li_ca_1)*(1-SOC)+X_Li_ca_1; % cathode balancing + % Import all Cantera phases anode = Solution(inputCTI, 'anode'); cathode = Solution(inputCTI, 'cathode'); @@ -56,27 +65,29 @@ set(cathode_interface,'T',T,'P',P); % Calculate cell voltage, separately for each entry of the input vectors -E_cell = zeros(length(SOC),1); +V_cell = zeros(length(SOC),1); +phi_l_an = 0; +phi_s_ca = 0; for i = 1:length(SOC) % Set anode electrode potential to 0 phi_s_an = 0; % Calculate anode electrolyte potential - phi_l_an = fzero(@(E) anode_curr(phi_s_an,E,X_Li_an(i),anode,elde,elyt,anode_interface,S_an)+I_app, 0); + phi_l_an = fzero(@(E) anode_curr(phi_s_an,E,X_Li_an(i),anode,elde,elyt,anode_interface,S_an)-I_app, phi_l_an); % Calculate cathode electrolyte potential phi_l_ca = phi_l_an + I_app*R_elyt; % Calculate cathode electrode potential - phi_s_ca = fzero(@(E) cathode_curr(E,phi_l_ca,X_Li_ca(i),cathode,elde,elyt,cathode_interface,S_ca)+I_app, 0); + phi_s_ca = fzero(@(E) cathode_curr(E,phi_l_ca,X_Li_ca(i),cathode,elde,elyt,cathode_interface,S_ca)-I_app, phi_s_ca); % Calculate cell voltage - E_cell(i) = phi_s_ca - phi_s_an; + V_cell(i) = phi_s_ca - phi_s_an; end % Let's plot the cell voltage, as a function of the state of charge: figure(1); -plot(SOC*100,E_cell,'linewidth',2.5) +plot(SOC*100,V_cell,'linewidth',2.5) ylim([2.5,4.3]) xlabel('State of charge / %') ylabel('Cell voltage / V') @@ -85,12 +96,10 @@ %-------------------------------------------------------------------------- % Helper functions +% ----------------------------------------------------------------------------- % This function returns the Cantera calculated anode current (in A) function anCurr = anode_curr(phi_s,phi_l,X_Li_an,anode,elde,elyt,anode_interface,S_an) - - global F - % Set the active material mole fraction set(anode,'X',['Li[anode]:' num2str(X_Li_an) ', V[anode]:' num2str(1-X_Li_an)]); @@ -98,18 +107,16 @@ setElectricPotential(elde,phi_s); setElectricPotential(elyt,phi_l); - % Get the net reaction rate at the cathode-side interface - r = rop_net(anode_interface).*1e3; % [mol/m2/s] + % Get the net reaction rate at the anode-side interface + % Reaction according to cti file: Li+[elyt] + V[anode] + electron <=> Li[anode] + r = rop_net(anode_interface)*1e3; % [mol/m2/s] . Factor 1e3 for kmol->mol - % Calculate the current - anCurr = r*96485*S_an*1; % F = 96485 C/mol Faraday's constant + % Calculate the current. Should be negative for cell discharge. + anCurr = r*96485*S_an; % F = 96485 C/mol Faraday's constant end % This function returns the Cantera calculated cathode current (in A) function caCurr = cathode_curr(phi_s,phi_l,X_Li_ca,cathode,elde,elyt,cathode_interface,S_ca) - - global F - % Set the active material mole fractions set(cathode,'X',['Li[cathode]:' num2str(X_Li_ca) ', V[cathode]:' num2str(1-X_Li_ca)]); @@ -118,8 +125,9 @@ setElectricPotential(elyt,phi_l); % Get the net reaction rate at the cathode-side interface - r = rop_net(cathode_interface).*1e3; % [mol/m2/s] + % Reaction according to cti file: Li+[elyt] + V[cathode] + electron <=> Li[cathode] + r = rop_net(cathode_interface)*1e3; % [mol/m2/s] . Factor 1e3 for kmol->mol - % Calculate the current + % Calculate the current. Should be negative for cell discharge. caCurr = r*96485*S_ca*(-1); % F = 96485 C/mol Faraday's constant end From 55d021691ff58fc785907986d3fa2e89c8efbe27 Mon Sep 17 00:00:00 2001 From: Steven DeCaluwe Date: Wed, 26 Jun 2019 10:31:27 -0600 Subject: [PATCH 3/4] Updating matlab Li ion battery sample. Corrected one typo (stray mid-line comment symbol) and converted hard-coded faraday constant to the corresponding Matlab toolbox function (added with PR #640). --- samples/matlab/lithium_ion_battery.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/matlab/lithium_ion_battery.m b/samples/matlab/lithium_ion_battery.m index 9edf293c86..8f894876cd 100644 --- a/samples/matlab/lithium_ion_battery.m +++ b/samples/matlab/lithium_ion_battery.m @@ -1,4 +1,4 @@ -% This example file calculates the cell voltage of a lithium-ion % battery +% This example file calculates the cell voltage of a lithium-ion battery % at given temperature, pressure, current, and range of state of charge (SOC). % % The thermodynamics are based on a graphite anode and a LiCoO2 cathode, @@ -109,10 +109,10 @@ % Get the net reaction rate at the anode-side interface % Reaction according to cti file: Li+[elyt] + V[anode] + electron <=> Li[anode] - r = rop_net(anode_interface)*1e3; % [mol/m2/s] . Factor 1e3 for kmol->mol + r = rop_net(anode_interface); % [kmol/m2/s] % Calculate the current. Should be negative for cell discharge. - anCurr = r*96485*S_an; % F = 96485 C/mol Faraday's constant + anCurr = r*faradayconstant*S_an; % end % This function returns the Cantera calculated cathode current (in A) @@ -126,8 +126,8 @@ % Get the net reaction rate at the cathode-side interface % Reaction according to cti file: Li+[elyt] + V[cathode] + electron <=> Li[cathode] - r = rop_net(cathode_interface)*1e3; % [mol/m2/s] . Factor 1e3 for kmol->mol + r = rop_net(cathode_interface); % [kmol/m2/s] % Calculate the current. Should be negative for cell discharge. - caCurr = r*96485*S_ca*(-1); % F = 96485 C/mol Faraday's constant + caCurr = r*faradayconstant*S_ca*(-1); % end From 29de6c56640080cbbe1ce9bdc52a62d9dea01a03 Mon Sep 17 00:00:00 2001 From: Ray Speth Date: Wed, 26 Jun 2019 17:57:43 -0400 Subject: [PATCH 4/4] [Input] Fix CTI to YAML conversion of phases with no elements --- interfaces/cython/cantera/cti2yaml.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interfaces/cython/cantera/cti2yaml.py b/interfaces/cython/cantera/cti2yaml.py index a3760eecd6..a0d64bfa23 100644 --- a/interfaces/cython/cantera/cti2yaml.py +++ b/interfaces/cython/cantera/cti2yaml.py @@ -1087,7 +1087,8 @@ def to_yaml(cls, representer, node): def get_yaml(self, out): out['name'] = self.name out['thermo'] = self.thermo_model - out['elements'] = FlowList(self.elements.split()) + if self.elements: + out['elements'] = FlowList(self.elements.split()) if len(self.species) == 1 and self.species[0][0] == 'species': # all local species