Handling cycling protocols
In this tutorial, we demonstrate functionality to handle cycling protcols. We will illustrate the effect that the DRate has on battery performance during discharge, using a constant-current (CC) discharge protocol.
Load required packages and data
We start by loading the necessary parameters sets and instantiating a model. For the cyling protocol, we'll start from the default constant current discharge protocol.
using BattMo, GLMakie, Printf
Load cell and model setup
cell_parameters = load_cell_parameters(; from_default_set = "Chen2020")
cc_discharge_protocol = load_cycling_protocol(; from_default_set = "CCDischarge")
{
"TotalNumberOfCycles" => 0
"InitialControl" => "discharging"
"InitialStateOfCharge" => 0.99
"InitialTemperature" => 298.15
"Metadata" => {
"Description" => "Parameter set for a constant current discharging protocol."
"Title" => "CCDischarge"
}
"DRate" => 0.5
"LowerVoltageLimit" => 2.4
"Protocol" => "CC"
"UpperVoltageLimit" => 4.1
}
Load default model
model_setup = LithiumIonBattery()
LithiumIonBattery("Setup object for a P2D lithium-ion model", {
"RampUp" => "Sinusoidal"
"Metadata" => {
"Description" => "Default model settings for a P2D simulation including a current ramp up, excluding current collectors and SEI effects."
"Title" => "P2D"
}
"TransportInSolid" => "FullDiffusion"
"ModelFramework" => "P2D"
}, true)
Handle, access and edit cycling protocols
We manipulate a cycling protocol in the same was as we do cell parameters in the previous tutorial. To list all outermost keys:
keys(cc_discharge_protocol)
KeySet for a Dict{String, Any} with 9 entries. Keys:
"TotalNumberOfCycles"
"InitialControl"
"InitialStateOfCharge"
"InitialTemperature"
"Metadata"
"DRate"
"LowerVoltageLimit"
"Protocol"
"UpperVoltageLimit"
Show all keys and values
cc_discharge_protocol.all
Dict{String, Any} with 9 entries:
"TotalNumberOfCycles" => 0
"InitialControl" => "discharging"
"InitialStateOfCharge" => 0.99
"InitialTemperature" => 298.15
"Metadata" => {…
"DRate" => 0.5
"LowerVoltageLimit" => 2.4
"Protocol" => "CC"
"UpperVoltageLimit" => 4.1
Search for a specific parameter
search_parameter(cc_discharge_protocol, "rate")
1-element Vector{Any}:
"[DRate] => 0.5"
Access a specific parameter
cc_discharge_protocol["DRate"]
0.5
Change protocol parameters as dicitonaries
cc_discharge_protocol["DRate"] = 2.0
2.0
Compare cell performance across DRates
Lets now do something more fun. Since we can edit scalar valued parameters as we edit dictionaries, we can loop through different DRates and run a simulation for each. We can then compare the cell voltage profiles for each DRate.
Let’s define the range of C-rates to explore:
d_rates = [0.2, 0.5, 1.0, 2.0]
4-element Vector{Float64}:
0.2
0.5
1.0
2.0
Now loop through these values, update the protocol, and store the results:
outputs = []
for d_rate in d_rates
protocol = deepcopy(cc_discharge_protocol)
protocol["DRate"] = d_rate
sim = Simulation(model_setup, cell_parameters, protocol)
output = solve(sim; config_kwargs = (; end_report = false))
push!(outputs, (d_rate = d_rate, output = output))
end
✔️ Validation of CellParameters passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of CyclingProtocol passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of SimulationSettings passed: No issues found.
──────────────────────────────────────────────────
Jutul: Simulating 5 hours, 30 minutes as 401 report steps
✔️ Validation of CellParameters passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of CyclingProtocol passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of SimulationSettings passed: No issues found.
──────────────────────────────────────────────────
Jutul: Simulating 2 hours, 12 minutes as 163 report steps
✔️ Validation of CellParameters passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of CyclingProtocol passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of SimulationSettings passed: No issues found.
──────────────────────────────────────────────────
Jutul: Simulating 1 hour, 6 minutes as 84 report steps
✔️ Validation of CellParameters passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of CyclingProtocol passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of SimulationSettings passed: No issues found.
──────────────────────────────────────────────────
Jutul: Simulating 33 minutes, 0.0002274 nanoseconds as 44 report steps
Analyze Voltage and Capacity
We'll extract the voltage vs. time and delivered capacity for each C-rate:
fig = Figure(size = (1000, 400))
ax1 = Axis(fig[1, 1], title = "Voltage vs Time", xlabel = "Time / s", ylabel = "Voltage / V")
for result in outputs
states = result.output[:states]
t = [state[:Control][:Controller].time for state in states]
E = [state[:Control][:Phi][1] for state in states]
I = [state[:Control][:Current][1] for state in states]
label_str = @sprintf("%.1fC", result.d_rate)
lines!(ax1, t, E, label = label_str)
end
fig[1, 3] = Legend(fig, ax1, "C-rates", framevisible = false)
fig
We see this cell has poor power capabilities since its capacity decreases quite rapidly with DRate.
Example on GitHub
If you would like to run this example yourself, it can be downloaded from the BattMo.jl GitHub repository as a script.
This page was generated using Literate.jl.