How can I create a piecewise inline function in MATLAB? - matlab

I have a function in MATLAB which takes another function as an argument. I would like to somehow define a piecewise inline function that can be passed in. Is this somehow possible in MATLAB?
Edit: The function I would like to represent is:
f(x) = { 1.0, 0.0 <= x <= 0.5,
-1.0, 0.5 < x <= 1.0
where 0.0 <= x <= 1.0

You really have defined a piecewise function with three break points, i.e., at [0, 0.5, 1]. However, you have not defined the value of the function outside of the breaks. (By the way, I've used the term "break" here, because we are really defining a simple form of spline, a piecewise constant spline. I might also have used the term knot, another common word in the world of splines.)
If you absolutely know that you will never evaluate the function outside of [0,1], then there is no problem. So then just define a piecewise function with ONE break point, at x = 0.5. The simple way to define a piecewise constant function like yours is to use a logical operator. Thus the test (x > 0.5) returns a constant, either 0 or 1. By scaling and translating that result, it is easy to generate a function that does what you wish.
constfun = #(x) (x > 0.5)*2 - 1;
An inline function does a similar thing, but inline functions are VERY slow compared to an anonymous function. I would strongly recommend use of the anonymous form. As a test, try this:
infun = inline('(x > 0.5)*2 - 1','x');
x = 0:.001:1;
tic,y = constfun(x);toc
Elapsed time is 0.002192 seconds.
tic,y = infun(x);toc
Elapsed time is 0.136311 seconds.
Yes, the inline function took wildly more time to execute than did the anonymous form.
A problem with the simple piecewise constant form I've used here is it is difficult to expand to when you have more break points. For example, suppose you wished to define a function that took on three different values depending on what interval the point fell in? While this can be done too with creative use of tests, carefully shifting and scaling them, it can get nasty. For example, how might one define the piecewise function that returns
-1 when x < 0,
2 when 0 <= x < 1,
1 when 1 <= x
One solution is to use a unit Heaviside function. So first, define a basic unit Heaviside function.
H = #(x) (x >= 0);
Our piecewise function is now derived from H(x).
P = #(x) -1 + H(x)*3 + H(x-1)*(-1);
See that there are three pieces to P(x). The first term is what happens for x below the first break point. Then we add in a piece that takes effect above zero. Finally, the third piece adds in another offset in above x == 1. It is easily enough plotted.
ezplot(P,[-3,3])
More sophisticated splines are easily generated from this beginning. Se that I've called this construct a spline again. Really, this is where we might be leading. In fact, this is where this leads. A spline is a piecewise function, carefully tied together at a list of knots or break points. Splines in particular often have specified orders of continuity, so for example, a cubic spline will be twice differentiable (C2) across the breaks. There are also piecewise cubic functions that are only C1 functions. My point in all of this is I've described a simple beginning point to form any piecewise function. It works quite well for polynomial splines, although there may be a wee bit of mathematics required to choose the coefficients of these functions.
Another way to create this function is as an explicit piecewise polynomial. In MATLAB, we have the little known function mkpp. Try this out...
pp = mkpp([0 .5 1],[1;-1]);
Had you the splines toolbox, then fnplt will plot this directly for you. Assuming that you don't have that TB, do this:
ppfun = #(x) ppval(pp,x);
ezplot(ppfun,[0 1])
Looking back at the mkpp call, it is rather simple after all. The first argument is the list of break points in the curve (as a ROW vector). The second argument is a COLUMN vector, with the piecewise constant values the curve will take on in these two defined intervals between the breaks.
Several years ago I posted another option, piecewise_eval. It can be downloaded from the MATLAB Central file exchange. This is a function that will allow a user to specify a piecewise function purely as a list of break points, along with functional pieces between those breaks. Thus, for a function with a single break at x = 0.5, we would do this:
fun = #(x) piecewise_eval(x,0.5,{1,-1});
See that the third argument provides the value used in each segment, although those pieces need not be purely constant functions. If you wish the function to return perhaps a NaN outside of the interval of interest, this too is easily accomplished.
fun = #(x) piecewise_eval(x,[0 0.5 1],{NaN,1,-1,NaN});
My point in all of this rather lengthy excursion is to understand what a piecewise function is, and several ways to build one in MATLAB.

Unfortunately, MATLAB doesn't have a ternary operator which would make this sort of thing easier, but to expand slightly on gnovice's approach, you could create an anonymous function like so:
fh = #(x) ( 2 .* ( x <= 0.5 ) - 1 )
In general, anonymous functions are more powerful than inline function objects, and allow you to create closures etc.

If you really want to make an inline function (as opposed to an anonymous function), then the following would probably be the simplest way:
f = inline('2.*(x <= 0.5)-1');
However, as pointed out in the other answers, anonymous functions are more commonly used and are more efficient:
f = #(x) (2.*(x <= 0.5)-1);

I just had to solve that problem, and I think the easiest thing to do is use anonymous functions. Say that you have a piecewise function:
when x<0 : x^2 + 3x
when 0<=x<=4: e^x
when x>4 : log(x)
I'd first define logical masks for each piecewise region:
PIECE1 = #(x) x<0
PIECE2 = #(x) x>=0 & x<=4
PIECE3 = #(x) x>4
Then I'd put them all together:
f = #(x) PIECE1(x).*(x.^2+3*x) + PIECE2(x).*exp(x) + PIECE3(x).*log(x)
x = -10:.1:10
figure;
plot(x,f(x))

Related

MATLAB finding roots, and # operator

x=1;
f=#(x) x^3 - (5/x^2)-4*sin(x)-2;
fzero(f,x)
ans =
1.9227
I am supposed to find the root of the equation, x^3 - (5/x^2)-4*sin(x)-2, and the above code is the solution for it.
I don't understand the general mechanism of this code.
(1) What does # operator do?
I know its something like function handle, but I don't understand what function handle is.
(2) How does it work when it includes x in the parenthesis?
(3) How can there be a function fzero(), when I haven't made a script for fzero()?
(4) why are there two variables inside fzero()?
I don't understand that the variable 'f' does there
(5) Why did it declare x=1 in the beginning?
Please consider that I am pretty much new to MATLAB, and don't know much.
f = #(x) ... is the way to declare an anonymous function in MATLAB, actually not very different than creating a function normally in MATLAB such as function output = f(input) .... It is just the pratical way especially when you are working with mathematical functions.
#(x) defines that x is the variable of which is the same as f(x) in mathematics. fzero() is MATLAB's existing function to calculate the x value for f(x) = 0 which means calculating roots of defined funtion. Giving your x a real value at the beginning does mean the starting point to find the root. It will find the roots greater than 1 in your case. It will be very clear for you when you read existing documentation of MATLAB.
Edit:
If you give an interval such as x = [0 1] instead of x = 1, fzero(f,x) would try to calculate roots of f function in given interval, if there is no roots exist in that interval it woud return a NaN value.

Numerically normalize within a function

I'm trying to (elegantly) normalize a function numerically, depending on the parameters that are passed into it. The example below gives a Gaussian that tries to normalize within the function but fails.
I know I could do this with a couple extra lines of code, or for this example normalize analytically; I'm specifically asking about creating a numerically normalized anonymous function:
x = linspace(-10,10,10000);
my_gauss = #(w) exp(-1/(2*w^2) * x.^2) / trapz((x(2)-x(1))*my_gauss(w));
There is a big difference between an elegant solution and a solution that is efficient, clear, and correct. MATLAB has no built-in method that normalizes an array.
Based on the example that you have provided, you are trying to do too much with your anonymous function, and as a result it's not actually that general (can't deal with non-uniform sampling, etc).
I think you'd be better off creating two anonymous functions: one to perform the normalization, and the other to compute the gaussian:
x = linspace(-10, 10, 10000);
normalize = #(x, g)g ./ trapz(x, g);
gaussian = #(x, w)exp(-1 / (2 * w^2) * x.^2);
normalized_gaussian = normalize(x, gaussian(x, 10));
disp(trapz(x, normalized_gaussian))
1
% Or if you want to provide a single anonymous function
ngaussian = #(x, w)normalize(x, gaussian(w));
This is much more explicit and breaks out the functionality into more logical units that can be better understood and tested. Additionally, it can handle functions evaluated at random intervals.

How to solve an equation with piecewise defined function in Matlab?

I have been working on solving some equation in a more complicated context. However, I want to illustrate my question through the following simple example.
Consider the following two functions:
function y=f1(x)
y=1-x;
end
function y=f2(x)
if x<0
y=0;
else
y=x;
end
end
I want to solve the following equation: f1(x)=f2(x). The code I used is:
syms x;
x=solve(f1(x)-f2(x));
And I got the following error:
??? Error using ==> sym.sym>notimplemented at 2621
Function 'lt' is not implemented for MuPAD symbolic objects.
Error in ==> sym.sym>sym.lt at 812
notimplemented('lt');
Error in ==> f2 at 3
if x<0
I know the error is because x is a symbolic variable and therefore I could not compare x with 0 in the piecewise function f2(x).
Is there a way to fix this and solve the equation?
First, make sure symbolic math is even the appropriate solution method for your problem. In many cases it isn't. Look at fzero and fsolve amongst many others. A symbolic method is only needed if, for example, you want a formula or if you need to ensure precision.
In such an old version of Matlab, you may want to break up your piecewise function into separate continuous functions and solve them separately:
syms x;
s1 = solve(1-x^2,x) % For x >= 0
s2 = solve(1-x,x) % For x < 0
Then you can either manually examine or numerically compare the outputs to determine if any or all of the solutions are valid for the chosen regime – something like this:
s = [s1(double(s1) >= 0);s2(double(s2) < 0)]
You can also take advantage of the heaviside function, which is available in much older versions.
syms x;
f1 = 1-x;
f2 = x*heaviside(x);
s = solve(f1-f2,x)
Yes, the Heaviside function is 0.5 at zero – this gives it the appropriate mathematical properties. You can shift it to compare values other than zero. This is a standard technique.
In Matlab R2012a+, you can take advantage of assumptions in addition to the normal relational operators. To add to #AlexB's comment, you should convert the output of any logical comparison to symbolic before using isAlways:
isAlways(sym(x<0))
In your case, x is obviously not "always" on one side or the other of zero, but you may still find this useful in other cases.
If you want to get deep into Matlab's symbolic math, you can create piecewise functions using MuPAD, which are accessible from Matlab – e.g., see my example here.

Is my equation too complex for matlab to integrate?

I have a code that needs to evaluate the arc length equation below:
syms x
a = 10; b = 10; c = 10; d = 10;
fun = 4*a*x^3+3*b*x^2+2*c*x+d
int((1+(fun)^2)^.5)
but all that returns is below:
ans = int(((40*x^3 + 30*x^2 + 20*x + 10)^2 + 1)^(1/2), x)
Why wont matlab evaluate this integral? I added a line under to check if it would evaulate int(x) and it returned the desired result.
Problems involving square roots of functions may be tricky to intgrate. I am not sure whether the integral exists or not, but it if you look up the integral of a second order polynomial you will see that this one is already quite a mess. What you would have, would you expand the function inside the square root, would be a ninth order polynomial. If this integral actually would exist it may be too complex to calculate.
Anyway, if you think about it, would anyone really become any wiser by finding the analytical solution of this? If that is not the case a numerical solution should be sufficient.
EDIT
As thewaywewalk said in the comment, a general rule to calculate these kinds of integrals would be valuable, but to know the primitive function to the particular integral would probably be overkill (if a solution could be found).
Instead define the function as an anonymous function
fun = #(x) sqrt((4*a*x.^3+3*b*x.^2+2*c*x+d).^2+1);
and use integral to evaluate the function between some range, eg
integral(fun,0,100);
for evaluating the function in the closed interval [0,100].

How to have square wave in Matlab symbolic equation

My project require me to use Matlab to create a symbolic equation with square wave inside.
I tried to write it like this but to no avail:
syms t;
a=square(t);
Input arguments must be 'double'.
What can i do to solve this problem? Thanks in advance for the helps offered.
here are a couple of general options using floor and sign functions:
f=#(A,T,x0,x) A*sign(sin((2*pi*(x-x0))/T));
f=#(A,T,x0,x) A*(-1).^(floor(2*(x-x0)/T));
So for example using the floor function:
syms x
sqr=2*floor(x)-floor(2*x)+1;
ezplot(sqr, [-2, 2])
Here is something to get you started. Recall that we can express a square wave as a Fourier Series expansion. I won't bother you with the details, but you can represent any periodic function as a summation of cosines and sines (à la #RTL). Without going into the derivation, this is the closed-form equation for a square wave of frequency f, with a peak-to-peak amplitude of 2 (i.e. it goes from -1 to 1). Recall that the frequency is the amount of cycles per seconds. Therefore, f = 1 means that we repeat our square wave every second.
Basically, what you have to do is code up the first line of the equation... but how in the world would you do that? Welcome to the world of the Symbolic Math Toolbox. What we will need to do before hand is declare what our frequency is. Let's assume f = 1 for now. With the Symbolic Math Toolbox, you can define what are considered as mathematics variables within MATLAB. After, MATLAB has a whole suite of tools that you can use to evaluate functions that rely on these variables. A good example would be if you want to use this to define a closed-form solution of a function f(x). You can then use diff to differentiate and see what the derivative is. Try it yourself:
syms x;
f = x^4;
df = diff(f);
syms denotes that you are declaring anything coming after the statement to be a mathematical variable. In this case, x is just that. df should now give you 4x^3. Cool eh? In any case, let's get back to our problem at hand. We see that there are in fact two variables in the periodic square function that need to be defined: t and k. Once we do this, we need to create our function that is inside the summation first. We can do this by:
syms t k;
f = 1; %//Define frequency here
funcSum = (sin(2*pi*(2*k - 1)*f*t) / (2*k - 1));
That settles that problem... now how do we encapsulate this into an infinite sum!? The sum command in MATLAB assumes that we have a finite array to sum over. If you want to symbolically sum over a function, we must use the symsum function. We usually call it like this:
funcOut = symsum(func, v, start, finish);
func is the function we wish to sum over. v is the summation variable that we wish to use to index in the sum. In our case, that's k. start is the beginning of the sum, which is 1 in our case, and finish is where we wish to finish up our summation. In our case, that's infinity, and so MATLAB has a special keyword called Inf to denote that. Therefore:
xsquare = (4/pi) * symsum(funcSum, k, 1, Inf);
xquare now contains your representation of a square wave defined in terms of the Symbolic Math Toolbox. Now, if you want to plot your square wave and see if we have this right. We can do the following. Let's go between -3 <= t <= 3. As such, you would do something like this:
tVector = -3 : 0.01 : 3; %// Choose a step size of 0.01
yout = subs(xsquare, t, tVector);
You will notice though that there will be some values that are NaN. The reason why is because right at a multiple of the period (T = 1, 2, 3, ...), the behaviour is undefined as the derivative right at these points is undefined. As such, we can fill this in using either 1 or -1. Let's just choose 1 for now. Also, because the Fourier Series is generally a complex-valued function, and the square-wave is purely real, the output of this function will actually give you a complex-valued vector. As such, simply chop off the complex parts to get the real parts only:
yout = real(double(yout)); %// To cast back to double.
yout(isnan(yout)) = 1;
plot(tVector, yout);
You'll get something like:
You could also do this the ezplot way by doing: ezplot(xsquare). However, you'll see that at the points where the wave repeats itself, we get NaN values and so there is a disconnect between the high peak and low peak.
Note:
Natan's solution is much more elegant. I was still writing this post by the time he put something up. Either way, I wanted to give a more signal processing perspective to how to do this. Go Fourier!
A Fourier series for the square wave of unit amplitude is:
alpha + 2/Pi*sum(sin( n * Pi*alpha)/n*cos(n*theta),n=1..infinity)
Here is a handy trick:
cos(n*theta) = Re( exp( I * n * theta))
and
1/n*exp(I*n*theta) = I*anti-derivative(exp(I*n*theta),theta)
Put it all together: pull the anti-derivative ( or integral ) operator out of the sum, and you get a geometric series. Then integrate and finally take the real part.
Result:
squarewave=
alpha+ 1/Pi*Re(I*ln((1-exp(I*(theta+Pi*alpha)))/(1-exp(I*(theta-Pi*alpha)))))
I tried it in MAPLE and it works great! (probably not very practical though)