Matlab IFFT in 3-dimension - matlab

I am trying to use Matlab's ifftn in 3-dimensions to get solution in physical space. In particular I am trying to use ifftn on 1/k^2. The analytical solution to that in physical space is 1/(4*pi*r). However I am not recovering that. Please note: $r = sqrt(x^2 + y^2 + z^2)$ and $k = sqrt(kx^2 + ky^2 + kz^2)$.
clc; clear;
n = 128; % no. of points for ifft
L = 2*pi; % size of the periodic domain
x = linspace(-L/2,L/2,n); y = x; z = x; % creating vectors for x-y-z direction
[X,Y,Z] = meshgrid(x,y,z); % creating meshgrid for physical space
R = sqrt(X.^2 + Y.^2 + Z.^2); % use for 1/(4*pi*r)
k = (2*pi/L)*[0:n/2 -n/2+1:-1]; % wave vector;
[k1,k2,k3] = meshgrid(k,k,k);
denom = (k1.^2 + k2.^2 + k3.^2); % This is k^2
F = 1./denom; F(1,1,1) = 0; % The first value is set to zero as it is infinite
phi = 1./(4*pi*R); % physical domain solution
phys = fftshift(ifftn(F)); % Using ifftn
ph_abs = abs(phys);
mid = ph_abs(n/2,:,:); % looking at the midplane of the output
mid = permute(mid,[3 2 1]); % permuting for contourplot.
PHI = phi(n/2,:,:); %looking at the midplane of the physical space.
PHI = permute(PHI,[3 2 1]);
figure(1)
surf(x,z,log(mid))
shading flat
colorbar();
figure(2)
surf(x,z,log10(abs(PHI)))
shading flat
colorbar();

Related

Airfoil plot issue

