Technical Articles

Running PyBaMM from MATLAB: Expanding Battery Simulation Capabilities

By Sebastian Arias Alfaro, Chris Lim, and Xiangchun Zhang, MathWorks


Introduction

Battery modeling is a crucial activity for designing battery management systems in many industries. Battery models are embedded in the battery control software as part of a real-time state-of-charge estimation algorithm. They are used for rapid prototyping and development of the battery control strategy, to explore design sensitivities in research and development activities, and to perform virtual design and verification during a battery product design cycle. All these tasks can be conducted using MATLAB®, Simulink®, and Simscape™, which provide a powerful environment for virtual battery testing, with the control software integrated with the rest of the system.

Graphic showing six aspects of battery modeling: design, lifetime, safety, control, characterization, and thermal.

Figure 1. Battery modeling applications.

PyBaMM is a leading open-source tool that provides a library of battery models with several levels of complexity depending on your requirements. These detailed, high-resolution electrochemical battery models, with built-in degradation effects, can run directly from a MATLAB script, or they can be embedded into Simulink. In addition, you can import PyBaMM parameter sets directly into Simscape Battery™ blocks, which support code generation, automated battery pack model creation, and electrothermal system modeling as well as fully acausal modeling workflows.

This article explains how to run PyBaMM directly from MATLAB, import PyBaMM battery models into Simulink, and import the parameters from PyBaMM battery models into equivalent Simscape Battery blocks. Files that accompany the content are available for download.

Diagram showing three integration methods between PyBaMM and MATLAB: running PyBaMM directly from MATLAB, co-simulation, and importing PyBaMM parameter sets into Simscape blocks.

Figure 2. PyBaMM to MATLAB integration workflows.

PyBaMM Installation

To run PyBaMM within MATLAB, you must first set up a Python environment that is accessible within MATLAB. (See compatible versions of Python for each MATLAB release.) For this example, we are using MATLAB R2025a and Python 3.11.

To install PyBaMM within your Python environment, follow the instructions on the PyBaMM website.

Once you have a compatible Python environment with PyBaMM installed, you can run a PyBaMM simulation from within MATLAB. If you have multiple Python installations on your machine (or are using virtual environments), point MATLAB to the Python executable you want it to use:

% pe = pyenv("Version", "<path_to_Python.exe>");

To get the path to your Python executable within the Python environment, run the following commands from the Python command prompt:

>>> import sys
>>> print(sys.executable)

To check whether PyBaMM is installed in the Python environment that MATLAB is using, run the following command in the MATLAB command line:

tf = check_pybamm_install()

  tf = logical
     1

Once you’ve verified that MATLAB is using a Python environment with PyBaMM installed, you’re ready to run a PyBaMM simulation from within MATLAB.

Run PyBaMM Within MATLAB

Running a PyBaMM experiment within MATLAB is similar to how you would run it in Python. We’re using an example from the PyBaMM documentation.

First, import the PyBaMM module and set up the model and simulation object. Then run a simulation (in this case, for 1 hour at 90-second time steps) to retrieve the solution:

pybamm = py.importlib.import_module('pybamm');
model = pybamm.lithium_ion.SPMe();
simulation = pybamm.Simulation(model);
solution = simulation.solve(0:90:3600);

Next, extract the variables that you are interested in from the solution object. Populate the solution data dictionary with the variables (in this case, time and voltage) before converting them to double data types that can be used in MATLAB:

variables = py.list({'Time [s]', 'Voltage [V]'});
solution.update(variables);
t = double(solution.data.get('Time [s]'));
v = double(solution.data.get('Voltage [V]'));

The x and y variables are now MATLAB arrays that you can plot using the normal MATLAB syntax:

figure; hold on;
plot(t, v, "-");
plot(t, v, ".", "MarkerSize", 5);
grid on; xlabel("Time (s)"); ylabel("Voltage (V)");
Line graph showing battery voltage gradually decreasing over time, with a sharp drop near the end of the cycle.

Figure 3. Battery terminal voltage from the PyBaMM SPMe model simulated in MATLAB.

Run PyBaMM Within Simulink

Since MATLAB R2025a, Python code can be run in Simulink using the Python Code block. This block allows users to write native Python code and execute it within a Simulink model.

