How to declare parameters in matlabFunction?

129 ビュー (過去 30 日間)
Abiy Wubneh
Abiy Wubneh 2019 年 9 月 24 日
編集済み: Walter Roberson 2019 年 10 月 2 日
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:
Error using odearguments (line 95)
@(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.
Error in ode45 (line 115)
odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options, varargin);
Any help will be greatly appreciated.
Thanks,
  2 件のコメント
darova
darova 2019 年 9 月 24 日
Maybe odeToVectorField wil help
Abiy Wubneh
Abiy Wubneh 2019 年 9 月 28 日
Hi darova,
Thank you for your comment! Could you please elaborate or provide an example?
Cheers!

サインインしてコメントする。

採用された回答

Walter Roberson
Walter Roberson 2019 年 9 月 29 日
編集済み: Walter Roberson 2019 年 10 月 2 日
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 件のコメント
darova
darova 2019 年 9 月 30 日
ok
Abiy Wubneh
Abiy Wubneh 2019 年 10 月 1 日
Hi Walter,
The odeFunction you suggested resolved the problem. I created vectors of the state variables and the parameters symbols and passed them to odeFunction as in1 and in2, respectively.
Thank you so much for your help!

サインインしてコメントする。

その他の回答 (1 件)

darova
darova 2019 年 9 月 28 日
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

製品


リリース

R2019a

Community Treasure Hunt

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

Start Hunting!

Translated by