Developing Battery Management Systems Algorithms
Overview
Electrification is driving the use of batteries across a wide range of applications and industries. These have different requirements for battery system design. In this webinar we will demonstrate how Simulink can support you from cell modeling to algorithm development and Hardware-in-the-loop (HIL) testing.
Highlights
- Cell modeling and battery pack design
- Battery management system (BMS) algorithm development
- Integrating components for desktop simulation and virtual testing
- Real-time simulation of batteries and production code generation for the BMS algorithm
About the Presenter
Eva Pelster is a senior application engineer at MathWorks. She holds degree in Aerospace Engineering from the University of Stuttgart. Her area of expertise is model-based design workflows and the application of physical modeling. Before joining MathWorks, she worked in a technical consulting company.
Recorded: 26 Apr 2023
Welcome to today's webinar. My name is Eva Pelster, and I'm an application engineer at MathWorks, where I focus on modeling, simulation, and model-based design. Today is the first part of a series. We will discuss how to develop battery management systems using MATLAB and Simulink.
Our main points for today will be how you can make use of Simscape to create battery models, how, based on that, you can develop and implement the Battery Management System, or BMS, in Simulink and Stateflow, and then we will have a look at how model-based design facilitates the verification, validation, testing, and deployment of those algorithms.
Why is this important? Well, batteries are everywhere, and their presence is growing. And we would like to address challenges in developing the battery management system from possible gaps in collaboration and long iteration cycles while developing a safety-critical system.
If you look at how a BMS development workflow could look like when working with Simulink, we can divide it into desktop simulation, real-time simulation, and hardware implementation. For the desktop simulation, the model would contain a plant model of battery, environment, circuits, and loads integrated with an algorithm model allowing you to perform intensive simulation-based testing early in the process.
From there, you can perform real-time simulation, which could be rapid prototyping, where your algorithms are running on a real-time computer without having the final hardware available. This is typically to test against the real system.
And you can also generate code from the physical model to run on the real-time hardware. This can be used to test against the final control hardware without having a physical prototype or without harming it. You can potentially also use the rapid prototyping system to test it against the hardware-in-the-loop setup.
And the final step is the hardware implementation. You can convert the previously tested control models into efficient and production-ready code for the BMS. If necessary, this can be incorporated into workflows that are compliant with formal certification standards.
Let's start by looking at how you can create a cell model and scale up into the battery pack. A common approach that is used in the context of controls development while being performant enough to use in real-time simulation is using detailed equivalent circuit models. They include a voltage source accounting for the open-circuit voltage of the battery. A resistor is representing the terminal voltage drop once a load is connected.
A network of one or more RC branches account for the time constants and frequency response of the battery. For some chemistries, parasitic charging losses and self-discharge are significant. However, these are minimal with lithium chemistries and are often ignored.
Finally, each of these elements in the circuit is a function of state of charge, temperature, and sometimes current or voltage. These relationships may be highly nonlinear, and the parameters can be lookup tables instead of scalar parameters for a higher-fidelity model.
One approach of representing these in a Simulink model is using existing Simscape components that represent the previously shown technique. The shipping components exist in a simpler version and a higher-fidelity one, which uses lookup tables.
Optionally, you can choose to enable a thermal model. And you can, when needed, include several modeling options, such as charge dynamics, fade, or calendar aging. Let's see what this looks like in an example.
Here, we see a test model which is incorporating the default cell block from the Simscape library. Through the interface, you provide circuit parameters and optionally add effects or change the number of RC branches that are being used to represent the cell.
Running this with a scenario where we are first charging and then repeating discharge pulses, you can see the model recreating the cell behavior, the voltage response to the pulses, as well as the changing SOC.
Beyond using existing cell blocks, you can also create your own custom models. These could be made up out of a combination of existing basic components, or you can start from scratch using Simscape language. So underneath the implementation of your own cell component could be a network out of basic components, as well as custom equations.
Besides the model structure, a common step in creating accurate models for algorithm development is to estimate the model parameters using measured data. If we look at a discharge event, such as a current pulse, there is a characteristic shape to the voltage response, and the model will have to accurately predict the voltage drop and the recovery.
There is one part of the voltage that is instantaneous, and there's a portion that is exponential in shape. And we will have to represent the decreasing open-circuit voltage as the cell is discharging.
If we look at the simplest equivalent circuit representation, we can adapt its parameters. The parameter should be selected so the instantaneous response, relaxation, and the open-circuit voltage behave accordingly. Here, the number of chosen RC branches will also inform the shape of the relaxation.
If we have collected measurement data, you can perform parameter estimation to achieve this. Here, the model with a certain set of parameters is reproducing results underneath the conditions that were used to collect the experimental data. The results of both are compared. And as long as they are not similar enough, this is repeated until we have satisfactory results.
For lithium chemistries, these elements are often modeled using lookup tables. For example, this table shows the open-circuit voltage against state of charge and temperature. This table would be populated with results of the parameter estimation process. And that should then characterize the battery behavior.
Again, let's see an example for that. In this example, we see a parameter estimation being set up for a single cell. Running the model for one simulation is creating results for the current parameter set.
The inputs are repeated discharge pulses. And this is being compared to experimental results. Since the parameters have not been tuned yet, we clearly see a mismatch between the simulated and experimental results.
Now, opening the parameter estimation tool is here loading a preconfigured session and opening the parameter estimation app. We see it already has been populated with the experimental data. The one RC branch equivalent circuit parameters have been selected to be tuned by the estimation. The interface initial values and boundaries can be defined here. All parameters are provided as tabular data.
The experiment section is used to define the input and output for one or multiple experiments that are being used for the parameter estimation. In the Estimation options, the session can be set up to use a parallel pool for speedup, and the underlying optimisation algorithm can be selected.
Running the session will start the parameter estimation process. Through repeated simulation, it is trying to tune the selected parameters with the goal to minimize the sum squared error between the simulated and the experimental results.
While this is running, the window is being updated with the current best results. And the Parameter window on the right-hand side is displaying the current parameter values.
As the simulation progresses, the simulated results match better with the experimental results. And depending on selected stopping criteria, the estimation stops, for example, once it hits its objective with a given accuracy. And if sufficient results have been found, this can be applied back to the model.
With a model that reproduces the desired behavior, before we move on to the algorithm development, we now want to scale the system from a single cell to the entire battery pack. For that purpose, we can use Simscape battery to assemble a desired geometry and stacking topology.
And the battery pack builder workflow allows us to use an app or MATLAB API to assemble cell models into modules and pack while defining the electrical and thermal connections. And along the way, we can select a grouping method to adjust the model fidelity.
Let's move to a MATLAB script that shows us this workflow. Here, we can see the script for going from a single battery cell to a pack that we can use for simulation. Step by step, this will build up parallel assembly, module, module assembly, and pack.
We start by creating an object for pouch geometry type cell, of which we can define geometric parameters and modeling options, such as thermal settings. Based on that cell object, we build a parallel assembly. Again, we provide options such as the number of parallel cells, geometrical arrangements, and model resolution, which will define the model fidelity.
Here, the chart is displaying the chosen configuration. The orange box marks the model resolution. Here, we have one electrical state for six parallel cells. And the next step, with a similar workflow, the module object is created out of the parallel assembly. Again, the relevant settings, such as number of series assemblies and model resolution and strategy, are defined within the command.
The chart again showing geometry and grouping properties of the resulting module. This approach is repeated for the modular assembly, building on top of the module object. Here, this is created out of four identical modules and series. And the last step is the creation of the battery pack. The resulting pack objects with a chosen grouping contains 96 cells for simulation.
To use this in simulation, this can now be converted into library blocks. The Build Battery command is using all of the information that is now in the battery pack object and, in the first step, converting this into corresponding Simscape language files and then creating a Simulink library out of those.
Here, we can see the resulting library blocks for the parallel assembly and for the module. The description is displaying information about the internal composition. The second model file contains the blocks for module assembly and battery pack.
Looking into the battery pack, I can again see its internal composition based on the choices we made. Within the library files, there's also a MATLAB script being created, which can be used to provide the proper parameterization for the battery component.
Besides defining the battery pack architecture, you can also make use of Simscape battery to model its thermal behavior. You can define the heat transfer between battery cells, the environment, and its cooling system. For this, you can make use of cooling peg components to control temperature variations and trade off pumping costs with cooling efficiency.
And Simscape battery also offers a library for BMS components. Among other things, it contains components for estimators, protection, and thermal management. Some of those we will also use in a later step.
The second part of our desktop model is the algorithm for the BMS. A BMS has to ensure the best possible performance while maintaining safe operation and optimal lifespan. And for that purpose, various functions are part of the BMS, such as state-of-charge estimation or cell balancing.
If we look at a BMS representation in a Simulink model-- this is the model we will also look at later-- you can see components for several tasks here, for example, the main state machine, SOC estimation, balancing logic, as well as charge and contactor management and fall detection.
If we look at the different state machines that are part of the BMS, they are, for example, defining the main operating status of the BMS or the charger and inverter on and off switching sequence. And all these that can be represented by state machines or similar logic are being implemented in state flow. We can see the animation of the active states as the state machines is being simulated for the contactor management on the right-hand side, for example.
Another important BMS functionality is the State-Of-Charge, or SOC, estimation. Since this cannot be measured directly, this relies on the measurement of other variables to estimate the state of charge.
Simscape battery ships with components implementing commonly used techniques, from a more simple Coulomb counting, which integrates the current, and additional options include the use of Kalman filters, which rely on a model of the unit cell to predict the SOC. Additionally, you can implement your own estimators, for example, based on neural networks.
This just to highlight some aspects of the entire BMS. To make use of the desktop simulation, we can integrate both algorithm model, as well as the plant model, and test this extensively on the desktop to see if there are any potential errors or to refine the design. Let's have a look at this model.
This model contains both the plant model and the BMS algorithm. And they are being simulated in a closed loop with the sensor measurements of the peg being fed back into the BMS functions.
Inside the plant model, we have components for charger load and precharger circuit. For the battery pack subsystem, there are two modeling options included. The currently active, higher-fidelity one contains the previously built peg configuration.
In the BMS subsystem, we see components for the different functions. For example, this subsystem calculates the updated current limits. Taking current cell voltages, it is determining the maximum current charge and discharge to avoid overvoltage. It is also taking the allowable temperature limits to adapt the current limits to avoid damage to the cell.
The algorithm model also contains several state machines, one for charge management, which is determining when charging at constant current and when at constant voltage. The contactor management defines the contactor on and off switching sequence for the charger and inverter.
Taking a closer look at the main state machine, we see it is defining four separate states-- driving, standby, charging, and fault. Depending on condition, different states will be active in path commands or values to other functions of the BMS. While the system is operating, it will define the state it is currently in and execute corresponding commands. Based on logical conditions, it uses transitions to define if the system is moving to a different state.
The two SOC estimation components contain several estimation approaches. One is using a neural network for estimation. The other contains two approaches-- Coulomb counting and an adaptive Kalman filter.
Here, for the purpose of comparison, several SOC estimation functions are included. The balancing logic component commands when single cells should access charge through bleed resistor to keep similar SOCs on all cells.
Let's now look at the simulation results. We have a scenario starting with driving and then going into charging mode. For six out of the 96 simulated cells, we see cell voltages and temperatures displayed. Since, in this model, a environment and cooling model is not included, we can only see slight variations in temperature.
As the balancing is active during charging, the cell voltages converge. During driving, the pack current is within the current limits. And as the system goes into charging, the pack current is close to the maximum charge current. The results allow us to assess the performance of the SOC estimation approaches.
We are still in the desktop simulation. And as I mentioned earlier, we can already make use of extensive testing capabilities in this early phase of development. And testing is crucial when dealing with a safety-critical system, such as a BMS, or a system that needs to be compliant with certification standards.
Looking at how the model-based design workflow can support that, if we break the development workflow into several steps, starting with requirements in textual form and design specification. Working with model-based design means that your model acts as an executable specification, which you can test and iterate on extensively. Based on that same model, you can move on to code generation. And the final step is compilation and linking.
In the model-based design verification workflow, you can use your model early for component and system testing or model verification. And you can perform code verification through code analysis tools and equivalence testing, all with the aim to gain complete confidence in your design.
Let's look at just a couple of tools that support this workflow in more detail. Our model in this workflow acts as the executable specification. And to implement requirements and test the implementation, we support, for example, the isolation of components to be tested, the setup and management of tests, as well as measuring coverage and generating tests for missing coverage.
Let's start with the first one here, the management of textual requirements. With the Requirements Toolbox, you can either start with requirements stored in a MATLAB external location, and the Import feature allows you to have the requirement items directly inside of Simulink.
As you make changes, you can synchronize these. And you also have the option to alter, add, or edit requirements right there. And the ReqIF support allows round tripping with external tools.
Let's look at an example for that. In the Requirements Editor, we can see both imported and created, or added, texture requirements, here divided into a section for BMS and state machine requirements. I can select any one of them and see a description and additional information, such as ID or existing links to model elements.
For example, in the state machine requirement, I could see one requirement, Implement Driving State, is describing a state that, while being active, should output the corresponding BMS state variable. This is linked to a previously seen implementation in state flow.
Opening up said state machine inside the BMS algorithm and then going into the Requirements perspective gives another view of the requirements. Selecting the same item here, I can again see the description. And I can see the model components it is linked to, the other driving state. Looking at that model component, it is also linked back to the requirements item.
Additionally, I can now activate the view on the implementation status. The size of the blue bar is indicating how complete my implementation of all requirements I have defined or imported are. In the next step, you can also isolate components into test harnesses and set up and manage tests.
Let's see how Simulink tests can support that. If we look at how to set up a test, let's say, for a model subcomponent, you would want to extract said component into a test harness. And the test itself consists of input, which could be signals stored in MATLAB or an Excel file or created as a test sequence. And with that input goes an assessment of the results, which, again, could be a comparison to a baseline or some logical expression.
And for simulation-based testing, you can run these in SIL, PIL, or HIL mode. And having already linked the model components to Requirements, you can also link them to test cases to track the status, not only of implementation but also verification. Let's, again, see an example for that.
From a model component, I can move to the test harness that is safe with the model. The test harness we already used for closed-loop simulation uses a test sequence block to define a scenario. It is using Stateflow-like logic to define a driving, balancing, and stop step of the test sequence. Depending on logic here, temporal logic is moving from one step of the testing scenario to the next and is outputting corresponding values to the component on the test.
Going back to the Requirements perspective, I can also gauge how many of the requirements have not only been linked to a component but also a test. The bar in yellow is indicating that the test has not been run yet.
Moving to one of the link tests is opening up the Test Manager. In that environment, I can create a managed suite of test or one test can be made up out of simulation settings, parameter overrides, assessments, or baseline comparisons, also depending on the type of test, which can, for example, be a baseline equivalence or simulation test.
Now starting the run for a subset out of the entire test suite definition, specifically the state machine test. This is running all tests in the background. Additional parallel computing can be used to speed this up. While this is running, intermediate results can already be checked.
The plots show which test cases ran successfully and if they passed. Depending on the selected assessment criteria, this is showing where signals have achieved our expected results. Going back to the Requirements perspective in the model window, the verification status for tests that have been run have also been updated.
To measure how extensively you have tested, you can now measure the model coverage and also aim to generate tests for missing coverage. You can generate coverage analysis based on your test cases to identify gaps in testing, missing tests, design errors, or missing requirements. This can be measured for different types of model components, such as Simulink Stateflow but also generated code.
If you have now detected gaps in coverage based on the manually created test, you can address that by automatically generating test cases to complete coverage. Using this, we'll generate additional test cases with the objective to achieve complete coverage.
Going back to our overview of the entire BMS workflow, we have spent all our time so far in desktop simulation and simulation-based testing. With those models, we can move on to real-time testing and simulation. This can consist of rapid prototyping and hardware-in-the-loop testing.
With rapid prototyping, you move to testing your control algorithms on a real-time-capable system. Starting with the desktop model of your algorithm, you can deploy this through code generation directly on Speedgoat real-time hardware and run this against the real physical plant. This allows you to test the system without your final embedded control arm and quickly iterate on your algorithm design. You can directly interact with the hardware and log data.
For HIL, or Hardware-In-the-Loop, simulation, this is where you use the real-time hardware to run an emulation of the physical plant. For this purpose, you go from the desktop simulation and deploy the physical plant to the target computer with the embedded controller running against this. With that, you can test your controller against the plant without having a real system prototype at hand but also without possibly damaging it, for example, when injecting faults into the system.
And the final step in the process is the hardware implementation where we move to code generation from the BMS algorithm. From the desktop algorithm model, you can directly generate C, C++, or HDL code that is optimized, compact, and readable. For back-to-back testing, you can reuse this for software or processor on the loop simulation.
Let's look at a quick example for that. In this example, I am generating code for one of the state machines. In this model, the configuration for C code generation has already been set up. Going to the C Code tab, you can start the process.
Once this is finished, there's an option of viewing generated code and model side by side. This contains hyperlinked comments, line numbers, variables and operators, allowing to switch back and forth and directly see impact of changes to the model.
Going back to the verification workflow with the generated code, you can perform SIL testing and, again, measure coverage. You can also perform code analysis with Polyspace, which works for both generated code and manual code. This workflow and its tools have been certified for standards such as ISO 26262. You can learn more about this on our website.
To sum up what we have seen today, we have looked at how Simulink, Simscape, and model-based design can support the development of a battery management system, starting from creating a battery model, implementing the algorithm, to full model-based design with automatic testing and code generation.