Related
I have always used R, so I am quite new to Matlab and running into some troubleshooting issues. I am running some code for a tensor factorization method (available here: https://github.com/caobokai/tBNE). To start I tried to run the demo code, which generates simulated data to run the method with, which results in the following error(s):
Error using feval
Undefined function or variable 'Sfun'.
Error in OptStiefelGBB (line 199)
[F, G] = feval(fun, X , varargin{:}); out.nfe = 1;
Error in tbne_demo>tBNE_fun (line 124)
S, #Sfun, opts, B, P, X, L, D, W, Y, alpha, beta);
Here is the block of code I am running:
clear
clc
addpath(genpath('./tensor_toolbox'));
addpath(genpath('./FOptM'));
rng(5489, 'twister');
m = 10;
n = 10;
k = 10; % rank for tensor
[X, Z, Y] = tBNE_data(m, n, k); % generate the tensor, guidance and label
[T, W] = tBNE_fun(X, Z, Y, k);
[~, y1] = max(Y, [], 2);
[~, y2] = max(T{3} * W, [], 2);
fprintf('accuracy %3.2e\n', sum(y1 == y2) / n);
function [X, Z, Y] = tBNE_data(m, n, k)
B = randn(m, k);
S = randn(n, k);
A = {B, B, S};
X = ktensor(A);
Z = randn(n, 4);
Y = zeros(n, 2);
l = ceil(n / 2);
Y(1 : l, 1) = 1;
Y(l + 1 : end, 2) = 1;
X = tensor(X);
end
function [T, W] = tBNE_fun(X, Z, Y, k)
% t-BNE computes brain network embedding based on constrained tensor factorization
%
% INPUT
% X: brain networks stacked in a 3-way tensor
% Z: side information
% Y: label information
% k: rank of CP factorization
%
% OUTPUT
% T is the factor tensor containing
% vertex factor matrix B = T{1} and
% subject factor matrix S = T{3}
% W is the weight matrix
%
% Example: see tBNE_demo.m
%
% Reference:
% Bokai Cao, Lifang He, Xiaokai Wei, Mengqi Xing, Philip S. Yu,
% Heide Klumpp and Alex D. Leow. t-BNE: Tensor-based Brain Network Embedding.
% In SDM 2017.
%
% Dependency:
% [1] Matlab tensor toolbox v 2.6
% Brett W. Bader, Tamara G. Kolda and others
% http://www.sandia.gov/~tgkolda/TensorToolbox
% [2] A feasible method for optimization with orthogonality constraints
% Zaiwen Wen and Wotao Yin
% http://www.math.ucla.edu/~wotaoyin/papers/feasible_method_matrix_manifold.html
%% set algorithm parameters
printitn = 10;
maxiter = 200;
fitchangetol = 1e-4;
alpha = 0.1; % weight for guidance
beta = 0.1; % weight for classification loss
gamma = 0.1; % weight for regularization
u = 1e-6;
umax = 1e6;
rho = 1.15;
opts.record = 0;
opts.mxitr = 20;
opts.xtol = 1e-5;
opts.gtol = 1e-5;
opts.ftol = 1e-8;
%% compute statistics
dim = size(X);
normX = norm(X);
numClass = size(Y, 2);
m = dim(1);
n = dim(3);
l = size(Y, 1);
D = [eye(l), zeros(l, n - l)];
L = diag(sum(Z * Z')) - Z * Z';
%% initialization
B = randn(m, k);
P = B;
S = randn(n, k);
S = orth(S);
W = randn(k, numClass);
U = zeros(m, k); % Lagrange multipliers
%% main loop
fit = 0;
for iter = 1 : maxiter
fitold = fit;
% update B
ete = (S' * S) .* (P' * P); % compute E'E
b = 2 * ete + u * eye(k);
c = 2 * mttkrp(X, {B, P, S}, 1) + u * P + U;
B = c / b;
% update P
ftf = (S' * S) .* (B' * B); % compute F'F
b = 2 * ftf + u * eye(k);
c = 2 * mttkrp(X, {B, P, S}, 2) + u * B - U;
P = c / b;
% update U
U = U + u * (P - B);
% update u
u = min(rho * u, umax);
% update S
tic;
[S, out] = OptStiefelGBB(...
S, #Sfun, opts, B, P, X, L, D, W, Y, alpha, beta);
tsolve = toc;
fprintf(...
['[S]: obj val %7.6e, cpu %f, #func eval %d, ', ...
'itr %d, |ST*S-I| %3.2e\n'], ...
out.fval, tsolve, out.nfe, out.itr, norm(S' * S - eye(k), 'fro'));
% update W
H = D * S;
W = (H' * H + gamma * eye(k)) \ H' * Y;
% compute the fit
T = ktensor({B, P, S});
normresidual = sqrt(normX ^ 2 + norm(T) ^ 2 - 2 * innerprod(X, T));
fit = 1 - (normresidual / normX);
fitchange = abs(fitold - fit);
if mod(iter, printitn) == 0
fprintf(' Iter %2d: fitdelta = %7.1e\n', iter, fitchange);
end
% check for convergence
if (iter > 1) && (fitchange < fitchangetol)
break;
end
end
%% clean up final results
T = arrange(T); % columns are normalized
fprintf('factorization error %3.2e\n', fit);
end
I know that there is little context here, but my suspicion is that I need to have Simulink, as Sfun is a Simulink related function(?). The script requires two toolboxes: tensor_toolbox, and FOptM.
Available at:
https://www.sandia.gov/~tgkolda/TensorToolbox/index-2.6.html
https://github.com/andland/FOptM
Thank you so much for your help,
Paul
Although SFun is an often used abbreviation for a Simulink S-Function, in this case the error has nothing to do with Simulink, and the name is a coincidence. (There is no Simulink related function specifically called Sfun, it is just a general term.)
Your error message has #Sfun in it, which is a way in MATLAB of creating a function handle to an (m-code) function called Sfun. I'd summize from the code you've shown that this is a cost function used in the optimization.
If you look at the code that your code is based on (tBNE_fun.m) you'll see that there is a function at the end of the file called Sfun. It is this that you are missing.
So I have a script which executes coordinate descent algorithm for a quadratic function. I also created a function to make different plots, this is the first part I add. The code executes without any error, but I'm unable to see the surface, I can only see the path of my algorithm descending.
The function updater:
function [f,delta] = fcalculator (Q, x0, c, p)
a = size(x0);
n = a(2);
f = (x0*Q*x0') - (c * x0') + p ;
delta = (Q*x0')- c';
endfunction
The main program:
clear all, close all,
fprintf(' 0 = probleme specifique \n 1 = probleme random \n 2 = Tapez votre propre probleme\n')
choix = input ('Choix : ');
n=0;
if (choix == 0)
[Q, x0, c, p] = quadfunctiongenerator(n,choix)
maxiter = input ( 'Nombre de iterations :');
[x, z] = coordinatedescent(Q,c,p,x0,maxiter);
visualizer(x, z, Q, c, p);
else
n = input ('Choix des dimensions: n = ');
[Q, x0, c, p] = quadfunctiongenerator(n,choix);
endif
The module to create the plots:
function [x1, x2, fuf] = visualizer(x, z, Q, c, p)
clf;
% Pour le cas le plus general, apres on fera:
% iters = 1:size(x)(1);
% plot(iters,x(:,1))
if size(x)(2)
% Afficher les iterees:
plot3(x(:,1), x(:,2), z)
hold on;
% fcalculator (Q, x0, c, p)
% Display the function's surface:
%% Calculate limits:
x1_low = x(1,1);
x1_hi = x(size(x)(1),1) + x1_low;
x2_low = x(1,2);
x2_hi = x(size(x)(1),2) + x2_low;
% Resolution will be the number of points:
resolution = 100;
x1 = (linspace(x1_low, x1_hi, resolution))';
x2 = (linspace(x2_low, x2_hi, resolution))';
f = [];
[xx, yy] = meshgrid (x1, x2);
for i=1:resolution
for j=1:resolution
[_tmp, _] = fcalculator(Q, [x1(i),x2(j)], c, p);
f(i,j) = _tmp;
endfor
endfor
_string = sprintf('%d ', size(x1));
fprintf('Answer: %s\n', _string);
_string = sprintf('%d ', size(x2));
fprintf('Answer: %s\n', _string);
_string = sprintf('%d ', size(f));
fprintf('Answer: %s\n', _string);
mesh(x1, x2, f);
endif
endfunction
I believe the problem is my call to mesh() as I didn't use the variables xx and yy created when calling meshgrid() but the dimensions of x1, x2 and f are the same as those of the variables used to create the famous sombrero plot:
tx = ty = linspace (-8, 8, 41)';
[xx, yy] = meshgrid (tx, ty);
r = sqrt (xx .^ 2 + yy .^ 2) + eps;
tz = sin (r) ./ r;
mesh (tx, ty, tz);
Am I supposed to create f as an elementwise operation as shown in the sombrero plot example?
Is there any octave function to help me create the surface of the function I am optimizing?
I found the problem. The call to mesh() was correct. The problem was the definition of the boundaries.
x1_low = x(1,1);
x1_hi = x(size(x)(1),1) + x1_low;
x2_low = x(1,2);
x2_hi = x(size(x)(1),2) + x2_low;
Yielded x1_low == x1_hi. The code was replaced with:
x1_low = min(x(:,1));
x1_hi = max(x(:,1));
x2_low = min(x(:,2));
x2_hi = max(x(:,2));
Which yielded the desired surface.
I want to solve a system of THREE differential equations with the Runge Kutta 4 method in Matlab (Ode45 is not permitted).
After a long time spent looking, all I have been able to find online are either unintelligible examples or general explanations that do not include examples at all. I would like a concrete example on how to implement my solution properly, or the solution to a comparable problem which I can build on.
I have come quite far; my current code spits out a matrix with 2 correct decimals on most of the components, which I am quite happy with.
However, when the step-size is decreased, the errors become enormous. I know the for-loop I have created is not entirely correct. I may have defined the functions incorrectly, but I am quite certain that the problem is solved if some minor changes are made to the for-loop because it appears to be solving the equation-system fairly well already in its current state.
clear all, close all, clc
%{
____________________TASK:______________________
Solve the system of differential equations below
in the interval 0<t<1, with stepsize h = 0.1.
x'= y x(0)=1
y'= -x-2e^t+1 y(0)=0 , where x=x(t), y=y(t), z=z(t)
z'= -x - e^t + 1 z(0)=1
THE EXACT SOLUTIONS for x y and z can be found in this pdf:
archives.math.utk.edu/ICTCM/VOL16/C029/paper.pdf
_______________________________________________
%}
h = 0.1;
t = 0:h:1
N = length(t);
%Defining the functions
x = zeros(N,1);%I am not entierly sure if x y z are supposed to be defined in this way.
y = zeros(N,1)
z = zeros(N,1)
f = #(t, x, y, z) -x-2*exp(t)+1;%Question: Do i need a function for x here as well??
g = #(t, x, y, z) -x - exp(t) + 1;
%Starting conditions
x(1) = 1;
y(1) = 0;
z(1) = 1;
for i = 1:(N-1)
K1 = h * ( y(i));%____I think z(i) is supposed to be here, but i dont know in what way.
L1 = h * f( t(i) , x(i) , y(i) , z(i));
M1 = h * g( t(i) , x(i) , y(i) , z(i));
K2 = h * (y(i) + 1/2*L1 + 1/2*M1);%____Again, z(i) should probably be here somewhere.
L2 = h * f(t(i) + 1/2*h, x(i)+1/2*K1 , y(i)+1/2*L1 , z(i)+1/2*M1);
M2 = h * g(t(i) + 1/2*h, x(i)+1/2*K1 , y(i)+1/2*L1 , z(i)+1/2*M1);
K3 = h * (y(i) + 1/2*L2 + 1/2*M2);%____z(i). Should it just be added, like "+z(i)" ?
L3 = h * f(t(i) + 1/2*h, x(i) + 1/2*K2 , y(i) + 1/2*L2 , z(i) + 1/2*M2);
M3 = h * g(t(i) + 1/2*h, x(i) + 1/2*K2 , y(i) + 1/2*L2 , z(i) + 1/2*M2);
K4 = h * (y(i) + L3 + M3);%_____z(i) ... ?
L4 = h * f( t(i)+h , x(i)+K3 , y(i)+L3, z(i)+M3);
M4 = h * g( t(i)+h , x(i)+K3 , y(i)+L3, z(i)+M3);
x(i+1) = x(i)+1/6*(K1+2*K2+2*K3+K4);
y(i+1) = y(i)+1/6*(L1+2*L2+2*L3+L4);
z(i+1) = z(i)+1/6*(M1+2*M2+2*M3+M4);
end
Answer_Matrix = [t' x y z]
So your main issue was not defining x properly. You were propagating its value using the Runge Kutta 4 (RK4) method, but never actually defined what its derivative was!
At the bottom of this answer is a function which can take any given number of equations and their initial conditions. This has been included to address your need for a clear example for three (or more) equations.
For reference, the equations can be directly lifted from the standard RK4 method described here.
Working Script
This is comparable to yours, but uses slightly clearer naming conventions and structure.
% Initialise step-size variables
h = 0.1;
t = (0:h:1)';
N = length(t);
% Initialise vectors
x = zeros(N,1); y = zeros(N,1); z = zeros(N,1);
% Starting conditions
x(1) = 1; y(1) = 0; z(1) = 1;
% Initialise derivative functions
dx = #(t, x, y, z) y; % dx = x' = dx/dt
dy = #(t, x, y, z) - x -2*exp(t) + 1; % dy = y' = dy/dt
dz = #(t, x, y, z) - x - exp(t) + 1; % dz = z' = dz/dt
% Initialise K vectors
kx = zeros(1,4); % to store K values for x
ky = zeros(1,4); % to store K values for y
kz = zeros(1,4); % to store K values for z
b = [1 2 2 1]; % RK4 coefficients
% Iterate, computing each K value in turn, then the i+1 step values
for i = 1:(N-1)
kx(1) = dx(t(i), x(i), y(i), z(i));
ky(1) = dy(t(i), x(i), y(i), z(i));
kz(1) = dz(t(i), x(i), y(i), z(i));
kx(2) = dx(t(i) + (h/2), x(i) + (h/2)*kx(1), y(i) + (h/2)*ky(1), z(i) + (h/2)*kz(1));
ky(2) = dy(t(i) + (h/2), x(i) + (h/2)*kx(1), y(i) + (h/2)*ky(1), z(i) + (h/2)*kz(1));
kz(2) = dz(t(i) + (h/2), x(i) + (h/2)*kx(1), y(i) + (h/2)*ky(1), z(i) + (h/2)*kz(1));
kx(3) = dx(t(i) + (h/2), x(i) + (h/2)*kx(2), y(i) + (h/2)*ky(2), z(i) + (h/2)*kz(2));
ky(3) = dy(t(i) + (h/2), x(i) + (h/2)*kx(2), y(i) + (h/2)*ky(2), z(i) + (h/2)*kz(2));
kz(3) = dz(t(i) + (h/2), x(i) + (h/2)*kx(2), y(i) + (h/2)*ky(2), z(i) + (h/2)*kz(2));
kx(4) = dx(t(i) + h, x(i) + h*kx(3), y(i) + h*ky(3), z(i) + h*kz(3));
ky(4) = dy(t(i) + h, x(i) + h*kx(3), y(i) + h*ky(3), z(i) + h*kz(3));
kz(4) = dz(t(i) + h, x(i) + h*kx(3), y(i) + h*ky(3), z(i) + h*kz(3));
x(i+1) = x(i) + (h/6)*sum(b.*kx);
y(i+1) = y(i) + (h/6)*sum(b.*ky);
z(i+1) = z(i) + (h/6)*sum(b.*kz);
end
% Group together in one solution matrix
txyz = [t,x,y,z];
Implemented as function
You wanted code which can "be applied to any equation system". To make your script more usable, let's take advantage of vector inputs, where each variable is on its own row, and then make it into a function. The result is something comparable (in how it is called) to Matlab's own ode45.
% setup
odefun = #(t, y) [y(2); -y(1) - 2*exp(t) + 1; -y(1) - exp(t) + 1];
y0 = [1;0;1];
% ODE45 solution
[T, Y] = ode45(odefun, [0,1], y0);
% Custom RK4 solution
t = 0:0.1:1;
y = RK4(odefun, t, y0);
% Compare results
figure; hold on;
plot(T, Y); plot(t, y, '--', 'linewidth', 2)
You can see that the RK4 function (below) gives the same result of the ode45 function.
The function RK4 is simply a "condensed" version of the above script, it will work for however many equations you want to use. For broad use, you would want to include input-checking in the function. I have left this out for clarity.
function y = RK4(odefun, tspan, y0)
% ODEFUN contains the ode functions of the system
% TSPAN is a 1D vector of equally spaced t values
% Y0 contains the intial conditions for the system variables
% Initialise step-size variables
t = tspan(:); % ensure column vector = (0:h:1)';
h = t(2)-t(1);% define h from t
N = length(t);
% Initialise y vector, with a column for each equation in odefun
y = zeros(N, numel(y0));
% Starting conditions
y(1, :) = y0(:)'; % Set intial conditions using row vector of y0
k = zeros(4, numel(y0)); % Initialise K vectors
b = repmat([1 2 2 1]', 1, numel(y0)); % RK4 coefficients
% Iterate, computing each K value in turn, then the i+1 step values
for i = 1:(N-1)
k(1, :) = odefun(t(i), y(i,:));
k(2, :) = odefun(t(i) + (h/2), y(i,:) + (h/2)*k(1,:));
k(3, :) = odefun(t(i) + (h/2), y(i,:) + (h/2)*k(2,:));
k(4, :) = odefun(t(i) + h, y(i,:) + h*k(3,:));
y(i+1, :) = y(i, :) + (h/6)*sum(b.*k);
end
end
Ok, turns out it was just a minor mistake where the x-variable was not defined as a function of y (as x'(t)=y according to the problem.
So: Below is a concrete example on how to solve a differential equation system using Runge Kutta 4 in matlab:
clear all, close all, clc
%{
____________________TASK:______________________
Solve the system of differential equations below
in the interval 0<t<1, with stepsize h = 0.1.
x'= y x(0)=1
y'= -x-2e^t+1 y(0)=0 , where x=x(t), y=y(t), z=z(t)
z'= -x - e^t + 1 z(0)=1
THE EXACT SOLUTIONS for x y and z can be found in this pdf:
archives.math.utk.edu/ICTCM/VOL16/C029/paper.pdf
_______________________________________________
%}
%Step-size
h = 0.1;
t = 0:h:1
N = length(t);
%Defining the vectors where the answer is stored.
x = zeros(N,1);
y = zeros(N,1)
z = zeros(N,1)
%Defining the functions
e = #(t, x, y, z) y;
f = #(t, x, y, z) -x-2*exp(t)+1;
g = #(t, x, y, z) -x - exp(t) + 1;
%Starting/initial conditions
x(1) = 1;
y(1) = 0;
z(1) = 1;
for i = 1:(N-1)
K1 = h * e( t(i) , x(i) , y(i) , z(i));
L1 = h * f( t(i) , x(i) , y(i) , z(i));
M1 = h * g( t(i) , x(i) , y(i) , z(i));
K2 = h * e(t(i) + 1/2*h, x(i)+1/2*K1 , y(i)+1/2*L1 , z(i)+1/2*M1);
L2 = h * f(t(i) + 1/2*h, x(i)+1/2*K1 , y(i)+1/2*L1 , z(i)+1/2*M1);
M2 = h * g(t(i) + 1/2*h, x(i)+1/2*K1 , y(i)+1/2*L1 , z(i)+1/2*M1);
K3 = h * e(t(i) + 1/2*h, x(i) + 1/2*K2 , y(i) + 1/2*L2 , z(i) + 1/2*M2);
L3 = h * f(t(i) + 1/2*h, x(i) + 1/2*K2 , y(i) + 1/2*L2 , z(i) + 1/2*M2);
M3 = h * g(t(i) + 1/2*h, x(i) + 1/2*K2 , y(i) + 1/2*L2 , z(i) + 1/2*M2);
K4 = h * e( t(i)+h , x(i)+K3 , y(i)+L3, z(i)+M3);
L4 = h * f( t(i)+h , x(i)+K3 , y(i)+L3, z(i)+M3);
M4 = h * g( t(i)+h , x(i)+K3 , y(i)+L3, z(i)+M3);
x(i+1) = x(i)+1/6*(K1+2*K2+2*K3+K4);
y(i+1) = y(i)+1/6*(L1+2*L2+2*L3+L4);
z(i+1) = z(i)+1/6*(M1+2*M2+2*M3+M4);
end
Answer_Matrix = [t' x y z]
I have an octave/Matlab function like this.
function [z] = baseline_als(y, lam, p, niter)
L = size(y);
D = sparse(diff(eye(L), 2));
w = ones(L);
for i = 1:niter
W = sparse.spdiags(w, 0, L, L); %error comes here
Z = W + lam * dot(D,transpose(D));
% z = spsolve(Z, w*y);
z= Z\(w*y);
w = p * (y > z) + (1-p) * (y < z);
end % End of For loop
end % End of function
I am calling this like this (in other file),
z = baseline_als(X,1000,0.00001,20)
plot(z)
Where X is 1D vector.
I have referred documentation from here. But could not figure out this error. How can I solve this?
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.