Why is MatLab breaking for certain variable inputs? - matlab

here's my code:
function test(n)
r = (0:1000)/n;
Phi = 2*pi*r;
[x,y] = pol2cart(Phi,r);
plot(x,y)
end
here's the output for n = 100,10,1 in that order:
what's happening with the last graph? Why is it freaking out? >.> ...
more fun shapes after n = 1:
here n = 0.9, 0.8, 0.7, 0.6

Mathematically, the right most one should connect the points (n,0) where n is a natural number between 0 and 1000. Due to floating point precision, it is slightly off the 0 and get's very small values close to zero for the y-value. Please notice the 10^-x (can't read the x because it is to small) which indicates the scale for the y-axes. These are very small numbers.
For any values <4 it is nearly impossible to recognize the original spiral, here is a plot which shows the inner 20 revolutions for four different n values.
For any small value of n you will see an output similar to n=0.01 but for any large n it's just some aliasing which is either a line (which looks rough because of precision errors if you zoom in enough) or some spiral.
Code used to plot:
r = 0:.01:20;
Phi = 2*pi*r;
[x,y] = pol2cart(Phi,r);
plot(x,y,'r')
hold on
r = 0:.9:20;
Phi = 2*pi*r;
[x,y] = pol2cart(Phi,r);
plot(x,y,'g')
r = 0:1:20;
Phi = 2*pi*r;
[x,y] = pol2cart(Phi,r);
plot(x,y,'b')
r = 0:1.1:20;
Phi = 2*pi*r;
[x,y] = pol2cart(Phi,r);
plot(x,y,'black')
legend({'0.01','.9','1','1.1'})

Related

How to evaluate function of two variables with different x and y vectors

I've been trying to evaluate a function in matlab. I want my x vector to go from 0 to 1000 and my y vector to go from 0 to 125. They should both have a length of 101.
The equation to be evaluated is z(x,y) = ay + bx, with a=10 and b=20.
a = 10;
b = 20;
n = 101;
dx = 10; % Interval length
dy = 1.25;
x = zeros(1,n);
y = zeros(1,n);
z = zeros(n,n);
for i = 1:n;
x(i) = dx*(i-1);
y(i) = dy*(i-1);
for j = 1:n;
z(i,j) = a*dy*(j-1) + b*dx*(j-1);
end
end
I get an answer, but I don't know if I did it correctly with the indices in the nested for loop?
See MATLAB's linspace function.
a=10;
b=20;
n=101;
x=linspace(0,1000,n);
y=linspace(0,125,n);
z=a*y+b*x;
This is easier and takes care of the interval spacing for you. From the linspace documentation,
y = linspace(x1,x2,n) generates n points. The spacing between the points is (x2-x1)/(n-1).
Edit:
As others have pointed out, my solution above makes a vector, not a matrix which the OP seems to want. As #obchardon pointed out, you can use meshgrid to make that 2D grid of x and y points to generate a matrix of z. Updated approached would be:
a=10;
b=20;
n=101;
x=linspace(0,1000,n);
y=linspace(0,125,n);
[X,Y] = meshgrid(x,y);
z=a*Y+b*X;
(you may swap the order of x and y depending on if you want each variable along the row or column of z.)

Spiral of non-overlapping circles

