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:
This is the subsystem:
This is the MATLAB Function block implementation (note that there's an error in the # symbol, since defining function_handle objects isn't allowed):
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.
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.
Related
I would like to use the ode23 solver for systems. My system has three equations and the first one depends on an variable 'z' which is declared in the code above.
Here´s the sample code:
clc; clear;
z=1;
function Fv=funsys(t,Y,z);
Fv(1,1)=2*Y(1)+Y(2)+5*Y(3)+exp(-2*t) + z;
Fv(2,1)=-3*Y(1)-2*Y(2)-8*Y(3)+2*exp(-2*t)-cos(3*t);
Fv(3,1)=3*Y(1)+3*Y(2)+2*Y(3)+cos(3*t);
end
[tv,Yv]=ode23('funsys',[0 pi/2],[1;-1;0]);
The get the error that the variable 'z' is not declared.
So, is there any possibility to solve this?
(The function 'funsys' needs to be dependent on 'z')
Yes, have a look at Pass Extra Parameters to ODE Function in the documentation:
you can pass in extra parameters by defining them outside the function
and passing them in when you specify the function handle
In your case, it would look something like this:
[tv,Yv]=ode23(#(t,y) funsys(t,y,z),[0 pi/2],[1;-1;0]);
I have a steady-state algebraic model (no der() expressions) with one non-linear equation. When translating in Dymola, the set of equations results in a numerical Jacobian. I would like to remove the numerical Jacobian (if possible) to improve performance of the model.
After setting the parameter Hidden.PrintFailureToDifferentiate=true (thanks to this tip from Claytex), I see that Dymola issues the warning:
Cannot find derivative of function:
InitializationParameterLoop.InitFunctions.interpolate(xVector, yVector, x, 1)
Note that the InitializationParameterLoop.InitFunctions.interpolate function is a copy of the Modelica.Math.Vectors.interpolate function, copied so that I can make modifications if necessary within my own package.
I attempted to add an explicit definition for the derivative dy/dx by making the following changes to the interpolate function:
Add the derivative annotation to the function definition:
function interpolate "Interpolate in a vector" extends Modelica.Icons.Function annotation(derivative = dydx);
Add a protected Real variable dydx:
Real dydx;
Calculate dydx in the algorithm section:
if abs(x2-x1)>0 then
dydx :=(y2 - y1)/(x2 - x1);
else
dydx := sign(y2 - y1)*Modelica.Constants.inf;
end if;
I was hoping that this simple method could be used to explicitly define dydx and remove the numerical Jacobian calculation, but it does not seem to make any change and Dymola still issues a warning about the
Am I misunderstanding the use of the derivative annotation? If so, can someone help me to understand how to define the derivative for the interpolate function?
Thank you!
This is the same issue as https://github.com/modelica/Modelica/issues/2078 and will be fixed in the next backward-compatible maintenance release of the Modelica Standard Library.
Is there any way to do i.e.
Surface = scatteredInterpolant(measurement_xz(:,1)*1E-3,measurement_xz(:,2)*1E-3,measurement_xz(:,3));
where measurement_xz is some data in a startup script for my simulink model and then use Surface in an embedded matlab function in the simulink model, i.e.
///embedded matlab function
function V = fcn(x,z)
V = Surface(x,z);
?
When I i.e. try to use Surface as a parameter for V like
function V = fcn(x,z,Surface)
V = Surface(x,z);
with Surface set as parameter in the Ports and data manager I get the error
Expression 'Surface' for initial value of data 'Surface' must
evaluate to a numeric or logical.
What you are trying to do is not supported by the Matlab Function block, MATLAB is unable to generate code for it. The problems are:
You are trying to access the variable Surface which is not visible in the scope
scatteredInterpolant is not supported at all for code generation (at least in my MATLAB version, might be improved in recent Versions).
To fix this on a code level, you could switch to interpreted MATLAB code. This can be done either switching to a Interpreded MATLAB block or using coder.extrinsic. It is a quick and simple fix, but I recommend not to do this because it will probably result in a slow model. Instead I recommend to switch to a lookup table, which is also capable of interpolating.
I'm trying to teach myself how to use MATLAB for solving state-space systems, I have what seems to be a pretty straight-forward system but have been unable to find any decent straight-forward examples for a novice thus far.
I'd like a simple walk-through of how to translate the system into MATLAB, what variables to set, and how to solve for about 50(?) seconds (from t=0 to 50 or any value really).
I'd like to use ode45 since it's a 4th order method using a Runge-Kutta variant.
Here's the 2nd-order equation:
θ''+0.03|θ'|θ'+4pi^2*sinθ=0
The state-space:
x_1'=x_2
x_2'=-4pi^2*sin(x_1)-0.03|x_2|x_2
x_1 = θ, x_2 = θ'
θ(0)=pi/9 rad, θ'(0)=0, h(step)=1
You need a derivative function function, which, given the current state of the system and the current time, returns the derivative of all of the state variables. Generally this function is of the form
function xDash=derivative(t,x)
and xDash is a vector with the derivative of each element, and x is a vector of the state variables. If your variables are called x_1, x_2 etc. it's a good idea to put x_1 in x(1), etc. Then you need a formula for the derivative of each state variable in terms of the other state variables, for example you could have xDash_1=x_1-x_2 and you would code this as xDash(1)=x(1)-x(2). Hopefully that clears something up.
For your example, the derivative function will look like
function xDash=derivative(t,x)
xDash=zeros(2,1);
xDash(1)=x(2);
xDash(2)=-4*pi^2*sin(x(1))-0.03*abs(x(2))*x(2);
end
and you would solve the system using
[T,X]=ode45(#derivative,0:50,[pi/9 0]);
This gives output at t=0,1,2,...,50.
I have created a function from sets of points using curve fitting toolbox. I used generate code function and generated function called createFit(a,b), where a and b are sets of points used for interpolation. As a result createFit returns my interpolated function.
Now I want to use this function as the u0 (initial conditions) of my PDE equation (I am using pdepe to solve PDE). To do that, in function where I need to establish u0 I need to invoke a createFit function, which is not a problem, I have access to it. A problem is that I cannot pass a and b as the parameters to this function. I tried to make them global but it did not worked. How to do that?
From the pdepe documentation:
Parameterizing Functions explains how to provide additional parameters to the functions pdefun, icfun, or bcfun, if necessary.
Essentially, use nested functions or anonymous functions to handle extra parameters.