Plotting a function in another .m file - matlab

i started programming Matlab the last week and i`ve been trying to plot a function file with no success.
This is my function file (impuls.m). It basicaly should set y = 0 for 0<=x<5 and x>10. y = 5 for 5<=x<=10).
function y = impuls(x)
if ((x>=0 && x<5) || x>10)
y=0;
else if (x>=5 && x<=10)
y=5;
end
end
end
I guess i did it right, because when i test it on my main file (fourierreihe.m) using impuls(1) i get a "0" and when using impuls(7) i get a 5. The problem is when i try to get all resuts for the interval [0 13] and plot them as a rectangular impuls.
I tried using:
impuls([0 13])
But i keep getting the error:
fouhierreihen
Operands to the || and && operators must be convertible to logical scalar values.
Error in impuls (line 3)
if ((x>=0 && x<5) || x>10)
Error in fouhierreihen (line 1)
impuls([0 13])
Shouldnt i be getting something as "ans = 0 0 0 0 0 5 5 5 5 5 5 0 0 0" this as an answer?
So guys, what am i doing wrong? I`ve searched for videos and posts and i cant find the mistake there. How could i possibly plot it for the interval?
Thank you in advance,
Pedro.

As the error message and documentation explain, inputs to the short-circuit logical operators must be scalars. It doesn't really make sense fundamentally trying to robustly short circuit with two arrays of truth values.
You can use logical indexing to accomplish the same task in a vectorized manner. For example:
function y = impuls(x)
y = zeros(size(x)); % Initialize the output array
y(x>=5 & x<=10) = 5; % Condition one
Which returns:
impuls(1) =
0
impuls(7) =
5
impuls([0 13]) =
0 0
impuls(0:13) =
0 0 0 0 0 5 5 5 5 5 5 0 0 0
That your original function works with fplot is a concession from MATLAB's developers. The function documentation repeatedly states that the function being plotted must accept vector inputs (though they don't actually enforce it, apparently):
The function must accept a vector input argument and return a vector
output argument of the same size
Your function doesn't do this, because && and || are scalar operations. However, fplot will revert to calculating function outputs element-by-element (a loop) in the event that the array input fails, throwing the following warning:
Warning: Function fails on array inputs. Use element-wise operators to increase speed.
> In matlab.graphics.function.FunctionLine>getFunction
In matlab.graphics.function.FunctionLine/updateFunction
In matlab.graphics.function.FunctionLine/set.Function_I
In matlab.graphics.function.FunctionLine/set.Function
In matlab.graphics.function.FunctionLine
In fplot>singleFplot (line 223)
In fplot>#(f)singleFplot(cax,{f},limits,extraOpts,args) (line 182)
In fplot>vectorizeFplot (line 182)
In fplot (line 153)
In trialcode (line 1)

My Friend....
Try this:
function y = impulse(t)
if 0
%% Example
t=(0:100)';
y=impulse(t)
plot(t,y);
end
for i=1:length(t)
if ((t(i)>=0 && t(i)<5) || t(i)>10)
y(i,1)=0;
else if (t(i)>=5 && t(i)<=10)
y(i,1)=5;
end
end
end
Note:
the for loop is critical in these cases,
the function impulse could exist anywhere, but your local version prevail,
the y(i,1) retain your vector as columns,
run the section inside the void loop (if 0)
the time is normally used here as variable :)....
hyp.

Related

Why does Matlab factorial function perceives an integer as a non-integer?

I'm trying to build a function in Matlab which generates a Taylor series around 0 for sine and the user can insert x (the value for which the sine is approximated) and a maximum error. Thus I want the function to check the maximum error and from this maximum it generates the amount of elements in the Taylor series.
I get the following error:
Error using factorial (line 20)
N must be an array of real non-negative integers.
Error in maxError (line 19)
y(x) = y(x) + (-1)^(j) * x^(2j+1)/factorial(2j+1)
Below my code.
function [n] = maxError(x,e);
%Computes number of iterations needed for a given absolute error.
n=1;
while abs(x)^(n+1)/factorial(n+1) >= e
n = n+1;
end
if mod(n,2) == 0
n=n+1;
end
y=#(x) x;
j=1;
while j<n
y(x) = y(x) + (-1)^(j) * x^(2j+1)/factorial(2j+1)
j=j+1;
end
return
I think I get the error because the factorial function can only take up integers, but the way I see it, I am feeding it an integer. Since j=1; and then gets larger by one per iteration, I don't see how Matlab can perceive this as something else than a integer.
Any help is appreciated.
You are using j as an indexing variable, which is also the complex number in Matlab, and your are forgetting a * multiply.
You can use j as a variable (not recommended!) but when you are putting a number in front of it, Matlab will stil interpret is as the complex number, and not as the variable.
Adding the multiplication symbol will solve the issue, but using i and j as variables will give you these hard to debug errors. If you had used a, the error would have been easier to understand:
>> a=10;
>> 2a+1
2a+1
↑
Error: Invalid expression. Check for missing multiplication operator, missing or
unbalanced delimiters, or other syntax error. To construct matrices, use brackets
instead of parentheses.

