I have a project in MATLAB where I am to approximate the solution of a diff equation. To do that, I use ode45 to get the "real solution" and compare it to Euler's approximation that I perform 3 times with halving the step every time. Here are my issues:
ode45 doesn't seem to work on my computer. I get this message:
No help found for ode45.m.
When I type help ode45 in the commando window and this
Error using ode45
Too many input arguments.
Error in Lab2 (line 51)
[f, u] = ode45(#myode, [pi/6 pi/2], 1);
So I switched to ode23 and got a what I thought to be a quite good result. Problem is though that I noticed that the error in the last approximation becomes slightly smaller which shouldn't happens since the error gets only larger by every step... right?
To makes things worse, I tried to run my code with ode23 on the school computer and got different results (different solution curve). I tried then ode45 and got the same results. When I look at the curve and its values it is totally wrong since in my diff equation values should be decreasing instead of increasing like they do when I run them on the school computer.
I don't understand how the same code can produce two different results on different computers.
I don't understand either why ode45 is missing from my computer. I have tried re-installing the new version and it is still the same.
I am totally confused...
Here is my code:
This is in a function file named myode
function dudf = myode(f,u)
k=1/20;
dudf = (-k*u.^3)/sin(f).^3;
end
This is the program
%Euler's method
f_init = pi/6;
f_final = pi/2;
u_init = 1;
k = 1/20;
n = 10; %number of steps
h(1) = (f_final-f_init)/n;
fh(1) = f_init;
uh(1) = u_init;
%calculate euler's approximation after every step
for i = 2:n+1
fh(i) = fh(i-1)+h;
uh(i) = uh(i-1)+h*(-k*uh(i-1)^3)/(sin(fh(i-1))^3);
end
%save vaules of ode45 at every step for first appr.
step0=pi/30;
fiend = pi/6 + step0;
odeu1 = [1];
step1 = [pi/6];
for i = 1:length(uh)-1
[f, u] = ode23(#myode, [pi/6 fiend], 1);
odeu1 = [odeu1 u(end)];
step1 = [step1 fislut];
fiend = fiend + step0;
end
Any help is appreciated!
Related
Given some data (from the function 1/x), I solved for powers of a model function made of the sum of exponentials. I did this for several different samples of data and I want to plot the powers that I find and test to see what type of distribution they have.
My main problems are:
My loops are quitting when the nlinfit() function says the function gives -Inf values. I've tried playing around with initial conditions but can't see how to fix it. I know that I am working with the function 1/x, so there may not be a way around this problem. Is there at least a way to force the loop to keep going after getting this error? It only happens for some iterations. If I manually regenerate my sample data and run it again it works. So if I could force the loop to keep going it would be ideal. I have tried switching the for loop to a while loop and putting a try catch statement inside but this just seems to run endlessly.
I have code set to test how if the distribution of the resulting power is close to the exponential distribution. Is this the correct way to do this? When I add in the Monte Carlo tolerance ('MCTol') it has a drastic effect on p in some cases (going from 0.5 to 0.9). Do I have it set up correctly? Is there a way to also see empirically how far the curve is from the exponential distribution?
Are there better ways to fit this curve or do any of the above? I'm just learning so any suggestions are appreciated.
Here is my current code :
%Function that I use to fit curve and get error for each iteration
function[beta,error] = Fit_and_Calc_Error(T,X,modelfun, beta0)
opts = statset('nlinfit');
opts.RobustWgtFun = 'bisquare';
beta = nlinfit(T,X,modelfun,beta0,opts);
error = immse(X,modelfun(beta,T));
end
%Starting actual loop stuff
tracking_a = zeros();
tracking_error = zeros();
modelfun = #(a,x)(exp(-a(1)*x)+exp(-a(2)*x));
for i = 1:60
%make new random data
x = 20*rand(300,1)+1; %between 1 and 21 (Avoiding x=0)
X = sort(x);
Y = 1./(X);
%fit random data
beta0 = [max(X(:,1))/10;max(X(:,1))/10];
[beta,error]= Fit_and_Calc_Error(X,Y,modelfun, beta0);
%storing data found
tracking_a(i,1:length(beta)) = beta;
tracking_error(i) = error;
end
%Testing if first power found has exponential dist
pdN = fitdist(tracking_a(:,1),'Exponential');
histogram(tracking_a(:,1),10)
hold on
x_values2 = 0:0.001:5;
y2 = pdf(pdN,x_values2);
plot(x_values2,y2)
hold off
[h,p] = lillietest(tracking_a(:,1),'Distribution','exponential','MCTol',1e-4)
%Testing if second power found has exponential dist
pdN2 = fitdist(tracking_a(:,2),'Exponential');
histogram(tracking_a(:,2),10)
hold on
y3 = pdf(pdN2,x_values2);
plot(x_values2,y3)
hold off
[h2,p2] = lillietest(tracking_a(:,2),'Distribution','exponential','MCTol',1e-4)
How would I numerically solve for the following simple system of differential equations using Octave?
Note:
I use the qualifier "simple" as, from my understanding, the system is
first order and is not coupled.
I have tried every
method and script online to try solve this including here,
here and here. In all options, I either get a hanging,
non-responsive Octave, a prompt stating "repeated convergence
failures", an error with recommendation that I manually adjust
the initial and maximum step size (which I did try and do, to no
avail), or something that initially seems like a solution on account of no errors but plotting the solution shows a blank graph
Where Octave provided for equivalent Matlab routines, I tried the various routines ode45, ode23, ode113, ode15s, ode23s, ode23t, ode23tb, ode15i and of course, Octaves own lsode command, all giving the same errors described above.
Let's first replicate the vanilla solution
% z = [x,y]
f = #(t,z) [ z(1).^2+t; z(1).*z(2)-2 ];
z0 = [ 2; 1];
[ T, Z ] = ode45(f, [0, 10], z0);
plot(T,Z); legend(["x";"y"]);
The integrator fails as reported with the warning
warning: Solving was not successful. The iterative integration loop exited at time t = 0.494898 before the endpoint at tend = 10.000000 was reached. This may happen if the stepsize becomes too small. Try to reduce the value of 'InitialStep' and/or 'MaxStep' with the command 'odeset'.
Repeating the integration up to shortly before the critical time
opt = odeset('MaxStep',0.01);
[ T, Z ] = ode45(f, [0, 0.49], z0, opt);
clf; plot(T,Z); legend(["x";"y"]);
results in the graph
where one can see that the quadratic term in the first equation leads to run-away growth. For some reason the solver does only recognize the ever reducing step size, but not the run-away values of the solution.
Indeed the first is a Riccati equation which are known to have poles at finite times. Using the typical parametrization x(t)=-u'(t)/u(t) has by the product/quotient rule the derivative
x' = -u''(t)/u(t) - u'(t)* (-u'(t)/u(t)^2) = -u''(t)/u(t) + x(t)^2
which then results in the ODE for u
u''(t)+t*u(t)=0, u(0)=-1, u'(0)=x(0)=2,
which is an Airy equation with the oscillating branch for t>0. The first root of u is a pole for x, there is no way to extend the solution beyond this point.
g=#(t,u) [u(2); -t.*u(1)]
u0 = [ 1; -2];
function [val,term, dir] = event(t,u)
val = u(1);
term = 0;
dir = 0;
end
opt = odeset('MaxStep',0.1, 'Events', #(t,u) event(t,u));
[T,U,Te,Ue,Ie] = ode45(g,[0,4],u0,opt);
disp(Te)
clf; plot(T,U); legend(["u";"u'"]);
which lists the zeros of u as 0.4949319379979706, 2.886092605590324, again confirming the reason for the warning, and gives the plot
EDIT: I used the profiler as suggested, and it looks like Matlab was spending a significant amount of time dealing with symbols and solving the system of equations. So, I will change my question slightly: is there a faster way to implement this system of equations, perhaps one that does not involve declaring symbols?
function [As_rad, Ae_rad] = pos_to_angle(x_pos, y_pos)
% Converts given x and y coordinates into angles (using link lengths)
Ls = 0.4064; % in meters
Le = 0.51435; % in meters
x_offset = 0.0;
y_offset = -0.65; % from computer running the robot
syms angle_s angle_e
x = x_pos + x_offset; % Account for offset of origins
y = y_pos + y_offset; % between motor and workspace
eqn1 = x == Ls*cos(angle_s) + Le*cos(angle_e); % Actual conversion
eqn2 = y == Ls*sin(angle_s) + Le*sin(angle_e);
sol1 = solve([eqn1, eqn2], [angle_s, angle_e]);
As_rad_mat = sol1.angle_s;
Ae_rad_mat = sol1.angle_e;
if As_rad_mat(1) > Ae_rad_mat(1);
As_rad = As_rad_mat(1);
Ae_rad = Ae_rad_mat(1);
else
As_rad = As_rad_mat(2);
Ae_rad = Ae_rad_mat(2);
end
end
To be more specific, it looked like a function mupadmex (which I believe is associated with symbols) took up about 80% of the computing time. The above is just an example of how I solved systems of equations throughout the script.
Thanks everyone for the responses! I ended up using profiler and found that the computation time was coming from solving the system of equations every time the program went through the loop. So I used a separate script to solve for the equation symbolically, so the script only has to do algebra. It is running MUCH quicker now.
I'm using a simple if loop to change my parameter values within my ode script. Here is an example script I wrote that exhibits the same problem. So first the version which works:
function aah = al(t,x)
if (t>10000 && t<10300)
ab = [0; 150];
else
ab = [150; 0];
end
aah = [ab];
this can be run using
t = [0:1:10400];
x0 = [0,0];
[t,x] = ode23tb(#al, t,x0);
and visualised with
plot(t,x(:,1))
plot(t,x(:,2))
Ok that's the good version. Now if all you do is change t to
t = [0:1:12000];
the whole thing blows up. You might think it's just matlab averaging out the graph but it's not because if you look at
x(10300,2)
the answer should be the same in both cases because the code hasn't changed. but this second version outputs 0, which is wrong!
What on earth is going on? Anyone got an idea?
Thank you so much for any help
Your function is constant (except 10000 < t < 10300), and therefore the internal solver starts to solve the system with very large time step, 10% of total time by default. (In the adaptive ODE solver, if the system is constant, higher order and lower order solution will give the same solution, and the (estimated) error will be zero. So the solver assumes that current time step is good enough.) You can see if you give tspan with just two element, start and end time.
t = [0 12000];
Usually the tspan does not affect to the internal time step of solver. The solvers solve the system with their internal time step, and then just interpolate at tspan given by the user. So if the internal time step unfortunately "leap over" the interval [10000, 10300], the solver won't know about the interval.
So you better set the maximum step size, relatively smaller than 300.
options = odeset('MaxStep', 10);
[t, x] = ode23tb(#al, t, x0, options);
If you don't want to solve with small step size whole time (and if you "know" when the function are not constant), you should solve separately.
t1 = [0 9990];
t2 = [9990 10310];
t3 = [10310 12000];
[T1, x1] = ode23tb(#al, t1, x0);
[T2, x2] = ode23tb(#al, t2, x1(end,:));
[T3, x3] = ode23tb(#al, t3, x2(end,:));
T = [T1; T2(2:end); T3(2:end)];
x = [x1; x2(2:end,:); x3(2:end,:)];
The code in question is here:
function k = whileloop(odefun,args)
...
while (sign(costheta) == originalsign)
y=y(:) + odefun(0,y(:),vars,param)*(dt); % Line 4
costheta = dot(y-normpt,normvec);
k = k + 1;
end
...
end
and to clarify, odefun is F1.m, an m-file of mine. I pass it into the function that contains this while-loop. It's something like whileloop(#F1,args). Line 4 in the code-block above is the Euler method.
The reason I'm using a while-loop is because I want to trigger upon the vector "y" crossing a plane defined by a point, "normpt", and the vector normal to the plane, "normvec".
Is there an easy change to this code that will speed it up dramatically? Should I attempt learning how to make mex files instead (for a speed increase)?
Edit:
Here is a rushed attempt at an example of what one could try to test with. I have not debugged this. It is to give you an idea:
%Save the following 3 lines in an m-file named "F1.m"
function ydot = F1(placeholder1,y,placeholder2,placeholder3)
ydot = y/10;
end
%Run the following:
dt = 1.5e-12 %I do not know about this. You will have to experiment.
y0 = [.1,.1,.1];
normpt = [3,3,3];
normvec = [1,1,1];
originalsign = sign(dot(y0-normpt,normvec));
costheta = originalsign;
y = y0;
k = 0;
while (sign(costheta) == originalsign)
y=y(:) + F1(0,y(:),0,0)*(dt); % Line 4
costheta = dot(y-normpt,normvec);
k = k + 1;
end
disp(k);
dt should be sufficiently small that it takes hundreds of thousands of iterations to trigger.
Assume I must use the Euler method. I have a stochastic differential equation with state-dependent noise if you are curious as to why I tell you to take such an assumption.
I would focus on your actual ODE integration. The fewer steps you have to take, the faster the loop will run. I would only worry about the speed of the sign check after you've optimized the actual integration method.
It looks like you're using the first-order explicit Euler method. Have you tried a higher-order integrator or an implicit method? Often you can increase the time step significantly.