This is my primer time using matlab especially plotting.
I try to plot the solutions for y = x^2 − x − 2 like in here
But I don't know how to model this plot in matlab (it makes sense because the solutions must be computed first) but shouldn't the shape of curve will remain the same.
I tried:
clc;
close all;
%y = x2 − x − 2
x = [-3:1:3];
y= x.^2 - x -2;
plot(y), grid on;
But the curve I got is totally different.
You're choosing wrong points for drawing the curve.
The image that you showed above takes the values of x in the interval [-2,3]. Fixing this gives exactly the same curve as that of the one in the question.
Also note that the minima of your function is at x=0.5. So, if x has equal number of values less than 0.5 and greater than 0.5, you will get the curve of the desired shape.
Code:
x = [-2:0.01:3]; %Choosing 0.01, because more the points, more the curve will be accurate
y= x.^2 - x -2;
plot(x,y), grid on;
Output:
Related
I have this hard coded version which fits data to a curve for linear, quadratic and cubic polynomials:
for some data x and a function y
M=[x.^0 x.^1];
L=[x.^0 x.^1 x.^2];
linear = (M'*M)\(M'*y);
plot(x, linear(1)+linear(2)*x, ';linear;r');
deg2 = (L'*L)\(L'*y);
plot(x, deg2(1)+deg2(2)*x+deg2(3)*(x.*x), ';quadratic plot;b');
I am wondering how can I turn this into a for loop to plot curves for degree n polynomials? The part I'm stuck on is the plotting part, how would I be able to translate the increase in the number of coefficients in to the for loop?
what I have:
for i = 1:5 % say we're trying to plot curves up to degree 5 polynomials...
curr=x.^(0:i);
degI = (curr'*curr)\(curr'*y);
plot(x, ???) % what goes in here<-
end
If it is only the plotting, you can use the polyval function to evaluate polynomials of desired grade by supplying a vector of coefficients
% For example, some random coefficients for a 5th order polynomial
% degI = (curr'*curr)\(curr'*y) % Your case
degi = [3.2755 0.8131 0.5950 2.4918 4.7987 1.5464]; % for 5th order polynomial
x = linspace(-2, 2, 10000);
hold on
% Using polyval to loop over the grade of the polynomials
for i = 1:length(degI)
plot(x, polyval(degI(1:i), x))
end
gives the all polynomials in one plot
I believe this should answer your question exactly. You just have to be careful with the matrix dimensions.
for i = 1:5
curr=x.^(0:i);
degI = (curr'*curr)\(curr'*y);
plot(x, x.^(0:i)*degI)
end
I wanted to plot the above function on Matlab so I used the following code
ezplot('-log(x)-log(y)+x+y-2',[-10 10 -10 10]);
However I'm just getting a blank screen. But clearly there is at least the point (1,1) that satisfies the equation.
I don't think there is a problem with the plotter settings, as I'm getting graphs for functions like
ezplot('-log(y)+x+y-2',[-10 10 -10 10]);
I don't have enough rep to embed pictures :)
If we use solve on your function, we can see that there are two points where your function is equal to zero. These points are at (1, 1) and (0.3203 + 1.3354i, pi)
syms x y
result = solve(-log(x)-log(y)+x+y-2, x, y);
result.x
% -wrightOmega(log(1/pi) - 2 + pi*(1 - 1i))
% 1
result.y
% pi
% 1
If we look closely at your function, we can see that the values are actually complex
[x,y] = meshgrid(-10:0.01:10, -10:0.01:10);
values = -log(x)-log(y)+x+y-2;
whos values
% Name Size Bytes Class Attributes
% values 2001x2001 64064016 double complex
It seems as though in older versions of MATLAB, ezplot handled complex functions by only considering the real component of the data. As such, this would yield the following plot
However, newer versions consider the magnitude of the data and the zeros will only occur when both the real and imaginary components are zero. Of the two points where this is true, only one of these points is real and is able to be plotted; however, the relatively coarse sampling of ezplot isn't able to display that single point.
You could use contourc to determine the location of this point
imagesc(abs(values), 'XData', [-10 10], 'YData', [-10 10]);
axis equal
hold on
cmat = contourc(abs(values), [0 0]);
xvalues = xx(1, cmat(1,2:end));
yvalues = yy(cmat(2,2:end), 1);
plot(xvalues, yvalues, 'r*')
This is because x = y = 1 is the only solution to the given equation.
Note that the minimum value of x - log(x) is 1 and that happens when x = 1. Obviously, the same is true for y - log(y). So, -log(x)-log(y)+x+y is always greater than 2 except at x = y = 1, where it is exactly equal to 2.
As your equation has only one solution, there is no line on the plot.
To visualize this, let's plot the equation
ezplot('-log(x)-log(y)+x+y-C',[-10 10 -10 10]);
for various values of C.
% choose a set of values between 5 and 2
C = logspace(log10(5), log10(2), 20);
% plot the equation with various values of C
figure
for ic=1:length(C)
ezplot(sprintf('-log(x)-log(y)+x+y-%f', C(ic)),[0 10 0 10]);
hold on
end
title('-log(x)-log(y)+x+y-C = 0, for 5 < C < 2');
Note that the largest curve is obtained for C = 5. As the value of C is decreased, the curve also becomes smaller, until at C = 2 it completely vanishes.
I'm using the interp1 function to interpolate some points on this graph
My problem is that I want the new points to be equidistant. But in the interp1 function the input arguments are the x(before) , y(before) and the x(new) which is the vertical coordinate and not the contour distance.
My question is if there is any other function which solves my problem? If not, does anyone know how can I transform the x-vector?
EDIT:
an example with my problem is here:
x=0:0.1:10;
y=x.^4;
xx=linspace(min(x),max(x),10);
yy=interp1(x,y,xx);
hold on;
plot(x,y);
plot(xx,yy);
plot(xx,yy,'ro');
hold off;
You can do this by reformulating your curve as a parametric function of length along the curve. What you want is for the final points (where you interpolate) to have equal length between them. It's possible to do this by approximating the 'true' curve as a piecewise linear curve that connects the original data points.
Say we have some data points in matrix xy, where each row is a point and the x/y coordinates are on columns 1/2:
% make some fake data
% triple exponential function has nonuniform spacing
x = linspace(.4, .8, 20)';
y = exp(exp(exp(x)));
x = (x - min(x)) ./ range(x);
y = (y-min(y)) ./ range(y);
xy = [x, y];
Find the length of each point along the curve, starting from 0 at the first point:
% distance of each point from previous point
% note that points need to be in order
ds = [0; sqrt(sum(diff(xy, 1, 1) .^ 2, 2))];
% integrate to find length along the curve
s = cumsum(ds);
Now, consider both x and y to be a function of s. Interpolate x and y at a set of equally spaced lengths along the curve:
% find a set of equally spaced lengths along the curve
si = linspace(s(1), s(end), 20)';
% interpolate x and y at these points
xyi = interp1(s, xy, si);
Verify that the solution works:
% distance between successive interpolated points
% they should all be equal
sqrt(sum(diff(xyi, 1, 1) .^ 2, 2)
Original data:
Interpolated:
clc
clear all
x= -2:0.1:4;
y= (3*x.^3)-(26*x)+10;
y1= diff(y)./diff(x);
y2= diff(y1)./diff(x);
plot(x,y,'R')
hold on
plot(x,y1,'G')
hold on
plot(x,y2,'B')
Is this right way to find second derivative?
It's not finding the second derivative and giving an error that matrix dimensions must agree in line 6.
You have values y that correspond to the values x. While calculating the approximation to the first derivatives y1 of y, you use finite differences. These kind of finite differences approximate the derivative best at the points inbetween x. This means your calculation of the approximation of the second derivative should involve (x(1:end-1)+x(2:end))/2:
x1 = (x(1:end-1) + x(2:end))/2;
y2 = diff(y1) / diff(x1);
Note that these approximations y2 best approximate the second derivative at the positions x2 = (x1(1:end-1) + x1(2:end))/2.
All in all your code might look like this:
%// Clear command window, delete all variables, close all figures
clc;
clear all;
close all;
%// Define function
f = #(x) (3*x.^3)-(26*x)+10;
%// Define positions
x = -2:0.1:4;
%// Calculate f(x)
y= f(x);
%// Calculate approximation to first derivative and their positions
x1 = (x(1:end-1) + x(2:end))/2;
y1 = diff(y) ./ diff(x);
%// Calculate approximation to second derivative and their positions
x2 = (x1(1:end-1) + x1(2:end))/2;
y2 = diff(y1) ./ diff(x1);
%// Plot
plot(x, y, 'R',...
x1,y1,'G',...
x2,y2,'B');
legend('f','f''', 'f''''');
I have a problem which is twofold:
How do I plot a toroidal surface in MATLAB, given a major radius R and a minor radius a? To avoid confusion, it is the toroidal/poloidal coordinate system, illustrated in the picture below, that I'm talking about.
Now, in any point (phi, theta) on this surface, the minor radius will be distorted by some value that I have stored in a matrix. How do I plot this distorted surface? This might be easy once I have the answer to part 1, but this is my actual goal, so any solution to part 1 that cannot handle this is pretty useless to me.
If anyone can tell me how to make the image appear smaller here, please do =)
Addressing your first question: first you will need to define the coordinates of your torus in toroidal coordinates (seems natural!) and then convert to Cartesian coordinates, which is how MATLAB expects all plots to be constructed (unless you are making a polar plot, of course). So we start of by defining our toroidal coordinates:
aminor = 1.; % Torus minor radius
Rmajor = 3.; % Torus major radius
theta = linspace(-pi, pi, 64) ; % Poloidal angle
phi = linspace(0., 2.*pi, 64) ; % Toroidal angle
We just want a single surface of the torus, so the minor radius is a scalar. We now make a 2D mesh of these coordinates:
[t, p] = meshgrid(phi, theta);
and convert to 3D Cartesian coordinates using the formulas given on the Wikipedia page linked to in the question:
x = (Rmajor + aminor.*cos(p)) .* cos(t);
y = (Rmajor + aminor.*cos(p)) .* sin(t);
z = aminor.*sin(p);
Now we have our torus defined in 3D, we can plot it using surf:
surf(x, y, z)
axis equal
Edit: To address your second question, it depends how you have your distortions stored, but say you have a matrix defined at each toroidal and poloidal point, you will just have to multiply the constant that is the minor radius by the distortion. In the following I create a distortion matrix that is the same dimensions as my toroidal and poloidal angle coordinate matrices and that is normally distributed about a mean of 1 with a FWHM of 0.1:
distortion = 1. + 0.1 * randn(64, 64);
x = (Rmajor + aminor .* distortion .*cos(p)) .* cos(t);
y = (Rmajor + aminor .* distortion .* cos(p)) .* sin(t);
z = aminor.* distortion .* sin(p);
surf(x, y, z)
The result of which is:
You can do this with surf - just create matrices with the x,y,z coordinates. The page you linked to has the trig equations to do this (they are exactly what you'd come up with on your own - I wrote the code below before checking your link).
R = 10;
a = 3;
tx=nan(41,21);
ty=nan(41,21);
tz=nan(41,21);
for j=1:21
for i=1:41
phi = (i-1)*2*pi/40;
theta = (j-1)*2*pi/20;
tx(i,j)= cos(phi) * (R+cos(theta)*a);
ty(i,j)= sin(phi) * (R+cos(theta)*a);
tz(i,j)= sin(theta)*a;
end
end
figure
surf(tx,ty,tz)
axis equal
To distort the surface, replace the constant a with a matrix of the desired minor radius values, and index into that matrix - i.e. tz(i,j) = sin(theta)*distortion(i,j) (but in all dimensions, obviously).