For a mathematics course for first year university science students we (the teaching assistants) need to prepare material for pc-sessions using Matlab. All computers are equipped with Matlab version R2016b.
We are working through some material from the previous years. In the section covering the plotting of piecewise functions, we found some inconsistencies in the way Matlab handles an if
condition.
I would like to know why these things happen so we are prepared for any difficulties the students might experience in these sessions. The goal of the exercise is to draw a house in the plotting window by plotting two piecewise functions.
The first function, f1(x)
, evaluates to x+2
when x <= 0
and evaluates to -x+2
otherwise. The students are asked to implement this function in Matlab using an if
/ else
construct. Our implementation is
function y = f1( x )
if x < 0
y = x + 2;
else
y = -x + 2;
end
end
The second function, f2(x)
, is the characteristic function of the interval [-1, 1]. It should also be implemented using if
/ else
conditions. Our implementation is
function y = f2( x )
if x < -1
y = 0;
elseif x > 1
y = 0;
else
y = 1;
end
end
Finally, the plotting code should draw both functions on the interval [-1.5, 1.5]
using fplot
like so
fplot(@f1, [-1.5, 1.5])
hold on
fplot(@f2, [-1.5, 1.5])
The function f2
is plotted without problems. In plotting f1
, however, it seems Matlab decided the first branch of the if-clause didn't matter as only the line -x+2
is plotted .
It seems vectorization issues lie at the heart of our problem since f1(-1)
evaluates correctly to 1 but f1([-1, 1])
evaluates to [3, 1]
. Then again, f2 seems to be evaluating correctly without any issues.
Things get stranger when we change the -x + 2
in the else
part of f1
to -x^2 + 2
. With this definition both functions are plotted correctly and Matlab seems to have no problem dealing with the conditionals.
In MATLAB if vector
is like if all(vector)
, and that is the source to your error. use indexing instead:
function y = f2( x )
y = zeros(size(x));
idxs1 = x >= -1;
idxs2 = x <= 1;
y(idxs1 & idxs2) = 1;
end
function y = f1( x )
y = zeros(size(x));
idxs = x < 0;
y(idxs) = x(idxs) + 2;
y(~idxs) = -x(~idxs) + 2;
end
fplot(@f1, [-1.5, 1.5])
hold on
fplot(@f2, [-1.5, 1.5])
Using an If Statement
You say that you want to specifically use an if
structure, in which case you will have to evaluate each element of the input vector in turn
function y = f1( x )
y = zeros(size(x)); % Initialise y to the correct size
for ii = 1:numel(x) % Loop through elements of x (and so y)
if x(ii) < 0
y(ii) = x(ii) + 2;
else
y(ii) = -x(ii) + 2;
end
end
end
This is because otherwise you may have the following issue:
x = [1, 2, -1, 3, -2];
% x < 0 = [0, 0, 1, 0, 1];
% "if x < 0" is the same as "if all(x < 0)" = false, so if statement skipped
Logical Indexing
If the course material can be changed / extended, then a much better option in Matlab is to leverage logical indexing.
x = [1, 2, -1, 3, -2];
y = -x + 2; % Initialise variable y, assign its values to -x + 2 by default
y(x<0) = x + 2; % Assign values of y, where x<0, to x + 2
Now it can be seen how this can be done in a one liner...
coef = (x < 0)*2 - 1; % For the above example, coef = [-1, -1, 1, -1, 1];
y = coef.*x + 2; % Coeff can be done in-line without being declared
So, with a similar (but even simpler) approach to f2
as well,
function y = f1(x)
y = ((x<0)*2 - 1).*x + 2;
end
function y = f2(x)
y = (abs(x) < 1);
end
Then your demo gives the desired result
As for your mysteries when changing part of the piecewise function and everything working... For me, your code all works anyway (2015b)! My guess is that this is something to do with how fplot
is calling your functions. I currently can't access the docs, which may contain the answer. In my above examples, I'm assuming x
is being passed as a vector (which may have 1 or more elements). If fplot
determines the x
values and calls the function as if for single points, then your code should work.
A way to edit the task to make things clearer may be to just use the normal plot
function , which I think is more useful for students to be familiar with anyway.
Then your demo would be called like so
x = -1.5:0.1:1.5 % or could use linspace(-1.5, 1.5, 100) etc
hold on;
plot(x, f1(x)); % x,y syntax, more apparent where the points will be plotted
plot(x, f2(x)); % than when using fplot
hold off; % good habit to hold off so that you don't accidentally plot on this fig later
Notice that, with this clear definition of x
, your -x^2 + 2
would throw an error as you are asking for matrix multiplication of a 1D vector. You would actually have to use -x.^2 + 2
. There's a cue for students to learn about element-wise operations in Matlab!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.