The Python Code block gives users the option to write Python code that is executed on model initialization, model step, and the termination of a simulation. Users are also able to define the ports and parameters for their Python code, which allows the block to interact with other blocks within Simulink and to parameterize the block as they would other blocks on the Simulink canvas.

In this example, we take a current load and output the voltage response of the PyBaMM simulation while also giving the user the ability to define the initial state of charge for the cell model.

Ports and Parameters

The ports and parameters are shown in Figure 4; parameters are defined as follows:

  • current_in is an input and defines the current load for the cell. In PyBaMM, a positive current input is used to denote discharging.
  • voltage_out is an output that will contain the cell’s voltage response.
  • StepSize is a parameter that will determine the fixed time step that the PyBaMM solver uses to step the simulation.
  • InitialStateOfCharge is a parameter that will be used to set the initial state of charge at the beginning of the simulation.
  • simulation is a persistent variable, which allows this parameter to remain in memory across different stages of the simulation.
Dialog box showing the ports and parameters section of the Python Code block mask.

Figure 4. Ports and parameters section of the Python Code block mask dialog.

Four of these ports and parameters are defined as “double” data types. They will automatically get converted to Python float data types. The simulation parameter is defined as a PythonObject because it’s a PyBaMM class.

Initialize

The “Initialize” tab contains the code that is executed once at the beginning of a Simulink simulation. We use this to define the PyBaMM model and to set initial conditions.

Dialog box showing the initialize section of the Python Code block mask.

Figure 5. Initialize code tab of the Python Code block mask dialog.

Here, we import the PyBaMM model and define the cell model to be used (in this case, an SPMe model). We create the PyBaMM Simulation object and store this in the simulation variable (defined as a persistent parameter). We then set the current function to be an input and set the simulation object to have our user-defined initial state of charge.

Output

The “Output” tab defines code that is executed on each step of the Simulink solver.

Dialog box showing the output section of the Python Code block mask.

Figure 6. Output code tab of the Python Code block mask dialog.

In this example, we update the current input with the latest value from the current_in port and step the simulation by the value defined in the StepSize parameter. We then retrieve the terminal voltage value from the results dictionary generated by the PyBaMM solution object and return the latest time series value through the voltage_out port.

Python Code Block Parameterization

In the “Ports and Parameters” section above, we defined two parameters for the Python Code block. These then appear in the block dialog parameters (see below).

Python Code block parameters dialog with fields for StepSize (0.1), InitialStateOfCharge (0.5), and sample time (0.1).

Figure 7. Python Code block mask after block dialog edits.

PyBaMM uses its own solvers for the simulation. Therefore, it’s important to remain in sync with the Simulink solver step time. In this case, we are using a fixed step solver with a 0.1-second time step (hence, we have defined the StepSize parameter as 0.1).

The Python Code block also has its own Sample time parameter. In this case, it also needs to be set to 0.1.

Running the Simulation

Once you have parameterized your PyBaMM simulation, you can then proceed to run the simulation as you normally would.

Example layout of the Python Code block in the Simulink canvas.

Figure 8. Python Code block in the Simulink canvas.

In our example, we are putting a 10 A load on the cell at 5 seconds into the simulation, starting at 50% state of charge. A positive current input value will cause battery discharge. This results in the voltage response shown in Figure 9.

Two plots showing voltage dropping after 5 seconds while current load steps up and remains constant until 10 seconds.

Figure 9. Current input and terminal voltage output time series from simulation.

This is the simplest configuration required to get a PyBaMM simulation running in Simulink.

Import PyBaMM Parameter Sets into Simscape Blocks

PyBaMM provides several predefined parameter sets for common battery chemistries, which are obtained from academic literature. Within PyBaMM, these sets are defined as class objects of type ParameterSets. To use one of these parameter sets in a MATLAB Simscape block, an “equivalent” Simscape electrochemical model block must be created first. In this example, a parameter set is imported to be used in the Simscape Battery Single Particle model with electrolyte block (TSPMe). This block is available within Simscape Battery.

