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, PrintfLoad cell and model setup
cell_parameters = load_cell_parameters(; from_default_set = "chen_2020")
cc_discharge_protocol = load_cycling_protocol(; from_default_set = "cc_discharge"){
"TotalNumberOfCycles" => 0
"InitialControl" => "discharging"
"InitialStateOfCharge" => 0.99
"Metadata" => {
"Description" => "Parameter set for a constant current discharging protocol."
"Title" => "cc_discharge"
}
"DRate" => 0.5
"LowerVoltageLimit" => 2.4
"Protocol" => "CC"
"UpperVoltageLimit" => 4.1
}Load default model
model = LithiumIonBattery()LithiumIonBattery("Setup object for a P2D lithium-ion model", {
"ButlerVolmer" => "Standard"
"RampUp" => "Sinusoidal"
"Metadata" => {
"Description" => "Default model settings for a P2D simulation including a current ramp up, excluding current collectors and SEI effects."
"Title" => "p2d"
}
"PotentialFlowDiscretization" => "GeneralAD"
"TransportInSolid" => "FullDiffusion"
"ModelFramework" => "P2D"
}, true, #undef)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 8 entries. Keys:
"TotalNumberOfCycles"
"InitialControl"
"InitialStateOfCharge"
"Metadata"
"DRate"
"LowerVoltageLimit"
"Protocol"
"UpperVoltageLimit"Show all keys and values
cc_discharge_protocol.allDict{String, Any} with 8 entries:
"TotalNumberOfCycles" => 0
"InitialControl" => "discharging"
"InitialStateOfCharge" => 0.99
"Metadata" => {…
"DRate" => 0.5
"LowerVoltageLimit" => 2.4
"Protocol" => "CC"
"UpperVoltageLimit" => 4.1Search for a specific parameter
search_parameter(cc_discharge_protocol, "rate")
Parameters
------------------
[ "DRate" ] => 0.5Access a specific parameter
cc_discharge_protocol["DRate"]0.5Change protocol parameters as dicitonaries
cc_discharge_protocol["DRate"] = 2.02.0Compare 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.0Now 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, cell_parameters, protocol)
output = solve(sim; info_level = -1)
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.
──────────────────────────────────────────────────
✔️ Validation of SolverSettings passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of CellParameters passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of CyclingProtocol passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of SimulationSettings passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of SolverSettings passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of CellParameters passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of CyclingProtocol passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of SimulationSettings passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of SolverSettings passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of CellParameters passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of CyclingProtocol passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of SimulationSettings passed: No issues found.
──────────────────────────────────────────────────
✔️ Validation of SolverSettings passed: No issues found.
──────────────────────────────────────────────────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
t = result.output.time_series["Time"]
E = result.output.time_series["Voltage"]
I = result.output.time_series["Current"]
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.