I have written the following Matlab function:
function EulerMethod(t_min,t_max,h,f,Y,yzero)
tlist = t_min:h:t_max;
N = (t_max - t_min)/h;
ylist = transpose(zeros(N+1,1));
ylist(1) = yzero;
for i=1:N
term = f(tlist(i),ylist(i))*h;
ylist(i+1) = ylist(i) + term;
end
yrange = Y(tlist);
% modified to generate a new figure window each time.
figure;
plot(tlist,yrange,'red','LineWidth', 2);
hold;
plot(tlist,ylist,'blue','LineWidth', 2);
plot(tlist, abs(yrange - ylist),'magenta','LineWidth', 2)
% modified to wrap the title.
title({'Graphs of the True Solution, Euler Solution,', 'and the Absolute Value of the Global Error (GE)'})
xlabel('t')
ylabel('Y(t)')
legend({'True Solution','Euler Solution', 'Absolute Value of the GE'},'Location','southwest')
end
I now try and call this function in another script. The variables f and Y in the function are symbolic functions; so, in the other file, I first declare these functions before calling this function. Here's the code:
clc
syms f(t,y)
syms Y(t)
f(t,y) = -y + 2.0*cos(t); %This the derivative of the function whose solution we're trying to computed
Y(t) = sin(t) + cos(t); %This is the true solution;
% Calling function
EulerMethod(0.0, 6.0, 0.2, f, Y, 1.0);
I, however, get errors when I run the second script. Can anyone help me figure out what's going wrong? I suspect this may be because of the way I have both input and used the symbolic functions f and Y but I am not sure.
Related
I'm having this problem: Let's suposse that a user wants to add an arbitrary Force (a function of time) to a spring mass damper system. In order to do that, we request the force as an input, i.e. F = cos(t). Well, I noticed that if we add a function of time in the code where the F is placed (inside ODE), then the solutions for the movement equations are correct. But i can't find a way to achieve this goal. I mean, to request the force as input so that ODE changes everytime i put a new force. I've tried almost everything like converting the input F to a function, etc.
I hope you could help me. Here is the problem in the code:
F = input('Insert force F(t)..............[N] = ','s');
u0 = [x0,v0]; % INITIAL CONDITIONS AS A VECTOR
ODE = #(t,u) [u(2) ; F - (c/m)*u(2) - (k/m)*u(1)]; % FORCED SPRING MASS DAMPER SYSTEM
[t,u] = ode45(ODE, [0 tf], u0);
The fix code results:
m = input('Insert mass of the system..........................[kg] = ');
c = input('Insert viscosity coefficient........................[ ] = ');
k = input('Insert elasticity constant..........................[m] = ');
x0 = input('Insert initial position.............................[m] = ');
v0 = input('Insert initial velocity...........................[m/s] = ');
tf = input('Insert time of complete movement....................[s] = ');
F = input('Insert external force as F(t).......................[N] = ','s');
F = str2func( ['#(t)' F] ); % CONVERT STRING TO FUNCTION
%=========================================================== ODE 45 =======
u0 = [x0,v0]; % INITIAL CONDITIONS AS A VECTOR
ODE = #(t,u) [u(2) ; F(t) - (c/m)*u(2) - (k/m)*u(1)];
[t,u] = ode45(ODE, [0 tf], u0);
u(:,3) = F(t) - (c/m)*u(:,2) - (k/m)*u(:,1); % ACCELERATION
%============================================================= PLOT =======
v = {'x','dx/dt','d2x/dt2'}; % CHAR VECTOR FOR PLOT
for i = 1:3 % PLOT WITH LOOP
subplot(3,1,i)
plot(t,u(:,i));
xlabel('t');
ylabel(v(i));
grid on;
end
Code just for personal uses. Not public because input allows malicious commands.
Thanks to #Wolfie and #Ander Biguri.
I'm going to take the liberty of simplifying your problem down to its main parts.
You have some char array from your user input which defines a function in terms of t. I'm going to entirely ignore all the reasons that blindly evaluating user-input functions is dangerous, but you shouldn't.
You want to combine this function with an existing function in terms of t to produce a single function
We can do this like so:
F = 'cos(t)'; % char version of function, e.g. from the input command
y = #(t) t; % some base function in terms of t
F = str2func( ['#(t)' F] ); % Convert function char to anonymous function
yF = #(t) y(t) + F(t); % combine the functions
You can test this with a quick plot
tt = 0:0.01:10; % axis data
figure; hold on;
plot( tt, y(tt), 'displayname', 'y(t)' );
plot( tt, yF(tt), 'displayname', 'yF(t)' );
legend('show');
In your actual example you have ODE in place of my example f, so assuming F is converted to an anonymous function as shown above, you would get
ODE = #(t,u) [u(2) ; F(t) - (c/m)*u(2) - (k/m)*u(1)];
I have to code the Secant Method: a variant of the Newton-Raphson method.
I have done the following:
function [SecantMethod] = SecantMethod(x0, x1);
%this is a variation on the Newton-Raphson MEthod, uses two inital guesses
%so that we do not have to explicitly work of the derivative of f(x).
x0 = 2;
x1 = 1;
%the two guesses
f0 = f(x0);
f1 = f(x1);
%two coressponding values of the function evaluated at x0 and x1
x = x1 - (f1*((x1 - x0)/(f1 - f0)));
%actual Secant Method (finds x axis intercept between two guesses
end
When I run the code in Matlab, an error appears "Undefined function or variable 'f'."
I dont have any particular function that I want to solve I just have to code it so I am not sure how to do so.
You can have a function take a function as an argument as follows:
function [SecantMethod] = SecantMethod(f,x0, x1);
disp(f(x0));
end
Then in your code:
%make anonymous function:
f=#(x)(x.^2);
%or:
f=#sin;
%and simply:
SecantMethod(f,1,2)
% or just:
SecantMethod(#myfucntion,1,2)
I am trying to implement the Taylor method for ODEs in MatLab:
My code (so far) looks like this...
function [x,y] = TaylorEDO(f, a, b, n, y0)
% syms t
% x = sym('x(t)'); % x(t)
% f = (t^2)*x+x*(1-x);
h = (b - a)/n;
fprime = diff(f);
f2prime = diff(fprime);
y(0) = y0,
for i=1:n
T((i-1)*h, y(i-1), n) = double(f((i-1)*h, y(i-1)))+(h/2)*fprime((i-1)*h, y(i-1))
y(i+1) = w(i) + h*T(t(i), y(i), n);
I was trying to use symbolic variables, but I donĀ“t know if/when I have to use double.
I also tried this other code, which is from a Matlab function, but I do not understand how f should enter the code and how this df is calculated.
http://www.mathworks.com/matlabcentral/fileexchange/2181-numerical-methods-using-matlab-2e/content/edition2/matlab/chap_9/taylor.m
As error using the function from this link, I got:
>> taylor('f',0,2,0,20)
Error using feval
Undefined function 'df' for input arguments of type 'double'.
Error in TaylorEDO (line 28)
D = feval('df',tj,yj)
The f I used here was
syms t
x = sym('x(t)'); % x(t)
f = (t^2)*x+x*(1-x);
This is a numerical method, so it needs numerical functions. However, some of them are computed from the derivatives of the function f. For that, you need symbolic differentiation.
Relevant Matlab commands are symfun (create a symbolic function) and matlabFunction (convert a symbolic function to numerical).
The code you have so far doesn't seem salvageable. You need to start somewhere closer to basics, e.g., "Matlab indices begin at 1". So I'll fill the gap (computation of df) in the code you linked to. The comments should explain what is going on.
function [T,Y] = taylor(f,a,b,ya,m)
syms t y
dfs(1) = symfun(f, [t y]); % make sure that the function has 2 arguments, even if the user passes in something like 2*y
for k=1:3
dfs(k+1) = diff(dfs(k),t)+f*diff(dfs(k),y); % the idea of Taylor method: calculate the higher derivatives of solution from the ODE
end
df = matlabFunction(symfun(dfs,[t y])); % convert to numerical function; again, make sure it has two variables
h = (b - a)/m; % the rest is unchanged except one line
T = zeros(1,m+1);
Y = zeros(1,m+1);
T(1) = a;
Y(1) = ya;
for j=1:m
tj = T(j);
yj = Y(j);
D = df(tj,yj); % syntax change here; feval is unnecessary with the above approach to df
Y(j+1) = yj + h*(D(1)+h*(D(2)/2+h*(D(3)/6+h*D(4)/24)));
T(j+1) = a + h*j;
end
end
Example of usage:
syms t y
[T, Y] = taylor(t*y, 0, 1, 2, 100);
plot(T,Y)
I'm trying to create a function, that has two output arguments:
1. The calculated f(x) value
2. The gradient
But it's calling itself recursively all the time.
What am I doing wrong?
function [y, gra] = f1(x)
y = x^2
syms z
gra = gradient(f1(z))
Thanks.
edit:
Now I have this:
function [y, gra] = f1(x)
y = x^2
if nargout == 2
syms x
gra = gradient(f1(x))
end
edit 2:
I'm trying to use the function in the following:
[y, grad] = f1(5);
y_derived = grad(10);
I think this is what you want to do:
function [y, gra] = f1(x)
f=#(x) x^2;
y=f(x); %// calculate y
syms z %// initialise symbolic variable
gra=gradient(f(z),z); %// symbolic differentiation
This will return g as a symbolic function. To calculate a value, you can use subs(gra,z,123), or, if you are going to evaluate it many times, do gradFunc=matlabFunction(gra) then gradFunc(v) where v is a vector or matrix of points you want to evaluate.
That's because the argument into gradient is your function name f1(z). As such, it keeps calling f1 when your original function is also called f1, and so the function keeps calling itself until you hit a recursion limit.
I think you meant to put gradient(y) instead. Try replacing your gradient call so that it is doing:
gra = gradient(y);
I don't know how to calculate the integral of the sum of function handles in a cell. Please see the below examples:
f{1} = #(x) x;
f{2} = #(x) x^2;
g = #(x) sum(cellfun(#(y) y(x), f));
integral(#(x) exp(g), -3,3);
Error: Input function must return 'double' or 'single' values. Found 'function_handle'.
PS: please don't change the formula, because this is just an example. My real problem is far more complicated than this. It has log and exp of this sum (integral(log(sum), -inf, inf)). So I can't break them up to do the integral individually and sum the integrals.I need to use sum(cellfun). Thank you.
Version: Matlab R2012a
Can anyone help me? Really appreciate.
You cannot add function handles, so anything that tries f{1}+f{2}+... would give an error.
But you can compute the integral of the sums like this, evaluating the function values one at a time and adding up the results:
function cellsum
f{1} = #(x) x;
f{2} = #(x) x.^2;
integral(#(x)addfcn(f,x), -3, 3)
end
function s = addfcn(f,x)
s = zeros(size(x));
for k = 1:length(f)
s = s + f{k}(x);
end
end
Note that x will usually be a vector when the integral command calls your functions with it. So your function definitions should be vectorized, .i.e., x.^2 instead of x^2, etc.