MATLAB symengine fails on a logical statement

I want to make matlab agree with the following simple statement:
(x-a)^b>=0 when x>0, a>0, b<0, x>a
In order to do so I write:
syms x a b
assume(x>0 & a>0 & b<0 & x>a);
isAlways((x-a)^b>=0,'Unknown','error')
And get the following error message:
Error using symengine
Cannot prove '0 <= (x - a)^b'.
Error in sym/isAlways (line 38)
Y = mupadmex('symobj::isAlways',X.s,isMath,['"Unknown' p.Unknown '"'],9);
Why does MATLAB fail to agree with such an evident statement?
I don't know why but instead of using as assumption x>a, use x-a > 0. I think MATLAB doesn't "compute" the difference between x and a and so it doesn't know if x-a is greater than 0 or not. So it must already know that x-a is greater than 0 when you check the condition.

build functions with str2func command in matlab

I want to build a series of different function with matlab and integrate and differentiate the results. but the mathwork says the output of the str2func can't access the variable or could bot be used by other function.
Is any one help me with this problem?
I want to create these function:
f1= #(x,l) x.*(l-x);
f2= #(x,l) x.^2.*(l-x).^2.*(l/2-x).^2;
f3= #(x,l) x.^3.*(l-x).^3;
f4= #(x,l) x.^4.*(l-x).^6.*(l/2-x).^4;
f5= #(x,l) x.^5.*(l-x).^5;
f6= #(x,l) x.^6.*(l-x).^6.*(l/2-x).^6;
f7= #(x,l) x.^7.*(l-x).^7;
f8= #(x,l) x.^8.*(l-x).^8.*(l/2-x).^8;
f9= #(x,l) x.^9.*(l-x).^9;
f10= #(x,l) x.^10.*(l-x).^10.*(l/2-x).^10;
I write this function:
syms x l
f=cell(10,1);
fun=cell(10,1);
for i=1:10
if mod(i,2) ~= 0
f{i}=['x','.^',num2str(i),'.*','(l-x)','.^',num2str(i)];
else
f{i}=['x','.^',num2str(i),'.*','(l-x)','.^',num2str(i),'.*','(l/2-x)','.^',num2str(i)];
end
end
for i=1:10
for j=1:10
if mod(i,2) ~= 0 & mod(j,2) ~= 0
Fs = ['(x)','x','.^',num2str(i),'.*','(l-x)','.^',num2str(i),'*','x','.^',num2str(j),'.*','(l-x)','.^',num2str(j)];
FS = str2func (Fs)
fjnew = str2func(['(x)','x','.^',num2str(j),'.*','(l-x)','.^',num2str(j)])
fj_diff = diff(fjnew,x)
when I run that the error is :
Undefined function '(x)x.^1.*(l-x).^1' for input arguments of type 'sym'.
Error in sym>funchandle2ref (line 1172)
S = x(S{:});
Error in sym>tomupad (line 989)
x = funchandle2ref(x);
Error in sym (line 142)
S.s = tomupad(x,'');
Error in sym/privResolveArgs (line 810)
argout{k} = sym(arg);
Error in sym/diff (line 21)
args = privResolveArgs(S,varargin{:});
Your Sincerely
Saeed Nasiri
I found all your problems.
The character "l" is not the character "1". One of them is L and the other is a number. You just wrote "l" \ell\ instead of "1" \one\ in (l-x). EDIT I just realised you actually want l not 1.
Function handles are not (x)x.^2 (random example), they are #(x)x.^2! You forgot to add the "#" in all the calls, thus =['(x)' should be =['#(x)'
3.Your functions are actually (as yourself described in the post), variable respect x and l. Thus, you need the function handle to say that. Change =['#(x)' for =['#(x,l)'.
Iam not sure if you are aware of this, but you dont use practically any of the parts of your code. Your code can be reduced to 4 lines and it will do exactly the same. Fs,FS adn f are never use.:
The result of your code is the same as:
for i=1:10
for j=1:10
if mod(i,2) ~= 0 & mod(j,2) ~= 0
fjnew = str2func(['#(x,l)','x','.^',num2str(j),'.*','(l-x)','.^',num2str(j)])
fj_diff = diff(fjnew,x)
end
end
end
So unless you are doing more stuff with it later, there is no need to compute stuff unnecessarily.

Saving derivative values in ode45 in Matlab

I'm simulating equations of motion for a (somewhat odd) system with mass-springs and double pendulum, for which I have a mass matrix and function f(x), and call ode45 to solve
M*x' = f(x,t);
I have 5 state variables, q= [ QDot, phi, phiDot, r, rDot]'; (removed Q because nothing depends on it, QDot is current.)
Now, to calculate some forces, I would like to also save the calculated values of rDotDot, which ode45 calculates for each integration step, however ode45 doesn't give this back. I've searched around a bit, but the only two solutions I've found are to
a) turn this into a 3rd order problem and add phiDotDot and rDotDot to the state vector. I would like to avoid this as much as possible, as it's already non-linear and this really makes matters a lot worse and blows up computation time.
b) augment the state to directly calculate the function, as described here. However, in the example he says to make add a line of zeros in the mass matrix. It makes sense, since otherwise it will integrate the derivative and not just evaluate it at the one point, but on the other hand it makes the mass matrix singular. Doesn't seem to work for me...
This seems like such a basic thing (to want the derivative values of the state vector), is there something quite obvious that I'm not thinking of? (or something not so obvious would be ok too....)
Oh, and global variables are not so great because ode45 calls the f() function several time while refining it's step, so the sizes of the global variable and the returned state vector q don't match at all.
In case someone needs it, here's the code:
%(Initialization of parameters are above this line)
options = odeset('Mass',#massMatrix);
[T,q] = ode45(#f, tspan,q0,options);
function dqdt = f(t,q,p)
% q = [qDot phi phiDot r rDot]';
dqdt = zeros(size(q));
dqdt(1) = -R/L*q(1) - kb/L*q(3) +vs/L;
dqdt(2) = q(3);
dqdt(3) = kt*q(1) + mp*sin(q(2))*lp*g;
dqdt(4) = q(5);
dqdt(5) = mp*lp*cos(q(2))*q(3)^2 - ks*q(4) - (mb+mp)*g;
end
function M = massMatrix(~,q)
M = [
1 0 0 0 0;
0 1 0 0 0;
0 0 mp*lp^2 0 -mp*lp*sin(q(2));
0 0 0 1 0;
0 0 mp*lp*sin(q(2)) 0 (mb+mp)
];
end
The easiest solution is to just re-run your function on each of the values returned by ode45.
The hard solution is to try to log your DotDots to some other place (a pre-allocated matrix or even an external file). The problem is that you might end up with unwanted data points if ode45 secretly does evaluations in weird places.
Since you are using nested functions, you can use their scoping rules to mimic the behavior of global variables.
It's easiest to (ab)use an output function for this purpose:
function solveODE
% ....
%(Initialization of parameters are above this line)
% initialize "global" variable
rDotDot = [];
% Specify output function
options = odeset(...
'Mass', #massMatrix,...
'OutputFcn', #outputFcn);
% solve ODE
[T,q] = ode45(#f, tspan,q0,options);
% show the rDotDots
rDotDot
% derivative
function dqdt = f(~,q)
% q = [qDot phi phiDot r rDot]';
dqdt = [...
-R/L*q(1) - kb/L*q(3) + vs/L
q(3)
kt*q(1) + mp*sin(q(2))*lp*g
q(5)
mp*lp*cos(q(2))*q(3)^2 - ks*q(4) - (mb+mp)*g
];
end % q-dot function
% mass matrix
function M = massMatrix(~,q)
M = [
1 0 0 0 0;
0 1 0 0 0;
0 0 mp*lp^2 0 -mp*lp*sin(q(2));
0 0 0 1 0;
0 0 mp*lp*sin(q(2)) 0 (mb+mp)
];
end % mass matrix function
% the output function collects values for rDotDot at the initial step
% and each sucessful step
function status = outputFcn(t,q,flag)
status = 0;
% at initialization, and after each succesful step
if isempty(flag) || strcmp(flag, 'init')
deriv = f(t,q);
rDotDot(end+1) = deriv(end);
end
end % output function
end
The output function only computes the derivatives at the initial and all successful steps, so it's basically doing the same as what Adrian Ratnapala suggested; re-run the derivative at each of the outputs of ode45; I think that would even be more elegant (+1 for Adrian).
The output function approach has the advantage that you can plot the rDotDot values while the integration is being run (don't forget a drawnow!), which can be very useful for long-running integrations.

matlab cant divide using /

I have some simple function that takes in a value
This value is the checked off a number of if or elseif statements to calculate another value.
The problem is it seems to find an error when trying to run which says
Error using /
Matrix dimensions must agree.
Error in abc (line 9)
a = 5000 / g;
the code is as follows
function abc(g)
if (g == 100)
a = 1;
elseif (g <= 99 & g >= 50)
a = 200 -2*g;
elseif (g <= 50 & g >= 1)
a = 5000 / g;
else
warning('Invalid value passed, a defaults to 1');
a =1;
end
end
So, im passing in abc 100 and i expect a to be 1 but instead it runs through each if / elseif and throws an error on a = 5000/g
I should also mention that i initially tried using && in the elseifs but this also gave an error which said
Operands to the || and && operators must be convertible to logical scalar values.
Error in abc (line 6)
elseif (g <= 99 && g >= 50)
Anybody any idea whats going on here ?
Thanks
You are probably passing a matrix to your function, e.g. when you call
abc(yourdata)
yourdata is actually not one number, but a matrix. If you called directly
abc(100)
you should not see your problem (or do you?).
In other words, your main problem is not inside your function, but when you call it!
Given your description, it seems that you set yourdata(1) to the value 100 that you want to test, but some other element of the matrix has a different value, which is why the if construct branches into the else case. There, you need ./ instead of / if you want to do element-wise division instead of matrix division.
But really you probably just need to make sure that yourdata is scalar when you call your function.