In addition, a MATLAB script or object class is required that can:

  • Store the TSPMe parameters.
  • Perform the parameter conversion from the standard PyBaMM convention to Simscape.
  • Automatically parameterize the Simscape block.

As part of this article, we provide a TSPMeParameterSet custom object, which serves as a parameter container for the TSPMe block and can import the following PyBaMM parameter sets into the Battery Single Particle Simscape block: ["Chen2020","Marquis2019","OKane2022 ","Ai2020 "]. This class can be extended to use other parameter sets or to parameterize any other type of model (e.g., an equivalent circuit model or a P2D model). To import a parameter set, first define the required parameter set name in MATLAB:

ParameterSetName = "OKane2022";

To instantiate the parameter container object and import the PyBaMM parameter set, run the following commands from the Command Window:

SimscapeParameterSet = TSPMeParameterSet(ParameterSet = ParameterSetName);

Importing geometry parameters...Done.
Importing min/max stoichiometries...Done.
Importing OCP vectors...Done.
Importing electrode parameters...Done.
Importing electrolyte parameters...Done.
Importing electrolyte diffusion and electrolyte coefficients...Done.
Importing charge transfer rates...Done.
Importing thermal mass...Done.
Importing initial electrolyte concentration...Done.

The parameter container object now contains the specified parameter set from PyBaMM. To automatically parameterize a Battery Single Particle block from Simscape, run the following commands in the MATLAB Command Window:

modelname = "PyBaMM_Simscape_Example";
batteryBlockPath = strcat(modelname,"/","Battery");
open_system(modelname);
parameterizeTSPMe(SimscapeParameterSet, batteryBlockPath);

The code snippet above should have parameterized the Battery block in the Simscape example model.

Diagram of a battery model with load, plant, and measurements blocks.

Figure 10. Parameterized Battery Single Particle block.

Validate Simscape TSPMe Output

Next, you can validate your parameterization of the Battery Single Particle block by running a simulation using both PyBaMM and Simscape and comparing the output battery terminal voltages. First, define the load current and the boundary conditions:

BatteryCurrent = 2.5; % A
AmbientTemperature = 298.15; % K

PyBaMM Simulation

To run a PyBaMM simulation with these conditions, you first need to create and update a PyBaMM parameter set. To accomplish this, execute the following code in the MATLAB command line: 

PyBaMMParameterSet = pybamm.ParameterValues(ParameterSetName);
PyBaMMParameterSet.update(py.dict(dictionary("Ambient temperature [K]", AmbientTemperature)));
PyBaMMParameterSet.update(py.dict(dictionary("Current function [A]", BatteryCurrent)));

This PyBaMM parameter set also includes parameters related to the ambient heat transfer, so you can use them for both simulations. To extract these parameters for use in the Simscape simulation, execute the following code in the MATLAB command line:

CoolingSurfaceArea = PyBaMMParameterSet.get('Cell cooling surface area [m2]');
HeatTransferCoefficient = PyBaMMParameterSet.get('Total heat transfer coefficient [W.m-2.K-1]');

To run the PyBaMM simulation, execute the following code:

model = pybamm.lithium_ion.SPMe();
simulation = pybamm.Simulation(model,parameter_values=PyBaMMParameterSet);
solution = simulation.solve(0:10:3600*2);

Simscape Simulation

To run the same simulation in Simscape, execute the following code:

set_param(modelname,"StopTime","3600*2")
set_param(modelname,"SimscapeLogType","all")
out = sim(modelname);

As before, you extract the variables you are interested in from the PyBaMM solution object. Populate the solution data dictionary with your variables (in this case, time and voltage) before converting them to double data types that you can use in MATLAB:

variables = py.list({'Time [s]', 'Voltage [V]'});
solution.update(variables);
time = double(solution.data.get('Time [s]'));
voltage = double(solution.data.get('Voltage [V]'));

The Simscape out simulation output object contains the battery voltage and all other variables tracked by the TSPMe block. To create a comparison plot between PyBaMM and Simscape, run the following command:

figure;
plot(time, voltage, "o");
hold on
plot(out.simlog.Battery.batteryVoltage.series.time,out.simlog.Battery.batteryVoltage.series.values,"r");
grid on
xlabel("Time (s)")
ylabel("Voltage (V)")
legend(["PyBaMM","Simscape"])
Graph comparing two voltage curves over time, showing close alignment with a sharp drop near the end of discharge.

