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.
Related
I'm trying to run a program in matlab to obtain the direct and inverse DFT for a grey scale image, but I'm not able to recover the original image after applying the inverse. I'm getting complex numbers as my inverse output. Is like i'm losing information. Any ideas on this? Here is my code:
%2D discrete Fourier transform
%Image Dimension
M=3;
N=3;
f=zeros(M,N);
f(2,1:3)=1;
f(3,1:3)=0.5;
f(1,2)=0.5;
f(3,2)=1;
f(2,2)=0;
figure;imshow(f,[0 1],'InitialMagnification','fit')
%Direct transform
for u=0:1:M-1
for v=0:1:N-1
for x=1:1:M
for y=1:1:N
F(u+1,v+1)=f(x,y)*exp(-2*pi*(1i)*((u*(x-1)/M)+(v*(y-1)/N)));
end
end
end
end
Fab=abs(F);
figure;imshow(Fab,[0 1],'InitialMagnification','fit')
%Inverse Transform
for x=0:1:M-1
for y=0:1:N-1
for u=1:1:M
for v=1:1:N
z(x+1,y+1)=(1/M*N)*F(u,v)*exp(2*pi*(1i)*(((u-1)*x/M)+((v-1)*y/N)));
end
end
end
end
figure;imshow(real(z),[0 1],'InitialMagnification','fit')
There are a couple of issues with your code:
You are not applying the definition of the DFT (or IDFT) correctly: you need to sum over the original variable(s) to obtain the transform. See the formula here; notice the sum.
In the IDFT the normalization constant should be 1/(M*N) (not 1/M*N).
Note also that the code could be made mucho more compact by vectorization, avoiding the loops; or just using the fft2 and ifft2 functions. I assume you want to compute it manually and "low-level" to verify the results.
The code, with the two corrections, is as follows. The modifications are marked with comments.
M=3;
N=3;
f=zeros(M,N);
f(2,1:3)=1;
f(3,1:3)=0.5;
f(1,2)=0.5;
f(3,2)=1;
f(2,2)=0;
figure;imshow(f,[0 1],'InitialMagnification','fit')
%Direct transform
F = zeros(M,N); % initiallize to 0
for u=0:1:M-1
for v=0:1:N-1
for x=1:1:M
for y=1:1:N
F(u+1,v+1) = F(u+1,v+1) + ...
f(x,y)*exp(-2*pi*(1i)*((u*(x-1)/M)+(v*(y-1)/N))); % add term
end
end
end
end
Fab=abs(F);
figure;imshow(Fab,[0 1],'InitialMagnification','fit')
%Inverse Transform
z = zeros(M,N);
for x=0:1:M-1
for y=0:1:N-1
for u=1:1:M
for v=1:1:N
z(x+1,y+1) = z(x+1,y+1) + (1/(M*N)) * ... % corrected scale factor
F(u,v)*exp(2*pi*(1i)*(((u-1)*x/M)+((v-1)*y/N))); % add term
end
end
end
end
figure;imshow(real(z),[0 1],'InitialMagnification','fit')
Now the original and recovered image differ only by very small values, of the order of eps, due to the usual floating-point inaccuacies:
>> f-z
ans =
1.0e-15 *
Columns 1 through 2
0.180411241501588 + 0.666133814775094i -0.111022302462516 - 0.027755575615629i
0.000000000000000 + 0.027755575615629i 0.277555756156289 + 0.212603775716506i
0.000000000000000 - 0.194289029309402i 0.000000000000000 + 0.027755575615629i
Column 3
-0.194289029309402 - 0.027755575615629i
-0.222044604925031 - 0.055511151231258i
0.111022302462516 - 0.111022302462516i
Firstly, the biggest error is that you are computing the Fourier transform incorrectly. When computing F, you need to be summing over x and y, which you are not doing. Here's how to rectify that:
F = zeros(M, N);
for u=0:1:M-1
for v=0:1:N-1
for x=1:1:M
for y=1:1:N
F(u+1,v+1)=F(u+1,v+1) + f(x,y)*exp(-2*pi*(1i)*((u*(x-1)/M)+(v*(y-1)/N)));
end
end
end
end
Secondly, in the inverse transform, your bracketing is incorrect. It should be 1/(M*N) not (1/M*N).
As an aside, at the cost of a bit more memory, you can speed up the computation by not nesting so many loops. Namely, when computing the FFT, do the following instead
x = (1:1:M)'; % x is a column vector
y = (1:1:N) ; % y is a row vector
for u = 0:1:M-1
for v = 0:1:N-1
F2(u+1,v+1) = sum(f .* exp(-2i * pi * (u*(x-1)/M + v*(y-1)/N)), 'all');
end
end
To take this method to the extreme, i.e. not using any loops at all, you would do the following (though this is not recommended, since you would lose code readability and the memory cost would increase exponentially)
x = (1:1:M)'; % x is in dimension 1
y = (1:1:N) ; % y is in dimension 2
u = permute(0:1:M-1, [1, 3, 2]); % x-freqs in dimension 3
v = permute(0:1:N-1, [1, 4, 3, 2]); % y-freqs in dimension 4
% sum the exponential terms in x and y, which are in dimensions 1 and 2.
% If you are using r2018a or older, the below summation should be
% sum(sum(..., 1), 2)
% instead of
% sum(..., [1,2])
F3 = sum(f .* exp(-2i * pi * (u.*(x-1)/M + v.*(y-1)/N)), [1, 2]);
% The resulting array F3 is 1 x 1 x M x N, to make it M x N, simply shiftdim or squeeze
F3 = squeeze(F3);
% create variable x with array of all necessary values
x=linspace(0.1,13,50);
for i=x
% create equation to determine y
y=(sqrt(2.*i)*4*i.^3)/(4.*i+7.^(i/10));
%create equation to determine z
z=log10(2.*i+5)+(4.*i+exp(i))/(2./3+4.*i.^2);
end
Using Matlab and im trying to use values from my x array to create two arrays, y and z, im pretty new to matlab and im struggling, thanks.
The problem in you code is that you did not use for loop properly. You can run through the index of x, then assign x(i) to a new variable k in each iteration, i.e.,
x=linspace(0.1,13,50);
for k = 1:length(x)
i = x(k);
% create equation to determine y
y(k) =(sqrt(2.*i)*4*i.^3)/(4.*i+7.^(i/10));
%create equation to determine z
z(k) =log10(2.*i+5)+(4.*i+exp(i))/(2./3+4.*i.^2);
end
Since MATLAB is able to vectorize the operations, so you are recommended to do it like below to speed up (for loop in MATLAB is expensive)
x = linspace(0.1,13,50);
y = (sqrt(2*x).*4.*x.^3)./(4*x+7^(x/10));
z = log10(2*x+5)+(4*x+exp(x))./(2/3 + 4*x.^2);
Remarks: you should be careful about the difference between .* and *, or ./ and /, where * and / are not element-wise operations.
Method 1:
you can initialize y and z into empty arrays and just append the corresponding result at the end:
% create variable x with array of all necessary values
x=linspace(0.1,13,50);
y=[];
z=[];
for i=x
% create equation to determine y
y(end+1)=(sqrt(2.*i)*4*i.^3)/(4.*i+7.^(i/10));
%create equation to determine z
z(end+1)=log10(2.*i+5)+(4.*i+exp(i))/(2./3+4.*i.^2);
end
This approach can prove to be poor in terms of efficiency, since the size of y and z changes dynamically.
Method 2:
If you still want to use a for loop, it is better to preallocate memory for y and z and iterate the indices of x, something like:
% create variable x with array of all necessary values
x=linspace(0.1,13,50);
% Memory allocation
y = zeros(1, length(x));
z = zeros(1, length(x));
for i = 1 : length(x)
% create equation to determine y
y(i)=(sqrt(2.*x(i)*4*x(i).^3)/(4.*x(i)+7.^(x(i)/10));
%create equation to determine z
z(i)=log10(2.*x(i)+5)+(4.*x(i)+exp(x(i)))/(2./3+4.*x(i).^2);
end
Method 3 (preferred one):
It is generally more efficient to vectorize your implementations. In your case you could use something like:
x = linspace(0.1,13,50);
y = (sqrt(2.*x)*4*.*x.^3) ./ (4*x + 7.^(x./10));
z = log10(2*x+5) + (4*x + exp(x)) ./ (2/3 + 4*x.^2);
For a mathematics course for first year university science students we (the teaching assistants) need to prepare material for pc-sessions using Matlab. All computers are equipped with Matlab version R2016b.
We are working through some material from the previous years. In the section covering the plotting of piecewise functions, we found some inconsistencies in the way Matlab handles an if condition.
I would like to know why these things happen so we are prepared for any difficulties the students might experience in these sessions. The goal of the exercise is to draw a house in the plotting window by plotting two piecewise functions.
The first function, f1(x), evaluates to x+2 when x <= 0 and evaluates to -x+2 otherwise. The students are asked to implement this function in Matlab using an if/else construct. Our implementation is
function y = f1( x )
if x < 0
y = x + 2;
else
y = -x + 2;
end
end
The second function, f2(x), is the characteristic function of the interval [-1, 1]. It should also be implemented using if/else conditions. Our implementation is
function y = f2( x )
if x < -1
y = 0;
elseif x > 1
y = 0;
else
y = 1;
end
end
Finally, the plotting code should draw both functions on the interval [-1.5, 1.5] using fplot like so
fplot(#f1, [-1.5, 1.5])
hold on
fplot(#f2, [-1.5, 1.5])
The function f2 is plotted without problems. In plotting f1, however, it seems Matlab decided the first branch of the if-clause didn't matter as only the line -x+2 is plotted.
It seems vectorization issues lie at the heart of our problem since f1(-1) evaluates correctly to 1 but f1([-1, 1]) evaluates to [3, 1]. Then again, f2 seems to be evaluating correctly without any issues.
Things get stranger when we change the -x + 2 in the else part of f1 to -x^2 + 2. With this definition both functions are plotted correctly and Matlab seems to have no problem dealing with the conditionals.
What is going wrong?
Is there a way we can edit the exercises such that it never poses any problems but is still accessible to students having their first experiences with Matlab?
In MATLAB if vector is like if all(vector), and that is the source to your error. use indexing instead:
function y = f2( x )
y = zeros(size(x));
idxs1 = x >= -1;
idxs2 = x <= 1;
y(idxs1 & idxs2) = 1;
end
function y = f1( x )
y = zeros(size(x));
idxs = x < 0;
y(idxs) = x(idxs) + 2;
y(~idxs) = -x(~idxs) + 2;
end
fplot(#f1, [-1.5, 1.5])
hold on
fplot(#f2, [-1.5, 1.5])
Using an If Statement
You say that you want to specifically use an if structure, in which case you will have to evaluate each element of the input vector in turn
function y = f1( x )
y = zeros(size(x)); % Initialise y to the correct size
for ii = 1:numel(x) % Loop through elements of x (and so y)
if x(ii) < 0
y(ii) = x(ii) + 2;
else
y(ii) = -x(ii) + 2;
end
end
end
This is because otherwise you may have the following issue:
x = [1, 2, -1, 3, -2];
% x < 0 = [0, 0, 1, 0, 1];
% "if x < 0" is the same as "if all(x < 0)" = false, so if statement skipped
Logical Indexing
If the course material can be changed / extended, then a much better option in Matlab is to leverage logical indexing.
x = [1, 2, -1, 3, -2];
y = -x + 2; % Initialise variable y, assign its values to -x + 2 by default
y(x<0) = x + 2; % Assign values of y, where x<0, to x + 2
Now it can be seen how this can be done in a one liner...
coef = (x < 0)*2 - 1; % For the above example, coef = [-1, -1, 1, -1, 1];
y = coef.*x + 2; % Coeff can be done in-line without being declared
So, with a similar (but even simpler) approach to f2 as well,
function y = f1(x)
y = ((x<0)*2 - 1).*x + 2;
end
function y = f2(x)
y = (abs(x) < 1);
end
Then your demo gives the desired result
As for your mysteries when changing part of the piecewise function and everything working... For me, your code all works anyway (2015b)! My guess is that this is something to do with how fplot is calling your functions. I currently can't access the docs, which may contain the answer. In my above examples, I'm assuming x is being passed as a vector (which may have 1 or more elements). If fplot determines the x values and calls the function as if for single points, then your code should work.
A way to edit the task to make things clearer may be to just use the normal plot function, which I think is more useful for students to be familiar with anyway.
Then your demo would be called like so
x = -1.5:0.1:1.5 % or could use linspace(-1.5, 1.5, 100) etc
hold on;
plot(x, f1(x)); % x,y syntax, more apparent where the points will be plotted
plot(x, f2(x)); % than when using fplot
hold off; % good habit to hold off so that you don't accidentally plot on this fig later
Notice that, with this clear definition of x, your -x^2 + 2 would throw an error as you are asking for matrix multiplication of a 1D vector. You would actually have to use -x.^2 + 2. There's a cue for students to learn about element-wise operations in Matlab!
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
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!