Tip

An interactive online version of this notebook is available, which can be accessed via Open this notebook in Google Colab


Alternatively, you may download this notebook and run it offline.

Attention

You are viewing this notebook on the latest version of the documentation, where these notebooks may not be compatible with the stable release of PyBaMM since they can contain features that are not yet released. We recommend viewing these notebooks from the stable version of the documentation. To install the latest version of PyBaMM that is compatible with the latest notebooks, build PyBaMM from source.

Tutorial 5 - Run experiments#

In Tutorial 4 we saw how to change the parameters, including the applied current. However, in some cases we might want to prescribe a given voltage, a given power or switch between different conditions to simulate experimental setups. We can use the Experiment class for these simulations.

[1]:
%pip install "pybamm[plot,cite]" -q    # install PyBaMM if it is not installed
import pybamm
import numpy as np

[notice] A new release of pip is available: 23.3.1 -> 24.0
[notice] To update, run: pip install --upgrade pip
Note: you may need to restart the kernel to use updated packages.
An NVIDIA GPU may be present on this machine, but a CUDA-enabled jaxlib is not installed. Falling back to cpu.

String-based instructions#

We start defining an experiment, which consists on a set of instructions on how to cycle the battery. These instructions can be defined in two different ways, but the simplest is to use strings. The instructions can be of the form "(Dis)charge at x A/C/W", "Rest", or "Hold at x V". The instructions can also include how long each step should run for. The duration is introduced by the word "for" followed by the duration, e.g. "for 10 seconds", "for 3 minutes" or "for 1 hour". Terminating conditions can also be specified. In this case, the step will stop when that condition is met. These conditions should be a circuit state and are introduced by the word "until", e.g. "until 1 A", "until C/50" or "until 3 V". Duration and termination conditions can be combined using the word "or" and the step will either finish when the condition is met or after the specified duration (whichever happens first).

Some examples of experiment instructions are:

"Discharge at 1C for 0.5 hours",
"Discharge at C/20 for 0.5 hours",
"Charge at 0.5 C for 45 minutes",
"Discharge at 1 A for 90 seconds",
"Charge at 200mA for 45 minutes",
"Discharge at 1 W for 0.5 hours",
"Charge at 200 mW for 45 minutes",
"Rest for 10 minutes",
"Hold at 1 V for 20 seconds",
"Charge at 1 C until 4.1V",
"Hold at 4.1 V until 50 mA",
"Hold at 3V until C/50",

These steps can be concatenated in a list, so they are executed sequentially. To create an experiment, the list can then be passed when creating an Experiment object:

[2]:
experiment = pybamm.Experiment(
    [
        "Discharge at C/10 for 10 hours or until 3.3 V",
        "Rest for 1 hour",
        "Charge at 1 A until 4.1 V",
        "Hold at 4.1 V until 50 mA",
        "Rest for 1 hour",
    ]
)

In order to reproduce real cycling conditions, often the experiments will be composed of several “cycles”, where a cycle is a user-defined collection of steps. In PyBaMM, we can define a cycle as a tuple of steps, which means that we can process the solution in terms of cycles. For more information on this functionality, please see the long experiments notebook. We can also leverage the list addition and multiplication operators to combine and repeat cycles. For example, if we want a three cycles of constant current C/10 discharge, a one hour rest, a constant current (1 A) constant voltage (4.1 V) and another one hour rest, followed by a cycle of 1C discharge we can write:

[3]:
experiment = pybamm.Experiment(
    [
        (
            "Discharge at C/10 for 10 hours or until 3.3 V",
            "Rest for 1 hour",
            "Charge at 1 A until 4.1 V",
            "Hold at 4.1 V until 50 mA",
            "Rest for 1 hour",
        )
    ]
    * 3
    + [
        "Discharge at 1C until 3.3 V",
    ]
)

Note that if a cycle is made of one step only (like the 1C discharge) we do not need to define it as a tuple. One key difference between cycles and steps, is that PyBaMM allows for steps to be skipped (e.g. if you try to charge an a fully charged battery) but not cycles.

Then we can choose our model and create our simulation, passing our experiment using a keyword argument

[4]:
model = pybamm.lithium_ion.DFN()
sim = pybamm.Simulation(model, experiment=experiment)

We then solve and plot the solution

[5]:
sim.solve()
sim.plot()
At t = 522.66 and h = 1.1556e-13, the corrector convergence failed repeatedly or with |h| = hmin.
[5]:
<pybamm.plotting.quick_plot.QuickPlot at 0x7f1a11f76690>

The solution variable in the simulation object has a cycles variable that allows to access the solution for a specific cycle. That solution can be processed and plotted as usual. For example, if we want to plot the first cycle only we can do

