Piecewise function as condition in another piecewise function

Hello everyone,
I am using Symbolic Math Toolbox in order to define a matlabFunction to be used in Simulink.
I am having problem when evaluating the code that follows:
x = sym('x',[N 1]);
L = 100;
z(1,1) = x(2) - x(1); % delta x(N)
z(1,1) = piecewise(z(1)<0,L+z(1),z(1)>=0,z(1));
V(1,1) = piecewise(z(1)<=3,0,3<z(1)<5,z(1),10);
matlabFunction(V,'File','FUNCTION','Vars',{z});
The original code is more complex, but a simplified version is this one.
I get the following error message:
Error using symengine
Unable to evaluate to Boolean.
Error in sym/mupadmexnout (line 1057)
out = mupadmex(fcn,args{:});
Error in sym/matlabFunction>optimize (line 468)
[tvalues,f,tnames] = mupadmexnout('symobj::optimizeWithIntermediates',f{:});
Error in sym/matlabFunction>writeMATLAB (line 443)
[f,tvalues,tnames] = optimize(f,optim);
Error in sym/matlabFunction (line 183)
g = writeMATLAB(funs,file,varnames,outputs,body, opts.Optimize, opts.Sparse, opts.Comments);
Error in main (line 94)
matlabFunction(V,'File','FUNCTION','Vars',{z});
Where (line 94) refers to the line where I call the matlabFunction.
I'm not sure, but I tried to modify something and I think that what gives problems is that in the 2nd piecewise function I use the evaluation of the output of another piecewise function, because in the 2nd piecewise function I use z(1) that comes out from the 1st piecewise.
Do you think it may be the problem? Because if I exchange the order ot the two piecewise functions it works. Unfortunately I want to evaluate z(1) and then modify it before evaluating V(1).
z(1) is a symbolic variable, but maybe it doesn't like it because from the 1st piecewise z(1) is a piecewise function and it is not good to use it to evaluate a condition in another piecewise.
I was trying to use an alternative to the 2nd piecewise, that implements a saturation function, but I don't know if there's another way, maybe smarter. What do you think?
Thank you in advance

 Respuesta aceptada

matlabFunction(V,'File','FUNCTION','Vars',{x});
worked for me. You cannot use z as your Vars in matlabFunction because you need to list the names of the independent variables.
Caution: in some recent releases, the optimization done by default in matlabFunction writing to a file is broken. Until that is known to be fixed I recommend turning off optimization:
matlabFunction(V,'File','FUNCTION','Vars',{x}, 'optimize', 0);
Note: when you use matlabFunction on an expression that includes piecewise() then the resulting code is not vectorized in any variable appearing in the piecewise() conditional tests.

5 comentarios

Thank you very much,
you're right, actually my original code did have an independent variable in input to matlabFunction, it was like the following:
% Declaration of symbolic variables
x = sym('x',[N 1]);
z = sym('z', [N 1]);
Vopt = sym('v',[N 1]);
%% Plant definition
b = 20; % [1/s]
L = 100; % [m]
z(N,1) = x(1) - x(N); % delta x(N)
Vopt(N,1) = piecewise(z(N,1)<b,0, b<=z(N,1)<L,0, z(N,1)>=L,0);
for i=1:N-1,
z(i,1) = x(i+1) - x(i); % delta x(i)
Vopt(i,1) = piecewise(z(i,1)<b,0, b<=z(i,1)<L,0, z(i,1)>=L,0);
end
matlabFunction(Vopt,'File','OptimalVelocity','Vars',{x},'optimize', 0);
Now, this simple code works! It is due to the optimization, I believe, so thank you very much for your help! Now I'm going to do it to my more complex problem and hope it works with this hint.
I don't understand well what you mean here:
Note: when you use matlabFunction on an expression that includes piecewise() then the resulting code is not vectorized in any variable appearing in the piecewise() conditional tests.
Suppose you had something like
syms x y
f = matlabFunction( x.^2 + y.^2, 'vars', [x, y])
then the output would be
@(x,y)x.^2+y.^2
Notice that you can pass in arrays of compatible sizes, so you could use
f(rand(3,5), rand(3,5))
and even if you use
syms x y
f = matlabFunction( x.^2 + y.^2, 'vars', {[x, y]})
you get out
@(in1)in1(:,1).^2+in1(:,2).^2
Notice you can pass in multiple rows (with two columns) and it will treat each row as an x, y pair:
f(rand(15,2))
So mostly when you use matlabFunction, the resulting function handle you get out is vectorized (following the pattern established by the 'vars' parameter)
However, if the expression includes an int() that cannot be removed, or if the expression contains piecewise(), then the resulting function handle is not vectorized. For example,
syms x y
f = matlabFunction( int(sqrt(sin(x)-x.^2),x,0,y), 'vars', {y})
gives back
@(y)integral(@(x)sqrt(sin(x)-x.^2),0.0,y)
which can only be evaluated for scalar parameters y.
If you use int() then you can at least use matlabFunction to return an anonymous function. When you use piecewise() then you will get an error unless you tell it to write to a file using the 'File' option. The resulting code might look something like
1 function V = FUNCTION(in1)
2 %FUNCTION
3 % V = FUNCTION(IN1)
4
5 % This function was generated by the Symbolic Math Toolbox version 8.6.
6 % 28-Nov-2020 15:49:10
7
8 x1 = in1(1,:);
9 x2 = in1(2,:);
10 t2 = -x1;
11 t3 = t2+x2;
12 if ((t3 <= -9.7e+1) | ((0.0 <= t3) & (t3 <= 3.0)))
13 V = 0.0;
14 elseif ((t3 < -9.5e+1) & (-9.7e+1 < t3))
15 V = t3+1.0e+2;
16 elseif ((3.0 < t3) & (t3 < 5.0))
17 V = t3;
18 else
19 V = 1.0e+1;
20 end
Notice how on lines 12 and 14 and 16, the code assumes that t3 is a scalar -- the code is not vectorized in its inputs.
Thank you very much.
May I ask one more thing? I don't know exactly the usage of expressions like this:
@(x,y)x.^2+y.^2
Are they used to define functions, right? But I'm not sure to understand how it works.
PS: my original complex code works! Thank you again, you saved my life!
Thank you, you're very kind.

Iniciar sesión para comentar.

Más respuestas (0)

Community Treasure Hunt

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

Start Hunting!

Translated by