Vectorizing a Simulink Model

I'm interested in vectorizing a Simulink model so that it'll be more flexible and computationally efficient. I'm analyzing traffic flow - the position and velocity of a leading car influence how the car behind it is going to react. I've shown this for the first three following cars below.
Needless to say, this gets difficult to implement for higher numbers of cars - my team's current solution is hardcoded to run this simulation for 175 cars, each one represented by subsystems like the ones shown above (it's a big system). Being able to represent n cars with a vectorized solution would be better, but I'm not sure how to implement it. Any thoughts? I'd also want to know how to initialize each car using vectors (e.g. a vector for the initial position, velocity of every car)
TL;DR - I want to express all of these Simulink subsytems as a single subsystem that outputs vectors representing the important outputs (Position, Velocity, Acceleration, etc.) whose lengths are based on the number of cars we decide to simulate. Solutions using Vectorization would be preferred, but any solution would be appreciated!

Answers (1)

Fangjun Jiang
Fangjun Jiang on 9 Oct 2023
Simulink supports vector, so if designed carefully, a single Simulink subsystem could process N velocity and postion to generate N Energy and Power. The "Gap" might need special attention but overall, it is possible.
If the subsystem is designed to process single vehicle, then you can use the For Each Subsystem

11 Comments

Paul
Paul on 9 Oct 2023
Edited: Paul on 9 Oct 2023
Not the OP ....
Can the For Each Subsystem be used when the output of one copy is the input to the next copy?
Fangjun Jiang
Fangjun Jiang on 9 Oct 2023
Edited: Fangjun Jiang on 9 Oct 2023
Yes. At the dialog of the "For Each Subsystem", there are input partition and output partition. As long as the partition is correct, it should work. There would be a feedback outside of the "For Each Subsystem".
You may be asking about timing. It is like this. At time 0, loop N times. At time 1, loop N times, etc.
I don't think you can do this. At time 0, loop N times, but the result of loop 1 is directly feed to or impacting loop 2. It is easy to do that in code, but not in Simulink model. Maybe it could if using Memory Store/Read/Write. You could experiment if need to /want to figure it out.
Hi Fangjun
I think I understand what you're saying as far as the feedback. Have you actually tried wrapping a feeback loop around a For Each Subsystem (without any delay on that signal)? I'd be quite surprised, but happily so, if that actually worked. My mental model of this block is that the input to the block are defined prior to block execution, then the input is partitioned, each subystem is then executed in parallel (conceptually, i.e., no signal flow between subsystems), and then the outputs of each subsystem are concatenated to form a single output of the block.
Having said that, I might not really understand your response because it sounds like the last paragarph is directly contradicting the first, so i must not understand one or both of those paragraphs.
"(conceptually, i.e., no signal flow between subsystems)". I have the same understanding and assumption.
But I think I can use a Memory block to break this. Each loop will read the memory first and then write to the memory. Loop 1,2,3,... is carried out in series, not in parallel. Need to do an experiment to figure it out.
The OP's diagram may or may not demand this. Hesitate to spend time to figure it out but I think I can definitely figure it out.
Fangjun Jiang
Fangjun Jiang on 9 Oct 2023
Edited: Fangjun Jiang on 9 Oct 2023
That was quick. Simulink doesn't support Data Store Read or Data Store Write inside a "For Each Subsystem". So the answer is NO.
"Can the For Each Subsystem be used when the output of one copy is the input to the next copy?"
Yes, but not feeding the value of the same time step.
This is an interesting discussion! Could you show a screenshot of what you've done? Do you know how fast it would be compared to a for loop?
Paul
Paul on 10 Oct 2023
Edited: Paul on 10 Oct 2023
@Paul the OP,
Regarding this statement: "this gets difficult to implement for higher numbers of cars"
what exactly is difficult to implement?.
With the current implementation, you should consider putting your car susbystem into a Custom Library, as discussed here. That way you can modify your car subsystem in the library and it will propagate to all instances of that subsystem in your model. This all assuming that your 175 cars are identical. If the cars all have the same equations but have different parameters, there would be options as well.
I assume the difficulty is to have 175 duplicated blocks in the model. And how do you change the number of vehicles from simulation to simulation.
The best way is to design your subsystem to deal with N vehicles directly. If using "For Each Subsystem", the performance is not an issue (in my experience). In fact, I think it should be faster than duplicating N blocks in the model.
@Paul, thanks for the suggestion! We're assuming that all the cars are governed by the same equations so we've already put our car subsystem into a custom library. I'm interested in what you have to say about using different parameters for each car, but for the time being, the "difficulty" I'm referring to is changing the vehicles from simulation to simulation, as @Fangjun Jiang has mentioned.
If we wanted to raise the number of vehicles simulated from 175 to 200, we could, of course, duplicate the vehicle blocks 25 more times, but this would be tedious and makes the model difficult to work with. Instead, I'm interested in running the simulation for N vehicles so the code can be flexible. I'm new to Simulink, so I'm not sure how (or if) I can compute the state for each car in parallel. I've looked into the "For Each" block, but I don't know how to implement it here, or if there's a better solution I don't know about (hence the original question).
Feeding the value of 1 to the Gain of 2, you got 2. Feeding the Value of [1 2 3] to the same Gain block, you got [2,4,6]. That is how Simulink works. Almost every block supports that.
Try this on your single vehilce model. Feed three velocities and three positions instead of one. See how the model simulates. It might not be difficult to make your single vehicle model work for multiple vehicles.
I believe that @Fangjun Jiang is refering to a feature called Scalar Expansion of Inputs and Parameters. Some blocks support that feature, like the Integrator, but others do not, like the Transfer Fcn. So if you go down this path, keep in mind that even if the model can be implemented this way today, it might limit what blocks you can use in the future if you need to modify your model for some reason. Unfortunately, the doc pages for each block in the Simulink libraries are lacking clarity, IMO, as to whether or not a block supports that feature, so there may be a bit of trial and error involved.
If you want to use different parameters for each car, start reading Parameter Interfaces for Reusable Components and links therefrom. Typically done using a masked subsystem from a custom library, or a Model reference block (which itself comes with parameterization options).
I think we've already determined that the For Each block won't work, at least not without adding an artificial time delay on the signals that flow from one vehicle the next.
Another option may be to use a Dynamic Masked Subystem. In this approach, we'd have a masked subsystem that has N as a block parameter and then the mask initiialization code can be used to add N instances of the IIDCar subsystem, connect them all up and create the output signals (speaking of which, it might be better to collect all of the output signals from the cars in vectors or a bus, rather than using all of those Goto blocks), and set the parameters for each car, if needed, based on a parameters of the top level mask. However, if you're new to Simulink this might be a long bridge to cross. Also, there may be a cost to pay in terms of rebuilding the model every time you change the N parameter. Disclaimer: I don't have too much experience with Dynamic Masks so don't know for sure if this will work, but offhand it seems like it should be doable.
Another, and possibly the simplest, option would be to bite the bullet and implement the maximum number of cars you'd ever possibly need, with the outputs of all cars combined into vectors and possibly a bus (or buses), but only use the outputs from the subset of cars you care about in any particular run. Wrapping the car subsystem inside an Enabled Subsystem and using copies of the enabled subsystem may be of interest to improve run time if that becomes an issue.

Sign in to comment.

Categories

Find more on General Applications in Help Center and File Exchange

Products

Release

R2023a

Asked:

on 9 Oct 2023

Commented:

on 10 Oct 2023

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!