`ode45` and tspan error Attempted to access - matlab

I'm using ode45 to solve second order differential equation. the time span is determined based on how many numbers in txt file, therefore, the time span is defined as follows
i = 1;
t(i) = 0;
dt = 0.1;
numel(theta_d)
while ( i < numel(theta_d) )
i = i + 1;
t(i) = t(i-1) + dt;
end
Now the time elements should not exceed the size of txt (i.e. numel(theta_d)). In main.m, I have
x0 = [0; 0];
options= odeset('Reltol',dt,'Stats','on');
[t, x] = ode45('ODESolver', t, x0, options);
and ODESolver.m header is
function dx = ODESolver(t, x)
If I run the code, I'm getting this error
Attempted to access theta_d(56); index out of bounds because numel(theta_d)=55.
Error in ODESolver (line 29)
theta_dDot = ( theta_d(i) - theta_dPrev ) / dt;
Why the ode45 is not being fixed with the time span?
Edit: this is the entire code
main.m
clear all
clc
global error theta_d dt;
error = 0;
theta_d = load('trajectory.txt');
i = 1;
t(i) = 0;
dt = 0.1;
numel(theta_d)
while ( i < numel(theta_d) )
i = i + 1;
t(i) = t(i-1) + dt;
end
x0 = [pi/4; 0];
options= odeset('Reltol',dt,'Stats','on');
[t, x] = ode45(#ODESolver, t, x0, options);
%e = x(:,1) - theta_d; % Error theta
plot(t, x(:,2), 'r', 'LineWidth', 2);
title('Tracking Problem','Interpreter','LaTex');
xlabel('time (sec)');
ylabel('$\dot{\theta}(t)$', 'Interpreter','LaTex');
grid on
and ODESolver.m
function dx = ODESolver(t, x)
persistent i theta_dPrev
if isempty(i)
i = 1;
theta_dPrev = 0;
end
global error theta_d dt ;
dx = zeros(2,1);
%Parameters:
m = 0.5; % mass (Kg)
d = 0.0023e-6; % viscous friction coefficient
L = 1; % arm length (m)
I = 1/3*m*L^2; % inertia seen at the rotation axis. (Kg.m^2)
g = 9.81; % acceleration due to gravity m/s^2
% PID tuning
Kp = 5;
Kd = 1.9;
Ki = 0.02;
% theta_d first derivative
theta_dDot = ( theta_d(i) - theta_dPrev ) / dt;
theta_dPrev = theta_d(i);
% u: joint torque
u = Kp*(theta_d(i) - x(1)) + Kd*( theta_dDot - x(2)) + Ki*error;
error = error + (theta_dDot - x(1));
dx(1) = x(2);
dx(2) = 1/I*(u - d*x(2) - m*g*L*sin(x(1)));
i = i + 1;
end
and this is the error
Attempted to access theta_d(56); index out of bounds because numel(theta_d)=55.
Error in ODESolver (line 28)
theta_dDot = ( theta_d(i) - theta_dPrev ) / dt;
Error in ode45 (line 261)
f(:,2) = feval(odeFcn,t+hA(1),y+f*hB(:,1),odeArgs{:});
Error in main (line 21)
[t, x] = ode45(#ODESolver, t, x0, options);

The problem here is because you have data at discrete time points, but ode45 needs to be able to calculate the derivative at any time point in your time range. Once it solves the problem, it will interpolate the results back onto your desired time points. So it will calculate the derivative many times more than at just the time points you specified, thus your i counter will not work at all.
Since you have discrete data, the only way to proceed with ode45 is to interpolate theta_d to any time t. You have a list of values theta_d corresponding to times 0:dt:(dt*(numel(theta_d)-1)), so to interpolate to a particular time t, use interp1(0:dt:(dt*(numel(theta_d)-1)),theta_d,t), and I turned this into an anonymous function to give the interpolated value of theta_p at a given time t
Then your derivative function will look like
function dx = ODESolver(t, x,thetaI)
dx = zeros(2,1);
%Parameters:
m = 0.5; % mass (Kg)
d = 0.0023e-6; % viscous friction coefficient
L = 1; % arm length (m)
I = 1/3*m*L^2; % inertia seen at the rotation axis. (Kg.m^2)
g = 9.81; % acceleration due to gravity m/s^2
% PID tuning
Kp = 5;
Kd = 1.9;
Ki = 0.02;
% theta_d first derivative
dt=1e-4;
theta_dDot = (thetaI(t) - theta(I-dt)) / dt;
%// Note thetaI(t) is the interpolated theta_d values at time t
% u: joint torque
u = Kp*(thetaI(t) - x(1)) + Kd*( theta_dDot - x(2)) + Ki*error;
error = error + (theta_dDot - x(1));
dx=[x(2); 1/I*(u - d*x(2) - m*g*L*sin(x(1)))];
end
and you will have to define thetaI=#(t) interp1(0:dt:(dt*(numel(theta_d)-1)),theta_d,t); before calling ode45 using [t, x] = ode45(#(t,x) ODESolver(t,x,thetaI, t, x0, options);.
I removed a few things from ODESolver and changed how the derivative was computed.
Note I can't test this, but it should get you on the way.

Related

matlab: not enough input arguments error

I am new to Matlab and trying to find a solution to the error of my code:
Not enough input arguments.
Error in F9>f (line 42)
y = (2 - 2*t*x) / (x^2 + 1) ;
Error in F9 (line 18)
e = euler(f, trange(1), y0_value, h, trange(end));
function [] = F9()
% Euler's Method to solve given functions
% Set initial values
hi = [1/2, 1/4];
trange = [0, 2];
y0_value = 1;
% Set functions' and exact functions' handles
% Calculate and show results
% Loop for functions
for i = 1:2
fprintf('###########\n');
fprintf('Function #%d\n', i)
fprintf('###########\n');
exact_value = f_exact(trange(end));
% Loop for h
for h = hi
% Euler calculations
e = euler(f, trange(1), y0_value, h, trange(end));
fprintf('\nh: %f\n', h);
fprintf('\nEuler: %f \n', e(end));
fprintf('Error: %f\n\n', abs((e(end)-exact_value)/exact_value));
end
fprintf('Exact: %f\n\n', exact_value);
end
end
% Euler's Method
function y = euler(f, t0, y0, h, tn)
n = (tn-t0)/h;
% Initialize t, y
[t, y] = deal(zeros(n, 1));
% Set t0, y0
t(1) = t0;
y(1) = y0;
for i = 1:n
t(i+1) = t(i) + h;
y(i+1) = y(i) + h/2 * (f(t(i), y(i))+ f(t(i+1) , y(i) + h * f(t(i), y(i))));
end
end
% Functions to solve
function y = f(t, x)
y = (2 - 2*t*x) / (x^2 + 1) ;
end
function y = f_exact(x)
y = (2*x + 1) / (x^2 + 1);
end
When you pass f to euler you need to pass it as a handle, i.e. precede it with a #:
e = euler(#f, trange(1), y0_value, h, trange(end));

Solving System of Second Order Ordinary Differential Equation in Matlab

Introduction
I am using Matlab to simulate some dynamic systems through numerically solving systems of Second Order Ordinary Differential Equations using ODE45. I found a great tutorial from Mathworks (link for tutorial at end) on how to do this.
In the tutorial the system of equations is explicit in x and y as shown below:
x''=-D(y) * x' * sqrt(x'^2 + y'^2)
y''=-D(y) * y' * sqrt(x'^2 + y'^2) + g(y)
Both equations above have form y'' = f(x, x', y, y')
Question
However, I am coming across systems of equations where the variables can not be solved for explicitly as shown in the example. For example one of the systems has the following set of 3 second order ordinary differential equations:
y double prime equation
y'' - .5*L*(x''*sin(x) + x'^2*cos(x) + (k/m)*y - g = 0
x double prime equation
.33*L^2*x'' - .5*L*y''sin(x) - .33*L^2*C*cos(x) + .5*g*L*sin(x) = 0
A single prime is first derivative
A double prime is second derivative
L, g, m, k, and C are given parameters.
How can Matlab be used to numerically solve a set of second order ordinary differential equations where second order can not be explicitly solved for?
Thanks!
Your second system has the form
a11*x'' + a12*y'' = f1(x,y,x',y')
a21*x'' + a22*y'' = f2(x,y,x',y')
which you can solve as a linear system
[x'', y''] = A\f
or in this case explicitly using Cramer's rule
x'' = ( a22*f1 - a12*f2 ) / (a11*a22 - a12*a21)
y'' accordingly.
I would strongly recommend leaving the intermediate variables in the code to reduce chances for typing errors and avoid multiple computation of the same expressions.
Code could look like this (untested)
function dz = odefunc(t,z)
x=z(1); dx=z(2); y=z(3); dy=z(4);
A = [ [-.5*L*sin(x), 1] ; [.33*L^2, -0.5*L*sin(x)] ]
b = [ [dx^2*cos(x) + (k/m)*y-g]; [-.33*L^2*C*cos(x) + .5*g*L*sin(x)] ]
d2 = A\b
dz = [ dx, d2(1), dy, d2(2) ]
end
Yes your method is correct!
I post the following code below:
%Rotating Pendulum Sym Main
clc
clear all;
%Define parameters
global M K L g C;
M = 1;
K = 25.6;
L = 1;
C = 1;
g = 9.8;
% define initial values for theta, thetad, del, deld
e_0 = 1;
ed_0 = 0;
theta_0 = 0;
thetad_0 = .5;
initialValues = [e_0, ed_0, theta_0, thetad_0];
% Set a timespan
t_initial = 0;
t_final = 36;
dt = .01;
N = (t_final - t_initial)/dt;
timeSpan = linspace(t_final, t_initial, N);
% Run ode45 to get z (theta, thetad, del, deld)
[t, z] = ode45(#RotSpngHndl, timeSpan, initialValues);
%initialize variables
e = zeros(N,1);
ed = zeros(N,1);
theta = zeros(N,1);
thetad = zeros(N,1);
T = zeros(N,1);
V = zeros(N,1);
x = zeros(N,1);
y = zeros(N,1);
for i = 1:N
e(i) = z(i, 1);
ed(i) = z(i, 2);
theta(i) = z(i, 3);
thetad(i) = z(i, 4);
T(i) = .5*M*(ed(i)^2 + (1/3)*L^2*C*sin(theta(i)) + (1/3)*L^2*thetad(i)^2 - L*ed(i)*thetad(i)*sin(theta(i)));
V(i) = -M*g*(e(i) + .5*L*cos(theta(i)));
E(i) = T(i) + V(i);
end
figure(1)
plot(t, T,'r');
hold on;
plot(t, V,'b');
plot(t,E,'y');
title('Energy');
xlabel('time(sec)');
legend('Kinetic Energy', 'Potential Energy', 'Total Energy');
Here is function handle file for ode45:
function dz = RotSpngHndl(~, z)
% Define Global Parameters
global M K L g C
A = [1, -.5*L*sin(z(3));
-.5*L*sin(z(3)), (1/3)*L^2];
b = [.5*L*z(4)^2*cos(z(3)) - (K/M)*z(1) + g;
(1/3)*L^2*C*cos(z(3)) + .5*g*L*sin(z(3))];
X = A\b;
% return column vector [ed; edd; ed; edd]
dz = [z(2);
X(1);
z(4);
X(2)];

Can't recover the parameters of a model using ode45

I am trying to simulate the rotation dynamics of a system. I am testing my code to verify that it's working using simulation, but I never recovered the parameters I pass to the model. In other words, I can't re-estimate the parameters I chose for the model.
I am using MATLAB for that and specifically ode45. Here is my code:
% Load the input-output data
[torque outputs] = DataLogs2();
u = torque;
% using the simulation data
Ixx = 1.00;
Iyy = 2.00;
Izz = 3.00;
x0 = [0; 0; 0];
Ts = .02;
t = 0:Ts:Ts * ( length(u) - 1 );
[ T, x ] = ode45( #(t,x) rotationDyn( t, x, u(1+floor(t/Ts),:), Ixx, Iyy, Izz), t, x0 );
w = x';
N = length(w);
q = 1; % a counter for the A and B matrices
% The Algorithm
for k=1:1:N
w_telda = [ 0 -w(3, k) w(2,k); ...
w(3,k) 0 -w(1,k); ...
-w(2,k) w(1,k) 0 ];
if k == N % to handle the problem of the last iteration
w_dash(:,k) = (-w(:,k))/Ts;
else
w_dash(:,k) = (w(:,k+1)-w(:,k))/Ts;
end
a = kron( w_dash(:,k)', eye(3) ) + kron( w(:,k)', w_telda );
A(q:q+2,:) = a; % a 3N*9 matrix
B(q:q+2,:) = u(k,:)'; % a 3N*1 matrix % u(:,k)
q = q + 3;
end
% Forcing J to be diagonal. This is the case when we consider our quadcopter as two thin uniform
% rods crossed at the origin with a point mass (motor) at the end of each.
A_new = [A(:, 1) A(:, 5) A(:, 9)];
vec_J_diag = A_new\B;
J_diag = diag([vec_J_diag(1), vec_J_diag(2), vec_J_diag(3)])
eigenvalues_J_diag = eig(J_diag)
error = norm(A_new*vec_J_diag - B)
where my dynamic model is defined as:
function [dw, y] = rotationDyn(t, w, tau, Ixx, Iyy, Izz, varargin)
% The output equation
y = [w(1); w(2); w(3)];
% State equation
% dw = (I^-1)*( tau - cross(w, I*w) );
dw = [Ixx^-1 * tau(1) - ((Izz-Iyy)/Ixx)*w(2)*w(3);
Iyy^-1 * tau(2) - ((Ixx-Izz)/Iyy)*w(1)*w(3);
Izz^-1 * tau(3) - ((Iyy-Ixx)/Izz)*w(1)*w(2)];
end
Practically, what this code should do, is to calculate the eigenvalues of the inertia matrix, J, i.e. to recover Ixx, Iyy, and Izz that I passed to the model at the very begining (1, 2 and 3), but all what I get is wrong results.
Is the problem with using ode45?
Well the problem wasn't in the ode45 instruction, the problem is that in system identification one can create an n-1 samples-signal from an n samples-signal, thus the loop has to end at N-1 in the above code.

Finding a root in matlab, not compiling

i have to do an assignment where i have to find the depth of how much the ball is under water depending on the water's density, then i have to plot it. i don't have matlab at home but i'm using octave and for some reason it's not compiling, and it's not saying any errors. here is my code
function my_script()
% weight function
function func = weight(x,p)
func = p *pi* 4- 3 * pi*x ^2 + pi* x ^3;
% make the secant method
function root = secant(func , p, x0, x1, tol, count)
while count ~= 0
y1 = func(x0,p);
y2 = func(x1, p);
k = (x1 - x0)/(y2 - y1);
R = y2 * k;
root = x1 - R;
if abs(func(root,p)) < tol
break;
end
x0 = x1;
x1 = root;
count = count - 1;
end
%create array for depth values
y_val = [];
%input the roots into the array with a loop
for p = 0:0.01:1
t = secant(#weight, p, 0, 1, 0.000001, 1000000);
disp (t);
y_val = [y_val t];
end
% create the x - axis
x_val = 0 : 0.01 : 1;
%plotting the graph
figure;
plot (x_val, y_val)
xlabel('Density');
ylabel('Depth ');
title('Floating Sphere vs Density ');
Another way of creating what you have written is to split it into three different functions.
You'd have the weight function, weight.m,
% weight function
function func = weight(x,p)
func = p *pi* 4- 3 * pi*x ^2 + pi* x ^3;
and the secant method function, secant.m,
% make the secant method
function root = secant(func , p, x0, x1, tol, count)
while count ~= 0
y1 = func(x0,p);
y2 = func(x1, p);
k = (x1 - x0)/(y2 - y1);
R = y2 * k;
root = x1 - R;
if abs(func(root,p)) < tol
break;
end
x0 = x1;
x1 = root;
count = count - 1;
end
%create array for depth values
y_val = [];
%input the roots into the array with a loop
for p = 0:0.01:1
t = secant(#weight, p, 0, 1, 0.000001, 1000000);
disp (t);
y_val = [y_val t];
end
% create the x - axis
x_val = 0 : 0.01 : 1;
%plotting the graph
figure;
plot (x_val, y_val)
xlabel('Density');
ylabel('Depth ');
title('Floating Sphere vs Density ');
Then you'd have my_script():
function my_script()
but it is an empty function, so the output is correct! You have to have all the commands for each function finished before you define the next function.
I have a feeling that you want to take out everything from the end of the while loop onwards from the secant function and put it into the main my_script() function.
Here's your code, Octave style. Observe that I temporarily commented the "disp(t);" statement to avoid a long listing of values. This way, the plot is plotted immediately. Hopefully this helps.
function my_script
%create array for depth values
y_val = [];
%input the roots into the array with a loop
for p = 0:0.01:1
t = secant(#weight, p, 0, 1, 0.000001, 1000000);
%disp (t);
y_val = [y_val t];
endfor
% create the x - axis
x_val = 0 : 0.01 : 1;
%plotting the graph
figure(1)
plot (x_val, y_val)
xlabel('Density');
ylabel('Depth ');
title('Floating Sphere vs Density ');
endfunction
% make the secant method
function root = secant(func , p, x0, x1, tol, count)
while count ~= 0
y1 = func(x0,p);
y2 = func(x1, p);
k = (x1 - x0)/(y2 - y1);
R = y2 * k;
root = x1 - R;
if abs(func(root,p)) < tol
break;
end
x0 = x1;
x1 = root;
count = count - 1;
endwhile
endfunction
% weight function
function func = weight(x,p)
func = p *pi* 4- 3 * pi*x ^2 + pi* x ^3;
endfunction

Forward Euler Method to solve first order ODEs in Matlab

I wrote this Matlab program that is supposed to solve the IVP du/dx= -5000(u(t) - cos(t)) - sin(t) with u(0)=1. My exact solution should be u(t) = cos(t) but the solution I am getting from Euler's forward in my code is huge in comparison to what it should be and what I calculated but I'm not sure where I've gone wrong in my code. Can you find my error?
function main
dt=5;
u0 = 1;
n=50;
[T,U] = euler(dt, u0, n);
uexact = cos(T);
plot(T,U)
hold on
plot(T, uexact, 'r')
end
function [T,U]= euler( dt, u0, n)
R= dt/n;
T=zeros(1,n+1);
U=zeros(1,n+1);
U(1)=u0;
T(1) = 0;
for j=1:n
U(j+1)= U(j)+ R*(rhs(T(j),U(j)));
T(j+1)= T(j) + R;
end
end
function dP = rhs(t, P)
P = zeros(1,1);
dP = (-5000)*(P - cos(t)) - sin(t);
end
You don not have to set P = zeros(1,1) insde the function that approximate de derivative with the formula.
Moreover, the problem you have is the [numerical unstability of forward Euler method][1]. You need a very small time step to make it converge (because of the large coefficient of P inside function dP).
function main
dt=5;
u0 = 1;
n=50000; % increase the number or subintervals (smaller time step) to get stability
[T,U] = euler(dt, u0, n);
uexact = cos(T);
plot(T,U,'bs')
hold on
plot(T, uexact, 'r')
end
function [T,U]= euler( dt, u0, n)
R= dt/n;
T=zeros(1,n+1);
U=zeros(1,n+1);
U(1)=u0;
T(1) = 0;
for j=1:n
% Implicit method converges
% U(j+1) = ( U(j) - R*(-5000)*cos(T(j)) - R*sin(T(j)))/(1 - R*(-5000));
U(j+1)= U(j)+ R*(rhs(T(j),U(j)));
T(j+1)= T(j) + R;
end
end
function dP = rhs(t, P)
%P = zeros(1,1); %% It must not be here
dP = (-5000)*(P - cos(t)) - sin(t);
end
[1]: http://en.wikipedia.org/wiki/Euler_method