3

I'm trying to figure out how to solve a system of ODEs inside a subsystem in a Simulink model. Basically, each call to this subsystem, which happens at each tick of the simulation clock (fixed-step), entails solving the ODEs. So there's like a different "clock" for the subsystem.

I have an M-file that implements the function for the system of ODEs. Currently, I have a MATLAB Function block for that. It needs a lot of parameters that I can get from the base workspace (via evalin and using coder.extrinsic('evalin') at the beginning). But I'm not allowed to define function_handle objects or inner functions to parameterize the function that is used by ode*. I think that if I'm able to solve the ODEs in this block, I'll have solved my problem. But those restrictions are "ruining" it.

I'd appreciate if you have any ideas of how to accomplish this. I welcome different approaches.

Thank you.

EDIT

A simple example is given below. It attempts to solve the van der Pol equation by changing the mu parameter randomly. This is the main idea I have at the moment, which doesn't work because of the problems mentioned above.

This is the main model with the subsystem:

enter image description here

This is the subsystem:

enter image description here

This is the MATLAB Function block implementation (note that there's an error in the @ symbol, since defining function_handle objects isn't allowed):

enter image description here

Ryan Livingston
  • 1,898
  • 12
  • 18
Bruno
  • 1,329
  • 2
  • 15
  • 35

2 Answers2

3

Just use the MATLAB Function block as a wrapper. Put the bulk of your code into a "standard" MATLAB function (i.e. one callable from MATLAB, not the MATLAB Function block) and call that function (after defining it as coder.extrinsic) from the MATLAB Function block.

Phil Goddard
  • 10,571
  • 1
  • 16
  • 28
  • Thank you so much! That's a simple solution that allows me to keep everything as it is with just a few modifications. – Bruno Aug 27 '15 at 19:13
  • This doesn't work when you try to generate C code from the model. – NoamG Oct 20 '20 at 06:47
1

This will be a bit more complex than Phil Goddard's solution. The advantage is that it will allow you to generate standalone code, if necessary, whereas extrinsic functions are not compatible with standalone code generation.

The functions ode23 and ode45 are supported for code generation as of MATLAB R2014b so this applies if your MATLAB release is at least that new. Supposing so, the main limitation you are seeing is that anonymous functions are not supported for code generation.

Simulate Anonymous Function Parameters with Persistent Variables

However, these parameterized anonymous functions can be simulated using a normal function with a persistent. To simulate your function with the parameter mu, make a MATLAB file odefcn.m:

function x = odefcn(t,y)
%#codegen
persistent mu;
if isempty(mu)
  % Adjust based on actual size, type and complexity
  mu = 0;
end
if ischar(t) && strcmp(t,'set')
  % Syntax to set parameter
  mu = y;
else
  x = [y(2); mu*(1-y(1)^2)*y(2)-y(1)];
end

Then in the MATLAB Function Block, use:

function y = fcn(mu)
%#codegen
% Set parameter
odefcn('set',mu);

% Solve ODE
[~,Y] = ode45(@odefcn,[0, 20], [2; 0]);
y = Y(end,1);

That should work both for simulation and for code generation. You can just add more arguments to odefcn if you need more parameters.

Community
  • 1
  • 1
Ryan Livingston
  • 1,898
  • 12
  • 18
  • Thanks for your contribution! I didn't know about persistent variables in MATLAB. They're much better than global variables, which I always avoid using. As of now, I don't have the need for standalone code generation. And I may want to try different ODE solvers (e.g., ode113 and ode23tb) depending on the model. I'm glad this problem got solved. But I'm running into another problem: Simulink is having issues converging due to algebraic loops... :( – Bruno Aug 29 '15 at 21:01