How to declare parameters in matlabFunction?
124 views (last 30 days)
Show older comments
Abiy Wubneh
on 24 Sep 2019
Edited: Walter Roberson
on 2 Oct 2019
Hi there,
I have been struggling with this for a while, and I am hoping someone will be able to tell me where I am making mistakes. Thank you very much in advance for taking your time to look into this :)
I have been trying to convert symbolic expressions into MATLAB functions using matlabFunction. The original symbolic expressions were generated by another function and contain both parameters and variables, and the converted function doesn't seem to understand the difference btween the two. I am interested in converting the symbolic expressions into a MATLAB functions, and only then bind the values of the parameters in. I am doing this because it takes about an hour and half to do the conversion (not the example shown below!). Delaying the binding to a later stage would allow me to avoid running matlabFunction every time I run my code for a different set of parameter values. The ultimate goal is to use these functions in ode45.
Here is an example:
syms a b c d e % parameters
syms u v w x y z % variables
M_sym = [a*b*w c*x e*d*v;
c*y a*e*w z;
c*e*y a*b*u a*c*e*z];
B_sym = [a*x + b*y - e*z;
c*x + d*u - a*e*v;
d*w + e*a];
param = [c a d e b]
var = [u x y w z u v]
vec = [param var];
M_fun = matlabFunction(M_sym,'Vars',{vec});
B_fun = matlabFunction(B_sym,'Vars',{vec});
The resulting function handles M_fun and B_fun expect a vector input argument with the parameters and the variables combined as elements of the vector (length = 12). Ideally, what I want is to bind in the values of the parameters in M_fun and B_fun first and use the resulting functions in ode45 as M(var,t) and the B(var,t) (M*y = B).
My question is:
a) Is there a way to tell matlabFunction in advance what the parameters are and what their order/sequence is?
Eg. param = [c a d e b]
b) If (a) is not an option, is there a method for passing the parameter values to M_fun and B_fun in a vector form and still use the results in ode45?
Eg. param_val = [0.1 0.25 0.012 0.5 0.33]
I have tried something like the following, but it didn't work (probably because M_fun and B_fun don’t recognize param and var)
f1 = @(param,var)(@(var)M_fun);
f2 = @(param,var)(@(var)B_fun);
param_val = [0.1 0.25 0.012 0.5 0.33]
g1 = f1(param_val);
g2 = f2(param_val);
M = @(t,Y_val)g2(Y_val);
B = @(t,Y_val)g1(Y_val);
time_span = linspace(0.0, 5, 30);
int_cond = [0.0 0.01 0.02 0.1 0.13 0.12 0.05];
opt = odeset('Mass',M);
[t_span,QUf_sol] = ode45(B,time_span,int_cond,opt);
And i am getting the following error:
@(T,Y_VAL)G1(Y_VAL) returns a vector of length 1, but the length of initial conditions vector is 7. The vector returned by @(T,Y_VAL)G1(Y_VAL) and the initial conditions vector must have the same number of elements.
odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options, varargin);
Any help will be greatly appreciated.
Thanks,
Accepted Answer
Walter Roberson
on 29 Sep 2019
Edited: Walter Roberson
on 2 Oct 2019
MATLAB does not have any distinction between parameters and variables.
You should probably be looking more closely at the 'vars' option of matlabFunction. It accepts a cell array. Within the cell array you can have vectors (even arrays) of variables as entries. All of the entries that are in the same vector or array are bundled into the same input slot.
matlabFunction(a+b+c, 'vars', {a, b, c}) -> @(a, b, c) a+b+c
matlabFunction(a+b+c, 'vars', {a, [b c]}) -> @(a, in1) a+in1(:,1)+in2(:,2)
matlabFunction(a+b+c, 'vars', {a, [b;c]}) -> @(a, in1) a+in1(1,:)+in2(2,:)
The state information for ode45 calls should go into a column vector of variables.
If you use odeFunction instead of matlabFunction then it constructs the state information automatically.
6 Comments
More Answers (1)
darova
on 28 Sep 2019
clc,clear
syms x(t) y(t) z(t) % variables
syms a b c % parameters
% set up derivatives
d2y = diff(y,2);
dx = diff(x);
d3z = diff(z,3);
% equations
eqn = [d2y + y^2 + 3*t
dx*y - a
d3z/t - b - c];
% let MATLAB do all work for us
[Y, Y_subs] = odeToVectorField(eqn);
% create a function for ode45
F = matlabFunction(Y,'vars',{'t' 'Y' [a b c]});
% set up order of initial conditions
X0 = matlabFunction(Y_subs,'vars',{'x' 'y' 'z' 'Dy' 'Dz' 'D2z'});
tspan = [0.1 2];
x0 = X0( 0,1,1,2,0.5,1.1 ); % initial x y z Dy Dz D2z (order is important)
in3 = [2 1 -0.5]; % parameters (a,b,c)
[t, X] = ode45(@(t,y)F(t,y,in3), tspan, x0);
plot(t,X)
And here is outputs
% EQUATIONS CONVERTED TO FIRST ORDER
Y =
a/Y[2]
Y[3]
- 3*t - Y[2]^2
Y[5]
Y[6]
t*(b + c)
% SUBSTITUTIONS WERE MADE
Y_subs =
x
y
Dy
z
Dz
D2z
% MATLAB FUNCTION FOR ode45 INPUT (in3 - a,b,c coeffs)
F =
@(t,Y,in3)[in3(:,1)./Y(2);Y(3);t.*-3.0-Y(2).^2;Y(5);Y(6);t.*(in3(:,2)+in3(:,3))]
% ORDER OF INITIAL CONDITIONS
X0 =
@(x,y,z,Dy,Dz,D2z)[x;y;Dy;z;Dz;D2z]
See also HERE
0 Comments
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!