The Battery Simulation Model
In the previous sections, we have seen how to run a simulation from a single json input. In this section, we detail the simulation process. This is useful for a more advanced usage where a direct access to the solver is required, for example for a case that is not covered by the json input interface.
To run a simulation, we need:
A Battery model, which knows how to setup and solve the governing equations of our problem,
An initial state and
A schedule, which provides the time stepping and can also contain setup for control (covered in an other section).
We use the governing equations provided in the serie of papers [LZ13, LZ16, LZI11]. They correspond to the standard PXD model. The equations are non-linear. The charge and mass conservation equations are partial differential equations. First, the equations are discretized. We use a finite volume method which ensures conservation at the discrete level. For stability, we use a fully implicit method, also called backward Euler. For each time step, we end us with a set of non-linear equations that we have to solve. We use Newton method.
The function simulateScheduleAD with the following signature takes as argument an initial state, a model and a schedule and returns global variables, a cell array of states and a report. Each state in the cell array corresponds to the solution computed at a given time step.
function [globVars, states, schedulereport] = simulateScheduleAD(initState, model, schedule, varargin)
In this function, the model has the task of assemblying the discrete residual equations, given the solution at the given time step, and send them to a Newton solver.
Initialisation of a battery simulation model
To initialise a model using json input, we can use the function setupModelFromJson. For example,
jsonstruct = parseBattmoJson('Examples/JsonDataFiles/sample_input.json')
model = setupModelFromJson(jsonstruct)
Then, we obtain a model
which is an instance of Battery.
Internally, the json input is converted into a matlab input object which we typically call inputparams
and
which is here an instance of BatteryInputParams. An advanced user does not have to use the json interface but
can work only with the matlab input structures. This approach with a double layer for input (first json then matlab) can
appear redundant but the advantage is for the developper to operate within the same Matlab environment: The computation
models (for example Battery model) is initiated using a matlab object (for this example
BatteryInputParams). In particular, it enables us to run validation methods on the input (doing the same
operations directly on json files would have been significantly more complicated to implement).
Let us now have a closer look to the setupModelFromJson
function, line by line. Given a matlab structure
jsonstruct
obtained as above by parsing a json file, we first convert the data that is specified with units to
SI units,
jsonstruct = resolveUnitInputJson(jsonstruct);
Note
Within the simulator, all the quantities are used with SI units.
Then, we construct the matlab input object:
inputparams = BatteryInputParams(jsonstruct);
To every submodel (see BattMo Model Architecture for an overview of those), there corresponds a matlab input parameter object, which is given the name of the submodel with the suffix InputParams. For example, corresponding to the ActiveMaterial model, we find the ActiveMaterialInputParams input model. Typically, the property of the object corresponds to the property of the corresponding json input.
We add the geometry using the function setupBatteryGridFromJson which uses the json input
inputparams = setupBatteryGridFromJson(inputparams, jsonstruct);
Now the object inputparams
contains also the grids for each of the submodels. In general, the grids are
generated using so-called grid generator, see the dedicated section. When we
use a standard parameterized geometry, then the grid parameters can be pass in the json structure (an example is given
here for a Jelly Roll geometry). The
function setupBatteryGridFromJson then takes care of calling the appropriate grid generator with the
parameter, as given in the json input file.
The input parameter object can now be validated. This step is important. In the BattMo Model Architecture, sub-models can use the same parameters. However, the submodels are instantiate in a parallel manner. The validate method which is called recursively at each model level can ensure the consistency of the submodels. (For example in the ActiveMaterialInputParams, we make sure that the Interface model and the Solid Diffusion model use the same volumetric surface area). We can thus call
inputparams = inputparams.validateInputParams();
and make sure our data is consistent. In fact, this function is called in the setup of model so that we do not need to run it separately. Finally, we use our input parameter object to instantiate our battery model
model = Battery(inputparams)
Inspection of the model
The model contains all the parameters of the battery. You can inspect simply using the command window. There are properties that are used by the solver that will remain obscure for a standard user. Yet, most of the names are explicit enough and match with the json schema definition so that their meaning will be clear. For example,
>> model
model =
Battery with properties:
con: [1x1 PhysicalConstants]
NegativeElectrode: [1x1 Electrode]
PositiveElectrode: [1x1 Electrode]
Electrolyte: [1x1 Electrolyte]
Separator: [1x1 Separator]
ThermalModel: [1x1 ThermalComponent]
Control: [1x1 CCDischargeControlModel]
SOC: 0.9900
initT: 298.1500
...
Here, we recognize the battery model architecture. Just as an example, we can look at the properties of the active material in the negative electrode
>> model.NegativeElectrode.Coating.ActiveMaterial
ans =
ActiveMaterial with properties:
Interface: [1x1 Interface]
SolidDiffusion: [1x1 FullSolidDiffusionModel]
electronicConductivity: 100
density: 2240
massFraction: 0.9400
thermalConductivity: 1.0400
specificHeatCapacity: 632
and we recognize the property names and values given in the input json file that is used in this example.
Some properties of the model are computed at initialisation. This is the case for example of the effective electronic conducitivities. Therefore,
Warning
In general, you should never change the properties of the model directly. You can do so if you know the model in details.
The reason is that some parameters are used to compute other dependent parameters. This computation is done at the model setup.
To change a model parameter, you can either do it in your json input structure or, as described earlier, using the
matlab input parameter object (inputparams
). The effectrive electronic conductivity of the coating in the
negative electrode is
>> model.NegativeElectrode.Coating
ans =
Coating with properties:
ActiveMaterial : [1x1 ActiveMaterial]
Binder : [1x1 Binder]
ConductingAdditive : [1x1 ConductingAdditive]
...
electronicConductivity : 100.3328
effectiveElectronicConductivity : 82.5961
...
The intrinsic electronic conductivity of the coating is computed from the electronic conductivity of its constituent (active material, binder, conducting additive). Then the effective electronic conductivity, which is used in the charge conservation equation, takes into account the coating volume fraction and the Bruggeman coefficient.
Let us change the conductivity of the active material from 100 to 120 (remember we always use SI inside the code so that those values are in Siemens/cm^2). We can proceed as follows
jsonstruct = parseBattmoJson('JsonDataFiles/sample_input.json');
[model, inputparams] = setupModelFromJson(jsonstruct);
% Change the value the electronic conductivity
inputparams.NegativeElectrode.Coating.ActiveMaterial.electronicConductivity = 120;
model = Battery(inputparams);
Then,
>> model.NegativeElectrode.Coating
ans =
Coating with properties:
electronicConductivity: 118.4873
effectiveElectronicConductivity: 97.5413
Computing and inspecting some standard static properties of the model
For a battery cell, utility functions are available to compute the standard properties listed below
computeCellMass computes the mass of the battery and its components
computeCellCapacity computes the capacity of the the electrodes
computeCellEnergy computes the total energy of the battery when discharged at equilibrium conditions. It means that the transport effects are totally neglicted and corresponds to the case of an infinitly small CRate.
To print to screen all these properties, we can use conveniently an instance of the CellSpecificationSummary as shown below.
jsonstruct = parseBattmoJson('JsonDataFiles/sample_input.json');
model = setupModelFromJson(jsonstruct);
css = CellSpecificationSummary(model);
Then, using the printSpecifications
method, we get
>> css.printSpecifications
Packing mass : 0 [kg]
Temperature : 24.85 [C]
Mass : 3.59526e-05 [kg]
Volume : 1.36e-05 [L]
Total Capacity : 0.00301148 [Ah]
Negative Electrode Capacity : 0.00310324 [Ah]
Positive Electrode Capacity : 0.00301148 [Ah]
N/P ratio : 1.03047 [-]
Energy : 0.0115753 [Wh]
Specific Energy : 321.958 [Wh/kg]
Energy Density : 851.122 [Wh/L]
Initial Voltage : 4.17686 [V]
We can also mention here the utility function computeCellEnergyGivenDrate, even it is not a static property. The function computes the energy produced by a cell for a given CRate.
>> output = computeCellEnergyGivenDrate(model, 2);
>> fprintf('Energy at Crate=2 : %g [Wh]', output.energy / (watt*hour));
Energy at Crate = 2 : 0.0110781 [Wh]