Matlab - Defining a math function - matlab

What is the difference in defining a function with syms or # (x)?
For example:
syms f(t)
f(t) = 0.5*cos(280*pi * t) + 0.5 * sin(260*pi * t) + 0.5 * cos(300*pi * t);
and
f = # (t) 0.5*cos(280*pi * t) + 0.5 * sin(260*pi * t) + 0.5 * cos(300*pi * t);
Thanks

Symbolic function
syms f(t)
f(t) = 0.5*cos(280*pi * t) + 0.5 * sin(260*pi * t) + 0.5 * cos(300*pi * t);
defines a symbolic function. This means that there is no loss of precision when using the function. The results are always exact:
>> f(1)
ans =
1
Also, you can apply symbolic operations to the function. For example, you can compute its derivative function, among other operations:
>> g = diff(f)
g(t) =
130*pi*cos(260*pi*t) - 140*pi*sin(280*pi*t) - 150*pi*sin(300*pi*t)
This is a new symbolic function, which can be used normally:
>> g(1/260)
ans =
140*pi*sin(pi/13) - 130*pi + 150*pi*sin((2*pi)/13)
Note how, again, the result is exact. If you want to obtain its numerical value (which will necessarily be an approximation) you can convert to double floating-point representation:
>> double(g(1/260))
ans =
-84.154882885760415
or, if you need more decimals, you can use vpa:
>> vpa(g(1/260), 50)
ans =
-84.154882885760413712114778738680201384788201830179
Using symbolic functions incurs a cost in efficiency: the code will generally be slower than with standard functions. Besides, they are limited to mathematical operations, whereas standard functions can do many other things, such as dealing with text or files.
Standard, numerical function
f = # (t) 0.5*cos(280*pi * t) + 0.5 * sin(260*pi * t) + 0.5 * cos(300*pi * t);
defines a standard, numerical function. More specifically, it defines an anonymous function, and then defines f as a handle to that function, with the result that f can be used as the function name.
You can "only" use this function to pass inputs and get outputs as result. Besides, with the default floating-point double data type you may encounter some numerical inaccuracies. For example, f(1) gives
>> f(1)
ans =
0.999999999999963
instead of the exact result 1.
In contrast with the symbolic case, Matlab doesn't know how to compute its derivative, so in this case you would have to do it numerically (using finite differences), which is an approximation (both because of using finite differences and because of working with floating-point values):
>> t0 = 1/260;
>> h = 1e-9;
>> (f(t0+h)-f(t0))/h
ans =
-84.154498258826038
Compared with symbolic functions, standard functions are faster (and don't require the Symbolic Toolbox), and as mentioned above, are not limited to mathematical operations.

Related

Extracting arrays of a symbolic vector in MATLAB

I have a vector of symbolic function of the following form defined in MATLAB R2021a:
O_BF(t) =
[JTP*(diff(theta(t), t)*(w1 + w3 - w4 - w2*(cos(beta)*cos(gamma) +
sin(alpha)*sin(beta)*sin(gamma))) - w2*(cos(gamma)*sin(beta) -
cos(beta)*sin(alpha)*sin(gamma))*diff(say(t), t)), -JTP*(diff(phi(t), t)*(w1 + w3 - w4 - w2*
(cos(beta)*cos(gamma) + sin(alpha)*sin(beta)*sin(gamma))) +
w2*cos(alpha)*sin(gamma)*diff(say(t), t)), JTP*(w2*(cos(gamma)*sin(beta) -
cos(beta)*sin(alpha)*sin(gamma))*diff(phi(t), t) + w2*cos(alpha)*sin(gamma)*diff(theta(t),
t))]
And I want the following results, which obviously is the extracted parts of the above vector:
[JTP*(diff(theta(t), t)*(w1 + w3 - w4 - w2*(cos(beta)*cos(gamma) +
sin(alpha)*sin(beta)*sin(gamma))) - w2*(cos(gamma)*sin(beta) -
cos(beta)*sin(alpha)*sin(gamma))*diff(say(t), t))
-JTP*(diff(phi(t), t)*(w1 + w3 - w4 - w2*
(cos(beta)*cos(gamma) + sin(alpha)*sin(beta)*sin(gamma))) +
w2*cos(alpha)*sin(gamma)*diff(say(t), t))
JTP*(w2*(cos(gamma)*sin(beta) -
cos(beta)*sin(alpha)*sin(gamma))*diff(phi(t), t) +
w2*cos(alpha)*sin(gamma)*diff(theta(t),
t))]
As You can see, this is clearly a vector, but I cannot extract the arrays because MATLAB considers this vector as a function of time. How can I do that?
O_BF(t) in your question is a symbolic function with respect to t that returns a matrix.
This a common issue when working with symbolic functions and Matlab symfun objects. Here's a simpler example that I think reproduces the behavior observed in the question:
syms t a; %define symbolic variables
f(t) = [t a*t 2*t^2]; %define symfun array as function of t
Calling f(1) evaluates the symfun for t = 1 rather than extracting the first element of the 1-by-3 array:
>> f(1)
ans =
[1, a, 2]
To access the elements of the underlying array one must assign the contents to an intermediate symbolic variable:
g = f(t); %or even f=f(t) to redefine f as sym rather than symfun
g(1)
>> g(1)
ans =
t
This is equivalent to using the formula function:
g = formula(f);
g(1)
>> g(1)
ans =
t
I know of no current way to directly access the elements of an array defined as a symfun without going through the above steps.

Series expansion of a function about infinity - how to return coefficients of series as a Matlab array?

This question is connected to this one. Suppose again the following code:
syms x
f = 1/(x^2+4*x+9)
Now taylor allows the function f to be expanded about infinity:
ts = taylor(f,x,inf,'Order',100)
But the following code
c = coeffs(ts)
produces errors, because the series does not contain positive powers of x (it contains negative powers of x).
In such a case, what code should be used?
Since the Taylor Expansion around infinity was likely performed with the substitution y = 1/x and expanded around 0, I would explicitly make that substitution to make the power positive for use on coeffs:
syms x y
f = 1/(x^2+4x+9);
ts = taylor(f,x,inf,'Order',100);
[c,ty] = coeffs(subs(ts,x,1/y),y);
tx = subs(ty,y,1/x);
The output from taylor is not a multivariate polynomial, so coeffs won't work in this case. One thing you can try is using collect (you may get the same or similar result from using simplify):
syms x
f = 1/(x^2 + 4*x + 9);
ts = series(f,x,Inf,'Order',5) % 4-th order Puiseux series of f about 0
c = collect(ts)
which returns
ts =
1/x^2 - 4/x^3 + 7/x^4 + 8/x^5 - 95/x^6
c =
(x^4 - 4*x^3 + 7*x^2 + 8*x - 95)/x^6
Then you can use numden to extract the numerator and denominator from either c or ts:
[n,d] = numden(ts)
which returns the following polynomials:
n =
x^4 - 4*x^3 + 7*x^2 + 8*x - 95
d =
x^6
coeffs can then be used on the numerator. You may find other functions listed here helpful as well.

Explicit polyfit with variables

I am using polyfit to get the following 4-degree polynomial:
0.5152 -1.0687 0.0269 1.1781 -0.4943
I need this polynomial explicitly, i.e., I need to have the variables in it, too. That is I need it as a symbolic expression, e.g.,
f(q) = 0.5152 q^4 -1.0687 q^3 0.0269 q^2 1.1781 q -0.4943
because my function f(q) is the input of another function g(q). Example: I am having function g as:
g(q) = q^2
and I need f(q) WITH variable q in it so that I can evaluate g at f symbolically. That is, the result should be a SYMBOLIC function g:
g(f(q)) = ( 0.5152 q^4 -1.0687 q^3 0.0269 q^2 1.1781 q -0.4943 )^2
Any ideas how I can represent f(q) from polyfit such that I can use it as symbolic input in g?
Use poly2sym to transform the vector of coefficients into a symbolic polynomial:
>> poly2sym([1 2 3],'x')
ans =
x^2 + 2*x + 3

Simplify behavior on symbolic expression with limit

I want to simplify this symbolic expression, and then take the limit of it (this is not too hard on a paper) using Matlab
syms n x
sn = 8^n * n^2 * (sin(x))^(3*n)
simplify(sn^(1/n))
which results in
ans =
8*n^(2/n)*(sin(x)^(3*n))^(1/n)
This must be like 8 * n^(2/n) * (sin(x))^3. However, if I use
x = sym('x', 'positive'); n = sym('n', 'positive');
sn = 8^n * n^2 * (sin(x))^(3*n)
simplify(sn^(1/n))
to obtain a similar answer and then take limit, I get:
limit(ans, n, inf)
ans =
8*limit(n^(2/n)*(sin(x)^(3*n))^(1/n), n == Inf)
instead of 8*sin(x)^3.
If I simplify this on paper and then take limit, everything works:
limit(8*n^(2/n)*sin(x)^3, n, inf)
ans =
8*sin(x)^3
Is it possible to solve this using Matlab?
MuPAD doesn't simplify the expression, and thus can't take the limit, because you haven't provided the appropriate assumptions. It's not true that an expression such as (sin(x)^n)^(1/n) simplifies to sin(x) if n and x are positive. You need to fully restrict the range of x as it the argument of a periodic function:
x = sym('x','positive');
n = sym('n','real');
assumeAlso(x<=sym(pi));
sn = 8^n * n^2 * (sin(x))^(3*n);
sn2 = simplify(sn^(1/n))
limit(sn2, n, Inf)
which returns the answer you were expecting
ans =
8*sin(x)^3
If you have access to Mathematica, this sort of thing can be accomplished very easily:
Limit[(8^n n^2 Sin[x]^(3 n))^(1/n), n -> \[Infinity], Assumptions -> {n \[Element] Reals, x >= 0, x <= \[Pi]}]

how to solve a system of Ordinary Differential Equations (ODE's) in Matlab

I have to solve a system of ordinary differential equations of the form:
dx/ds = 1/x * [y* (g + s/y) - a*x*f(x^2,y^2)]
dy/ds = 1/x * [-y * (b + y) * f()] - y/s - c
where x, and y are the variables I need to find out, and s is the independent variable; the rest are constants. I've tried to solve this with ode45 with no success so far:
y = ode45(#yprime, s, [1 1]);
function dyds = yprime(s,y)
global g a v0 d
dyds_1 = 1./y(1) .*(y(2) .* (g + s ./ y(2)) - a .* y(1) .* sqrt(y(1).^2 + (v0 + y(2)).^2));
dyds_2 = - (y(2) .* (v0 + y(2)) .* sqrt(y(1).^2 + (v0 + y(2)).^2))./y(1) - y(2)./s - d;
dyds = [dyds_1; dyds_2];
return
where #yprime has the system of equations. I get the following error message:
YPRIME returns a vector of length 0, but the length of initial
conditions vector is 2. The vector returned by YPRIME and the initial
conditions vector must have the same number of elements.
Any ideas?
thanks
Certainly, you should have a look at your function yprime. Using some simple model that shares the number of differential state variables with your problem, have a look at this example.
function dyds = yprime(s, y)
dyds = zeros(2, 1);
dyds(1) = y(1) + y(2);
dyds(2) = 0.5 * y(1);
end
yprime must return a column vector that holds the values of the two right hand sides. The input argument s can be ignored because your model is time-independent. The example you show is somewhat difficult in that it is not of the form dy/dt = f(t, y). You will have to rearrange your equations as a first step. It will help to rename x into y(1) and y into y(2).
Also, are you sure that your global g a v0 d are not empty? If any one of those variables remains uninitialized, you will be multiplying state variables with an empty matrix, eventually resulting in an empty vector dyds being returned. This can be tested with
assert(~isempty(v0), 'v0 not initialized');
in yprime, or you could employ a debugging breakpoint.
the syntax for ODE solvers is [s y]=ode45(#yprime, [1 10], [2 2])
and you dont need to do elementwise operation in your case i.e. instead of .* just use *