在Matlab中绘制分段函数的不一致性

时间:2017-04-18 10:55:23

标签: matlab vectorization

对于第一年大学理科学生的数学课程,我们(教学助理)需要使用Matlab为pc会话准备材料。所有计算机都配有Matlab版本R2016b。

我们正在研究前几年的一些材料。在涵盖分段函数绘图的部分中,我们发现Matlab处理if条件的方式存在一些不一致。

我想知道为什么会发生这些事情,所以我们已经为学生在这些课程中可能遇到的任何困难做好了准备。练习的目的是通过绘制两个分段函数在绘图窗口中绘制一个房子。

第一个函数f1(x)x+2时评估为x <= 0,否则评估为-x+2。要求学生使用if / else构造在Matlab中实现此功能。我们的实施是

function y = f1( x )
    if x < 0
        y = x + 2;
    else
        y = -x + 2;
    end
end

第二个函数f2(x)是区间[-1,1]的特征函数。它也应该使用if / else条件来实现。我们的实施是

function y = f2( x )
    if x < -1
        y = 0;
    elseif x > 1
        y = 0;
    else
        y = 1;
    end
end

最后,绘图代码应使用[-1.5, 1.5]fplot区间内绘制两个函数,如此

fplot(@f1, [-1.5, 1.5])
hold on
fplot(@f2, [-1.5, 1.5])

绘制函数f2没有问题。 然而,在绘制f1时,似乎Matlab认为if子句的第一个分支并不重要,因为只绘制了行-x+2

似乎矢量化问题是我们问题的核心,因为f1(-1)正确评估为1但f1([-1, 1])评估为[3, 1]。然后,f2似乎正在正确评估,没有任何问题。

当我们将-x + 2 else部分f1更改为-x^2 + 2时,事情变得更加奇怪。通过这个定义,两个函数都被正确绘制,Matlab似乎没有问题处理条件。

  1. 出了什么问题?
  2. 有没有办法可以编辑练习,这样就不会出现任何问题,但是第一次使用Matlab的学生仍然可以使用它?

2 个答案:

答案 0 :(得分:0)

在MATLAB中,if vectorif all(vector)类似,这是您的错误的来源。改为使用索引:

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])

enter image description here

答案 1 :(得分:0)

使用If语句

您说您想要专门使用if结构,在这种情况下,您必须依次评估输入向量的每个元素

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

这是因为否则您可能会遇到以下问题:

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

逻辑索引

如果可以更改/扩展课程材料,那么Matlab中更好的选择是利用逻辑索引。

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

现在可以看到如何在一个班轮中完成这个......

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

所以,对f2采用类似(但更简单)的方法,

function y = f1(x)
    y = ((x<0)*2 - 1).*x + 2;
end

function y = f2(x)
    y = (abs(x) < 1);  
end

然后您的演示会提供所需的结果

house

至于改变部分功能和一切正常工作时的神秘感......对我而言,你的代码无论如何都有效(2015b)!我的猜测是,这与fplot如何调用你的函数有关。我目前无法访问可能包含答案的文档。在上面的例子中,我假设x作为向量传递(可能有一个或多个元素)。如果fplot确定x值并将函数调用为单点,则代码应该有效。

编辑任务以使事情更清晰的方法可能只是使用普通的plot函数,我认为这对学生来说更有用。

然后你的演示会像这样被调用

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

请注意,如果明确定义x,则-x^2 + 2会因为要求矩阵乘以1D向量而引发错误。你实际上必须使用-x.^2 + 2。学生可以在Matlab中学习元素操作!