Plot symbolic equation using standard plot function in Matlab - matlab

In order to obtain a graphical representation of the behaviour of a fluid it is common practice to plot its streamlines.
For a given two-dimensional fluid with speed components u = Kx and v = -Ky (where K is a constant, for example: K = 5), the streamline equation can be obtained integrating the flow velocity field components as follows:
Streamline equation: ∫dx/u = ∫dy/v
The solved equation looks like this: A = B + C (where A is the solution of the first integral, B is the solution of the second integral and C is an integration constant).
Once we have achieved this, we can start plotting a streamline by simply assigning a value to C, for example: C = 1, and plotting the resulting equation. That would generate a single streamline, so in order to get more of them you need to iterate this last step assigning a different value of C each time.
I have successfully plotted the streamlines of this particular flow by letting matlab integrate the equation symbolically and using ezplot to produce a graphic as follows:
syms x y
K = 5; %Constant.
u = K*x; %Velocity component in x direction.
v = -K*y; %Velocity component in y direction.
A = int(1/u,x); %First integral.
B = int(1/v,y); %Second integral.
for C = -10:0.1:10; %Loop. C is assigned a different value in each iteration.
eqn = A == B + C; %Solved streamline equation.
ezplot(eqn,[-1,1]); %Plot streamline.
hold on;
end
axis equal;
axis([-1 1 -1 1]);
This is the result:
The problem is that for some particular regions of the flow ezplot is not accurate enough and doesn't handle singularities very well (asymptotes, etc.). That's why a standard "numeric" plot seems desirable, in order to obtain a better visual output.
The challenge here is to convert the symbolic streamline solution into an explicit expression that would be compatible with the standard plot function.
I have tried to do it like this, using subs and solve with no success at all (Matlab throws an error).
syms x y
K = 5; %Constant.
u = K*x; %Velocity component in x direction.
v = -K*y; %Velocity component in y direction.
A = int(1/u,x); %First integral.
B = int(1/v,y); %Second integral.
X = -1:0.1:1; %Array of x values for plotting.
for C = -10:0.1:10; %Loop. C is assigned a different value in each iteration.
eqn = A == B + C; %Solved streamline equation.
Y = subs(solve(eqn,y),x,X); %Explicit streamline expression for Y.
plot(X,Y); %Standard plot call.
hold on;
end
This is the error that is displayed on the command window:
Error using mupadmex
Error in MuPAD command: Division by zero.
[_power]
Evaluating: symobj::trysubs
Error in sym/subs>mupadsubs (line 139)
G =
mupadmex('symobj::fullsubs',F.s,X2,Y2);
Error in sym/subs (line 124)
G = mupadsubs(F,X,Y);
Error in Flow_Streamlines (line 18)
Y = subs(solve(eqn,y),x,X); %Explicit
streamline expression for Y.
So, how should this be done?

Since you are using subs many times, matlabFunction is more efficient. You can use C as a parameter, and solve for y in terms of both x and C. Then the for loop is very much faster:
syms x y
K = 5; %Constant.
u = K*x; %Velocity component in x direction.
v = -K*y; %Velocity component in y direction.
A = int(1/u,x); %First integral.
B = int(1/v,y); %Second integral.
X = -1:0.1:1; %Array of x values for plotting.
syms C % C is treated as a parameter
eqn = A == B + C; %Solved streamline equation.
% Now solve the eqn for y, and make it into a function of `x` and `C`
Y=matlabFunction(solve(eqn,y),'vars',{'x','C'})
for C = -10:0.1:10; %Loop. C is assigned a different value in each iteration.
plot(X,Y(X,C)); %Standard plot call, but using the function for `Y`
hold on;
end

Related

How to solve a differential equation with non-constant coefficient?

