How to use sym and function handle(@) in same code

9 views (last 30 days)
I have a typical problem. I want to write a script which contains both syms and @() for initializing variables.
First i used syms for variable 'theta'.
After some steps, i want to substitute 't' in place of theta and proceed for furthur calculations.(Dont suggest, u can directly take 't' and avoid theta)
I used function handle @(t) for variable 't'.
Is it possible to mingle both(sym and '@()') in one script. Otherwise do i need to give syms theta t for doing this calculations.
I tried this way
syms theta
Ai = cos(theta).*[1 1 2;
4 5 6;
9 1 3]
Bi = tan(theta).*[6 9 1;
2 5 7;
1 2 6]
Af = @(t)subs(Ai, t)
A = vpa(Af, 4)
Bf = @(t)subs(Bi, t)
B = vpa(Bf, 4)
Wr = 50
V = @(t)[cos(Wr*t);
cos(Wr*t-2*pi/3);
cos(Wr*t+2*pi/3)];
odefun = @(t,Y) A(t)\(V(t)-(B(t)*Y));
tspan = [0 10];
Y0=zeros(3,1);
[t, Y] = ode45(odefun, tspan, Y0);
Iam getting the following error
Array indices must be positive integers or logical values.
Error in sym/subsref (line 909)
R_tilde = builtin('subsref',L_tilde,Idx);
Error in checking>@(t,Y)A(t)\(V(t)-(B(t)*Y)) (line 19)
odefun = @(t,Y) A(t)\(V(t)-(B(t)*Y));
Error in odearguments (line 90)
f0 = feval(ode,t0,y0,args{:}); % ODE15I sets args{1} to yp0.
Error in ode45 (line 115)
odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options, varargin);
Error in checking (line 23)
[t, Y] = ode45(odefun, tspan, Y0);
Is there any way to rectify this without avoiding sym??

Accepted Answer

Wan Ji
Wan Ji on 1 Sep 2021
Hi,
use matlabFunction, my friend
syms theta
Ai = cos(theta).*[1 1 2;
4 5 6;
9 1 3]
Bi = tan(theta).*[6 9 1;
2 5 7;
1 2 6]
Af = @(t)subs(Ai, t)
A = vpa(Af, 4)
Bf = @(t)subs(Bi, t)
B = vpa(Bf, 4)
Wr = 50
V = @(t)[cos(Wr*t);
cos(Wr*t-2*pi/3);
cos(Wr*t+2*pi/3)];
B0 = matlabFunction(B); % That's how to use matlab function
A0 = matlabFunction(A);
odefun = @(t,Y) A0(t)\(V(t)-(B0(t)*Y));
tspan = [0 10];
Y0=zeros(3,1);
[t, Y] = ode45(odefun, tspan, Y0);

More Answers (1)

Walter Roberson
Walter Roberson on 1 Sep 2021
Is it possible to mingle both(sym and '@()') in one script.
Yes, it is.
odefun = @(t,Y) A(t)\(V(t)-(B(t)*Y));
Ok, so now we need to look back to see what A and V and B are
V = @(t)[cos(Wr*t);
cos(Wr*t-2*pi/3);
cos(Wr*t+2*pi/3)];
V is a function handle of a single parameter, and which does not use any symbolic variables. So far so good, that looks okay.
Ai = cos(theta).*[1 1 2;
4 5 6;
9 1 3]
Bi = tan(theta).*[6 9 1;
2 5 7;
1 2 6]
Those are symbolic arrays, no problem.
Af = @(t)subs(Ai, t)
And that is a function handle that does a subs(). It would be more clear and more reliable if you specified the variable to be substituted for,
Af = @(t)subs(Ai, theta, t)
That would be okay. The output of the function would be a symbolic array.
A = vpa(Af, 4)
Ah... that is kind of odd, but is valid. The symbolic toolbox will see the function handle, and will pick out the parameter name 't' from the function handle, and will create a symbolic variable with that name and pass it to the function handle. That will cause a subs() to happen that will substitute in the passed-in symbolic variable t (created by symbolic engine upon seeing the function handle) in place of theta in Ai, getting back a symbolic array that is expressed in terms of t . Then that symbolic array will be vpa()'d to 4 decimal places. The result, to be stored in A, is a symbolic array, not a function handle, and not a symbolic function. When you vpa() a function handle, MATLAB does not wrap the result into a function handle.
Bf = @(t)subs(Bi, t)
B = vpa(Bf, 4)
same issues for B: B is going to end up being a symbolic array.
odefun = @(t,Y) A(t)\(V(t)-(B(t)*Y));
[t, Y] = ode45(odefun, tspan, Y0);
ode45 is going to pass numeric t and Y to the function handle, with the t being continuous time, not time-step number and not index. In particular, the first t is going to be 0.
So now A(t) is processed. t is 0, and A is a symbolic array. Indexing an array at 0 is an error.
If you overcome that issue by changing the details of how you assign to A so that you wrap a function handle around the result of the vpa, then as discussed, the result would be a symbolic array. Likewise with B, take care of the function / array issue and the result would be a symbolic array. V(t) is fine, it will produce a numeric array. So now you have symbolic array \ symbolic array, which is going to give you back a symbolic array.
And now you have a problem, because the value you return from the odefun must be strictly numeric -- in particular must be of class single() or double()
Yes, you can combine symbolic expressions and anonymous functions, and it can be useful to do so. But you have to be careful about whether the result is function handle or symbolic function or symbolic expression or numeric expression.
I would recommend that you not do things the way you are doing them, and that instead you use symbolic functions and symbolic expressions to build your expression -- and then that you use matlabFunction() to convert into an anonymous function.
Be careful with your Y, though: at the symbolic level you will need to tell it that Y is a 3 x 1 array. And when you use matlabFunction, be sure to use the 'vars' option carefully:
matlabFunction(Expression, 'vars', {t, Y})
where Y must be 3 x 1 for this purpose (and not 1 x 3 !)
  1 Comment
Bathala Teja
Bathala Teja on 1 Sep 2021
Thank you for your suggestion sir. But i got a way(which wan ji suggested above) to proceed in my script.

Sign in to comment.

Products


Release

R2021a

Community Treasure Hunt

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

Start Hunting!