Running Simulink model with root-level I/O ports and internal states from C++ in loop

6 views (last 30 days)
Hi,
I'm working on a concept for running a simulink model from C++. The model has a collection of input and output ports at the root. I need to drive the model input ports from a C++ application and retrieve the output port values after stepping through the model once. I have been able to use MatlabEngine to interact with Simulink session.
Here's what I have tried so far:
Using sim command:
I created a Simulink.SimulationInput object and used it to provide values for all root-level input ports. The model uses discrete fixed-step solver so I set both sample time and stop time to same fixed value e.g. 50ms. Then I ran the simulation using sim command and was able to retrieve the output port values using Simulink.SimulationOutput object. This seems to work fine for simple cases. However, the calling C++ application would be required to simulate the model in a loop with different input values. Since sim command would only simulate the model for one frame (due to the aforementioned configuration), if the model has internal states, these states would not persist between individual simulation attempts. This means that the simulation output will be incorrect if it depends on a value from previous frame. I did some digging into ModelOperatingPoint to try to use FinalState of simulation from previous frame as InitialState for current frame however that didn't work since the snapshot time of FinalState from previous frame would be same as stop time (e.g. 50ms) and I only want the model to run for a single step every time it gets called from C++.
Using Simulink debugger:
I tried using debug mode with step top to get the model to step only once. However, this approach does not allow driving the input ports.
Using set_param with SimulationCommand:
I created a Simulink.SimulationData.Dataset object (similar to first approach) to drive root-level input ports and used that as ExternalInput for the model. Now instead of sim command, I used set_param(<model>, 'SimulationCommand', 'start', 'SimulationCommand', 'pause') to start and set_param(<model>, 'SimulationCommand', 'continue', 'SimulationCommand', 'pause') for each iteration of C++ loop. This seems to run the simulation once and the internal states seem to persist as expected. However, if I change any input via Simulink.SimulationData.Dataset object the new value does not get used for simulation. If I stop and restart simulation using SimulationCommand, it does pick the new value but now it has lost the internal state info.
Is there anyway to implement what I'm trying to do?
Any help would be much appreciated.
Cheers,
sunny

Answers (1)

surya venu
surya venu on 17 Apr 2024 at 8:53
Hi,
You're on the right track with exploring different approaches to run your Simulink model from C++. Here's a breakdown of the limitations you encountered and some alternative solutions:
1. Using "sim" Command with Internal States:
The issue is that the sim command with a fixed stop time resets the model states. Here are some alternative approaches:
  • State Updates: Instead of setting a stop time, use a zero-crossing detection block in your Simulink model to trigger a single simulation step. This block outputs a signal when a specific condition is met (e.g., a timer reaches a specific value). Connect the block's output to a stop simulation block to terminate the simulation after one step. Inside your C++ code, after retrieving the output, reset the trigger signal in the model (using "set_param") before providing new inputs for the next iteration.
  • External Mode: Consider setting your model to "External" mode. This allows Simulink to run for one step whenever an external trigger is received. You can trigger the simulation step from your C++ code using "set_param" with SimulationCommand set to "update".
2. Simulink Debugger:
The debugger doesn't allow input port manipulation directly. However, you can combine it with other approaches:
  • Set Breakpoint and Update Inputs: Set a breakpoint at the beginning of your model. In the C++ code, use "set_param" to update the input values before resuming the simulation using the debugger. This allows you to inspect the model state after one step but requires manual intervention.
3. set_param with ExternalInput:
The challenge here is that ExternalInput doesn't update dynamically. Here's a potential solution:
  • Temporary Model Modification: Consider temporarily modifying your Simulink model within your C++ code. You can create a copy of the original model, update the ExternalInput data, run the simulation with set_param commands, and then discard the modified model.
Hope it helps.

Products


Release

R2018a

Community Treasure Hunt

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

Start Hunting!