I have an equation like this:
dy/dx = a(x)*y + b
where a(x) is a non-constant (a=1/x) and b is a vector (10000 rows).
How can I solve this equation?
Let me assume you would like to write a generic numerical solver for dy/dx = a(x)*y + b. Then you can pass the function a(x) as an argument to the right-hand side function of one of the ODE solvers. e.g.
a = #(x) 1/x;
xdomain = [1 10];
b = rand(10000,1);
y0 = ones(10000,1);
[x,y] = ode45(#(x,y,a,b)a(x)*y + b,xdomain,y0,[],a,b);
plot(x,y)
Here, I've specified the domain of x as xdomain, and the value of y at the bottom limit of x as y0.
From my comments, you can solve this without MATLAB. Assuming non-zero x, you can use an integrating factor to get a 10000-by-1 solution y(x)
y_i(x) = b_i*x*ln(x) + c_i*x
with 10000-by-1 vector of constants c, where y_i(x), b_i and c_i are the i-th entries of y(x), b and c respectively. The constant vector c can be determined at some point x0 as
c_i = y_i(x0)/x_0 - b_i*ln(x0)

Solving time-dependent Schrodinger equation using MATLAB ode45

The Schrodinger equation for a time-dependent Hamiltonian is:
I try to implement a solver for the Schrodinger equation for a time-dependent Hamiltonian in ode45. However, because the Hamiltonian $H(t)$ is dependent on time. I do not know how to do interpolation in ode45. Can you give me some hints?
psi0 = [0 1];
H = [1 0;0 1]*cos(t); %this is wrong, I do not know how to implement this and pass it to ode45
hbar = 1;
t = [0:1:100];
[T, psi] = ode45(dpsi, t, psi);
function dpsi = f(t, psi, H, psi0)
dpsi = (1/i)*H*psi;
I also try to come up with a solution of matrix interpolation in
MATLAB: Interpolation that involve a matrix.
H is just an identity matrix in your case, so we can just multiply it with the psi vector to get back the psi vector itself. Then, we bring i*hbar to the right-hand-side of the equation so that the final equation is in a form that ode45 accepts. Finally, we use the following code to solve for psi:
function schrodinger_equation
psi0 = [0;1];
hbar = 1;
t = [0 100];
[T,psi] = ode45(#(t,psi)dpsi(t,psi,hbar),t,psi0);
for i = 1:length(psi0)
figure
plot(T,real(psi(:,i)),T,imag(psi(:,i)))
xlabel('t')
ylabel('Re(\psi) or Im(\psi)')
title(['\psi_0 = ' num2str(psi0(i))])
legend('Re(\psi)','Im(\psi)','Location','best')
end
end
function rhs = dpsi(t,psi,hbar)
rhs = 1/(1i*hbar)*cos(t).*ones(2,1);
end
Note that I have plotted the two components of psi separately and for each such plot, I have also plotted the real and imaginary components separately. Here are the plots for two different values of psi0:

Finding solution to Cauchy prob. in Matlab

I need some help with finding solution to Cauchy problem in Matlab.
The problem:
y''+10xy = 0, y(0) = 7, y '(0) = 3
Also I need to plot the graph.
I wrote some code but, I'm not sure whether it's correct or not. Particularly in function section.
Can somebody check it? If it's not correct, where I made a mistake?
Here is separate function in other .m file:
function dydx = funpr12(x,y)
dydx = y(2)+10*x*y
end
Main:
%% Cauchy problem
clear all, clc
xint = [0,5]; % interval
y0 = [7;3]; % initial conditions
% numerical solution using ode45
sol = ode45(#funpr12,xint,y0);
xx = [0:0.01:5]; % vector of x values
y = deval(sol,xx); % vector of y values
plot(xx,y(1,:),'r', 'LineWidth',3)
legend('y1(x)')
xlabel('x')
ylabel('y(x)')
I get this graph:
ode45 and its related ilk are only designed to solve first-order differential equations which are of the form y' = .... You need to do a bit of work if you want to solve second-order differential questions.
Specifically, you'll have to represent your problem as a system of first-order differential equations. You currently have the following ODE:
y'' + 10xy = 0, y(0) = 7, y'(0) = 3
If we rearrange this to solve for y'', we get:
y'' = -10xy, y(0) = 7, y'(0) = 3
Next, you'll want to use two variables... call it y1 and y2, such that:
y1 = y
y2 = y'
The way you have built your code for ode45, the initial conditions that you specified are exactly this - the guess using y and its first-order guess y'.
Taking the derivative of each side gives:
y1' = y'
y2' = y''
Now, doing some final substitutions we get this final system of first-order differential equations:
y1' = y2
y2' = -10*x*y1
If you're having trouble seeing this, simply remember that y1 = y, y2 = y' and finally y2' = y'' = -10*x*y = -10*x*y1. Therefore, you now need to build your function so that it looks like this:
function dydx = funpr12(x,y)
y1 = y(2);
y2 = -10*x*y(1);
dydx = [y1 y2];
end
Remember that the vector y is a two element vector which represents the value of y and the value of y' respectively at each time point specified at x. I would also argue that making this an anonymous function is cleaner. It requires less code:
funpr12 = #(x,y) [y(2); -10*x*y(1)];
Now go ahead and solve it (using your code):
%%// Cauchy problem
clear all, clc
funpr12 = #(x,y) [y(2); -10*x*y(1)]; %// Change
xint = [0,5]; % interval
y0 = [7;3]; % initial conditions
% numerical solution using ode45
sol = ode45(funpr12,xint,y0); %// Change - already a handle
xx = [0:0.01:5]; % vector of x values
y = deval(sol,xx); % vector of y values
plot(xx,y(1,:),'r', 'LineWidth',3)
legend('y1(x)')
xlabel('x')
ylabel('y(x)')
Take note that the output when simulating the solution to the differential equation by deval will be a two column matrix. The first column is the solution to the system while the second column is the derivative of the solution. As such, you'll want to plot the first column, which is what the plot syntax is doing.
I get this plot now:

USE DIFFERENTIAL MATRIX OPERATOR TO SOLVE ODE

We were asked to define our own differential operators on MATLAB, and I did it following a series of steps, and then we should use the differential operators to solve a boundary value problem:
-y'' + 2y' - y = x, y(0) = y(1) =0
my code was as follows, it was used to compute this (first and second derivative)
h = 2;
x = 2:h:50;
y = x.^2 ;
n=length(x);
uppershift = 1;
U = diag(ones(n-abs(uppershift),1),uppershift);
lowershift = -1;
L= diag(ones(n-abs(lowershift),1),lowershift);
% the code above creates the upper and lower shift matrix
D = ((U-L))/(2*h); %first differential operator
D2 = (full (gallery('tridiag',n)))/ -(h^2); %second differential operator
d1= D*y.'
d2= ((D2)*y.')
then I changed it to this after posting it here and getting one response that encouraged the usage of Identity Matrix, however I still seem to be getting no where.
h = 2;
n=10;
uppershift = 1;
U = diag(ones(n-abs(uppershift),1),uppershift);
lowershift = -1;
L= diag(ones(n-abs(lowershift),1),lowershift);
D = ((U-L))/(2*h); %first differential operator
D2 = (full (gallery('tridiag',n)))/ -(h^2); %second differential operator
I= eye(n);
eqn=(-D2 + 2*D - I)*y == x
solve(eqn,y)
I am not sure how to proceed with this, like should I define y and x, or what exactly? I am clueless!
Because this is a numerical approximation to the solution of the ODE, you are seeking to find a numerical vector that is representative of the solution to this ODE from time x=0 to x=1. This means that your boundary conditions make it so that the solution is only valid between 0 and 1.
Also this is now the reverse problem. In the previous post we did together, you know what the input vector was, and doing a matrix-vector multiplication produced the output derivative operation on that input vector. Now, you are given the output of the derivative and you are now seeking what the original input was. This now involves solving a linear system of equations.
Essentially, your problem is now this:
YX = F
Y are the coefficients from the matrix derivative operators that you derived, which is a n x n matrix, X would be the solution to the ODE, which is a n x 1 vector and F would be the function you are associating the ODE with, also a n x 1 vector. In our case, that would be x. To find Y, you've pretty much done that already in your code. You simply take each matrix operator (first and second derivative) and you add them together with the proper signs and scales to respect the left-hand side of the ODE. BTW, your first derivative and second derivative matrices are correct. What's left is adding the -y term to the mix, and that is accomplished by -eye(n) as you have found out in your code.
Once you formulate your Y and F, you can use the mldivide or \ operator and solve for X and get the solution to this linear system via:
X = Y \ F;
The above essentially solves the linear system of equations formed by Y and F and will be stored in X.
The first thing you need to do is define a vector of points going from x=0 to x=1. linspace is probably the most suitable where you can specify how many points we want. Let's assume 100 points for now:
x = linspace(0,1,100);
Therefore, h in our case is just 1/100. In general, if you want to solve from the starting point x = a up to the end point x = b, the step size h is defined as h = (b - a)/n where n is the total number of points you want to solve for in the ODE.
Now, we have to include the boundary conditions. This simply means that we know the beginning and ending of the solution of the ODE. This means that y(0) = y(1) = 0. As such, we make sure that the first row of Y has only the first column set to 1 and the last row of Y has only the last column set to 1, and we'll set the output position in F to both be 0. This symbolizes that we already know the solution at these points.
Therefore, your final code to solve is just:
%// Setup
a = 0; b = 1; n = 100;
x = linspace(a,b,n);
h = (b-a)/n;
%// Your code
uppershift = 1;
U = diag(ones(n-abs(uppershift),1),uppershift);
lowershift = -1;
L= diag(ones(n-abs(lowershift),1),lowershift);
D = ((U-L))/(2*h); %first differential operator
D2 = (full (gallery('tridiag',n)))/ -(h^2);
%// New code - Create differential equation matrix
Y = (-D2 + 2*D - eye(n));
%// Set boundary conditions on system
Y(1,:) = 0; Y(1,1) = 1;
Y(end,:) = 0; Y(end,end) = 1;
%// New code - Create F vector and set boundary conditions
F = x.';
F(1) = 0; F(end) = 0;
%// Solve system
X = Y \ F;
X should now contain your numerical approximation to the ODE in steps of h = 1/100 starting from x=0 up to x=1.
Now let's see what this looks like:
figure;
plot(x, X);
title('Solution to ODE');
xlabel('x'); ylabel('y');
You can see that y(0) = y(1) = 0 as per the boundary conditions.
Hope this helps, and good luck!

Making a function in terms of a sum from 1 to n in Matlab

I'm trying to get Matlab to take this as a function of x_1 through x_n and y_1 through y_n, where k_i and r_i are all constants.
So far my idea was to take n from the user and make two 1×n vectors called x and y, and for the x_i just pull out x(i). But I don't know how to make an arbitrary sum in MATLAB.
I also need to get the gradient of this function, which I don't know how to do either. I was thinking maybe I could make a loop and add that to the function each time, but MATLAB doesn't like that.
I don't believe a loop is necessary for this calculation. MATLAB excels at vectorized operations, so would something like this work for you?
l = 10; % how large these vectors are
k = rand(l,1); % random junk values to work with
r = rand(l,1);
x = rand(l,1);
y = rand(l,1);
vals = k(1:end-1) .* (sqrt(diff(x).^2 + diff(y).^2) - r(1:end-1)).^2;
sum(vals)
EDIT: Thanks to #Amro for correcting the formula and simplifying it with diff.
You can solve for the gradient symbolically with:
n = 10;
k = sym('k',[1 n]); % Create n variables k1, k2, ..., kn
x = sym('x',[1 n]); % Create n variables x1, x2, ..., xn
y = sym('y',[1 n]); % Create n variables y1, y2, ..., yn
r = sym('r',[1 n]); % Create n variables r1, r2, ..., rn
% Symbolically sum equation
s = sum((k(1:end-1).*sqrt((x(2:end)-x(1:end-1)).^2+(y(2:end)-y(1:end-1)).^2)-r(1:end-1)).^2)
grad_x = gradient(s,x) % Gradient with respect to x vector
grad_y = gradient(s,y) % Gradient with respect to y vector
The symbolic sum and gradients can be evaluated and converted to floating point with:
% n random data values for k, x, y, and r
K = rand(1,n);
X = rand(1,n);
Y = rand(1,n);
R = rand(1,n);
% Substitute in data for symbolic variables
S = double(subs(s,{[k,x,y,r]},{[K,X,Y,R]}))
GRAD_X = double(subs(grad_x,{[k,x,y,r]},{[K,X,Y,R]}))
GRAD_Y = double(subs(grad_y,{[k,x,y,r]},{[K,X,Y,R]}))
The gradient function is the one overloaded for symbolic variables (type help sym/gradient) or see the more detailed documentation online).
Yes, you could indeed do this with a loop, considering that x, y, k, and r are already defined.
n = length(x);
s = 0;
for j = 2 : n
s = s + k(j-1) * (sqrt((x(j) - x(j-1)).^2 + (y(j) - y(j-1)).^2) - r(j-1)).^2
end
You should derive the gradient analytically and then plug in numbers. It should not be too hard to expand these terms and then find derivatives of the resulting polynomial.
Vectorized solution is something like (I wonder why do you use sqrt().^2):
is = 2:n;
result = sum( k(is - 1) .* abs((x(is) - x(is-1)).^2 + (y(is) - y(is-1)).^2 - r(is-1)));
You can either compute gradient symbolically or rewrite this code as a function and make a standard +-eps calculation. If you need a gradient to run optimization (you code looks like a fitness function) you could use algorithms that calculate them themselves, for example, fminsearch can do this