How can I assign values to a surface in matlab? - matlab

I am trying to build a 3D CFD pipe flow model using MATLAB, and I am hoping to assign values (boundary conditions) on the pipe wall. I've tried building a pipe using the cylinder function:
[X Y Z] = cylinder
but this generates me several points on the surface, which are not enough.
Aside, is there a better way to build a 3D CFD pipeflow model using MATLAB?

I would use a struct to embed information in your CFD object.
% radius = 10
r = 10;
% number of radial points = 30
n = 30;
CFD_cyl = struct;
[CFD_cyl.X, CFD_cyl.Y, CFD_cyl.Z] = cylinder(r, n);
% Creates a value vector in the CFD_cyl struct that can relate to the cylinder X, Y, Z
CFD_cyl.value = CFD_cyl.X(:,:) + CFD_cyl.Y(:,:) + CFD_cyl.Z(:,:);
Change the value field accordingly for the useful relationship that you wish to express.

Related

Potential flow, define theta in matlab

I have made this matlab script for a potential flow around a cylinder and I would like to add a point source. See the definition of point source in picture. How can you define theta in matlab? And plot this its streamlines Psi?
clear
% make axes
xymax = 2;
x = linspace(-xymax,xymax,100);
y = linspace(-xymax,xymax,100);
% note that x and y don't include 0
[xmesh,ymesh] = meshgrid(x,y);
x_c=0;
y_c=0;
q=1;
U=1
r = sqrt((xmesh-x_c).^2+(ymesh-y_c).^2);
sin_th= ((ymesh-y_c)./r)
%(ymesh-y_c)./r = sin(teta)
%(xmesh-x_c)./r = cos(teta)
psi1 = -q./r.*((ymesh-y_c)./r);
psi2 = r.*sin_th;
psi=psi1+psi2;
figure
contour(xmesh,ymesh,psi,[-xymax:.25:xymax],'-b');
To plot the streamlines in potential flow you are correct that you have to plot contour lines of constant stream function.
In the case of a point source, if you are plotting in cartesian coordinates in MATLAB you have to convert theta to cartesian coordinates using arctangent as follows: theta = arctan(y/x). In MATLAB use the function atan2 which will limit the number of discontinuities to between -PI and PI: https://www.mathworks.com/help/matlab/ref/atan2.html
Your code should read: psi2 = ( m/(2*PI) ) * atan2(y,x)
For more information on plotting elements of potential flow in 2D cartesian coordinates, see more information here:
https://potentialflow.com/flow-elements
https://potentialflow.com/equations

Retrieving data on coordinates which or not on the data grid through interpolation

I'm using Matlab to read a large (NetCDF) data set with information about a magnetic field. The data set is a three-dimensional array of 318x562x554 and I can retrieve have three one-dimensional array (318x1, 562x1 and 554x1) with each axis values of the coordinates. I would like to know the magnetic field values on points that do not fit on the data set grid. These points are in this case trajectory coordinates of a spacecraft placed in a two-dimensional array (3xn,n depends on how many coordinates you have).
x = ncread(file,'X_axis');
y = ncread(file,'Y_axis');
z = ncread(file,'Z_axis');
Bx = ncread(file,'Bx');
[x2,y2,z2] = meshgrid(y,x,z);
length = numel(interval_ET_5000);
Bx_intp = zeros(1,length);
for i = 1:length
[xi,yi,zi] = meshgrid(position_MEX_Mars_5000(1,i),...
position_MEX_Mars_5000(2,i),...
position_MEX_Mars_5000(3,i));
F = interp3(x2,y2,z2,Bx,xi,yi,zi);
Bx_intp(i) = F;
end
I have tried many things that didn't even work. This 'works' but not correct because the values in Bx_intp are way to high. Also because of the doing coordinates one at the time in a for loop makes it very slow, a normal run is about 3500 coordinates.
So basicly what I am looking for is a reverse scatteredInterpolant. This function accepts random data points and you interpolate the values on a meshgrid. But now I have a regular grid and I want interpolation on random points.
Thanks for the tip Ashish Uthama! I got it working with the code below. For other people with the same problem. You need ndgrid instead of meshgrid for griddedInterpolant and the coordinates need to be monotonic increasing.
x = ncread(file,'X_axis');
y = ncread(file,'Y_axis');
z = ncread(file,'Z_axis');
Bx = ncread(file,'Bx');
[x2,y2,z2] = ndgrid(x,y,z);
F = griddedInterpolant(x2,y2,z2,Bx,'linear','none');
Bx_intp = F(position_MEX_Mars_5000(1,i),...
position_MEX_Mars_5000(2,i),...
position_MEX_Mars_5000(3,i));

How would I plot the for loop from my code below?

