How to declare parameters in matlabFunction?
129 ビュー (過去 30 日間)
古いコメントを表示
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,
採用された回答
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 件のコメント
その他の回答 (1 件)
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
0 件のコメント
参考
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!