How to use piecewise function within differential equations in MATLAB? - matlab

I'm struggling to use piecewise function in this pdpk model in MATLAB I keep getting the error of
"Error using odearguments (line 113)
Inputs must be floats, namely single or double.
Error in ode45 (line 106)
odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options, varargin);"
Please help!
listed code below***
vnf = 1; qnf = 1; vf = 1; qf = 1;
vb = 1; pf = 20; vl = 1; ql = 1;
vmax = 1; Km = 1; pl = 2; pb = 18;
Ci = 0.32; % benzene conc in inhaled air
Qp = 5.74; % alveolar ventilation rate
conds = [0 0 0 0]; %--- initial conditions order: [NF F B L]
pul = piecewise(t > 6, 0, t <= 6, 1);
f = #(t,x) [qnf*(x(3)/vb - x(1)/vnf);...
qf*(x(3)/vb - x(2)/vf/pf);...
-qnf*(x(3)/vb - x(1)/vnf) - qf*(x(3)/vb - x(2)/vf/pf) - ql*(x(3)/vb - x(4)/vl/pl) + pul*Qp*(Ci - (x(3)/vb - pb));...
ql*(x(3)/vb - x(4)/vl/pl) - vmax*x(4)/vl/(Km + x(4)/vl)];
[t,x] = ode45(f, [0 10], conds);

Related

Problem converting Matlab function to a Simulink function

I need to convert this function, which implements the gradient descent algorithm:
function [xopt, fopt, niteration, gnorm, dx] = grad_descent2(varargin)
if nargin == 0
x0 = [3 3]';
elseif nargin == 1
x0 = varargin{1};
end
tolerance = 1e-6;
maxiteration = 1000;
dxmin = 1e-6;
alpha = 0.01;
gnorm = inf;
x = x0;
niteration = 0;
dx = inf;
f = #(x1, x2) x1.^2 + 3*x2.^2;
figure(1); clf; fcontour(f, [-5 5 -5 5]); axis equal;hold on
f2 = #(x) f(x(1), x(2));
while and(gnorm >= tolerance, and(niteration <=maxiteration, dx >= dxmin))
g = grad(x);
gnorm = norm(g);
xnew = x - alpha*g;
plot([x(1) xnew(1)], [x(2) xnew(2)], 'ko-')
refresh
niteration = niteration + 1;
dx = norm(xnew - x);
x = xnew;
end
xopt = x;
fopt = f2(xopt);
niteration = niteration - 1;
end
function g = grad(X)
g = [2*X(1)
2*X(2)];
end
My X to minimize is the value to do of a model of a pmsm motor. At the moment, I write this script:
function[x1opt,x2opt] = grad_descent2(isdpred,isqerr,isdmiss,isqmiss)
x1=isdpred;
x2=isqerr;
x0=[isdmiss,isqmiss];
tolerance = 1e-6;
maxiteration = 1000;
dxmin = 1e-6;
alpha = 0.01;
gnorm = inf;
x = x0;
niteration = 0;
dx = inf;
f = x1.^2+x2.^2;
figure(1); clf; fcontour(f, [-5 5 -5 5]); axis equal;hold on
while and(gnorm >= tolerance, and(niteration <=maxiteration, dx >= dxmin))
g = grad(x);
gnorm = norm(g);
xnew = x - alpha*g;
niteration = niteration + 1;
dx = norm(xnew - x);
x = xnew;
end
x1opt=x(1);
x2opt=x(2);
niteration = niteration - 1;
end
function g = grad(X)
g = [2*X(1)
2*X(2)];
end
But Simulink reports this error:
This function does not fully set the dimensions of output port 2

4d integral in matlab

I'm trying to evaluate the integral using MATLAB with an equation containing 4 related random variables, thus the boundaries of the integrals are not constant.
There are 2 exponential pdfs, and 2 other hyper exponential , and 1 Reyleigh CDF all multiplied together and with (x - y - z).
I'm trying to evaluate it using integral Q = (#(w) integral3(#(x,y,z,w),xmin,xmax,ymin,ymax,zmin,zmax),wmin,wmax);
I'm getting an error always. this is my code down here :
u_x = 10; % rate!
x_th = .3;
sigma = 1.33;
u_y = 10;
u_w = 100;
a= 1;
fun = #(x,y,z,w) (x - y - z )*u_x*exp(-u_x*x)*u_y*exp(-u_y*y)*((a/(a+1))*(a*u_w)*exp(-a*u_w*w)+((1/(a+1))*(u_w/a))*exp(-u_w*w/a))*((a/(a+1))*(a*u_w)*exp(-a*u_w*z)+((1/(a+1))*(u_w/a))*exp(-u_w*z/a))*(1-exp(-x_th/sigma^2))
xmin = #(y)y;
xmax = #(y,w)y + w;
ymin = 0;
ymax = inf;
zmin = 0;
zmax = #(w) w;
wmin = 0;
wmax = inf;
Q = integral(#(w) integral3(fun,xmin,xmax,ymin,ymax,zmin,zmax),wmin,wmax);
ERROR MESSAGE :
Error using integral3 (line 63)
XMIN must be a floating point scalar.
Error in numerical_int>#(w)integral3(fun,xmin,xmax,ymin,ymax,zmin,zmax)
Error in integralCalc/iterateScalarValued (line 314)
fx = FUN(t);
Error in integralCalc/vadapt (line 132)
[q,errbnd] = iterateScalarValued(u,tinterval,pathlen);
Error in integralCalc (line 83)
[q,errbnd] = vadapt(#AToInfInvTransform,interval);
Error in integral (line 88)
Q = integralCalc(fun,a,b,opstruct);
Error in numerical_int (line 28)
Q = integral(#(w) integral3(fun,xmin,xmax,ymin,ymax,zmin,zmax),wmin,wmax);
integral3() requires all the lower bounds to be real
number
int() does not, but need to use syms function instead of function
handle
For element-wise calculation use the dot. operator followed by the
concerned operator like
1) * ---> .* 2) / ---> ./ 3) ^ ---> .^
Read this for more information on how to use int() for nd
integral
The code is as follows
syms x y z w
u_x = 10; % rate!
x_th = .3;
sigma = 1.33;
u_y = 10;
u_w = 100;
a= 1;
fun = (x - y - z ).*u_x.*exp(-u_x*x).*u_y.*exp(-u_y.*y)...
.*((a./(a+1)).*(a.*u_w).*exp(-a.*u_w.*w)+((1./(a+1)).*(u_w./a))...
.*exp(-u_w.*w./a)).*((a./(a+1)).*(a*u_w)*exp(-a.*u_w.*z)...
+((1./(a+1)).*(u_w./a))*exp(-u_w.*z./a)).*(1-exp(-x_th./sigma.^2));
xmin = y;
xmax = y + w;
ymin = 0;
ymax = inf;
zmin = 0;
zmax = w;
wmin = 0;
wmax = inf;
% Integrate along x
intx = int(fun, x, xmin, xmax);
% Integrate along y
intxy = int(intx, y, ymin, ymax);
% Integrate along z
intxyz = int(intxy, z, zmin, zmax);
% Integrate along w
intxyzw = int(intxyz, w, wmin, wmax);
value = vpa(intxyzw, 3);
% 2.14e-5

