Writing a matlab function that implements Euler's method? - matlab

I should write a MATLAB function that takes a first order ordinary differential equation in form y’(t) = a*y(t) +b with an initial point y(t0)=y0 as inputs and calculates first 15 points of the solution. Also draws the solution curve for first 15 points.
And the equation that we want to solve is ;y’(t) = 4*y(t)+1 with the initial point y(0)=0.
For this function I wrote the bellowing code but this gives me an error about y. How should I implement the euler function correctly? And also I could not determine how I can draw the solution curves..
function E=euler(f,y)
%Input - f is the function entered as a string 'f'
% - a and b are the left and right endpoints
% - ya is the initial condition y(a)
% - M is the number of steps
%Output - E=[T' Y'] where T is the vector of abscissas and
% Y is the vector of ordinates
h=0.1;
y(0)=0;
for j=0:15
Y(j+1)=Y(j)+h*feval(4*(y(t)+1));
end

Patch:
h = 0.1;
y(1) = 0;
for j = 1:16
Y(j + 1) = Y(j) + h * feval(4 * (y(t - 1) + 1));
end
Well, I am not sure about the mathematical part, but - The indices need to start at "1". Other then e.g. in C, you must not use "0" as an index.

Related

Matlab Plotting by Conditional Statements

I am attempting to plot the wave equation for a single time step, t, in matlab based on an array of x that are passed into a function, u.
I am not very familiar with matlab and am not sure if this is the proper way to iterate through all x values and plot them. The process does not seem entirely similar to something like python and matplotlib.
EDIT: This code does not seem to be executing properly, how then can I iterate through the array and plot? ex: for element in x: do function
Thanks,
% defining the bounds of my x values
x=-10:.02:10;
% defining my time step, t
t = 1;
x1=[0 0];
y1=[-0.01 0.01];
x2=[-10 10];
y2=[0 0];
% defining some constants to make below equation simpler
xpt2= x + t;
xmt2= x - t;
% plotting based on the values of x - should iterate through the array?
if abs(x) > 1
u = 0.5 .* ((-(xpt2) .* exp(-abs(xpt2))./abs(xpt2)) + ((xmt2).*exp(-abs(xmt2))./abs(xmt2)));
plot(x,u,x1,y1,x2,y2);
xlabel('t=1');ylabel('u');
else
u = 0.5 .* abs(xpt2) + 0.5 .* abs(xmt2) + 0.5 .* (-(xpt2) .* exp(-abs(xpt2)./abs(xpt2)) + ((xmt2).*exp(-abs(xmt2))./abs(xmt2)));
plot(x,u,x1,y1,x2,y2);
xlabel('t=1');ylabel('u');
end
This code may not solve your issue but it may help you to find the error. I expect the error in the else part.
I use for loop to make if-clause work while #slayer way is more professional to work without a loop.
% defining the bounds of my x values
close all
clear
x=-10:.02:10;
% defining my time step, t
t = 1;
x1=[0 0];
y1=[-0.01 0.01];
x2=[-10 10];
y2=[0 0];
% defining some constants to make below equation simpler
xpt2= x + t;
xmt2= x - t;
% plotting based on the values of x - should iterate through the array?
for i=1:length(x)
if abs(x(i)) > 1
u(i) = 0.5 .* ((-(xpt2(i)) .* exp(-abs(xpt2(i)))./abs(xpt2(i))) + ((xmt2(i)).*exp(-abs(xmt2(i)))./abs(xmt2(i))));
else
u(i) = 0.5 .* abs(xpt2(i)) + 0.5 .* abs(xmt2(i)) + 0.5 .* (-(xpt2(i)) .* exp(-abs(xpt2(i))./abs(xpt2(i))) + ((xmt2(i)).*exp(-abs(xmt2(i)))./abs(xmt2(i))));
end
%display step by step
plot(x(1:i),u)
hold on
plot(x1,y1)
plot(x2,y2);
xlabel('t=1');ylabel('u');
pause(1/1000)
end
plot(x,u)
hold on
plot(x1,y1)
plot(x2,y2);
xlabel('t=1');ylabel('u');
You have a number of issues with your code.
1) Your conditional is on a vector so how can you check a conditional for every point in your vector? Well you can't this way.
2) You are taking the abs() of a vector but it looks like you want the negative parts to be accounted for? The abs([-1 0 1]) will return output [1 0 1], which makes your entire vector positive and remove the negative parts.
Now I see why you were asking for a for-loop to check the condition of every x variable in the vector. You can do that with:
for ii=1:numel(x) % This iterates through the vector
x(ii) % this accesses the current index of ii
end
But you still don't need a for loop. Instead use a conditional vector to keep track of the neg and pos points in x like:
idx_neg = x < 0; % boolean of all negative points in x
Then use the idx_neg on the vector you want the equation to be applied to. And the invert of the idx for the positive values like:
u = zeros(1, numel(x)); % initialize empty vector for storage
% for positive x values, use ~idx_neg to find the pos points
u(~idx_neg) = 0.5 .* ((-(xpt2(~idx_neg)) .* exp(-abs(xpt2(~idx_neg)))./abs(xpt2(~idx_neg))) + ((xmt2(~idx_neg)).*exp(-abs(xmt2(~idx_neg)))./abs(xmt2(~idx_neg))));
% now apply to neg points in x:
u(idx_neg) = 0.5 .* abs(xpt2(idx_neg(idx_neg))) + 0.5 .* abs(xmt2(idx_neg)) + 0.5 .* (-(xpt2(idx_neg)) .* exp(-abs(xpt2(idx_neg))./abs(xpt2(idx_neg))) + ((xmt2(idx_neg)).*exp(-abs(xmt2(idx_neg)))./abs(xmt2(idx_neg))));
I didn't check for syntax errors but this is basically what you are looking for.

