`streamline` not plotting this vector field - matlab

I am trying to test streamline with a very simple 3D vector field. I fill in a mesh using 3 for loops (not the best, but this is reminescent of a different expression for "v" which I couldn't easily vectorise). Then I define the vector field v as r. Simple radial field. My full code is below. quiver3 is fine, but unfortunately streamline gives me the following error:
Error using griddedInterpolant
Interpolation requires at least two
sample points in each dimension.
N = 5;
L = 2;
dl = 2*L/N;
for i = 1:N+1
for j = 1:N+1
for k = 1:N+1
x = -L + (i-1)*dl;
y = -L + (j-1)*dl;
z = -L + (k-1)*dl;
X(i,j,k) = x;
Y(i,j,k) = y;
Z(i,j,k) = z;
r = [x,y,z];
v = r-r0;
Vx(i,j,k) = v(1);
Vy(i,j,k) = v(2);
Vz(i,j,k) = v(3);
end
end
end
quiver3(X,Y,Z,Vx,Vy,Vz);
[sx,sy,sz] = meshgrid(0:0.1:1,0:1:5,0:1:5);
streamline(X,Y,Z,Vx,Vy,Vz,sx,sy,sz);
hold on;
streamslice(X,Y,Z,Vx,Vy,Vz,[],[],5);
pbaspect([1,1,1])

It returns back to gridded X, Y variables, if you use transposed version of X and Y, you will not get this interpolation error in the streamline function. To transpose a N-D array in MATLAB, use permute function, like:
X = permute(X, [2,1,3]); % to rearrange X and Y dimension
or just define correct form of X and Y at the first place [in the loop]

Related

How to create a 3D pseudosphere (tractrix) with Matlab with meshgrid() and surf()

I use Matlab once or twice every other year, so please let me know if the question is not good enough to stay, and I will erase it, but I checked the dimensions of the three columns in S below, and I am not sure why it wouldn't work, so if you can give a tip on what's going on in terms of linear algebra types of structures in the code, I will be very appreciative.
This is what I want (more or less):
This is what I tried:
v = linspace(0,2*pi);
w = linspace(0,5);
x = cos(v)./cosh(w);
y = sin(v)./cosh(w);
[x,y] = meshgrid(v,w);
z = w - tanh(w);
S = [x;y;z];
h = surf(x,y,z)
set(h,'edgecolor','none')
colormap summer
This is the error:
Error using surf (line 71)
Z must be a matrix, not a scalar or vector.
Which I thought it was after being concatenated to the other two columns in S.
The parametrization works like this:
a = 0.3;
u = 0:0.01:(2 * pi);
v = 0:0.01:5;
[X,Y] = meshgrid(u,v);
x = a.* cos(X) ./ cosh(Y);
y = a.* sin(X) ./ cosh(Y);
z = a.* (Y - tanh(Y));
h = surf(x,y,z);
zlim([0, 0.9]);
set(h,'edgecolor','none')
colormap summer

How to plot and define with Matlab a function defined on different subintervals, which enters an ODE

I am trying to plot and then to use it with Matlab
in an ODE as coefficient, the function
f : [2,500] -> [0,1],
But I don't know how to write the code for the definition of the function, since it is given on different subintervals.
Below is an example that uses anonymous functions/function handles. It uses each region/condition and evaluates the boundaries numerically and stores them into variables Bounds_1 and Bounds_2. These boundaries are then used to truncate each signal by multiplying each section of the piecewise function by its corresponding condition which is a logical array. It's also good to note that this plot will almost be seen as an impulse since the bounds are really small. Alternatively, you can probably achieve the same results using the built-in piecewise() function but I think this method gives a little more insight. As i increases you'll see a plot that resembles more and more of an impulse. To plot this for multiple values or i this can be run in a for-loop.
clc;
i = 3;
Bounds_1 = [i - (1/i^2),i];
Bounds_2 = [i,i + (1/i^2)];
Bounds = [Bounds_1 Bounds_2];
Min = min(Bounds);
Max = max(Bounds);
f1 = #(x) (i^2.*x - i^3 + 1).*(Bounds_1(1) < x & x <= Bounds_1(2));
f2 = #(x) (-i^2.*x + i^3 + 1).*(Bounds_2(1) < x & x <= Bounds_2(2));
f = #(x) f1(x) + f2(x);
fplot(f);
xlim([Min-2 Max+2]);
ylim([0 1.1]);
Here is another solution. You can specify the steps along the x-axis withxstep. With xlower and xupper you can specify the range of the x-axis:
figure ; hold on;
xlabel('x'); ylabel('f(x)');
for i= 2:500
[f,x] = myfunction(0.5,i);
plot (x,f,'DisplayName',sprintf('%i',i));
end
% legend
function [f,x]=myfunction(xstep,i)
%xstep: specifies steps for the x values
% specify max range x \in = [xlower -> xupper]
xlower = -10;
xupper = 600;
x2 = (i-1/i^2): xstep: i;
f2 = i^2*x2 - i^3 + 1;
x3 = i+xstep:xstep:(1+1/i^2);
f3 = -i^2*x3 + i^3 +1;
x1 = xlower:xstep:(i-1/i^2);
f1 = 0*x1;
x4 = (i+1/i^2):xstep:xupper;
f4 = 0*x4;
f = [f1,f2,f3,f4];
x = [x1,x2,x3,x4];
end
Here is what I get
Besides, I am not exactly sure what you mean with ODE (ordinary differential equation) in f(x). For me it seems like an algebraic equation.

Unable to perform assignment because the size of the left side is 1-by-2 and the size of the right side is 2-by-2

the code tries to implement the Euler's method and improve Euler's method to second order differential equations but there is a dimensionality error with the ys values array which store the values of y and dy
f=#(x,y) [y(2); (2/x)*y(2)-(2/x^2)*y(1)]; % function through a function handle
x0 = 1; y0 = [4,9]; xf=2; % IC
% Improve and Euler's Method
[xs,ys] = ode45(f,[x0,xf],y0);
[xsi1,ysi1] = Ieuler(f,[x0,xf],y0,0.1);
[xse1,yse1] = euler(f,[x0,xf],y0,0.1);
[xsi2,ysi2] = Ieuler(f,[x0,xf],y0,0.5);
[xse2,yse2] = euler(f,[x0,xf],y0,0.5);
% plotting all solutions
plot(xsi1,ysi1(:,1),'-b','LineWidth',1.5); hold on;
plot(xse1,yse1(:,1),'-r','LineWidth',1.5); hold on;
plot(xsi2,ysi2(:,1),'-g','LineWidth',1.5); hold on;
plot(xse2,yse2(:,1),'-k','LineWidth',1.5); hold on;
plot(xs,ys(:,1),'-b','LineWidth',1.5); hold on;
axis([0 xf -0.1 4]); xlabel('x');ylabel('y')
In the second part of the code are the constructed function to implement Euler's method
%Function calls
% function: Euler's Method implementation
function [xs,ys] = euler(f,xv,y0,h)
x0 = xv(1); X = xv(2);
N = (X-x0)/h;
xs = zeros(N+1,1); ys = zeros(N+1,length(y0));
x = x0; y = y0;
xs(1) = x; ys(1,:) = y';
for i = 1:N
s1 = f(x,y); %evaluate direction field at current point
y= y+s1*h; %find new y
x = x+h;
xs(i+1) = x; ys(i+1,:) = y'; %store y(1), y(2) in a row array
end
end
% function: Improved Euler's Method implementation
function [xs,ys] = Ieuler(f,xv,y0,h)
x0 = xv(1); X = xv(2);
N = (X-x0)/h;
xs = zeros(N+1,1); ys = zeros(N+1,length(y0));
x = x0; y = y0;
xs(1) = x; ys(1,:) = y';
for i = 1:N
s1 = f(x,y); %evaluate direction field at current point
yE= y+s1*h; %find Euler value yE
s2 = f(x+h,yE); %evalute direction field at Euler point
y = y + h*((s1+s2)/2); *%find new y*
x = x+h;
xs(i+1) = x; ys(i+1,:) = y'; *%store y(1), y(2) in a row array*
end
end
Unable to perform assignment because the size of the left side is 1-by-2 and the
size of the right side is 2-by-2.
Error in Untitled>Ieuler (line 63)
xs(i) = x; ys(i,:) = y';
Error in Untitled (line 20)
[xsi1,ysi1] = Ieuler(f,[x0,xf],y0,0.1);
stop writing several logic lines (terminated with a ;) in one text
line. It is not even clear, which command causes the error, since
there are two in this line! (BTW, it is this ys(i+1,:) = y';)
strip your code. You should provide a minimal reproducible example
(its not an art contest... and as the error occurs in Ieuler the rest is not necessary).
your error is: that your function handle ´f´ returns a vector, but y is an array => you'll get a matrix, which you want to assign to an array ys(i+1,:) = y' (for whatever reason you are transposing this). solution: let f return an array: f=#(x,y) [y(2), (2/x)*y(2)-(2/x^2)*y(1)]; (note the comma) or transpose its return value s1 = f(x,y).'; (its good practice to use the .' for non-complex transpositions -- for clarity.
Advice: have a look how to debug in MATLAB. You probably could have tracked this down by placing a breakpoint just before the line where the error occurs (or even activate Pause on Errors) and checking the dimensions.

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.)

Optimize Reorganization of Matrix without Loops

TL;DR: I am trying to optimize the following short code in Matlab. Because it involves loops over large matrices, it is too slow.
for i = 1:sz,
for j = 1:sz,
if X(j) == Q(i) && Y(j) == R(i),
S(i) = Z(j);
break
end
end
end
Specifics: Basically, I started with three vectors of x, y and z data that I wanted to plot as a surface. I generated a mesh of the x and y data and then made a matrix for the corresponding z values using
[X, Y] = meshgrid(x, y);
Z = griddata(x, y, z, X, Y);
Because the data is collected in random order, when generating the surface plot the connections are all wrong and the plot looks all triangulated like the following example.
So, to make sure Matlab was connecting the right dots, I then reorganized the X and Y matrices using
[R, R_indx] = sort(Y);
[Q, Q_indx] = sort(X, 2);
From here I thought it would be a simple problem of reorganizing the matrix Z based on the indices of the sorting for matrix X and Y. But I run into trouble because no matter how I use the indices, I cannot produce the correct matrix. For example, I tried
S = Z(R_indx); % to match the rearrangement of Y
S = S(Q_indx); % to match the rearrangement of X
and I got this barcode...
Running the first block of code gives me the "desired" result pictured here. However, this takes far too long as it is a double loop over a very large matrix.
Question: How can I optimize this rearrangement of the matrix Z without for loops?
Please have a look at the following solutions, and test both with your matrices. Do they perform faster? The array indexing solution does, what you asked for, i.e. the re-arrangement of the matrices. The vector indexing might be even better, since it sorts your original vectors instead of the matrices, and generates the output directly from there.
% Parameters.
dim = 4;
% Test input.
x = [2, -2, 5, 4];
y = [1, -4, 6, -2];
z = rand(dim);
[X, Y] = meshgrid(x, y);
Z = griddata(x, y, z, X, Y);
[R, R_indx] = sort(Y);
[Q, Q_indx] = sort(X, 2);
% Initialize output.
S = zeros(dim);
% Provided solution using loop.
for i = 1:numel(z)
for j = 1:numel(z)
if (X(j) == Q(i) && Y(j) == R(i))
S(i) = Z(j);
break
end
end
end
% Output.
S
% Solution using array indexing; output.
S_array = reshape(((X(:) == Q(:).') & (Y(:) == R(:).')).' * Z(:), dim, dim)
% Solution using vector indexing; output.
[r, r_indx] = sort(y);
[q, q_indx] = sort(x);
[X, Y] = meshgrid(q, r);
Z = griddata(q, r, z, X, Y);
idx = (ones(dim, 1) * ((q_indx - 1) * dim) + r_indx.' * ones(1, dim));
S_vector = Z(idx)
Example output:
S =
0.371424 0.744220 0.777214 0.778058
0.580353 0.686495 0.356647 0.577780
0.436699 0.217288 0.883900 0.800133
0.594355 0.405309 0.544806 0.085540
S_array =
0.371424 0.744220 0.777214 0.778058
0.580353 0.686495 0.356647 0.577780
0.436699 0.217288 0.883900 0.800133
0.594355 0.405309 0.544806 0.085540
S_vector =
0.371424 0.744220 0.777214 0.778058
0.580353 0.686495 0.356647 0.577780
0.436699 0.217288 0.883900 0.800133
0.594355 0.405309 0.544806 0.085540