I want to create a spiral of circle markers which never overlap with each other. This is what I got so far, but it overlaps the first markers, and the last ones are too far apart from each other.
t = pi : pi/20 : 20*pi;
t = asind(1./t);
r = t;
x = r .* cos(t);
y = r .* sin(t);
plot(x,y,'o-');
axis equal; hold on
Plotting without redefining t as asinf(1/t) as follows, is shown in the second plot.
t = pi : pi/20 : 20*pi;
r = t;
x = r .* cos(t);
y = r .* sin(t);
plot(x,y,'o-');
Any ideas on how does the spacing of the angles t must be to accomplish that the markers don't overlap?
You can approximate the arc length, greatly simplifying Gilles-Phillipe's solution. This is a simplification, which means that the distance between the markers is not identical everywhere. However the distances are fairly consistent, especially further out.
The approximation here is to assume that the spiral is, locally, a circle. The arc length then is r*dt at a position in the spiral a distance r from the origin, for a change in angle of dt radian.
We now no longer need to solve symbolic equations. I wrote the code in a loop. I'm sure it's possible to vectorize it, making the whole thing two lines of code, but I'll leave that as an exercise to the reader.
This is the code:
d = 1; % step size
q = 1/(2*pi); % spiral constant -- radius grows by q every 1 radian turn
N = 300; % number of points
t = 0; % initial angle
r = d; % initial radius
p = zeros(100,2);
p(1,:) = [r*cos(t),r*sin(t)]; % first point
for ii=2:N
dt = d/r;
t = t+dt;
r = r+dt*q;
p(ii,:) = [r*cos(t),r*sin(t)];
end
clf
plot(p(:,1),p(:,2),'o-')
axis equal
Try this:
syms s;
scale = 10;
l = scale/2 : scale/2 : 40*scale;
t = double(arrayfun(#(y) vpasolve((0.5*(s*sqrt(1+s^2)+asinh(s)))==y,s), l));
x = t .* cos(t);
y = t .* sin(t);
plot(x,y,'o-');
pbaspect([1 1 1]);
axis(scale*[-5 5 -5 5])
The idea is to parameterize using the arclength of the curve. The arclength of this spiral is l=1/2*(t*sqrt(1+t*t)+asinh(t)) (can be found using Matlab symbolic integration). To place points uniformly, we do a uniform sampling of the arclength, and find the corresponding t by solving the equation. Since it cannot be solved easily symbolically, we use a numerical solver.
Note that the scale and the aspect ratio of the plot is really important for it to look uniform and non-overlapping. This is why I added axis/ratio definition. Since each point is solved numerically, it can take quite some time to evaluate. There may be a faster way to do it, but at least you have a result.
I obtain the following result:

Double integral of the equation in Matlab

How to implement this equation
in Matlab,
where: A and B are mxm matrices.
for example:
A = [3.45 32.54 78.2; 8.4 33.1 4.66; 68.2 9.336 33.87 ]
B = [6.45 36.54 28.24; 85.4 323.1 74.66; 98.2 93.336 38.55 ]
my code:
f1 = #(A) (abs(A) ).^2;
f2 = #(B) (abs(B) ).^2;
Q = integral2( f1, 0, 1, 0, 1) * integral2(f2, 0, 1, 0, 1);
But when i run the code I got the error "Too many input arguments.".
What is the problem in the code?
After clarification of your question, let me change my post.
What you are after is numerical integration of a function that was already sampled on a fixed grid, and the function values are stored in matrices A and B that are two dimensional M by M. I suppose that you have the associated gridpoints as well, suppose they are denoted xc and yc. Then, if you have sufficiently fine sampling of a smooth function, the integral approaches:
xc = linspace(0,1,M);
yc = linspace(0,1,M);
Q = trapz(xc,trapz(yc, abs(A).^2)) * trapz(xc,trapz(yc, abs(B).^2 ));
To test that, I made a simple example that evaluates the surface of a circle, i.e.
so to do that with trapezoidal method with N samples for r and M samples for phi, we have,
r = 2; % Pick a value for r
M = 100; % Pick M samples for the angular coordinate from 0 to 2*pi
N = 101; % Pick N samples for the radial coordinate from 0 to r
phic = linspace(0,2*pi,M); % take M samples uniformly for example
rc = linspace(0,r,N); % take N samples uniformly for example
integrand = repmat(rc,M,1); % Make MxN matrix, phi along rows, r along columns
I = trapz(rc, trapz(phic, integrand));
So for the case r=2, it gives indeed 4*pi.

Gradient descent in linear regression goes wrong

I actually want to use a linear model to fit a set of 'sin' data, but it turns out the loss function goes larger during each iteration. Is there any problem with my code below ? (gradient descent method)
Here is my code in Matlab
m=20;
rate = 0.1;
x = linspace(0,2*pi,20);
x = [ones(1,length(x));x]
y = sin(x);
w = rand(1,2);
for i=1:500
h = w*x;
loss = sum((h-y).^2)/m/2
total_loss = [total_loss loss];
**gradient = (h-y)*x'./m ;**
w = w - rate.*gradient;
end
Here is the data I want to fit
There isn't a problem with your code. With your current framework, if you can define data in the form of y = m*x + b, then this code is more than adequate. I actually ran it through a few tests where I define an equation of the line and add some Gaussian random noise to it (amplitude = 0.1, mean = 0, std. dev = 1).
However, one problem I will mention to you is that if you take a look at your sinusoidal data, you define a domain between [0,2*pi]. As you can see, you have multiple x values that get mapped to the same y value but of different magnitude. For example, at x = pi/2 we get 1 but at x = -3*pi/2 we get -1. This high variability will not bode well with linear regression, and so one suggestion I have is to restrict your domain... so something like [0, pi]. Another reason why it probably doesn't converge is the learning rate you chose is too high. I'd set it to something low like 0.01. As you mentioned in your comments, you already figured that out!
However, if you want to fit non-linear data using linear regression, you're going to have to include higher order terms to account for the variability. As such, try including second order and/or third order terms. This can simply be done by modifying your x matrix like so:
x = [ones(1,length(x)); x; x.^2; x.^3];
If you recall, the hypothesis function can be represented as a summation of linear terms:
h(x) = theta0 + theta1*x1 + theta2*x2 + ... + thetan*xn
In our case, each theta term would build a higher order term of our polynomial. x2 would be x^2 and x3 would be x^3. Therefore, we can still use the definition of gradient descent for linear regression here.
I'm also going to control the random generation seed (via rng) so that you can produce the same results I have gotten:
clear all;
close all;
rng(123123);
total_loss = [];
m = 20;
x = linspace(0,pi,m); %// Change
y = sin(x);
w = rand(1,4); %// Change
rate = 0.01; %// Change
x = [ones(1,length(x)); x; x.^2; x.^3]; %// Change - Second and third order terms
for i=1:500
h = w*x;
loss = sum((h-y).^2)/m/2;
total_loss = [total_loss loss];
% gradient is now in a different expression
gradient = (h-y)*x'./m ; % sum all in each iteration, it's a batch gradient
w = w - rate.*gradient;
end
If we try this, we get for w (your parameters):
>> format long g;
>> w
w =
Columns 1 through 3
0.128369521905694 0.819533906064327 -0.0944622478526915
Column 4
-0.0596638117151464
My final loss after this point is:
loss =
0.00154350916582836
This means that our equation of the line is:
y = 0.12 + 0.819x - 0.094x^2 - 0.059x^3
If we plot this equation of the line with your sinusoidal data, this is what we get:
xval = x(2,:);
plot(xval, y, xval, polyval(fliplr(w), xval))
legend('Original', 'Fitted');

How to integrate matrices (Sum of Matrices with dx spacing) in MATLAB?

I'm pretty confused on how I would go about summing an infinite amount of matrices in MATLAB. Lets say I have this function (a gaussian):
%Set up grid/coordinate system
Ngrid=400;
w=Ngrid;
h=Ngrid;
%Create Gaussian Distribution
G = zeros ([w, h]);
Sig = 7.3; %I want the end/resultant G to be a summation of Sign from 7.3 to 10 with dx
for x = 1 : w
for y = 1 : h
G (x, y) = exp (-((Sig^-2)*((x-w/2+1)^2 + (y-h/2+1)^2)) / (2));
end
end
I essentially want the end/resultant function G to be a summation of Sign from 7.3 to 10 with dx (which is infinitesimally) small ie integration. How would I go about doing this? I am pretty confused. Can it even be done?
You don't appear to actually be summing G over a range of Sig values. You never change the value of Sig. In any case, assuming that dx isn't too small and that you have the memory this can be done without any loops, let alone two.
Ngrid = 400;
w = Ngrid;
h = Ngrid;
% Create range for Sig
dx = 0.1;
Sig = 7.3:dx:10;
% Build mesh of x and y points
x = 1:w;
y = 1:h;
[X,Y] = meshgrid(x,y);
% Evaluate columnized mesh points at each value of Sig, sum up, reshape to matrix
G = reshape(sum(exp(bsxfun(#rdivide,-((X(:)-w/2+1).^2+(Y(:)-h/2+1).^2),2*Sig.^2)),2),[h w]);
figure
imagesc(G)
axis equal
This results in a figure like this
The long complicated line above can be replaced by this (uses less memory, but may be slower):
G = exp(-((X-w/2+1).^2+(Y-h/2+1).^2)/(2*Sig(1)^2));
for i = 2:length(Sig)
G = G+exp(-((X-w/2+1).^2+(Y-h/2+1).^2)/(2*Sig(i)^2));
end