[6]:
sim.solution.cycles[0].plot()
[6]:
<pybamm.plotting.quick_plot.QuickPlot at 0x7f1a105ecb50>

Note that because sol.cycles is a list, the indexing starts at 0.

As we will see in the next section, we can pass additional arguments such as a period, temperature, or tags when defining a step. The method pybamm.step.string can be used to add these additional conditions to a string-defined step:

[7]:
pybamm.step.string(
    "Discharge at 1C for 1 hour", period="1 minute", temperature="25oC", tags=["tag1"]
)
[7]:
_Step(C-rate, 1.0, duration=1 hour, period=1 minute, temperature=25oC, tags=['tag1'], description=Discharge at 1C for 1 hour)

Direct instructions#

Experiments can also be specified programmatically without having to use string formatting. For example,

[8]:
pybamm.step.current(1, duration="1 hour", termination="2.5 V")
[8]:
_Step(current, 1, duration=1 hour, termination=2.5 V)

is equivalent to

[9]:
pybamm.step.string("Discharge at 1A for 1 hour or until 2.5V")
[9]:
_Step(current, 1.0, duration=1 hour, termination=2.5V, description=Discharge at 1A for 1 hour or until 2.5V)

The available methods are current, c_rate, voltage, power, and resistance. These methods also take optional keyword arguments, such as the period, temperature, tags or starting times (a complete list can be found in the documentation).

These methods can also be used for drive cycles. In this case, the value argument should be a 2-column array, where the first column is time in seconds (should start at zero) and the second column the values (i.e. current, voltage, power…). Here is an example for a synthetically defined drive cycle:

[10]:
t = np.linspace(0, 1, 60)
sin_t = 0.5 * np.sin(2 * np.pi * t)
drive_cycle_power = np.column_stack([t, sin_t])
experiment = pybamm.Experiment([pybamm.step.power(drive_cycle_power)])
sim = pybamm.Simulation(model, experiment=experiment)
sim.solve()
sim.plot()
[10]:
<pybamm.plotting.quick_plot.QuickPlot at 0x7f1a1a4c2ed0>

For a drive cycle, the duration is until the final time provided and the period is the smallest time step. For best results, we recommend using a constant time step size.

In this notebook we have seen how to use the Experiment class to run simulations of more complex operating conditions. In Tutorial 6 we will see how to manage the outputs of the simulation.

References#

The relevant papers for this notebook are:

[11]:
pybamm.print_citations()
[1] Joel A. E. Andersson, Joris Gillis, Greg Horn, James B. Rawlings, and Moritz Diehl. CasADi – A software framework for nonlinear optimization and optimal control. Mathematical Programming Computation, 11(1):1–36, 2019. doi:10.1007/s12532-018-0139-4.
[2] Marc Doyle, Thomas F. Fuller, and John Newman. Modeling of galvanostatic charge and discharge of the lithium/polymer/insertion cell. Journal of the Electrochemical society, 140(6):1526–1533, 1993. doi:10.1149/1.2221597.
[3] Charles R. Harris, K. Jarrod Millman, Stéfan J. van der Walt, Ralf Gommers, Pauli Virtanen, David Cournapeau, Eric Wieser, Julian Taylor, Sebastian Berg, Nathaniel J. Smith, and others. Array programming with NumPy. Nature, 585(7825):357–362, 2020. doi:10.1038/s41586-020-2649-2.
[4] Scott G. Marquis, Valentin Sulzer, Robert Timms, Colin P. Please, and S. Jon Chapman. An asymptotic derivation of a single particle model with electrolyte. Journal of The Electrochemical Society, 166(15):A3693–A3706, 2019. doi:10.1149/2.0341915jes.
[5] Peyman Mohtat, Suhak Lee, Jason B Siegel, and Anna G Stefanopoulou. Towards better estimability of electrode-specific state of health: decoding the cell expansion. Journal of Power Sources, 427:101–111, 2019.
[6] Valentin Sulzer, Scott G. Marquis, Robert Timms, Martin Robinson, and S. Jon Chapman. Python Battery Mathematical Modelling (PyBaMM). Journal of Open Research Software, 9(1):14, 2021. doi:10.5334/jors.309.
[7] Pauli Virtanen, Ralf Gommers, Travis E. Oliphant, Matt Haberland, Tyler Reddy, David Cournapeau, Evgeni Burovski, Pearu Peterson, Warren Weckesser, Jonathan Bright, and others. SciPy 1.0: fundamental algorithms for scientific computing in Python. Nature Methods, 17(3):261–272, 2020. doi:10.1038/s41592-019-0686-2.
[8] Andrew Weng, Jason B Siegel, and Anna Stefanopoulou. Differential voltage analysis for battery manufacturing process control. arXiv preprint arXiv:2303.07088, 2023.