I am trying to rotate the derivative of a gaussian (or the original guassian for that matter) by applying a rotation matrix to the X,Y coordinates and then plotting it as a mesh in matlab, but I'm running into an issue that the plot will only rotate by 90 degress each time and for all n*pi points there is no mesh appearing at all. I am wondering what I am doing wrong, hopefully someone can spot my error. I'm fairly new to matlab so forgive me if the code is not pretty. Thank you!
This is the code that I have:
sigma = 4;
[x,y] = deal(-3*sigma:.5:3*sigma);
[X,Y] = meshgrid(x,y);
B = [transpose(x) transpose(y)];
for i=1:1:16
figure(i);
theta = i*pi/8;
rotation = [cos(theta) sin(theta); -sin(theta) cos(theta)];
A = B * rotation;
[x_new, y_new] = meshgrid(A(:,1)', A(:,2)');
mesh(x_new, y_new, dgauss_x(x_new, y_new, sigma));
end
function f = dgauss_x(x, y, sigma)
%first order derivative of Gaussian
f = -x .* gaussian(x, y, sigma) ./ sigma^2;
function f = gaussian(x, y, sigma)
f = exp(-(x .^ 2 + y .^ 2)/(2*sigma^2)) / (sqrt(2*pi*(sigma^2)));
I figure it out. It was a dumb error. Basically I had to create a meshgrid for X and Y, reshape it into an Nx2 matrix of X and Y. Apply the rotation matrix, then reshape back and apply the Gaussian.
The code looks as follows (could be cleaned up):
for i=1:1:16
figure(i);
theta = i*pi/8;
rotation = [cos(theta) -sin(theta); sin(theta) cos(theta)];
X1 = reshape(X, length(x)*length(x), 1);
Y1 = reshape(Y, length(y)*length(y), 1);
B2 = [X1 Y1];
A = B2 * rotation;
X1 = A(:,1);
X1 = reshape(X1, length(x), length(x));
Y1 = A(:,2);
Y1 = reshape(Y1, length(y), length(y));
mesh(X1, Y1, dgauss_x(X1, Y1, sigma));
end
Related
I want to create a shape that is a sphere on top of the 3D Gaussian.
something like this:
for plotting Gaussian I wrote tihs:
% isotropic Gaussian parameters
n = 100; % resolution
s = 2; % width
x = linspace(-5,5,n);
[X,Y] = meshgrid(x);
gaus2d = exp( -(X.^2 + Y.^2 )/(2*s^2));
figure(1), clf
surf(x,x,gaus2d)
and for sphere:
rotate3d on
hold on
[x1,y1,z1] = sphere;
% adjusting the radius of sphere
x1 = x1*s;
y1 = y1*s;
z1 = z1*s;
surf(x1,y1,z1)
The problem is: I don't know how to shift the sphere on top of the Gaussian. How to transfer sphere on top of the Gaussain?
You can add a constant to the sphere's z-values in ordner to 'lift' it up:
% isotropic Gaussian parameters
n = 100; % resolution
s = 2; % width
x = linspace(-5,5,n);
[X,Y] = meshgrid(x);
gaus2d = exp( -(X.^2 + Y.^2 )/(2*s^2));
figure(1), clf
surf(x,x,gaus2d)
rotate3d on
hold on
[x1,y1,z1] = sphere;
% adjusting the radius of sphere
x1 = x1*s;
y1 = y1*s;
z1 = z1;
% add a constant to sphere, so that it is on top of gauss
addi = max(gaus2d(:)) - min(z1(:));
z1 = z1 + addi;
surf(x1,y1,z1)
I have this piece of MATLAB code that outputs x,y, and z angles and I would like draw a line using them. Can someone point me in the right direction on how to do this?
C = pi;
A = pi;
B = pi;
Z = [cos(C),-sin(C),0; sin(C),cos(C),0; 0,0,1];
X = [1,0,0;0,cos(A),-sin(A);0,sin(A),cos(A)];
Y = [cos(B),0,sin(B);0,1,0;-sin(B),0,cos(B)];
R =(X*Y)*Z;
yaw=atan2(R(2,1),R(1,1))
pitch=atan2(-R(3,1),sqrt(R(3,2)^2+R(3,3)^2))
roll=atan2(R(3,2),R(3,3))
X, Y, and Z are not angles, they are rotation matrices defined by the angles A, B, and C.
it's not clear what's the meaning of "draw a line using them", they are just used to rotate vectors in the 3D space.
here is an example of drawing a rotated vector with them:
% define rotation angles (around the axes)
C = pi/2;
A = pi/4;
B = pi/4;
% generate rotation matrices
Z = [cos(C),-sin(C),0; sin(C),cos(C),0; 0,0,1];
X = [1,0,0;0,cos(A),-sin(A);0,sin(A),cos(A)];
Y = [cos(B),0,sin(B);0,1,0;-sin(B),0,cos(B)];
R =(X*Y)*Z;
% generate a vector and rotate it
v = [1;1;1];
u = R*v;
% plot
quiver3(0,0,0,v(1),v(2),v(3));
hold on
quiver3(0,0,0,u(1),u(2),u(3));
xlim([-1 1]); ylim([-1 1]); zlim([-1 1])
axis square
legend('original','rotated')
I'm trying to surface bumpy spheres and wrinkled spheres in Matlab using
p = 1 + 0,2 * sin(phi * m) * sin(teta * n)
teta = 0:6.23;
phi = 0:3.14;
[teta,phi] = meshgrid(teta, phi);
figure, hold on
for m = 1:12
for n = 1:12
p = 1 + 0.2*sin(m*teta).*sin(n*phi);
surf(teta,phi,p)
pause(0.05)
clf('reset')
end
end
But it's not drawing any sphere just surfaces...what am I doing wrong and what should I change :) Thanks a lot!!!
I don't understand your example so I created a new one:
%We define the spherical coordinates.
theta = linspace(0,2*pi,50);
phi = linspace(0,pi,50);
[x1,x2] = meshgrid(linspace(0,12*pi,50),linspace(0,12*pi,50)); %the variation of rho will produce a bumpy sphere.
rho = 0.1*(sin(x1)+cos(x2))+1;
[theta,phi] = meshgrid(theta,phi);
%we calculate the cartesian coordinates.
x = rho.*cos(theta).*sin(phi);
y = rho.*sin(theta).*sin(phi);
z = rho.*cos(phi);
%plot
surf(x,y,z);
RESULT BUMPY
RESULT WRINKLED
Simply change the rho parameter by:
rho = 0.1*(sin(x1))+1;
I'm looking for a simple way for creating a random unit vector constrained by a conical region. The origin is always the [0,0,0].
My solution up to now:
function v = GetRandomVectorInsideCone(coneDir,coneAngleDegree)
coneDir = normc(coneDir);
ang = coneAngleDegree + 1;
while ang > coneAngleDegree
v = [randn(1); randn(1); randn(1)];
v = v + coneDir;
v = normc(v);
ang = atan2(norm(cross(v,coneDir)), dot(v,coneDir))*180/pi;
end
My code loops until the random generated unit vector is inside the defined cone. Is there a better way to do that?
Resultant image from test code bellow
Resultant frequency distribution using Ahmed Fasih code (in comments).
I wonder how to get a rectangular or normal distribution.
c = [1;1;1]; angs = arrayfun(#(i) subspace(c, GetRandomVectorInsideCone(c, 30)), 1:1e5) * 180/pi; figure(); hist(angs, 50);
Testing code:
clearvars; clc; close all;
coneDir = [randn(1); randn(1); randn(1)];
coneDir = [0 0 1]';
coneDir = normc(coneDir);
coneAngle = 45;
N = 1000;
vAngles = zeros(N,1);
vs = zeros(3,N);
for i=1:N
vs(:,i) = GetRandomVectorInsideCone(coneDir,coneAngle);
vAngles(i) = subspace(vs(:,i),coneDir)*180/pi;
end
maxAngle = max(vAngles);
minAngle = min(vAngles);
meanAngle = mean(vAngles);
AngleStd = std(vAngles);
fprintf('v angle\n');
fprintf('Direction: [%.3f %.3f %.3f]^T. Angle: %.2fº\n',coneDir,coneAngle);
fprintf('Min: %.2fº. Max: %.2fº\n',minAngle,maxAngle);
fprintf('Mean: %.2fº\n',meanAngle);
fprintf('Standard Dev: %.2fº\n',AngleStd);
%% Plot
figure;
grid on;
rotate3d on;
axis equal;
axis vis3d;
axis tight;
hold on;
xlabel('X'); ylabel('Y'); zlabel('Z');
% Plot all vectors
p1 = [0 0 0]';
for i=1:N
p2 = vs(:,i);
plot3ex(p1,p2);
end
% Trying to plot the limiting cone, but no success here :(
% k = [0 1];
% [X,Y,Z] = cylinder([0 1 0]');
% testsubject = surf(X,Y,Z);
% set(testsubject,'FaceAlpha',0.5)
% N = 50;
% r = linspace(0, 1, N);
% [X,Y,Z] = cylinder(r, N);
%
% h = surf(X, Y, Z);
%
% rotate(h, [1 1 0], 90);
plot3ex.m:
function p = plot3ex(varargin)
% Plots a line from each p1 to each p2.
% Inputs:
% p1 3xN
% p2 3xN
% args plot3 configuration string
% NOTE: p1 and p2 number of points can range from 1 to N
% but if the number of points are different, one must be 1!
% PVB 2016
p1 = varargin{1};
p2 = varargin{2};
extraArgs = varargin(3:end);
N1 = size(p1,2);
N2 = size(p2,2);
N = N1;
if N1 == 1 && N2 > 1
N = N2;
elseif N1 > 1 && N2 == 1
N = N1
elseif N1 ~= N2
error('if size(p1,2) ~= size(p1,2): size(p1,2) and/or size(p1,2) must be 1 !');
end
for i=1:N
i1 = i;
i2 = i;
if i > N1
i1 = N1;
end
if i > N2
i2 = N2;
end
x = [p1(1,i1) p2(1,i2)];
y = [p1(2,i1) p2(2,i2)];
z = [p1(3,i1) p2(3,i2)];
p = plot3(x,y,z,extraArgs{:});
end
Here’s the solution. It’s based on the wonderful answer at https://math.stackexchange.com/a/205589/81266. I found this answer by googling “random points on spherical cap”, after I learned on Mathworld that a spherical cap is this cut of a 3-sphere with a plane.
Here’s the function:
function r = randSphericalCap(coneAngleDegree, coneDir, N, RNG)
if ~exist('coneDir', 'var') || isempty(coneDir)
coneDir = [0;0;1];
end
if ~exist('N', 'var') || isempty(N)
N = 1;
end
if ~exist('RNG', 'var') || isempty(RNG)
RNG = RandStream.getGlobalStream();
end
coneAngle = coneAngleDegree * pi/180;
% Generate points on the spherical cap around the north pole [1].
% [1] See https://math.stackexchange.com/a/205589/81266
z = RNG.rand(1, N) * (1 - cos(coneAngle)) + cos(coneAngle);
phi = RNG.rand(1, N) * 2 * pi;
x = sqrt(1-z.^2).*cos(phi);
y = sqrt(1-z.^2).*sin(phi);
% If the spherical cap is centered around the north pole, we're done.
if all(coneDir(:) == [0;0;1])
r = [x; y; z];
return;
end
% Find the rotation axis `u` and rotation angle `rot` [1]
u = normc(cross([0;0;1], normc(coneDir)));
rot = acos(dot(normc(coneDir), [0;0;1]));
% Convert rotation axis and angle to 3x3 rotation matrix [2]
% [2] See https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
crossMatrix = #(x,y,z) [0 -z y; z 0 -x; -y x 0];
R = cos(rot) * eye(3) + sin(rot) * crossMatrix(u(1), u(2), u(3)) + (1-cos(rot))*(u * u');
% Rotate [x; y; z] from north pole to `coneDir`.
r = R * [x; y; z];
end
function y = normc(x)
y = bsxfun(#rdivide, x, sqrt(sum(x.^2)));
end
This code just implements joriki’s answer on math.stackexchange, filling in all the details that joriki omitted.
Here’s a script that shows how to use it.
clearvars
coneDir = [1;1;1];
coneAngleDegree = 30;
N = 1e4;
sol = randSphericalCap(coneAngleDegree, coneDir, N);
figure;plot3(sol(1,:), sol(2,:), sol(3,:), 'b.', 0,0,0,'rx');
grid
xlabel('x'); ylabel('y'); zlabel('z')
legend('random points','origin','location','best')
title('Final random points on spherical cap')
Here is a 3D plot of 10'000 points from the 30° spherical cap centered around the [1; 1; 1] vector:
Here’s 120° spherical cap:
Now, if you look at the histogram of the angles between these random points at the coneDir = [1;1;1], you will see that the distribution is skewed. Here’s the distribution:
Code to generate this:
normc = #(x) bsxfun(#rdivide, x, sqrt(sum(x.^2)));
mysubspace = #(a,b) real(acos(sum(bsxfun(#times, normc(a), normc(b)))));
angs = arrayfun(#(i) mysubspace(coneDir, sol(:,i)), 1:N) * 180/pi;
nBins = 16;
[n, edges] = histcounts(angs, nBins);
centers = diff(edges(1:2))*[0:(length(n)-1)] + mean(edges(1:2));
figure('color','white');
bar(centers, n);
xlabel('Angle (degrees)')
ylabel('Frequency')
title(sprintf('Histogram of angles between coneDir and random points: %d deg', coneAngleDegree))
Well, this makes sense! If you generate points from the 120° spherical cap around coneDir, of course the 1° cap is going to have very few of those samples, whereas the strip between the 10° and 11° caps will have far more points. So what we want to do is normalize the number of points at a given angle by the surface area of the spherical cap at that angle.
Here’s a function that gives us the surface area of the spherical cap with radius R and angle in radians theta (equation 16 on Mathworld’s spherical cap article):
rThetaToH = #(R, theta) R * (1 - cos(theta));
rThetaToS = #(R, theta) 2 * pi * R * rThetaToH(R, theta);
Then, we can normalize the histogram count for each bin (n above) by the difference in surface area of the spherical caps at the bin’s edges:
figure('color','white');
bar(centers, n ./ diff(rThetaToS(1, edges * pi/180)))
The figure:
This tells us “the number of random vectors divided by the surface area of the spherical segment between histogram bin edges”. This is uniform!
(N.B. If you do this normalized histogram for the vectors generated by your original code, using rejection sampling, the same holds: the normalized histogram is uniform. It’s just that rejection sampling is expensive compared to this.)
(N.B. 2: note that the naive way of picking random points on a sphere—by first generating azimuth/elevation angles and then converting these spherical coordinates to Cartesian coordinates—is no good because it bunches points near the poles: Mathworld, example, example 2. One way to pick points on the entire sphere is sampling from the 3D normal distribution: that way you won’t get bunching near poles. So I believe that your original technique is perfectly appropriate, giving you nice, evenly-distributed points on the sphere without any bunching. This algorithm described above also does the “right thing” and should avoid bunching. Carefully evaluate any proposed algorithms to ensure that the bunching-near-poles problem is avoided.)
it is better to use spherical coordinates and convert it to cartesian coordinates:
coneDirtheta = rand(1) * 2 * pi;
coneDirphi = rand(1) * pi;
coneAngle = 45;
N = 1000;
%perfom transformation preventing concentration of points around the pole
rpolar = acos(cos(coneAngle/2*pi/180) + (1-cos(coneAngle/2*pi/180)) * rand(N, 1));
thetapolar = rand(N,1) * 2 * pi;
x0 = rpolar .* cos(thetapolar);
y0 = rpolar .* sin(thetapolar);
theta = coneDirtheta + x0;
phi = coneDirphi + y0;
r = rand(N, 1);
x = r .* cos(theta) .* sin(phi);
y = r .* sin(theta) .* sin(phi);
z = r .* cos(phi);
scatter3(x,y,z)
if all points should be of length 1 set r = ones(N,1);
Edit:
since intersection of cone with sphere forms a circle first we create random points inside a circle with raduis of (45 / 2) in polar coordinates and as #Ahmed Fasih commented to prevent concentration of points near the pole we should first transform this random points, then convert polar to cartesian 2D coordinates to form x0 and y0
we can use x0 and y0 as phi & theta angle of spherical coordinates and add coneDirtheta & coneDirphi as offsets to these coordinates.
then convert spherical to cartesian 3D coordinates
I am trying to calculate maximum distance and maximum height of a projectile for an angle theta below.
I assume my way of plotting the graphs of distance against theta and height against theta (on the same graph) are wrong. Any pointers on that will be helpful.
e=100;
m = 1;
g = 9.8;
cd = 0.55;
r = 0.02;
p = 1.21;
a = pi*r^2;
v = sqrt((2*e)/m);
k = (1/2)*cd*a*p;
% For loop to calculate Distance and
for theta = (0:pi/4);
vx = v*cos(theta);
vy = v*sin(theta);
t = sqrt(m/(g*k))*atan(vy*sqrt(k/(m*g)));
x = (m/k)* log((1/vx)+(k/m)*t) - log(1/(vx));
h = (m/k)*(log(cos(atan(vy*sqrt(k/(m*g))-sqrt((g*k)/m)*t))-log(cos((atan(vy*sqrt(k/m*g)))))));
plot (x, theta);
plot (h, theta);
end
You don't need to loop through different values of theta. Try this instead:
theta = (0:0.01:pi/4); % theta = [0 0.01 0.02 0.03 ... pi/4]
vx = v*cos(theta);
vy = v*sin(theta);
t = sqrt(m/(g*k)) * atan(vy .* sqrt(k/(m*g))); % element wise matrix multiplication
x = (m/k)* log((1./vx)+(k/m)*t) - log(1./(vx));
h = (m/k)*(log(cos(atan(vy .* sqrt(k/(m*g))- sqrt((g*k)/m)*t))-log(cos((atan(vy .* sqrt(k/m*g)))))));
plot (x, theta);
plot (h, theta);
x vs theta:
Also try this:
MATLAB: Creating a Function to Plot Projectile with Drag
MATLAB: Numerical approximation of projectile motion with air resistance
Hope this helps!
The variable t is not defined. Also the loop variable should be integer, for example:
N = 10;
for i = 0:N-1
theta = pi/4*i/(N-1)
(...)
end