I have 3D flow data of the velocity of a fluid through a tube. I know the diameter of the tube and have looked at the velocity field and found the centre of the field for an xy plane at both ends of the tube. So I essentially have a line through the centre axis of the tube. I want to NaN all data points that are outside of the diameter. For this I am using an equation that gives the distance to a point from a line in 3D which I found here mathworld.wolfram.com/Point-LineDistance3-Dimensional.html. I then created an if statement which states points smaller than diameter will be NaN.
I am new to matlab so I don't know how I would now plot this.
%%
diff_axis = end_axis-start_axis;
diff_axis_mag = (diff_axis(1)^2 + diff_axis(2)^2 + diff_axis(3)^2)^0.5;
[rw col pl] = size(X);
for j = 1:col
for i = 1:rw
for k = 1:pl
x_curr = X(i,j,k);
y_curr = Y(i,j,k);
z_curr= Z(i,j,k);
x0 = [x_curr y_curr z_curr]
t = - dot((start_axis-x0),(diff_axis))./(diff_axis_mag)^2;
d = sqrt(((start_axis(1) - x0(1)) + (end_axis(1) - start_end(1))*t)^2 + ((start_axis(2)-x0(2))+(end_axis(2)-start_end(2))*t)^2+((start_axis(3)-x0(3))+(end_axis(3)-start_end(3))*t)^2);
if (d > D)
x_curr=NaN
y_curr=NaN
z_curr=NaN
end
end
end
end
It were nice to have explanatory names for your X, Y, and Z. I am guessing they are flow components, and diff_axis are axis coordinates? It is a very cumbersome notation.
what you do in your loops is you take point values (X,Y,Z), copy them to temporary constants and then set them to NaN if they fall out. But the problem is that usually you do not plot point-by-point in MATLAB. So these temorary guys like x_curr will be lost.
Also, the most optimal way to do things in MATLAB is to avoid loops whenever possible.
What you can do is to create first a mask
%// remember to put a dot like in `.^` for entrywise array operations
diff_axis_mag = sqrt(diff_axis(1).^2 + diff_axis(2).^2 + diff_axis(3).^2);
%// are you sure you need to include the third axis?
%// then it is a ball, not a tube
%// create a binary mask
mask = diff_axis_mag < tube_radius
X(~mask) = NaN;
Y(~mask) = NaN;
Z(~mask) = NaN;
Then you can plot your data with quiver3 or
stream3

Point Cloud Generation

I have a 3-D geometrical shape which I have to convert into a point cloud.
The resultant point cloud can be considered equivalent to a point cloud output from a Laser Scan of the object.
No mesh generation is neeeded
The points generated may be evenly spaced, or maybe just randomly spaced - doesn't matter
The 3-D shape can be provided in the form of a 3-D mathematical formula
This has to be done using MATLAB
It's difficult to answer without an example but it sounds like you just want to perform a montecarlo simulation?
Lets say your shape is defined by the function f and that you have X, Y limits stored in two element vector e.g. xlim = [-10 10] i.e. all possible x values of this shape lie between x = -10 and x = 10 then I would suggest that you make f return some sort of error code if there is no value for a specific x-y pair. I'm going to assume that will be NaN. So f(x,y) is a function you are writing that either returns a z if it can or NaN if it can't
n= 10000;
counter = 1;
shape = nan(n, 3)
while counter < n
x = rand*diff(xlim) + mean(xlmin);
y = rand*diff(ylim) + mean(ylim);
z = f(x,y)
if ~isnan(z)
shape(counter, :) = [x, y, z];
counter = counter + 1
end
end
So the above code will generate 10000 (non unique, but that's easily adapted for) points randomly sample across your shape.
Now after typing this I realise that perhaps your shape is actually not all that big and maybe you can uniformly sample it rather than randomly:
for x = xlim(1):xstep:xlim(2)
for y = ylim(1):ystep:ylim(2)
shape(counter, :) = [x, y, f(x,y)];
end
end
or if you write f to be vectorized (preferable)
shape = [(xlim(1):xstep:xlim(2))', (ylim(1):ystep:ylim(2))', f(xlim(1):xstep:xlim(2), ylim(1):ystep:ylim(2));
and then either way
shape(isnan(shape(:, 3), :) = []; %remove the points that fell outside the shape
Here is the code to create a Cloud image with a Depth image from a PrimeSense Camera.
The input/Ouput of this function :
-inputs
depth -depth map
topleft -topleft coordinates of the segmented image in the whole image
-outputs
pclouds -3d point clouds
MatLab code :
depth = double(depth);
% Size of camera image
center = [320 240];
[imh, imw] = size(depth);
constant = 570.3;
% convert depth image to 3d point clouds
pclouds = zeros(imh,imw,3);
xgrid = ones(imh,1)*(1:imw) + (topleft(1)-1) - center(1);
ygrid = (1:imh)'*ones(1,imw) + (topleft(2)-1) - center(2);
pclouds(:,:,1) = xgrid.*depth/constant;
pclouds(:,:,2) = ygrid.*depth/constant;
pclouds(:,:,3) = depth;
distance = sqrt(sum(pclouds.^2,3));
Edit : This source is from this current article http://www.cs.washington.edu/rgbd-dataset/software.html
You can find some other Cloud function in MatLab and C++ that can be interest you.

Create 3D logical mask from points

I have a set of 3D points specifying points on a surface of an object. From these points, i need to construct a 3D logical mask. How can I solve this with matlab? Hope to get some insights.
% parameters
num_coordinates = 100;
max_coordinate = 20;
% generate random coordinate
x = sort(randi(max_coordinate, [num_coordinates, 1]));
y = sort(randi(max_coordinate, [num_coordinates, 1]));
z = sort(randi(max_coordinate, [num_coordinates, 1]));
% create the mask
mask = false(max_coordinate, max_coordinate, max_coordinate);
for k = 1 : length(x)
mask(x(k), y(k), z(k)) = true;
end
If speed is important, I suppose there is a faster solution.
If you have the "Curve Fitting Toolbox" you could fit a surface formula to the data.
And if you now the exact type (like a ball, cone, ...) you can define that as formular to fit to.
Maybe you can provide some example data.