How to plot a piecewise parametric function in maple ?
An example :
f := proc (t) if t <= .2 and 0 <= t then -t, 2*t elif t <= .4 then 8*t-1.8, 2*t elif t <= .6 then 3*t+.2, -2*t+1.6 elif t <= .8 then 2*t+.8, -t+1 elif t <= 1 then -12*t+12, -t+1 end if end proc;
I found the answer.
In case someone needs it :
> X := piecewise(`and`(t <= .2, t >= 0), -t, t <= .4, 8*t-1.8, t <= .6, 3*t+.2, t <= .8, 10*t-4, t <= 1, -20*t+20);
Y := piecewise(`and`(t <= .2, t >= 0), 2*t, t <= .4, 2*t, t <= .6, -2*t+1.6, t <= .8, 1-t, t <= 1, 1-t);
> plot([X(t), Y(t), t = 0 .. 1]);
Related
I am having trouble using the bvp4c with piecewise defined functions.
I tested the code and it works fine when the piecewise defined functions are constant.
The problem is that I get wrong results in the graph (that I know for sure) in the area where the piecewise defined functions are not constant.
Any ideas or suggestions on how to handle this problem?
Thanks
function bvp4
xlow=0;
xhigh=0.30;
solinit=bvpinit(linspace(xlow,xhigh,1000),[0 0]);
sol = bvp4c(#bvp4ode,#bvp4bc,solinit);
xint=[xlow:0.0001:xhigh];
Sxint=deval(sol,xint);
Sxint1=abs(sqrt(Sxint));
xint=[xlow:0.0001:xhigh];
plot(xint,Sxint1(1,:),'r')
function dydx = bvp4ode(x,y)
So=0.00125;
s=1.5;
dydx = [y(2);
((G(x)+125*f(x)*y(1)*(1+1/s^2)^0.5-1000*9.81*So*H(x))/(1000*0.5*l(x)*(f(x)/8)^0.5)-y(2)*2*(-2/3*x+0.071+2/3*0.08)*(-2/3)*b(x))/H(x)/H(x)];
function res = bvp4bc(ya,yb)
res = [ya(1); yb(1)];
function fval = f(x)
if (x >= 0) && (x <= 0.08)
fval = 0.0187;
elseif (x > 0.08) && (x <= 0.17)
fval = 0.0298;
elseif (x > 0.17) && (x <= 0.3)
fval= 0.0408;
end
function Gval = G(xint)
if (xint >= 0) && (xint <= 0.08)
Gval = 0.1306;
elseif (xint > 0.08) && (xint <= 0.17)
Gval = 0.1306;
elseif (xint > 0.17) && (xint <= 0.3)
Gval = -0.0337;
end
function Hval = H(xint)
if (xint >= 0) && (xint < 0.08)
Hval = 0.071;
elseif (xint >= 0.08) && (xint <= 0.17)
Hval = -2/3*xint+(0.071+2/3*0.08);
elseif (xint >0.17) && (xint <= 0.3)
Hval = 0.011;
end
function bval = b(xint)
if (xint >= 0) && (xint < 0.08)
bval = 0;
elseif (xint >= 0.08) && (xint <= 0.17)
bval = 1;
elseif (xint > 0.17) && (xint <= 0.3)
bval= 0;
end
function lval = l(xint)
if (xint >= 0) && (xint <= 0.08)
lval = 0.067;
elseif (xint > 0.08) && (xint <= 0.17)
lval = 0.134;
elseif (xint > 0.17) && (xint <= 0.3)
lval= 1.165;
end
Thou shalt not surprise your fragile solver with sudden jumps.
Any order p solver expects an ODE function that is at least p times continuously differentiable to sensibly adapt the mesh of gridpoints resp. the local step size. Any deviation leads to excessive and possibly oscillating adaptation near the singular points, resulting in long computation times or underflow in the step size.
I see two possibilities to work around this problem, use events (if supported for BVP) to switch models/ODE functions or use the provided multipoint mechanism to split the integration interval into sections where your parameter functions are constant. Then you can also use simple arrays for the parameters instead of functions with many branchings.
I used the following simple code to check the properties of elseif command in MATLAB:
x = 10;
if x < 0
y = x;
elseif 0 <= x < 2
y = 3*x;
elseif x >= 2
y = 8*x;
end
y
I would have expected the result of this to be 80 since x >= 2. But something amazing happened! The result is 30, not 80!
But why? Any ideas?
Update: when I change the code (as recommended in the answers) to
x = 10;
if x < 0
y = x;
elseif (0 <= x) && ( x < 2 )
y = 3*x;
elseif x >= 2
y = 8*x;
end
y
I get 80 as expected. It's that double condition that threw me off.
When you write
if 0 <= x < 2
you are really writing (without realizing it)
if (0 <= x) < 2
Which is evaluated as
if (true) < 2
which is true, since true evaluates to 1.
So here is what is happening, line by line:
x = 10; % x is set to 10
if x < 0 % false
y = x; % not executed
elseif 0 <= x < 2 % condition is (true) < 2, thus true
y = 3*x; % y is set to 3*x, i.e. 30
elseif x >= 2 % since we already passed a condition, this is not evaluated
y = 8*x; % skipped
end % end of composite if
y % display the value of y - it should be 30
As an aside, when you use scalars, you should really use the && operator, not the & operator. See for example What's the difference between & and && in MATLAB?
0 <= x < 2 doesn't behave as you may expect. Use (0 <= x) & (x < 2)
How does 0 <= x < 2 behave? It is evaluated from left to right. First 0 <= x gives 1 (true), and then 1 < 2 gives 1 (true). So the condition gives true, not false as you would expect.
Since the second condition in your code (0 <= x < 2) is true, you get a value 30 for y. Changing the condition to (0 <= x) & (x < 2) you get a value 80 for y.
I have the following table
nc a b
0.9 <= nc 0.33 -0.45
0.5 <= nc < 0.9 0.95 -0.75
0.1 <= nc < 0.5 2.2 -0.97
nc < 0.1 1.18 -0.77
which says that if the observed cloud cover if between the ranges shown then a and b are given as the values expressed in the table. I have written some code in matlab that should return these values given a vector of nc values:
nc = [0.1, 0.6, 0.5 ,0.2, 0.9];
a = nan(length(nc),1); % pre-allocate arrays
b = nan(length(nc),1);
for i = 1:length(nc)
if nc(i) >= 0.9;
ai = 0.33;
bi = -0.45;
elseif nc(i) >= 0.5 & nc(i) < 0.9
ai = 0.95;
bi = -0.75;
elseif nc(i) >= 0.1 & nc(i) < 0.5
ai = 2.2;
bi = -0.97;
elseif nc(i) < 0.1
ai = 1.18;
bi = -0.77;
end
a(i) = ai;
b(i) = bi;
end
However, this seems like a very long way of doing this. In addition, this code will eventually be fed into a number of other functions and I'm a bit worried that having so many if statements and a for loop in general will slow things down. Could anyone comment on this or suggest a faster way (if useful) of doing this?
loops in matlab are slow. You can improve your solution vectorizing the operation:
nc = [0.1, 0.6, 0.5 ,0.2, 0.9];
a = 2.2 * ones(length(nc),1); % by default in the 0.1-0.5 range
b = -0.97 * ones(length(nc),1);
f = find(nc >= 0.9);
a(f) = 0.33; b(f) = -0.45;
f = find(nc >= 0.5 & nc < 0.9);
a(f) = 0.95; b(f) = -0.75;
f = find(nc < 0.1);
a(f) = 1.18; b(f) = -0.77;
find will list the indices of the element that match the criteria, so you can modify the elements in the other vectors.
Or you can use logical indexing, by-passing the need to use the find function:
nc = [0.1, 0.6, 0.5 ,0.2, 0.9];
a = 2.2 * ones(length(nc),1); % by default in the 0.1-0.5 range
b = -0.97 * ones(length(nc),1);
a(nc >= 0.9) = 0.33; b(nc >= 0.9) = -0.45;
a(nc >= 0.5 & nc < 0.9) = 0.95; b(nc >= 0.5 & nc < 0.9) = -0.75;
a(nc < 0.1) = 1.18; b(nc < 0.1) = -0.77;
I am having a hard time plotting a step function. The function involves is the Haar scaling function which is defind as:
ø(x) = 1 if 0 ≤ x < 1
ø(x) = 0 otherwise
I am supposed to plot the following function:
f(x) = 2ø(4x) + 2ø(4x - 1) + ø(4x - 2) - ø(4x - 3)
This is supposed to give me a plot where f = 2 on the interval 0 ≤ x < 0.5; f = 1 on the interval 0.5 ≤ x < 0.75; f = -1 on the interval 0.75 ≤ x < 1, and f = zero otherwise.
I tried the following code:
f = #(t) 2*(4*t > 0) + 2*(4*t > 1) + (4*t > 2) - (4*t > 3);
t = linspace(-2,2,100);
stairs(t,f(t))
However, this does not give me an accurate graph. So what am I doing wrong here? Any help will be greatly appreciated!
Your implementation of f only deals with half of your specification of phi.
f = #(t) 2*(4*t > 0) + 2*(4*t > 1) + (4*t > 2) - (4*t > 3);
In each of the terms applies the inequality 0 < X, rather than 0 <= X. Also nothing is done about the X < 1 inequality.
Rather than trying to make a custom version for each term, why not code up your formula directly?
phi = #(x) x >= 0 & x < 1;
f = #(x) 2*phi(4*x) + 2*phi(4*x-1) + phi(4*x - 2) - phi(4*x - 3);
it should be:
f = #(t) 2*(4*t > 0 & 4*t < 1) + 2*(4*t > 1 & 4*t < 2) + (4*t > 2 & 4*t < 3) - (4*t > 3);
Because every segment should be defined precisely with start and end values.
This question already has answers here:
Draw 3d Inequality on Matlab
(1 answer)
matlab - plot inequality in 3d with surf
(1 answer)
Closed 1 year ago.
I want to plot a 3d region in MATLAB bounded from a set of inequalities.
For example:
0 <= x <= 1
sqrt(x) <= y <= 1
0 <= z <= 1 - y
I found a 2d example that someone has done on this site but I'm not sure how to convert that to 3d. How to plot inequalities.
Edit:
From #Tobold's help I modified the code to restrict the points that are plotted to those that are defined by all three regions, but it plots only 2 or 3 points. It looks like the points in the vectors X1, Y1 and Z1 are right but for some reason its plotting only a few. Any ideas why it is only plotting a few points from the X1, Y1 and Z1 vectors instead of all of them?
[X,Y,Z]=meshgrid(0:0.1:1,0:0.1:1,0:0.1:1); % Make a grid of points between 0 and 1
p1=0.1; p2=0.2; % Choose some parameters
X1 = (X >= 0 & X <= 1) & (Y >= sqrt(X) & Y <= 1) & (Z >= 0 & Z <= 1 - Y);
Y1 = (X >= 0 & X <= 1) & (Y >= sqrt(X) & Y <= 1) & (Z >= 0 & Z <= 1 - Y);
Z1 = (X >= 0 & X <= 1) & (Y >= sqrt(X) & Y <= 1) & (Z >= 0 & Z <= 1 - Y);
ineq1 = (X >= 0 & X <= 1) * 2;
ineq2 = (Y >= sqrt(X) & Y <= 1) * 4;
ineq3 = (Z >= 0 & Z <= 1 - Y) * 8;
all = ineq1 & ineq2 & ineq3;
colors = zeros(size(X))+ineq1+ineq2+ineq3;
scatter3(X1(:),Y1(:),Z1(:),3,colors(:)','filled')
You can do almost the same thing as in the 2d case that you linked to. Just write down your three inequalities, use a 3d meshgrid, multiply each inequality with a number from a set of three numbers that has unique subset sums (e.g. 2, 4, 8) and use scatter3:
[X,Y,Z]=meshgrid(0:0.1:1,0:0.1:1,0:0.1:1); % Make a grid of points between 0 and 1
p1=0.1; p2=0.2; % Choose some parameters
ineq1 = (X >= 0 & X <= 1) * 2;
ineq2 = (X >= sqrt(X) & Y <= 1) * 4;
ineq3 = (Z >= 0 & Z <= 1 - Y) * 8;
colors = zeros(size(X))+ineq1+ineq2+ineq3;
scatter3(X(:),Y(:),Z(:),3,colors(:),'filled')
I've been trying to figure out the same thing, and the trick is to make the size of everything not in the intersection 0. Tobold's scatter3 line uses '3' as the option for size, meaning all points will show up as point 3. This can be substituted for a matrix of equal size to X1 with the set of sizes. The easiest way to do this is just make s = 3*all:
all = ineq1 & ineq2 & ineq3;
colors = zeros(size(X))+all;
sizes = 3 * all;
scatter3(X1(:),Y1(:),Z1(:),sizes,colors(:)','filled')
That should get you just the area in the intersection.
--
edit: The color variable needs to change too. You just want the intersection, not the other inequalities.
I don't understand several things in the code that you wrote as modification of #Tobold's help. For example what are the parameters p1 and p2 doing in your code?
Anyway, The code plotting only the points of your grid satisfying all of your inequalities;
[X,Y,Z]=meshgrid(0:0.1:1,0:0.1:1,0:0.1:1);
ineq1 = (X >= 0 & X <= 1);
ineq2 = (Y >= sqrt(X) & Y <= 1);
ineq3 = (Z >= 0 & Z <= 1 - Y);
all = ineq1 & ineq2 & ineq3;
scatter3(X(all),Y(all),Z(all),'b','filled')
The result is brought in the following image.