MATLAB: What's wrong with my quatrotate script?

My version of MATLAB doesn't have the quatrotate function included, so I wrote my own using the equation MathWorks provide here. Trouble is, I don't get the same answers they get in their example in my function, or when I hand calculate it.
Under their example if I input the following I should get an n vector [-1 1 1]:
q = [1 0 1 0]; r = [1 1 1]; n = quatrotate(q, r)
n =
-1.0000 1.0000 1.0000
In my function, and by hand, I get:
[-3 1 1]
What am I missing here? The more I search the more confused I get. As far as I can tell the answer should be [-3 1 1].
Here is the function I wrote:
function [n] = quatrotate(q,r)
%Rotate a given acceleration vector by a given quaternion
%
%Inputs:
% q: A matrix containing a set of quaternion vectors of the
% form q = [w,x,y,z]
% r: A matrix containing a set of linear acceleration vectors
% of the form r= [i,j,k] (also known as [x,y,z])
%
% Outputs:
% n: The solved matrix containing the rotated vector of each linear
% acceleration component
%
%This assumes that the quaternion is normalised (sqw + sqx + sqy + sqz =1),
%if not it should be normalised before doing the conversion.
%To normalise divide qx, qy, qz and qw by n where n=sqrt(qx2 + qy2 + qz2 + qw2)
for k = 1:size(q,1)
rot=[(1-2.*q(k,3).^2-2.*q(k,4).^2) 2.*(q(k,2).*q(k,3)+q(k,1).*q(k,4))...
2.*(q(k,2).*q(k,4)-q(k,1).*q(k,3));2.*(q(k,2).*q(k,3)-q(k,1).*q(k,4))...
(1-2.*q(k,2).^2-2.*q(k,4).^2) 2.*(q(k,3).*q(k,4)+q(k,1).*q(k,2));...
2.*(q(k,2).*q(k,4)+q(k,1).*q(k,3)) 2.*(q(k,3).*q(k,4)-q(k,1).*q(k,2))...
(1-2.*q(k,2).^2-2.*q(k,3).^2)];
n(k,:) = rot*r(k,:)';
end
Thanks in advance!
first of all you need to calculate the modulus of the given Quaternion q:
for index = size(q,1):-1:1
mod(index,:) = norm(q(index,:),2);
end
Then normalize it:
qn = q./(mod* ones(1,4));
Now calculate the Direct Cosine Matrix using these formulae:
dcm = zeros(3,3,size(qn,1));
dcm(1,1,:) = qn(:,1).^2 + qn(:,2).^2 - qn(:,3).^2 - qn(:,4).^2;
dcm(1,2,:) = 2.*(qn(:,2).*qn(:,3) + qn(:,1).*qn(:,4));
dcm(1,3,:) = 2.*(qn(:,2).*qn(:,4) - qn(:,1).*qn(:,3));
dcm(2,1,:) = 2.*(qn(:,2).*qn(:,3) - qn(:,1).*qn(:,4));
dcm(2,2,:) = qn(:,1).^2 - qn(:,2).^2 + qn(:,3).^2 - qn(:,4).^2;
dcm(2,3,:) = 2.*(qn(:,3).*qn(:,4) + qn(:,1).*qn(:,2));
dcm(3,1,:) = 2.*(qn(:,2).*qn(:,4) + qn(:,1).*qn(:,3));
dcm(3,2,:) = 2.*(qn(:,3).*qn(:,4) - qn(:,1).*qn(:,2));
dcm(3,3,:) = qn(:,1).^2 - qn(:,2).^2 - qn(:,3).^2 + qn(:,4).^2;
According to MATLAB documents, the rotation of a vector r by the calculated dcm can be found as follows:
if ( size(q,1) == 1 )
% Q is 1-by-4
qout = (dcm*r')';
elseif (size(r,1) == 1)
% R is 1-by-3
for i = size(q,1):-1:1
qout(i,:) = (dcm(:,:,i)*r')';
end
else
% Q is M-by-4 and R is M-by-3
for i = size(q,1):-1:1
qout(i,:) = (dcm(:,:,i)*r(i,:)')';
end
end
Well first of all, in order for quatrotate to work, you need to use a unit quaternion (i.e. length of 1).
Second of all, I see that you are using the matrix provided by the MATLAB page. I've recently derived that matrix myself and found that the MATLAB page has the wrong matrix.
According to this (page 45), rotating a vector by a quaternion is
p' = p + 2w(v × p)+2(v × (v × p))
Where,
p' is the output vector after rotation,
p is the starting vector to be rotated,
w is the first coefficient in the quaternion,
v is the vector of [second coefficent, third coefficient, fourth coefficient] of the quaternion,
× is the cross product operand.
I encourage you to go to the link and derive the matrix yourself. You will see that the matrix provided on the MATLAB page has the wrong additions and subtractions.
This is what's said on the MATLAB page:
Here's my derivation (here the quaternion is [q0, q1, q2, q3] and the vector is [x, y, z]):
First row:
Second row:
Third row:
Here you can see that the signs are incorrect on MATLAB's website. I've emailed them about the error and is waiting to hear back.

How do I plot the sum of two discrete time signals?

I have x[n] = {1,2,2,1,4} and −1 ≤ n ≤ 5
How do I plot y[n] = x[n] + y[n-1]?
I am new to matlab, and am not sure how to go about this.
This question does not seem well posed. Your vector for n in your first statement makes no sense (to me) in the context of your second statement.
If we ignore the first statement for n, your second statement appears to tell us how to build up a new value of y given x and given the previous previous of y. That's fine. You can easily solve for y with a for loop.
x = [1,2,2,1,4]; % this is your given input data
y = []; % this is your output
for I=1:length(x) % loop over each value of x
if (I==1) % the first time through is a special case
%assume that the previous value of y is zero
y(I) = x(I);
else
%your given equation
y(I) = x(I) + y(I-1);
end
end
y(:) %display y to the screen
The function y[n] = x[n] + y[n-1] is the sum (or discrete integration) of the signal x[n]. You can therefore remove the loop using the MATLAB command cumsum and come up with
x = [1,2,2,1,4];
y = cumsum(x);
stem(y); % plot y

Function handle for gradient and hessian problems MATLAB

I am having an issue with manipulating the function handles of my gradient and hessian.
I have the following code:
syms x1 x2
x = [x1,x2];
% Define the function phi(x)
phi = #(x1,x2) 10*x1^4 - 20*x1^2*x2 + 10*x2^2 + x1^2 - 2*x1 + 5;
% Define the gradient of the function phi(x)
gradphi = #(x1,x2) jacobian(phi,x).';
% Define the Hessian of phi(x)
hessphi = #(x1,x2) jacobian(gradphi,x);
Now when I input into the command terminal:
phi(1,2)
I get some scalar value.
But when I input
gradphi(1,2)
hessianphi(1,2)
I want the corresponding vector for the gradient evaluated at those points.
For the gradient, I just get
EDU>> gradphi(1,2)
ans =
2*x1 - 40*x1*x2 + 40*x1^3 - 2
- 20*x1^2 + 20*x2
Which is just the grad vector function. But I want the actual numerical result inputting x1 = 1 and x2 = 2.
EDU>> hessphi(1,2)
returns an error.
I am not sure why.
For multiplications and divisions on arrays, you need to use element-wise operators .*, ./, and .^ in the definition of hessianphi and gradphi. Otherwise, Matlab will try do do matrix multiplication/division/power, which won't go well.
/aside: searching for the text of the error message will bring up the most likely causes of the error.

Using MATLAB to write a function that implements Newton's method in two dimensions

I am trying to write a function that implements Newton's method in two dimensions and whilst I have done this, I have to now adjust my script so that the input parameters of my function must be f(x) in a column vector, the Jacobian matrix of f(x), the initial guess x0 and the tolerance where the function f(x) and its Jacobian matrix are in separate .m files.
As an example of a script I wrote that implements Newton's method, I have:
n=0; %initialize iteration counter
eps=1; %initialize error
x=[1;1]; %set starting value
%Computation loop
while eps>1e-10&n<100
g=[x(1)^2+x(2)^3-1;x(1)^4-x(2)^4+x(1)*x(2)]; %g(x)
eps=abs(g(1))+abs(g(2)); %error
Jg=[2*x(1),3*x(2)^2;4*x(1)^3+x(2),-4*x(2)^3+x(1)]; %Jacobian
y=x-Jg\g; %iterate
x=y; %update x
n=n+1; %counter+1
end
n,x,eps %display end values
So with this script, I had implemented the function and the Jacobian matrix into the actual script and I am struggling to work out how I can actually create a script with the input parameters required.
Thanks!
If you don't mind, I'd like to restructure your code so that it is more dynamic and more user friendly to read.
Let's start with some preliminaries. If you want to make your script truly dynamic, then I would recommend that you use the Symbolic Math Toolbox. This way, you can use MATLAB to tackle derivatives of functions for you. You first need to use the syms command, followed by any variable you want. This tells MATLAB that you are now going to treat this variable as "symbolic" (i.e. not a constant). Let's start with some basics:
syms x;
y = 2*x^2 + 6*x + 3;
dy = diff(y); % Derivative with respect to x. Should give 4*x + 6;
out = subs(y, 3); % The subs command will substitute all x's in y with the value 3
% This should give 2*(3^2) + 6*3 + 3 = 39
Because this is 2D, we're going to need 2D functions... so let's define x and y as variables. The way you call the subs command will be slightly different:
syms x, y; % Two variables now
z = 2*x*y^2 + 6*y + x;
dzx = diff(z, 'x'); % Differentiate with respect to x - Should give 2*y^2 + 1
dzy = diff(z, 'y'); % Differentiate with respect to y - Should give 4*x*y + 6
out = subs(z, {x, y}, [2, 3]); % For z, with variables x,y, substitute x = 2, y = 3
% Should give 56
One more thing... we can place equations into vectors or matrices and use subs to simultaneously substitute all values of x and y into each equation.
syms x, y;
z1 = 3*x + 6*y + 3;
z2 = 3*y + 4*y + 4;
f = [z1; z2];
out = subs(f, {x,y}, [2, 3]); % Produces a 2 x 1 vector with [27; 25]
We can do the same thing for matrices, but for brevity I won't show you how to do that. I will defer to the code and you can see it then.
Now that we have that established, let's tackle your code one piece at a time to truly make this dynamic. Your function requires the initial guess x0, the function f(x) as a column vector, the Jacobian matrix as a 2 x 2 matrix and the tolerance tol.
Before you run your script, you will need to generate your parameters:
syms x y; % Make x,y symbolic
f1 = x^2 + y^3 - 1; % Make your two equations (from your example)
f2 = x^4 - y^4 + x*y;
f = [f1; f2]; % f(x) vector
% Jacobian matrix
J = [diff(f1, 'x') diff(f1, 'y'); diff(f2, 'x') diff(f2, 'y')];
% Initial vector
x0 = [1; 1];
% Tolerance:
tol = 1e-10;
Now, make your script into a function:
% To run in MATLAB, do:
% [n, xout, tol] = Jacobian2D(f, J, x0, tol);
% disp('n = '); disp(n); disp('x = '); disp(xout); disp('tol = '); disp(tol);
function [n, xout, tol] = Jacobian2D(f, J, x0, tol)
% Just to be sure...
syms x, y;
% Initialize error
ep = 1; % Note: eps is a reserved keyword in MATLAB
% Initialize counter
n = 0;
% For the beginning of the loop
% Must transpose into a row vector as this is required by subs
xout = x0';
% Computation loop
while ep > tol && n < 100
g = subs(f, {x,y}, xout); %g(x)
ep = abs(g(1)) + abs(g(2)); %error
Jg = subs(J, {x,y}, xout); %Jacobian
yout = xout - Jg\g; %iterate
xout = yout; %update x
n = n + 1; %counter+1
end
% Transpose and convert back to number representation
xout = double(xout');
I should probably tell you that when you're doing computation using the Symbolic Math Toolbox, the data type of the numbers as you're calculating them are a sym object. You probably want to convert these back into real numbers and so you can use double to cast them back. However, if you leave them in the sym format, it displays your numbers as neat fractions if that's what you're looking for. Cast to double if you want the decimal point representation.
Now when you run this function, it should give you what you're looking for. I have not tested this code, but I'm pretty sure this will work.
Happy to answer any more questions you may have. Hope this helps.
Cheers!