Best Practices for Building Large Models from Components to Complex Systems
Brad Hieb, MathWorks
Erick Saldana Sanvicente, MathWorks
Model-Based Design processes are well established and have been in use for over two decades. With increased complexity of components, systems, and their interaction with other systems and infrastructure, model sizes are increasing, and implementation challenges are growing. In this talk, get an overview of best practices for dealing with these challenges:
- MATLAB Projects: Automate routine tasks, mistake-proof parts of your work, and integrate source control into MATLAB® and Simulink®.
- Components: Optimize Simulink componentization for simulation performance, testability, parallel development, and code generation.
- Interfaces: Define interfaces between components to speed up development and improve performance and code generation.
- Data Types and Parameters: Manage storage for private and shared data types, parameters, and configuration sets.
- Variants: Control design alternatives for data, components, and products via variants.
- Performance: Improve initialization and simulation performance with built-in tools in Simulink.
Published: 14 May 2024
So welcome to our session on Best Practices for Large-Scale Modeling with Simulink. So in the next approximately 25 minutes, Erick and I are going to take you through some of the issues that we hear from customers who are building and using large-scale models. And then we're going to review some of the best practices that we've accumulated over time to kind of deal with those issues.
Now, as you're wondering, we have 25 minutes. This is a very complicated topic. So our goals with this are fairly modest. So we want to do three things.
First, we want to make you aware that these best practices that we're going to talk about exist. Then we want to give you some information on where you can find them, where you can learn more about them. And finally, we encourage you to talk to us if you want to discuss any of this stuff we're about to talk about in more detail. Because obviously, we can't cover it in that kind of time.
So we're going to base our talk today on the activities at a fictional automotive company called Misfire Motors. So their goal is to design and simulate the most sophisticated vehicle in the world. And they gave us this nice marketing slide here that we could use. So there you go. You can take what you want from that.
Now, these guys started off pretty simple. They started with a simple model that they use to do some development. They quickly found that it was very useful. A lot of their engineers could see the benefit of a modeling approach and a model-based design kind of process. So they quickly started adding more capabilities, and the model grew in size and complexity.
Unfortunately, though, as they were doing this, they had so much pressure to deliver things on these really tight timelines that they just didn't take the time to put best practices into play. And they suffered several, I would say, challenging issues.
So the first one from model architecture point of view is they were developing and putting all their content into a single model file. And that thing got gigantic-- hundreds of thousands of blocks in there.
Second thing, from a data management point of view, is they were putting all their data in the base workspace. And we'll talk more about that in a while. Third, they had interfaces between components in the model that were hard to read and made the model difficult to understand. They had no real file management strategy at all. So that was a big problem for them. And finally, they suffered from poor simulation performance.
Does any of this sound familiar to you guys? Did I see any-- one or more of these? Anybody?
Yeah.
Yeah.
Yep.
OK, good. I was afraid you guys were going to say, nope. We got it. We're good. OK. All right. Fair enough. All right. So let's start talking about-- now that we've heard what kind of issues they've faced, and it sounds like these things are resonating with you guys, what do we do about them?
So the first one, the model architecture question, is they just didn't have one. So they started off pretty simple, as I said, and they were putting things into this single model file. And they had heard about doing componentization with reference models.
They looked into it a little bit. But they're like, oh, man. There's different ways of doing it, and we're not sure where we should do this technique or that technique. And they're always under this time pressure that I mentioned. So they decided we're just going to keep doing what we do. They put everything in a single model.
So Erick, I'm going to turn to you for this one. What-- I know you've done a lot of experience with model architecture kind of discussions at MathWorks and in your previous experience. What would we advise companies like Misfire Motors to do instead of what they're doing now?
Hey, Brad. Thanks for introducing us to Misfire Motors and their challenges. So as you already assume, this might be an imaginary company, but these questions and challenges are very real.
And hey, we get it. There is no universal answer. The complexity of these models and the requirements cannot be easily summarized in a table like the one I am about to show you. However, we have noticed that some components align better with certain use cases. So we want to show you that.
By the way, don't worry about taking pictures or making notes of this table. This table, along with this whole slides and an extra set of slides is going to be available to you at the end of this presentation in what I like to call the director's cut. We only have 20-something minutes, so we can only give you so much right now.
Anyway, with that out of the way, let's look at some of these use cases. For example, if you want to visually organize a group of blocks or components, we would recommend an in-model virtual subsystem. If you're looking to create utilities that change infrequently and are widely reused, a link subsystem, also known as libraries, is the way to go. And if you're looking to develop or simulate a component as a standalone model, then model reference is the option.
And speaking of model reference, it is the key to large-scale modeling componentization. There are a few reasons for this. The first is that it enables parallel development. Because with Simulink, you can develop your components as independent models.
So you will have independent slx file that is fully functional, fully simulatable. So in the case of misfire models, this meant that their engineers were now able to focus on their own components without worrying about tripping on each other's heels, trying to modify this huge slx file that they had before.
And then these models can be placed, as we say in MathWorks lingo reference, inside other models for easy integration. This enables a few things, and I want to highlight two of them.
First is the decrease build time when they are reused. So if you have multiple instances of a reference model, it will reduce the build time. And also, it enables the use of accelerator and rapid accelerator modes that Brad is going to explain a little bit later in the performance section. So back to the challenges of Misfire Motors for now.
Right. So thanks for that, Erick. So that explanation made sense to me, and it made sense them. So they ended up going and adopting that. So they started componentizing their model.
And after they were doing that they-- well, first, let me back up a second. I want to back up to the second problem with the data management thing. So as I mentioned before, they had put all their data in the base workspace.
So when they started out, their model was pretty simple, and they didn't have tons of parameters. So that worked for them. But as they started piling more stuff in, they had basically just more and more data accumulating. And they were storing it all in a single m-file, if you can imagine. And that thing was just getting huge, huge, huge. And it just became untenable.
So as they were looking around, looking for solutions. So like, hey. We just listened to Erick. He was telling us about componentizing. We're already doing that. Maybe we should do something like that with our data.
And Erick, I know this is front and center for you. You've been doing a lot of this kind of conversations with customers this past few months. What would you recommend for these guys?
So in this case-- I mean, we get it. The base workspace has several use cases. For example, if you're doing informal workflows, quick parameter tuning, rapid prototyping, if you have a single developer, or if you need universal visibility of your parameters. However, it has some drawbacks.
For example, the base workspace is cleared every time that you close your session. So you have to save it either in an m-script or a .mat file. And you have to be very intentional about making changes here.
Usually, we recommend data dictionaries when you want to work with large projects, distributed development, or scoped data. And Misfire Motors had the question, what is it about these data dictionaries that is so great for large-scale modeling? Well, there are a few things. We are going to cover three of them right now.
First, inherent data persistence. Simulink data dictionaries have their own dedicated file format, that .sldd file. So you do not need to worry about having to save your changes every time. And because this is separate from both the base workspace and the model, it allows for easier data organization.
So you can partition your data. Instead of having this huge monolithic thing that goes into a single mat file, you can partition it into multiple .sldd's. And then you can make reference to smaller .sldd's as you need them.
This also means that sometimes you might have things like name clashing, where you have two parameters or two signals with the same name in two separate .sldd's. But the good thing is that you will get warnings so you can get on top of the situation quickly.
And lastly, you have change tracking workflows. So you can see the changes. When was the last modification? Who made the last modification? So then you can show, revert, diff, and save these changes as you go.
And the last piece of advice that we had for Misfire Models is, hey, we get it. Switching from base workspace to data dictionary seems like a daunting task. You don't have to do it all at once because they can coexist. So you can slowly migrate from the base workspace into these multiple data dictionaries as your project scales up and then stop accessing the base workspace completely.
All right. Thanks for that, Erick. So the Misfire Motors engineers, they liked what you were saying, and they ended up taking his advice. They componentized their data, kind of in an analogous way to how they componentize the model structure, into a collection of Simulink data dictionary files.
But after they did that, then they started focusing on the next problem, which is their interfaces that made things hard to read. So again, they started off with this big single model. And they decided, well, let's partition it into some virtual subsystems to try to make it a little easier to understand.
But what they ended up doing then is interconnecting all these subsystems with just individual signals. And they had literally hundreds of them going in and out. I know this happens a lot, right? And because they did that, it was just hard to read and understand.
Then they componentized, as Erick was explaining, and they used that same interconnect philosophy, and the model was still hard to understand. So they're like, OK. What do we do now? So Erick, can you kind of help them out?
Yep. So I like this one because, at least in my mind, this one is easy-- just busses. At a minimum, when they are virtual, busses allow you to combine multiple signals into a single line.
So, for example, in this case, we have the fault detection component that takes in 11 different signals. But actually, many of them are related, and they are produced by just a handful of components.
If we look at the first four-- maximum cell voltage, minimum cell voltage, minimum cell temperature, maximum cell temperature-- they are all produced by the same model. So what we could do is package them into a single bus that we can call MinMax cells, and then feed it to the fault detection component.
If we do that with the other three categories of signals, then we will end up with only four busses feeding into our component. And this is much more readable and still conveys most of the information that we need.
Now, this might look like an oversimplification. You're probably dealing with hundreds instead of dozens of signals. And unfortunately, we do not have the time to go into all the details on how you can address this right now.
But the good thing is that in two weeks from now, on May 14, we're going to be kicking-- we're going to be starting a series of webinars that go deeper into these best practices. The first one is actually going to be componentization and interfaces. So then we will take the time to go into the details on how to go about using and leveraging busses. But for now, back to you, Brad, to hear more about Misfire Motors.
Right. So again, they like what you're saying. They really trust you by now. So they went ahead, changed their interface specs. So they packaged signals into buses. And they thought, yeah, this really helps. It really cleaned it up. So they're pretty happy.
But-- and there's always a but somewhere in a talk like this-- they followed our directions and componentized. And now they started-- they went from very few files when they started to a whole bunch of files. And as you remember, they didn't have any file management strategy at all.
So what they would do at the beginning-- again, small number of files. When they'd make changes, they would add a version number to the file name. Or maybe say something like model name underscore final, that kind of thing. People have done-- so this happens.
So they just didn't have a way of dealing with all this. And they're kind of looking at us saying, well, you told us to do all this. And now we have all these files. What do we do?
So I know, Erick, you and I have been talking a lot about this. We've even been doing presentations about it to a few customers. What should they be doing now to fix this?
Right. So we get it. And fortunately, there's a solution for this-- MATLAB projects, formerly known as Simulink projects-- which will be automating the little things, so you guys have the time to focus on the real important stuff. And there are a few ways in which this will happen.
First, when you're using a project, it will set up the path for you. And you can also configure the startup and shutdown files so that the environment is always the same every time that you open your project. It also allows you to launch common files whenever you open the project.
So if you're always opening the same top level model, you don't need to do that by hand anymore. You can just shove it into the project and it will happen every time that you open. One of my personal favorites is that it allows you to create shortcuts to commonly used tasks that will go into these dedicated shortcuts tab.
So I probably don't need to tell you this. It's not only the sheer number of files that you will have. It's also that you will probably be dealing with a complex folder structure where you have to constantly be looking down three levels to find the file that you need. If you create a shortcut, then you can avoid doing that. And projects are also about mistake-proofing your work. There are a number of features that help you with this, but I want to highlight just two of them.
First, shadowed models and libraries can give you an expected result. So the project will find them and will warn you. And I don't if this has happened to you. It has definitely happened to me, that I'm working on a project that has some libraries, some references. And then I get this result, this error about some interfaces not matching. I open my model. I'm staring at it, everything matches. So what's going on?
10, 15 minutes later, I go, I look at the path, and it turns out that there's a model with the exact same name that is just higher in the path hierarchy. And I just wasted some time looking for this. If I was using a project, this would not have happened.
Next, unsaved changes risk losing work or getting confusing results. So the project will always ask you to confirm. Hey, Erick, are you sure that you really want to close me with these unsafe changes? And again, this has happened to me.
It's 11:00 PM the day before the release. I'm tired. I've been working like crazy to make sure that everything works. And it finally did a few minutes ago. So I push my changes. I close everything. I go to sleep. Next day I come back. The PM is calling me. Everything is on fire because the results do not match what I did last night. What happened?
Well, I was tired and I closed the project, and I closed MATLAB while I had some unsaved changes, and now we have to go about fixing it. With the use of projects, this would be harder to happen. So these are the little things that projects can do that in the long term, between you and your whole organization, is going to save you a lot of time.
And just to close out this topic, I want to say that managing projects-- managing source control with projects is even easier. So if all you're going to do is your run of the mill operations, like refresh, pull, commit, push, or seeing the branches, all of that is available to you right in the MATLAB GUI.
Of course, you can still use a third-party version control tool if you want to do more complex operations. But if you're just doing regular stuff with MATLAB all the time, you have it right where you need it. Back to you, Brad.
Yeah. Thanks, Erick. All right. So these guys at Misfire Motors listened to him, adopted projects, tried it out and said, wow, this is a lot easier than we thought. And they were able to get all of this file management stuff magically under control. So it's really great. In fact, they've taken so much of your advice I'm surprised they haven't tried to hire you by now. I mean, come on.
So let's move on and talk a little bit about performance. Now, up to now, we've been focusing on best practices that are dealing with structuring your model and your datas-- and your data sets, managing your files, and basically trying to streamline your development process to set yourself up for long-term success.
At the same time, though, people want their models to run as fast as possible, initialize as fast as possible. I'm sure you would agree. And we often get calls from customers asking us to help with model performance issues that they're having.
Now, we have some engineering resources at MathWorks that can help. We've got technical support and application engineering teams. We can meet with customers. We do this a lot-- analyze the models, look for performance bottlenecks, and make some recommendations to fix them.
We have a consulting services organization. They can take that much further. They can come up with customized solutions to very challenging performance issues. And another thing they're very good at is once they've come up with these recommendations, they're good at automating the implementation. So sometimes if you have big, large model assemblies, and you have to manually change things, that can be pretty tedious. They can automate that stuff typically.
So, as I said earlier, the Misfire Motors engineers, when they started off with their original model, it was not too performant. So they instituted all the componentization things. And they noticed initially that, gosh, when the model initialized, it's already a little bit faster after they componentized. And they didn't really understand that, but they wondered why.
Then, they also asked us, well, we still like the thing to simulate faster. So what can we do about it. So let's take a look here in the next few minutes at some typical simulation performance analysis tools and techniques that you can use to address these problems.
So when we start any typical kind of performance analysis, we'd probably start off with running Performance Advisor. And what that'll do is check for model configurations and even modeling patterns that can slow down performance.
Next, we'd probably run MATLAB Profiler. And what this is good for is if you've got MATLAB code embedded in your model like callbacks, which most people do, this thing is going to measure how long that code takes to run. And then you can kind of identify hotspots and use that to help your initialization time-- maybe take some time out of that, get it to run faster.
If you're interested in speeding up your simulation time, we would then use Simulink Profiler, especially if you're using a fixed-step solver. And what that does, it's analogous to MATLAB Profiler, except it measures the time it takes the Simulink model to execute all the various components, subsystems. And then you can use that information to find hotspots and try to speed up your simulation time.
If you're using a variable step solver, we would also add in Solver Profiler. What that does is it looks for issues. Or places in where the simulation is slowing down, it'll identify things that the Solver might be doing that are affecting your simulation performance, like really small time steps. We've seen that a lot. Or maybe there's a whole bunch of Solver resets happening in different spots. It'll find those and give you suggestions on how to correct them.
Now, if you're having trouble, like me, remembering what all these tools are, where they are, when to use them, we've got this Simulink Performance Guide that we recently developed. And it'll help you-- think of it as like a cheat sheet. It'll help you start and complete these performance analysis projects.
Now, you can get it by scanning that QR code on the slide. And you can come to our booth in the exhibit area. We've got the same thing-- image up-- so you can get it there, too. So don't worry about doing it right now.
OK. Now-- oh, let me hit the back button. A couple of things-- I'd just like to point out two more little features, two more, I should say, not features, but capabilities that you can sometimes use to improve your model initialization time. Doesn't work every time, but I think it's worth mentioning them.
So when you componentize into reference models, and I think, Erick, you mentioned that before, you can use this technique called Accelerator Mode, Rapid Accelerator Mode. So in Accelerator Mode, what Simulink will do for that particular component is generate C code and compile it. And that we do that so that it'll initialize and simulate faster. So that's a clever thing to do.
Now, when Simulink does that, it stores that precompiled version of that component in a cache file. So cache files can be your friend. You need to definitely look into doing that.
When the model initialization stage happens, Simulink is going to scan all the available cache files. And any of those precompiled components that are in there that are up to date, it's going to just load those very quickly. And any that are out of date, it will rebuild. Now, that process we call incremental build.
So if you can get to the point where you've minimized the number of rebuild opportunities and maximized the number of, hey, it's already built and up to date, this can have a very big impact on improving your initialization time. But it relies on you having componentized your model.
And if you remember back when I said the Misfire Motors engineers, the model was componentized. And they went, hey, you know, it's initializing faster. Why is that? It's this. This incremental build is what did it.
Another thing you can use to speed up initialization time is Fast Restart. So this is a tool that you can use only under certain conditions. And that is I'm probably going to make-- or if I'm going to make lots of simulation runs in a given MATLAB session, and I'm not going to make any structural changes to the model-- just changing data-- then I can use this.
So what it's going to do is first, the model is going to have to go through its regular initialization time. So you'll pay that price once. So whatever time it normally takes you, it will take here.
But the beauty is Simulink will then be able to remember that compiled state. So that the next time you hit it, it'll start up almost instantly. So an example of that real quick.
We had a model that we ran, turned on a fast restart. And if you can see the highlighted, the top highlighted number, that was the initialization time the first time-- 5.65 seconds, if you can see it in the back. Then we hit Play a second time. The initialization time went to 38 milliseconds. That's what I mean by fast. So under these special circumstances, it's a click of a button. It's very effective.
Now, just to convince you that these techniques, best practices that we've been talking about actually work, here is an example of some performance optimization that our consultant services team did with a real customer model-- not Misfire Motors, but a real deal model.
So they used those same performance analysis tools that I talked about at the beginning, you know, the MATLAB Profiler, all that bit, and analyzed the customer model, found some opportunities for optimizing. They turned on accelerator mode in some select locations, were able to optimize the model.
And they took the initial models, which you can see in this really tall bar chart. You're probably guessing that. It was like 160x real time-- slower than real time.
After they did some initialization-- or optimizations, I should say-- they got it down to that really tiny bar on the right there-- 2.4 times slower than real time. It's a 67 times improvement. It's pretty dramatic. They're not always-- your mileage may vary, of course, but these things do work. So hopefully, I made that impression.
So that kind of wraps it up for the Misfire Motors guys. We've gotten them all squared away. Now what we need to do is turn our attention to going away from the fictional world and seeing how can you learn about and use these things in your real-world problems. So Erick, can we--
Yeah. So OK, let's speed run through this so you can get to lunch soon. If what we're saying is making some sense to you, if you are curious to learn more about these things, well, we have good news. Because, as I said, we're going to start a series of four webinars that we're going to be running on Tuesdays. By the way, these are free. You can register using this QR code.
So the first one on May 14 is going to be componentization and interfaces. Then on May 21, we will talk about what will MATLAB projects do for you. On June 4, we're going to be focusing on how to manage model parametric data in Simulink. And we'll wrap things up on June 11, with a talk on how to improve performance in Simulink simulations.
And, as we promised, probably what feels like a very long time ago, if you want to get these slides, including an extended version with more information on where to find best practices, you can scan this QR code, and you can use the passcode MACNA2024-- all caps-- to get these slides.
If you're having any issue scanning them now, or if you want to discuss some specific topics with us, we're also located right next to the entrance of the exhibit area. So you can come talk to us. We'll be happy to share this information or anything else that you might need from the large-scale modeling perspective.
Now, if you want to reinforce the knowledge about best practices, well, more good news because we have training available. So there is the Simulink Model Management and Architecture Training. That is a two-day course in which a trainer from MathWorks will show you how you can apply all these best practices to your organization.
So, lastly, we just want to take a minute to reflect about how we can go about avoiding Misfire Motors' mistakes. First of all, as Brad already mentioned, these best practices are available to you. Hopefully, this presentation serves as a gateway for you to find them. And we also have the webinars available. And all of this is great, but there is no replacement for training. Both foundational and advanced training is available to you.
I had something prepared to say here about MathWorks application engineering and how good it is, but I'm just going to remind you that Nate said it a few minutes ago. Brad helped them a lot with these things.
Application engineers are your friends. Talk to them. They will sit down with you. They will demo products and features. And they will help you identify and hopefully overcome some bottlenecks. Whenever the challenge is too time-consuming for the application engineering team, consulting services can help you get the model to where you want it to be.
And the last thing that I want to mention right now is, hey, there's maybe a couple hundred of you sitting right now in front of us. We know that we cannot reach everyone personally.
So if these things make sense to you, if you think that they will help you improve your modeling practices, we ask you to share them with your colleagues, your whole organization, even your suppliers, so that more people start adopting best practices, and the whole NBD process in Simulink becomes easier. Thanks.
[APPLAUSE]