Code Generation with MATLAB and Simulink for Student Competitions - MATLAB & Simulink
Video Player is loading.
Current Time 0:00
Duration 1:04:10
Loaded: 0.26%
Stream Type LIVE
Remaining Time 1:04:10
 
1x
  • Chapters
  • descriptions off, selected
  • captions off, selected
  • en (Main), selected
    Video length is 1:04:10

    Code Generation with MATLAB and Simulink for Student Competitions

    Overview

    This webinar will provide an overview of how teams can take algorithms they have developed in MATLAB and Simulink and generate C/C++ code for use on embedded controllers. We will start by covering the basics of preparing a model for code generation, why code generation can prevent introducing bugs, and how it fits in to a larger model based design workflow

    Highlights

    • Preparing MATLAB functions and Simulink Models for Code generation
    • Targeting hardware for deployment
    • Tracing Code back to model elements

    About the Presenter

    Sam Reinsel joined MathWorks in 2018 as in the engineering development group and has been on the Student Competition team since 2020. He primarily supports automotive student competitions in the US and Europe. Sam holds an M.S. in Mechanical Engineering from Virginia Tech, where he worked on EcoCAR for 5 years.

    Recorded: 14 Apr 2023

    All right, so what are we talking about today? We are, oops. Today, we are continuing our vehicle modeling and simulation live sessions. We're going to be talking about code generation with MATLAB and Simulink. We're going to talk about a bit of the why and what of code generation. We'll talk about hardware and deployment to hardware a little bit, but code generation in Simulink doesn't necessarily require that you know what hardware you're deploying to when you start.

    So if you saw the previous session with Veer and I, then you probably recognize me but my name is Sam Reinsel. I'm part of the Student Competition Team here at MathWorks. I support competition called Eco Car as well as some of the formula student events and the American Solar Challenge as sort of my primary one. So all automotive, pretty much everything moving electric, but my background is in hybrid electric vehicles. So I have some experience with the non-electric side of the house as well.

    So if you missed our last two webinars on vehicle dynamics simulation and visualization or electric vehicle powertrain sizing, there should be recordings up. If they're not already up, they will be pretty soon as well as this session and the ADAS session that we have in about two weeks here will also be recorded, and they'll be posted later. So if you miss those two sessions, or you're not going to be able to attend the ADAS session, then you can watch the recordings later.

    But this is our third of four for this round. And yeah you can, sorry, cat's trying to cross in front of me again. So with that, we'll go ahead and actually get started with what is generation? Because obviously, when we're working in MATLAB, we're working in Simulink. . We are writing code in MATLAB, it's actual text that we're writing. But in Simulink when we build a model of our control system, we're essentially writing code just in block diagram form.

    So when we talk about generating code, what we really mean is we're going to use Simulink here just because it's the easy way to explain it. But we build up on say, a simulation model in Simulink. It might be really simple like this, where we've got some stimulus to the system or some target that we want to hit. And then we take some feedback from the actual system, and we have an algorithm that we're using.

    It could be a PID. It could be a whole suite of different controllers and diagnostics that we've coded up in Simulink. And then the output of that algorithm is going to go to the environment or the plant model. And really what these are is our algorithm is what we're going to want to deploy onto a microcontroller or some sort of hardware. It might not necessarily be a microcontroller itself. And our environment is in this case, our vehicle, our car, boat, plane, whatever it is that you're building for your competition.

    But I think we're going to stick with the car example because it's what most of you are probably working on. So when we talk about code generation, there's sort of two sides of it. One is a little more easy to apply everywhere just because it's more in line with what you're probably wanting to do, and that's taking that algorithm that you've written in Simulink or written in MATLAB and generating code that can be deployed onto your controller.

    That might be a standard board like a Raspberry Pi or something. I've got a couple random stuff sitting on my desk right now. But it might be a custom board that you've kind of designed that's using a cortex M-series processor or something. Ultimately, you want to get code that you can compile for that to actually run in your vehicle. So the primary thing we're talking about is generating code from your algorithm to actually run in your vehicle.

    But there's also the other side of it really is that it might not necessarily be stand alone. Depending on the board you have, it might be possible to actually link up and through Simulink, do what we call processor in the loop or external mode. There's a couple of different ways that you can kind of hook up to it. But we could actually with processor in the loop or what we might want to do is actually still have a simulated model of our vehicle but have our processor hooked up to our computer and actually execute the code on that processor.

    So that way, we're not just generating the C code, we've actually compiled it and deployed it onto the processor. And we can test without a vehicle if everything's going to execute OK if the optimizations that we might need to make when we transfer from Simulink to C code are set up properly for our controller. The other side of code generation that I think is a little outside the scope of most competitions is hardware in the loop testing.

    So this would be, you've got your controller with your algorithm code in its final form. You're not hooked up to that through Simulink or anything like that. And you connect that to a real time machine that's actually running C code or HDL that's been generated from your vehicle model. In the industry, this has done a lot because you don't want to have to test every change to your code and verify that your controller is working 100% in vehicle, because vehicle prototypes are expensive and limited.

    So this is a really big part of what industry does to verify that the code that they've generated and deployed onto their production controllers is fully functional. But it's a little outside of the scope of what most student competitions will do, so we're not going to really go into hardware in the loop here in part because it's sort of its own beast that we would have to cover of all of the different ways that you can do it and what the strategy is.

    So we're going to focus on taking your algorithm and generating code from it to deploy. But it's an important part of the industry workflow. So I thought it would be good just to mention it. Really what we're talking about here, especially in the context of student competitions is you've probably built some model of your vehicle or your algorithm, and you've gone back and forth to simulate it and kind of determine is this a good model? Is this a good control algorithm for our system?

    You've made changes to it. You've gone back and forth and kind of figure out, OK, this is pretty good. After doing that a couple of times, we want to deploy that code onto a piece of hardware that we're going to have in the vehicle and actually go out and test it. But we want to catch as many problems as we can before we do the code gen in the modeling stage because we can, in the time it takes me to go run one test on road in a vehicle, I can probably run a couple dozen simulations or more of my vehicle.

    So a lot of this is about saving headaches, saving time. Because doing it in simulation whether it's your algorithm or your plant model can save us a lot of time debugging problems that we could have caught earlier on hardware and then code generation, this moving from the model to the embedded code, whether that's like a battery management system, or a motor controller, or anything like that.

    The goal is that if we test it an algorithm and simulate we don't want to have to then re-implement that and rewrite it in see when we can just have Simulink generate that C code for us to deploy to our hardware. And although most of what I'm talking about today, actually, pretty much all of it, and what I've mentioned so far is C and C++, that's done with MATLAB and Simulink coder with Embedded Coder. That's sort of an extra layer on top of MATLAB and Simulink coder where you can customize a lot of the code generation options to match the hardware you're using.

    So if there's certain math libraries or something that you want to use that are supported by your target hardware, you can tell Embedded Coder that ahead of time. And it'll build the code with that in mind. You can also from Simulink generate HDL for FPGAs. We're not going to talk about that much today but it's another option. And for some really specialized models especially stuff like Simscape, if you were to deploy that, you could get a higher fidelity simulation in real time on an HDL setup than you could in C or C++.

    And then I don't think anyone's using this for student competitions, but there's also structured text for PLCs. And something that's becoming more and more interesting across a bunch of different competitions, we can also generate GPU code in the form of CUDA for NVIDIA GPUs. So there's some embedded options like the NVIDIA Jetson that are out there that have an embedded CUDA processor, so we can generate CUDA for that for computer vision or machine learning tasks, that kind of stuff.

    We did talk about this a bit in a live stream that we did on the MathWorks YouTube channel if you go back to some of the live streams from last year. So we're not going to talk about that much today if at all. We're really going to focus on how do you actually generate code from MATLAB and from Simulink and inspect that code. Because it's not a black box, right? Once it's generated the code, you can go take a look at it. You can modify it if there's things that you need to change for your specific application.

    If you want to check if the hardware you have is supported, there is an entire page on a website dedicated to hardware support. So I'm going to just click that and drag it over here. So if you already know what hardware you have, you can always search for it. You can explore by vendor, or there's a bunch of nice lists here of different stuff that you might be interested in. And it's not just stuff like C 2000s, Arduinos, Raspberry Pis. There's also a lot of hardware that you might have for interfacing MATLAB.

    So for example, if I look for Curvasar, that's a can to USB, or there's a couple of different options. It's not all USB device that we can actually connect to MATLAB and Simulink directly. So this isn't necessarily code gen related, but it is hardware related. If you want to say interface with a canned bus from MATLAB and just read data straight off of it, you can do that using this. And in one of our past webinar sessions, not the current round, but from a previous year, we talked about canned communications some.

    I think we had a whole session on it. So you can find that on our webinar site. But really, the interesting stuff for us today is stuff like, if we go to ARM, the support package for Cortex A, ARM Cortex A processors for Embedded Coder or ARM Cortex M, there's a whole list of them. Beagle Bone, if you've ever used one of these, we can connect to that using Embedded Coder.

    So if you've got a piece of hardware, or you want to see if there's an optimized set of support for specific processors that you might have or specific boards you have, definitely go check out the hardware support site. The most of the examples I'm going to go through today are models that we've got on GitHub and the File Exchange. So if you want to go grab them from MATLAB itself, you can find it in the add on Explorer.

    But if you want to actually clone it from GitHub, you can do that as well. A quick walk through just of what this is. This is from a much longer form code generation training that we made a couple of years ago. And it's still updated and up to date for MATLAB now. But what it actually does is it's got two different algorithms that it looks at. And it's a little computer vision E. It's not really deep in computer vision.

    But what the demos it does walk through is, it's got a Raspberry Pi that's running some computer vision. And really all it's looking for is like a tennis ball. So it's just doing it based on the color. It's looking for a big green circle. And the webcam that we use in these demos is sitting on top of a motor, and the motor we control through an Arduino. And we program all of this through Simulink. So we'll kind of get to that as we go into the software demos.

    But just to be clear, you don't actually have to do it this way, and we'll talk about that. You could do the entire thing on a Raspberry Pi or instead of an Arduino, if you've got C2000 or something, you can take the same models and deploy it onto other hardware, and we'll kind of talk about the advantages of the ways that we set up this model to be pretty flexible.

    So I'm trying to keep it pretty light on slides just because there's only don't want to get a death by PowerPoint. So what I've got now is those files from our File Exchange post. I've got them actually cloned from the Git Repo because I'm one of the maintainers for this code. But the way it's packaged is in a Simulink project. So I'm going to go ahead and open that. It's going to add all of my different chapters and stuff from the video series to my path so I don't have to mess with that later.

    The first thing I kind of want to talk about, though, is generating C code from MATLAB. There's a couple of different things you might want to do here. Maybe you're prototyping, and you want to just write code really quickly, use a bunch of the built-in functions in MATLAB. And you want to just test it out. And then you decided all right, that's great. It works well. But I want to generate C code from this and deploy it to another machine, or I just want it to run faster.

    So what I've got here is, let's actually run the script first. So this is going to open up a video of some buoys just on the water. And it's just doing some really light computer vision algorithms. It's not that complicated. I don't want to get into the actual computer vision that it's doing. Because we're not actually interested in that here so much as we are how do we go about generating code from this.

    So if I click Run, it's going to open up this video player. And you can see, it's just looking for these buoys and circling them in the actual video. Maybe the video player part isn't as interesting to us for from a code gen perspective. But maybe we want to take this detection part and spit it out into C code that we can run somewhere else. So when you want to do this, what I'm going to use is MATLAB Coder Project.

    And you can open this to the apps. There's this MATLAB Coder app here, or you can search for it, MATLAB Coder. But I've already got a setup here that's got everything configured for me so we can talk about what it's going to do, and if Windows would cooperate. There we go. So what am I actually doing here? I've basically what I'm trying to tell it is I want to generate source code, so in C. And my target is not any specific board.

    I could say that I want to deploy this to a Raspberry Pi or something. But I just want to deploy this to my host computer, which means that the computer I'm working on right now. I'm telling it what do I actually want the output to be when I generate code. And I'm not actually going to generate code right away. Because I already did it. [LAUGH] I'm not sure how long this is going to take. So but really all you would do is you would hit this Generate button. It's the same as clicking it here.

    But I've broken out my code into three M files, right? I've got detect green buoys, which takes in an image. I've got this round pixel, which is very simple. It just rounds a value. And I've got my actual threshold, which also takes in the image. And I need to generate code for all of these. And you can see in the coder app, I've got all three of these here, and it's going to generate code for all of them.

    So the actual code that it generates, if I were to click Generate right now, would be these files down here. It includes the C files that I need as well as the header files. I've chosen to generate a report, and I'll show that in a second. But it also generates this main example file. And you can read this whole header if you want, but really what it's saying is this is just an example of how to call the generated code.

    Because of how I chose to set this up where I'm just generating the source code, we want to show you, hey, this is how you would go about calling this code if you're going to go integrate it into some other code that you've written by hand or some other libraries that you may already have. The other options that we could generate a library from it, a DLL or a static library.lib, or we could generate a MEX. If you're not familiar with what a MEX is, it's a MATLAB executable.

    But essentially, maybe this isn't always true. But when you MEX a file, you can get performance benefits because what we do is rather than having this M code that you might be you're able to edit it. We can set debug breakpoints and all of this. What you might want to do for performance reasons is actually generate code from this model and create a MEX where it's no longer code that we're going to go in and edit or set debug points or anything like that.

    And because we've generated code from it that doesn't have all of that in mind, we can get some performance benefits. So a lot of the times, if you have a function like this that you're trying to get to be sped up, especially on my computer is pretty good, but my laptop's not as strong. So it might be useful to have a MEX of these functions that's more performant. So when we MEX it, we can get that speed up without having to recode it and see ourselves or anything like that, it's through the app.

    Windows really doesn't want to cooperate with me today on this app window. But if we were to select that MEX and then hit Generate, it'll build the MEX for us, and you would call it the same way you would call any other MATLAB function. And instead of calling the MATLAB code, we'd be able to use the MEX file and potentially get performance benefits. This particular function is not super performance intensive. So I wouldn't get a huge benefit out of it.

    But on something that's really resource intensive or is going to go through a ton of calculations, it can be very helpful to actually MEX. So I said we were going to take a look at the report. And you see I did run it today. I ran it this morning. I'm not making this up. And if I look at that report, and I open up this new window, and it's got a similar breakdown, right? It's got my generated files, my example files, so my C and my H file. And then it's got the individual files that I generated code for.

    The really important part here is that I'm looking at this detect green buoys, that's C file. And I'm trying to understand which parts of this correspond to what parts of my M code. I can get that information by clicking on this Trace Code button. I'll go ahead and shrink some of the rest of this down. When I click on the Trace Code, it's actually going to bring up the C file and the M file side-by-side. And it's going to do a bunch of highlighting for me.

    Because what it's trying to show me is hey, this line in detect buoys, detect green buoys where I call blob analysis with all these options, that's generating, let me scroll down. That's getting mapped to all of this code over on the left in my C file. So the goal is not to generate a bunch of C code that you can't read and you have no idea what it's doing or anything like that. The goal is to produce human readable code.

    Because you might need to modify this or you might need to integrate it into other code that you've already written or that you've gotten from another program or something. So we want to be able to trace it back to OK, which part of my MATLAB function does this correspond to? If I want to look at roundpixel.m, which was pretty simple file. Where did that show up? Well, it ended up just being one line of code. Compared to the rest of my code, this isn't really that impactful.

    But you can see that the comments here in this case, it's just a copyright because it's a demo file. But if I provided some good comment here on what this function is doing, I also get that in the code. So if somebody is looking at just the C code, and you provide some helpful comments on what this function is, what it's doing, you can get that to appear in the C code as well. So again, in this case, I want to be able to go back to my M code and look at well, this chunk of my C file, where did that come from?

    And a really good example of why this is really useful is this one line of code is a built in function. This is a built in function that converts, in this case, it converts an image from the RGB color space to the LAB color space. And rather than having to write code myself to do that because it's just a built in MATLAB, I can get all of that generated as C code even though it's just one line in my MATLAB file.

    And there's a bunch of stuff that it does here to do the actual conversion. But because when I was working at MATLAB, I just threw it in one line of code. When I generate the C code, I get all of that functionality without having to write out this conversion myself. So especially if you were writing a prototype for some functionality that you want in MATLAB, rather than reimplementing it, we can just spit it out as C code using MATLAB Coder.

    And we can still be able to trace it back to OK, this is here I've got the comment where I'm actually calling it, and I can look at that same comment in my C code and be able to go, ah, OK, I know which function we generated this from. If I'm having problems with this running on my hardware or something, I can always go back and take a look how did we implement this in MATLAB? Is there something we can do, or do we need to modify this to run on some specific hardware that we've got?

    So that's the code gen report, the traceability report. It's really, really useful, especially as somebody who, my first language was actually C and then a little bit of C++ back when I was in undergrad. But I haven't actually written it by hand in a really long time. I probably could if I really needed to sit down and write all this out. But because I can just generate it from MATLAB and take a look and make sure OK, this is going to work for what I need.

    I'm going to be able to compile this or using the header files that I've got, I'll be able to call this in the rest of my code fairly easily. So that's great for MATLAB. But something that I think is a bit more relevant to all of you, and I'm trying to leave as much time as possible here to talk about is Simulink. Because this is great for a one and done run of some code that I've got. But ultimately in our vehicles, when we write control code, it's a loop, right?

    It's not run it once, and we're done. We've got to be able to respond to external inputs. We might need to interact with device drivers or other parts of our hardware and be able to read that data in. So I'm going to call it there for the MATLAB part of this. And then I'm going to get into our Simulink code generation part. I'm just going to check really quick if there were any questions in the Q&A.

    It looks like there was one about tire modeling. But it looks like somebody from the events team answered that. So if you've got questions, again, be sure to throw them in the chat. I'll keep my eye on it. I've got it up on a second monitor. And in between stuff, I'll try to answer any questions that you've got. OK, so let's talk about Simulink. This is where in the video series, it kind of breaks it down into I've got one thing running on a Raspberry Pi. I've got another thing running on an Arduino.

    But when we're doing this in Simulink, we might not be running these on separate machines at all. I go to the solution here because I want the entire thing. Oh, come on, Simulink. Here we go. So what this is doing is, this is what I talked about before. It's just trying to read some camera data. I've got two different algorithms that I've got. In this case, one is doing the vision, and the other is doing the control of do we want to go to the left or to the right.

    And here we go. What I'm actually doing in, come on Windows, maybe it's time for me to switch to Linux. [LAUGH] So you can see that these are actually the same model because what I'm doing here to try and make my life easy is using a model reference. So what a model reference is you can see I've got integratedsystemsolution.slx. is this particular model. But my algorithms themselves live in separate slx, files separate Simulink files because I want to be able to use them in different contexts.

    In this case, I've got my controller and my vision parts of this that I want to, at some point in the future deploy to separate boards. I'll deploy the vision algorithm to a Raspberry Pi. And I'll deploy my motor controlling algorithm to an Arduino and have them communicate with each other to actually coordinate. This is all just in the service of following a green ball with a webcam.

    But when I'm in Simulink, and I'm trying to test using pure simulation and just make sure that my control output makes sense, that it's going to try and move the motor in the right direction, I haven't made it to the stage where I'm generating code or I'm deploying to hardware. But I want to be able to use the exact same algorithm and the exact same model file that I'll use later. So I don't want to have to reimplement this or copy and paste it into another model or something like that.

    So instead, I reference it in a subsystem reference, or sorry, a model reference. In this case, there is another way to do it. So if I use the Quick Insert, I go to, I say model. This is how we get these subsystems in here. When I click on this, it's going to ask me for the model name, and I'll do vision dot, I'll just hit browse. Now select that. You can see, it's referencing this other slx file that I've got.

    So a model reference, this is a good thing in some ways, but it can be challenging with larger models. A model reference needs to be able to run on its own. So if I open up this right-click on it, and they say sorry open as top model up here. So I've just opened Vision Algorithm Solution. This model has to be able to run on its own.

    So it can't be relying on the context that it's in, which means I have to know what my input and output data types the sample time of my subsystem, what solver settings I'm going to use when I set up this model. In this case, everything's using the same solver settings. Everything's I kind of hooked up pretty simplistically with just like a matrix and a single output or a single value for each output. It's not like it's outputting a vector or a matrix.

    So the size of these isn't going to be an issue, so I haven't had to do much work to do this. But some things that you can't do with model references is for example, have the entire algorithm set up in such a way that it can handle different data types, different contexts that I might use this in. For that, what you would want to use is a subsystem reference, which is very similar. But you can think of this as more of like a subsystem that lives in a separate slx file.

    I want to say it's new, but I think it was introduced two or three years ago now. So time flies a little bit. But it's the newer option for separating out parts of a model to other files especially if you're working with Git or SVN, any sort of version control. Having these in separate files makes it a lot easier to manage changes to your algorithms over time. But the original way to do this the way that's been around a long time is model references.

    So I can use this. What we'll do here is I'll show you how I've got this set up elsewhere is that I have, it's actually chapter six, is that same vision algorithm, you got it over here. But I want that model reference to live not in a Simulink model that's co-simulating with other parts or against a plant model, but now I want to use it in the context I actually am going to deploy. So in this case, I'm deploying it to a Raspberry Pi.

    So I can take the same algorithm. I can use that model reference and rather than copy and paste or do any kind of funky stuff with a custom library, I can just pull in the same model reference. And instead of feeding it webcam data from my computer and just outputting to a video display on my computer, I can hook it up to Raspberry Pi specific I/O.

    And this is the best way to do this for being able to simulate an algorithm and deploy it is if we have this model reference, we can keep all of the inputs and outputs agnostic to what I hook it up to. So as long as this is the right resolution, in this case, 320 by 240 image, and as long as I'm doing something with the outputs, my algorithm doesn't really care whether it's hooked up to my computer's webcam or a webcam it's deployed to on a Raspberry Pi.

    When I generate the code, this interface is going to be hooked up to whatever it's hooked up to in my Simulink model. And for larger models or models that have multiple model references to different algorithms, you can actually only generate code for parts of a model that have changed. So in that case, maybe I make a change to how I'm doing this unpacked or how I'm doing this processing. But I didn't change my vision algorithm at all.

    When I generate code, rather than regenerate code for my vision algorithm, similarly, it's going to see that nothing has changed there, and it's just going to generate code for this part. For simple models, this isn't a huge timesaver. But for larger models, especially the kind of stuff that you might be deploying into a vehicle, let's say you have a battery management system. And you've got different model references that do charge and discharge buffers. You have one that's tracking state of charge, one that's tracking state of health.

    When you generate code, it's really inefficient use of time to try to regenerate code when you haven't changed anything, right? So having it in these model references, we can say, well, this is one chunk of the code. And as long as I've got it hooked up right, I don't have to regenerate for it. I don't want to do it here just because there's other stuff it's going to generate for the Raspberry Pi. But I do want to show you guys what it looks like when we actually generate code from Simulink.

    So somebody asked in the chat what is considered good practice when comparing the computational cost of two algorithms? Should I just deploy and compare then using Simulink Profiler? Or is there anything else I should consider? So I think my recommendation usually for, I have two options for an algorithm or even just I have one algorithm, and I'm trying to figure out how to speed it up is you always want to profile it.

    There are some cases where you can probably look at a set of code or a model and figure out where the bottleneck is or what's the most expensive part of it without really having to back it up with data where the classic example for this is in MATLAB, if I don't vector rise my code, if I do like a for loop that goes over each element of a large matrix, but the results of one iteration don't depend on past iterations, you can look at that in Matlab.

    And you can kind of just by inspection, say, it would probably be faster if I vectorized this, if I just took the vector, if I was doing a for loop that just was like multiply each line of a matrix by a constant value. A for loop is going to be slower than just using a matrix multiplication in MATLAB and letting it vectorize. So you can do a lot of stuff by inspection.

    In Simulink whether it's using the profiler or using a debug method on hardware or something, you can maybe look at it and just kind of tell from your model I've got this really intensive subsystem. Maybe I could replace that with instead of calculating that value, I could do like a lookup table or something where I remove a lot of the computation and put it into a map because it's not really going to change. And that way, I can still get the flexibility that chunk of code had but for less performance.

    You can do some of that just by inspection. But I think when you start getting into smaller and smaller returns where you're not really trying to remove a big performance hit that you know just by looking at it that it's less performant, you really need to start actually profiling the code and looking at what is actually taking up a ton of time. At a certain point, you can't really eyeball that. You might be able to do some stuff based on experience.

    But it's sort of a try it and see at a certain point. And when you profile things, then you actually have the data to back it up and say, oh, it's not this function threshold green buoys. Or it's not my, let me open this up. It's not my saturation method or anything like that that's causing this performance issue or not getting the speed that I want. It's actually the device driver for writing to the serial port or something.

    So you can eyeball it for eyeball performance improvements or comparisons at first just based on what I things about both of these algorithms. But especially with generated code and with more complicated models and even MATLAB scripts, profiling is your best friend. When you reach a certain level of complexity, you really need to back up your efforts with I'm trying to improve performance here because it's taking up 50% of the compute time on this model, right?

    So I'd always recommend once you're confident that you've kind of eyeballed the stuff that you can profiling that the code execution is going to be a much better approach to understanding where your code maybe can be improved or maybe where it's getting bottlenecked. OK, so let's talk about Simulink code gen. So you can do this with a hotkey Control and B for buoy. But you can also open up, there's a couple of different pages depending on what you're doing.

    In this case, I have this model set up for Embedded Coder. So if I open that up, what I'm going to get is this other tab that's just specific to all of my code gen tasks. So over on the left, I've got a configured for embedded C using Embedded Coder. I could do C++. You could generate code just to speed up simulation where you're just running it on this desktop, and I don't have plans to deploy it to anything.

    So you've got that option if you open the Quickstart. So this is how we set this model up initially. But we kind of walk through OK, what am I generating code for? I'm generating code for this model. How do I want the output setup? Am I deploying it to a specific piece of hardware, all of that stuff. The quick start guide is I always run through that first time I set up a model. And then any other settings I need to change, I can go and edit that later.

    So I've got two different options here in this dropdown. If I hit Control-B, that's going to actually run this build command. But I'm just going to generate code because I don't want to create a makefile. And what this is going to give me similar to the MATLAB Coder app is it's going to first give me this summary, right? It's going to say, OK, we generated code. Here's all the information you need about how things were hooked up.

    If you want to look at the C files that we generated, and you can see, it's got quite a bit more items here. And the reason is because what the main file is set up to do is not just execute this code once but to actually show you hey, the first thing we need to do is, oh, where is it? Oh, I don't have any, that's right, is I need to initialize this code. And then while my code is running, I'm going to call this RT1 step. So that's where the actual algorithm of this Simulink file is.

    And then once the code is done, I need to actually, I need to run my terminate code. And I'm having trouble finding it because it's been a while. So I'm doing-- I'm stopping data logging and stuff like that. But again, the main file is an example of how to implement this stuff. For the most part, you probably are going to want to take the main file and replace it with one of your own, especially if you're targeting some hardware that's not specifically hooked up to a support package where there may be a clock that you want to tie it to.

    In this case, you can see this is just doing a while the model, while I haven't errored out continue running the model. So this actually runs infinitely, which for embedded code, maybe that's fine because I'm going to have some way that I shut down, it's going to shut all this down on my controllers end. But at least for running this on desktop, I don't actually want it to run infinitely, so really simple thing to add to this for customization might just be some other exit conditions.

    Similarly to the MATLAB code gen report though we can actually get-- we can actually look at the C function that it generated and get information on where these parts of my code are coming from. Because again, this is supposed to be readable code and traceable code. We want to know where these, what parts of my model correspond to different parts of my function. So if we go to if we just click on something, [LAUGH] I didn't mean to jump to it right away.

    But in this case, this is just a PID with saturation on the output. So it's not terribly complicated. But I might want to be able to trace back to different parts of my code. So I can see that oh, that sum block, it's getting calculated right here. And if I'm just browsing through the code, I can click on that. And it'll bring me to the block that's providing the information to generate this part of the code.

    And this includes the function itself that's getting generated, has two inputs the desired position and the actual position since this is just a PID. And that includes being able to trace back that input to the root input port of this model. And it'll highlight it in my model. Or if I click on a model element, so if I click on Control Out, it'll show me where in the code that block is contributing.

    So although that's kind of getting taken care of here because if I click on this, you'll actually see it tells me, let's see if I can zoom in on this. You can see it's pretty chunky text. But it's saying that block, the subsystem I selected is a virtual block. So code is not generated specific to a virtual block. If you never heard the term virtual block before, basically what it's saying is this subsystem, even though I see it here in the editor from a computational standpoint, this is just a visual container.

    When I generate code, it's pulling everything that's inside up one level because there's nothing specific about this subsystem besides wanting to visually contain the blocks that makes it separate from everything else. The other thing, and this is there's a lot of customizations you can do with Embedded Coder, with Simulink Coder to customize how it outputs all of this C code. And one of the ones I want to talk about is in inlining.

    Because if we go to where we actually calculate the output of this filter coefficient, so it's this signal here. And of course, I scrolled it away. So it's this signal that I'm outputting from my filter coefficient is you can see how it's calculating it. It's taking the derivative gain. It's taking this other signal, the output of the sum as well as looking at the state of the filter itself. And then it just has this hardcoded number right this inline number.

    Because unlike KD, which is the derivative gain itself, I haven't specified that I want this to be a tunable parameter. So my KD is used in a couple of different places. It's used here, but I actually declare it elsewhere. Because I want to be able to change it in one place in my code where it's defined as, and you can see if I click, it actually tells me on line 22, we defined KD as 0.023 because I want to be able to tune that in one place in my generated code.

    The filter coefficient, I haven't specified that. You can, by default not inline anything. But in this case, for performance reasons and just optimizing my code, I don't need to be able to look in one spot and see where I've defined what this 58.958 is. So rather than making a declaration and having it be a variable that's going to be in memory, I'm just inlining it in the code. Because that FC filter coefficient, the value is 58.958.

    But I can save some trouble and annoying stuff by maybe having more variables than I need by just inlining this because it's only used here in my code. There's a lot of options like that in Embedded Coder where you can choose how you want the code to actually treat variables like this. We could set it so anything with a variable or any tunable parameter in any of these blocks will not be inlined.

    But then what that's going to do is instead of having these exported variables from just three places, it would export everything from my filter, from my filter coefficient, from a integrator for my saturation. And in the case of this model, the only things I actually care about being exported are my gains for my PAD because that's all I'm going to be tuning. I don't actually want to be able to tune this saturation because I have it hardcoded to in this case five and negative five as the upper and lower limits.

    Because I know ahead of time that's the limit of what my controller should be outputting. It might be a hard limit on voltage or a position that I can't exceed. And so I don't want that to be tunable in code. I just saw a question pop up. Is there a possibility of some kind of comment in the generated code to help readability of inline variables like the filter coefficient? I don't know off the top of my head.

    It's possible that you could customize the output to actually include a comment about the inline variables. I know the default is not do. It might be good, I don't know if we have time. Oh yeah, we're at 10:57. I don't really have time to dig into it live, but if you want to shoot us an email or contact us, I've got a couple of slides that cover how you can get in touch with us once we're wrapped up here.

    But feel free to shoot us an email at the racing lounge email address. Veer and myself and the rest of my team are all on that email, and we can dig it up offline and kind of chat with you about it. You will be able to, you can kind of see that if I highlight over it in the traceability that it shows me what block it's coming from. But in terms of if you move to the C file to another computer, or you were trying to integrate it elsewhere.

    Yeah, it doesn't really have a comment to let you know where that five came from other than well, it came from this block in my model. It doesn't necessarily say what parameter for the variable-- for the block it was. So shoot us an email after the webinar, and we can kind of follow up on it. I do want to switch back over now that we've kind of talked about generating code, traceability between code and model.

    Because that's really important, especially when if somebody you've given the code to somebody to deploy onto your controllers, and they have questions about a line, it helps a lot to be able to just be like, oh yeah, it's at line 73, where is that coming from? Can we change it so it does this? Or maybe we don't want to inline this 5.0 anymore. So we can use the traceability that we get out of the code gen to come back and make changes that we may be identified in, I was going to say production, not really production in our case, but on controller.

    OK, I want to cover really quick then the wrap up here, which is how you can get in touch with us. So we have a lot of resources. The actual files that I use today came from this code generation training. It's seven videos long, and it actually walks through, I was using the solution files. But it will walk you through how to set up a lot of this stuff from sort of a starting point. But there's also stuff on physical modeling and computer vision making vehicles and robots see.

    So you can check that out on the, if you go to the Student Competitions page, you've got all of our tutorials. And you can see Connell. He did the code gen webinar with me last year, but he it's not around here. It's just Veer and I. In addition to that, if you're looking for some courses that all of those are made by our team, the Student Competition Team. But there's a lot of self-paced courses that are called onramps available on The MathWorks website.

    The main one is MATLAB Onramp. But there's also Simulink Onramp. And it's started with those two, and it's really expanded to a lot of just quick introductions to different topics. So there's Deep Learning Onramp, a whole bunch of other machine learning related onramps, image processing, control design, all of these are short 1 and 1/2 to two hour courses just on getting started with these different topics. And there's more in the works. But these are made by our training team.

    So they're there for students, but they're also for folks in industry who are looking to get started with these topics. So they're good introduction videos for the different stuff. You can also get in touch with us on our Facebook groups or take a look at our blog, the Student Lounge Blog, used to be called the Racing Lounge Blog, So if you're more familiar with that name from our separate groups, the blog itself has been renamed to the Student Blog because it kind of includes all of our stuff, not just the Racing Lounge.

    You can also, so if you go onto The MathWorks website, you look on the student labs, we've got over 100 videos. The Facebook pages are pretty large, I think 19K is pretty outdated number, actually. But we also have our dedicated emails for our groups here. , I think for automotive competitions Racing Lounge at MathWorks is our group email that will go to myself, Veer, who's been kind of helping with some of the Q&A and just keeping an eye on chat.

    But he presented in the past two webinars. And that includes if you've got any questions about ADAS after the final session in our series here, we've also got Akshra and the rest of our ADAS folks who look at that email. We've got a bunch of posts on the Student Lounge Blog including a lot of posts that are not actually written by us, they're written by students because we don't-- it shouldn't just be us telling us how you can do this stuff.

    We want to highlight teams that participate in different competitions we support and the work that they do in MATLAB. And so there's a lot of blogs that are from teams. And if you meet one of us at a competition this summer, and you have a really great idea for a blog that you want to talk to us about, let us know. There's also we linked to one of the files, but there's a bunch of stuff from us on the File Exchange as well as on MATLAB Answers.

    So I must have pasted the same slide again. And just to summarize, racinglogicmathworks.com, the Facebook group, student competition tutorial videos, if you are looking for where you can get the sponsored software license, if you go to mathworks.com/academiastudentcompetitions and find the competition you're participating in, that'll show you how to request a license.

    And that's all I got. I'm a little over, but not too bad for our one hour target. So we've now covered our first three sessions, vehicle dynamics, electric vehicle powertrain sizing, and code generation. In two weeks on the 27th of April, Akshra from our team is going to be talking about ADAS and the automated driving tools that we have available for student competitions. Thanks, everybody, for stopping by.

    View more related videos