Figure 11. Terminal voltage comparison between the Battery Single Particle and PyBaMM SPMe.

Please note that the validation error varies depending on the applied C-rate and temperature conditions. The default Simscape TSPMe block does not contain concentration parameter dependence for diffusivity and electrolyte conductivity, which can be considered in the PyBaMM model. Therefore, you should expect a bigger discrepancy between terminal voltage values at higher C-rates.

Battery Cell-to-System Scale-up

To scale up our Simscape model from cell to system, use the Simscape Battery Pack Builder functionality. First, create a battery cell object and link it to the Battery Single Particle model block:

battCell = batteryCell();
battCell.CellModelOptions.CellModelBlockPath = "batt_lib/Cells/Electrochemical/Battery Single Particle";
battCell.CellModelOptions.BlockParameters.StoichiometryBreakpointsSpecification = "absolute";

After defining your battery cell object, scale up your cell model to the module level by running the following MATLAB command:

battPSet = batteryParallelAssembly(battCell,4, "Rows",4);
battModule = batteryModule(battPSet,4, ...
    "ModelResolution", "Detailed",...
    "AmbientThermalPath","CellBasedThermalResistance");

You can increase the model resolution by setting the ModelResolution property to “Detailed.” To automatically generate your battery model, run the following command:

buildBattery(battModule, "MaskParameters", "VariableNamesByType");

The code snippet above should have generated a battery library with your battery module model block as shown in Figure 12.

Image of a battery module model in the Simulink canvas generated with the buildBattery function.

Figure 12. Battery module model built using the Battery Single Particle block.

The parameters necessary to run this new model block are stored in the newly generated script: Batteries_param.m. To link the module parameters to the PyBaMM parameter set, run the following command:

Module1 = SimscapeParameterSet.getModuleElectrochemicalParameters(SimscapeParameterSet);

Using this newly created battery model block, you can now create and run a battery constant discharge simulation in the Simulink environment. In addition, you can use the BatterySimulationChart to visualize key battery variables dynamically across your simulation. To create and run the simulation, run the following command:

run("CreateAndRunBatterySimscapeModel.mlx")

Conclusion

In this article, we presented three different workflows for integrating PyBaMM battery modeling capability into MATLAB, Simulink, and Simscape. Each workflow has its own advantages and is better suited for specific activities. For example, integrating PyBaMM with Simulink is a good method for performing rapid prototyping and developing a battery management system. Importing PyBaMM parameter sets into Simscape is a good method for creating acausal physical models that can be scaled up efficiently and included in a wider electrical and thermal simulation. The scale-up from cell to system models can be done efficiently using the Simscape Battery Pack Builder functionality. This integration helps enhance the native capabilities of MATLAB and can add value to the different battery design and development workflows used in industry.

Future Work

The methods presented in this article are simple and rely on existing functionality. These methods can be refined and expanded to include more PyBaMM electrochemical models, support other parameter sets, and add complex system-level modeling, among other enhancements.

Moving forward, we will build on the workflows presented here by demonstrating how this integration can support practical battery design and verification activities. We also aim to explore other methods to establish connectivity between PyBaMM and MATLAB and present these in the context of the benefits they bring to the target battery application.

We see opportunities to showcase: 

  • Pack design and verification with module and pack-level systems for useful energy and power capability prediction under realistic thermal conditions
  • Enhanced battery system aging and warranty prediction relying on PyBaMM’s library of battery degradation models
  • Streamlined parameter-set usage from PyBaMM for a wider variety of Simscape blocks
  • How PyBaMM-based models can support controller development in Simulink

Acknowledgments

Special thanks to Professor Daniel Auger from Cranfield University for his collaboration, thoughts for areas of future work, and the several discussions we had on connectivity methods between MATLAB and PyBaMM with applications to battery systems.

References

Sulzer, V., Marquis, S. G., Timms, R., Robinson, M., & Chapman, S. J. (2021). Python Battery Mathematical Modelling (PyBaMM). Journal of Open Research Software, 9(1).

Published 2026

View Articles for Related Industries