I am having an issue with plotting my airfoil on matlab. It appears that there are some abberations with only one or two values. I have checked again and again with the formulas so they should be good. I have not converted to degrees so that's not the issue.
%% setup
clc
clear all
%type of airfoil
typeNACA = '2312';
%extract values of airfoil type
M = str2double(typeNACA(1)); % max camber %chord
P = str2double(typeNACA(2)); % chordwise position
Thmax = str2double(typeNACA(3:4));
M=M/100;
P=P/100
Thmax=Thmax/100;
% gridpoints
gridpoints = 1000;
% Airfoil grid
x = linspace(0,1,gridpoints);
%camber equations
%yc1(x) = (M/P^2)*(2*P*x-x^2);
%yc(x) = (M/(1-P)^2*(1-2*P+2*Px-x^2); % (for P =< x <1)
%dyc1 = (2*M/P^2)*(P-x)
%dyc2 = (2*M)/(1-P^2)*(P-x)
%Camber and gradient
yc = ones(gridpoints,1);
dyc= ones(gridpoints,1);
theta=ones(gridpoints,1);
for i=1:gridpoints
if (x(i) >= 0 && x(i) < P)
yc(i) = (M/P^2)*(2*P*x(i)-x(i)^2); % (for 0 =< x < P)
dyc(i)= ((2*M)/P^2)*(P - x(i)); %dyc/dx
elseif (x(i) >= P && x(i) <= 1) % (for P =< x <1)
yc(i)=(M/(1-P)^2)*(1-2*P+2*P*x(i)-x(i)^2);
dyc(i) = (2*M)/((1-P)^2*(P-x(i)));
end
theta(i) = atan(dyc(i)); %angle theta
end
% thickness coefficients
a0 = 0.2969;
a1 = -0.126;
a2 = -0.3516;
a3 = 0.2843;
a4 = -0.1036; % -0.1015 for open TE -0.1036 for closed TE
%thickness distribution
yt = ones(gridpoints,1);
for i=1:1:gridpoints
yt(i) = (Thmax/0.2)*(a0*x(i)^0.5 + a1*x(i) + a2*x(i)^2 + a3*x(i)^3 + a4*x(i)^4);
end
% Upper surface points
xu = ones(gridpoints,1);
yu = ones(gridpoints,1);
for i= 1:gridpoints
xu(i) = x(i) - yt(i)*sin(theta(i));
yu(i) = yc(i) + yt(i)*cos(theta(i));
end
% Lower surface points
xl = ones(gridpoints,1);
yl = ones(gridpoints,1);
for i=1:1:gridpoints
xl(i) = x(i) + yt(i)*sin(theta(i));
yl(i) = yc(i) - yt(i)*cos(theta(i));
end
%PLOT
f1 = figure(1);
hold on; grid on;
axis equal
plot(xu,yu,'r';
plot(xl,yl,'b');
well! The first problem is you've forgotten the closing parenthesis in the second line from the end. But if you want me to check your code, I need to have your typeNACA() function .m file to revise it. Or u can post its code here.
%PLOT
f1 = figure(1);
hold on; grid on;
axis equal
plot(xu,yu,'r';
plot(xl,yl,'b');

Output of streamline in Matlab is empty

I want to use streamline to show a vector field. The vector field is singular in a point. I want to remove regions near the singularity (fo example regions which their distance to singularity is less than 1). I wrote below code but it doesn't show anything. Could anyone help me?
clear all;
close all;
r1 = 1; r2 = 5; % Radii of your circles
x_0 = 0; y_0 = 0; % Centre of circles
[x,y] = meshgrid(x_0-r2:0.2:x_0+r2,y_0-r2:0.2:y_0+r2); % meshgrid of points
idx = ((x-x_0).^2 + (y-y_0).^2 > r1^2 & (x-x_0).^2 + (y-y_0).^2 < r2^2);
x = sort(x(idx));
[x, index] = unique(x);
y = sort(y(idx));
[y, index] = unique(y);
U=cos(x)/sqrt(x.^2+y.^2);
V=sin(x)/sqrt(x.^2+y.^2);
streamslice(x,y,U,V);
The problem with your code is that U and V are all zeros, so you get white space. The reason for that is that you don't use elementwise division with ./. So as a first step you should write:
U = cos(x)./sqrt(x.^2+y.^2);
V = sin(x)./sqrt(x.^2+y.^2);
Now U and V are not zeros but are also not matrices anymore, so they are not a valid input for streamslice. The reason for that is that x and y are converted to vectors when calling:
x = sort(x(idx));
y = sort(y(idx));
My guess is that you can remove all this indexing, and simply write:
r1 = 1; r2 = 5; % Radii of your circles
x_0 = 0; y_0 = 0; % Centre of circles
[x,y] = meshgrid(x_0-r2:0.2:x_0+r2,y_0-r2:0.2:y_0+r2); % meshgrid of points
U = cos(x)./sqrt(x.^2+y.^2);
V = sin(x)./sqrt(x.^2+y.^2);
streamslice(x,y,U,V);
so you get:
I think you misunderstood the concept of streamslice. Is this you expecting?
close all;
r1 = 1; r2 = 5; % Radii of your circles
x_0 = 0; y_0 = 0; % Centre of circles
[xx,yy] = meshgrid(x_0-r2:0.2:x_0+r2,y_0-r2:0.2:y_0+r2); % meshgrid of points
% idx = ((xx-x_0).^2 + (yy-y_0).^2 > r1^2 & (xx-x_0).^2 + (yy-y_0).^2 < r2^2);
% x = sort(xx(idx));
% [x, index] = unique(x);
% y = sort(yy(idx));
% [y, index] = unique(y);
U=cos(xx)./sqrt(xx.^2+yy.^2);
V=sin(xx)./sqrt(xx.^2+yy.^2);
streamslice(xx,yy,U,V);

Create random unit vector inside a defined conical region

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

Create a plane of points from a row of points

I am trying to create a "plane", so to speak, of points in MATLAB from a set of initial points. I have so far been able to create only one row of points, with the algorithm shown below:
% Generate molecular orientation and position
a = 4.309; % lattice constant in angstroms
l = 10; % number of lattices desired
placeHolder = [0 0 0 ; a/2 a/2 0; a/2 0 a/2; 0 a/2 a/2]; % centers of molecules
numMol = 4; %input('how many molecules are in the unit cell? \n # molecules = ');
numAtoms = 2; %input('how many atoms per molecule? \n # atoms per molecule = ');
atomPerUC = numMol*numAtoms; % number of atoms per unit cell
dir = zeros(numMol,3); % array for orientations
atomPosition = zeros(numAtoms*l^3,3,numMol); % array for positions of atoms
theta = zeros(numMol,1); % array for theta values
phi = zeros(numMol,1); % array for phi values
b = 1.54; % bond length in angstroms
for kk = 1:numMol % generate unit cell
% disp(['What is the molecular orientation for molecule ',num2str(kk),' ?']);
% dir(kk,1) = input('u = '); % ask for user input for molecular orientations
% dir(kk,2) = input('v = ');
% dir(kk,3) = input('w = ');
dir = [1,1,1;-1,1,1;-1,-1,1;1,-1,1];
u = dir(kk,1); % set variables for theta, phi computation
v = dir(kk,2);
w = dir(kk,3);
theta(kk) = w/sqrt(u^2+v^2+w^2); % theta value for molecule k
if v<0 % phi value for molecule k
phi(kk) = 2*pi - acos(abs(v)/sqrt(u^2+v^2+w^2));
else if v>0
phi(kk) = acos(u/sqrt(u^2+v^2+w^2));
end
end
theta = theta(kk); phi = phi(kk); % set variables for theta, phi for x,y,z computation
xp = placeHolder(kk,1); % cooridnates of center of molecule k
yp = placeHolder(kk,2);
zp = placeHolder(kk,3);
x1 = (b/2)*sin(theta)*cos(phi) + xp; % cooridnates for atoms in molecule
x2 = -(b/2)*sin(theta)*cos(phi) + xp;
y1 = (b/2)*sin(theta)*sin(phi) + yp;
y2 = -(b/2)*sin(theta)*sin(phi) + yp;
z1 = (b/2)*cos(theta) + zp;
z2 = -(b/2)*cos(theta) + zp;
atomPosition(1,:,kk) = [x1 y1 z1];
atomPosition(2,:,kk) = [x2 y2 z2];
end
for k = 1:numMol
x01 = atomPosition(1,1,k); y01 = atomPosition(1,2,k); z01 = atomPosition(1,3,k);
x02 = atomPosition(2,1,k); y02 = atomPosition(2,2,k); z02 = atomPosition(2,3,k);
for ii = 1:l-1
atomPosition(2*ii+1,:,k) = [(atomPosition(2*ii-1,1,k) + a) y01 z01];
atomPosition(2*ii+2,:,k) = [(atomPosition(2*ii,1,k) + a) y02 z02];
end
end
My problem is that I do not know how to, from here, turn this "row" of points into a "plane" of points. This can be thought of as taking the points that are known on the x-axis, and creating similar rows moving up in the y-direction to create an x-y plane of points.
Any help/suggestions would be appreciated!
Though I do not understand exactly what you are trying to do. In a simple case you can move from a row of points to a plane by adding the extra dimension.
ie.
x=[1,2,3,4,5]
y=x^2
changes to
x=[1,2,3,4,5]
y=[1,2,3,4,5]
[x,y] = meshgrid(x,y)
z=x^2+y^2

Projectile Motion with Drag Force Matlab

I'm trying to model projectile motion with air resistance.
This is my code:
function [ time , x , y ] = shellflightsimulator(m,D,Ve,Cd,ElAng)
% input parameters are:
% m mass of shell, kg
% D caliber (diameter)
% Ve escape velocity (initial velocity of trajectory)
% Cd drag coefficient
% ElAng angle in RADIANS
A = pi.*(D./2).^2; % m^2, shells cross-sectional area (area of circle)
rho = 1.2 ; % kg/m^3, density of air at ground level
h0 = 6800; % meters, height at which density drops by factor of 2
g = 9.8; % m/s^2, gravity
dt = .1; % time step
% define initial conditions
x0 = 0; % m
y0 = 0; % m
vx0 = Ve.*cos(ElAng); % m/s
vy0 = Ve.*sin(ElAng); % m/s
N = 100; % iterations
% define data array
x = zeros(1,N + 1); % x-position,
x(1) = x0;
y = zeros(1,N + 1); % y-position,
y(1) = y0;
vx = zeros(1,N + 1); % x-velocity,
vx(1) = vx0;
vy = zeros(1,N + 1); % y-velocity,
vy(1) = vy0;
i = 1;
j = 1;
while i < N
ax = -Cd*.5*rho*A*(vx(i)^2 + vy(i)^2)/m*cos(ElAng); % acceleration in x
vx(i+1) = vx(i) + ax*dt; % Find new x velocity
x(i+1) = x(i) + vx(i)*dt + .5*ax*dt^2; % Find new x position
ay = -g - Cd*.5*rho*A*(vx(i)^2 + vy(i)^2)/m*sin(ElAng); % acceleration in y
vy(i+1) = vy(i) + ay*dt; % Find new y velocity
y(i+1) = y(i) + vy(i)*dt + .5*ay*dt^2; % Find new y position
if y(i+1) < 0 % stops when projectile reaches the ground
i = N;
j = j+1;
else
i = i+1;
j = j+1;
end
end
plot(x,y,'r-')
end
This is what I am putting into Matlab:
shellflightsimulator(94,.238,1600,.8,10*pi/180)
This yields a strange plot, rather than a parabola. Also it appears the positions are negative values. NOTE: ElAng is in radians!
What am I doing wrong? Thanks!
You have your vx and vy incorrect... vx= ve*sin(angle in radians) and opposite for vy. U also u do not need a dot in between ur initial velocity and the *... That is only used for element by element multiplication and initial velocity is a constant variable. However the dot multiplier will not change the answer, it just isn't necessary..