`ode45` and tspan error Attempted to access

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.

Newton's method roots on Matlab

I am not so much experiences with Matlab. I just need it for the sake of solving some lengthy non-linear equations. Instead of using fzero, I wanna use Newton-Raphson's to solve the equation.
newton.m file contains the following code.
function [ x, ex ] = newton( f, df, x0, tol, nmax )
if nargin == 3
tol = 1e-4;
nmax = 1e1;
elseif nargin == 4
nmax = 1e1;
elseif nargin ~= 5
error('newton: invalid input parameters');
end
x(1) = x0 - (f(x0)/df(x0));
ex(1) = abs(x(1)-x0);
k = 2;
while (ex(k-1) >= tol) && (k <= nmax)
x(k) = x(k-1) - (f(x(k-1))/df(x(k-1)));
ex(k) = abs(x(k)-x(k-1));
k = k+1;
end
end
And in the main file, I have called this function as follows:
ext_H = newton( exp(x) + x^3, diff(exp(x) + x^3), 9, 0.5*10^-5, 10);
When I run this function, it gives me the following error.
Error using sym/subsref (line 9)
Error using maplemex
Error, (in MTM:-subsref) Array index out of range
Error in newton (line 37)
x(1) = x0 - (f(x0)/df(x0));
Error in main (line 104)
ext_H = newton( exp(x) + x^3, diff(exp(x) + x^3), 9, 0.5*10^-5, 10);
Could anyone please help me to get through this?
You can probably use Matlab's fsolve (http://uk.mathworks.com/help/optim/ug/fsolve.html) with a couple of options
x0 = 9;
options = optimoptions('fsolve','Algorithm','levenberg-marquardt','TolFun',5*10^-6,'MaxIter',100);
x = fsolve(#(x)(exp(x) + x^3), x0,options);
or just fzero (http://uk.mathworks.com/help/optim/ug/fzero.html) which implements BD algorithm
x = fzero(#(x)(exp(x) + x^3), x0);

matlab ode23 solver errors unknown

We are trying to model a DC/DC buck converter using matlab's ode23 solver. When we try to run our code the following errors come up:
??? Error using ==> odearguments at 91
The last entry in tspan must be different
from the first entry.
Error in ==> ode23 at 171
[neq, tspan, ntspan, next, t0, tfinal,
tdir, y0, f0, odeArgs, odeFcn, ...
Error in ==> buck2 at 13
[t,x] = ode23(#event1,[t0 tf],x0);
When we take out the code that modifies the initial condition array the code runs without errors but does not produce the expected result.
This is our code:
function buck2
close all
clear all
clc
t0 = 0;
tf = 1;
x0 = [0 0]; % Initial conditions
for i = 1:10
if (1 <= i <= 4),
[t,x] = ode23(#event1,[t0 tf],x0);
nt = length(t);
else
[t,x] = ode23(#event2,[t0 tf],x0);
nt = length(t);
end
t0 = t(nt);
x0 = x(nt);
end
plot(t,x)
function xdot = event1(t,x)
L = (12.12e-6);
C = (19.5e-6);
RC = (2.5*19.5e-6);
xdot = [(24/L) - (x(2)/L); (x(1)/C) - (x(2)/RC)];
function xdot = event2(t,x)
L = (12.12e-6);
C = (19.5e-6);
RC = (2.5*19.5e-6);
xdot = [-(x(2)/L); (x(1)/C) - (x(2)/RC)];
here's the problem:
in the loop, the first iteration:
you call the following
[t,x] = ode23(#event1,[t0 tf],x0);
t0 = 0; and tf = 1;
then further down the loop:
t0 = t(nt); %so t0 = 1;
next for loop iteration:
[t,x] = ode23(#event1,[t0 tf],x0);
in other words:
[t,x] = ode23(#event1,[1 1],x0);
solution:
either modify t0 = t(nt); or update tf with tf = t0 +1;
update:
also, you should correct the following x0 = x(nt,:);