Modeling SIR model in matlab and simulink - matlab

I am trying to model a SIR epidemic model in matlab and simulink. I think I've already done it in matlab but for some reason my simulink model won't work. It just shows straight lines in a scope. This is my function to calculate differential equations.
function dx = sir(t, x)
dx = [0; 0; 0];
beta = .5;
delta = .3;
dx(1) = -beta * x(1) * x(2);
dx(2) = beta * x(1) * x(2) - delta * x(2);
dx(3) = delta * x(2);
end
This is my workspace code to show plot
and this is mu simulink with yields this strange plot and this is after autoscaling with initial conditions set to S = 7900000 and R = 0 and I = 10

The List of Signals property of the summation block that is being fed by the Product3 and Product2 blocks should be |+- instead of |--.

Related

Gradient descent and normal equation not giving the same results, why?

I am working on a simple script that tries to find values for my hypothesis. I am using for one a gradient descent and the second the normal equation. The normal equation is giving me the proper results, but my gradient descent not. I can't figure it out with such a simple case why is not working.
Hi, I am trying to understand why my gradient descend does not match the normal equation on linear regression. I am using matlab to implement both. Here's what I tried:
So I created a dummy training set as such:
x = {1 2 3}, y = {2 3 4}
so my hypothesis should converge to the theta = {1 1} so I get a simple
h(x) = 1 + x;
Here's the test code comparing normal equation and gradient descent:
clear;
disp("gradient descend");
X = [1; 2; 3];
y = [2; 3; 4];
theta = [0 0];
num_iters = 10;
alpha = 0.3;
thetaOut = gradientDescent(X, y, theta, 0.3, 10); % GD -> does not work, why?
disp(thetaOut);
clear;
disp("normal equation");
X = [1 1; 1 2; 1 3];
y = [2;3;4];
Xt = transpose(X);
theta = pinv(Xt*X)*Xt*y; % normal equation -> works!
disp(theta);
And here is the inner loop of the gradient descent:
samples = length(y);
for epoch = 1:iterations
hipoth = X * theta;
factor = alpha * (1/samples);
theta = theta - factor * ((hipoth - y)' * X )';
%disp(epoch);
end
and the output after 10 iterations:
gradient descend = 1.4284 1.4284 - > wrong
normal equation = 1.0000 1.0000 -> correct
does not make sense, it should converge to 1,1.
any ideas? Do I have matlab syntax problem?
thank you!
Gradient Descend can solve a lot of different problems. You want to do a linear regression, i.e. find a linear function h(x) = theta_1 * X + theta_2 that best fits your data:
h(X) = Y + error
What the "best" fit is, is debatable. The most common way to define best fit is to minimize the square of the errors between fit and actual data. Assuming that is what you want ...
Replace the function with
function [theta] = gradientDescent(X, Y, theta, alpha, num_iters)
n = length(Y);
for epoch = 1:num_iters
Y_pred = theta(1)*X + theta(2);
D_t1 = (-2/n) * X' * (Y - Y_pred);
D_t2 = (-2/n) * sum(Y - Y_pred);
theta(1) = theta(1) - alpha * D_t1;
theta(2) = theta(2) - alpha * D_t2;
end
end
and change your parameters a bit, e.g.
num_iters = 10000;
alpha = 0.05;
you get the correct answer. I took the code snippet from here which might also provide a nice starting point to read up on what is actually happening here.
Your gradient descend is solving a different thing than the normal equation, you are not inputing the same data. On top of that you seem to overcomplicate a but the theta update, but that is not a problem. Minor changes in your code result in proper output:
function theta=gradientDescent(X,y,theta,alpha,iterations)
samples = length(y);
for epoch = 1:iterations
hipoth = X * theta;
factor = alpha * (1/samples);
theta = theta - factor * X'*(hipoth - y);
%disp(epoch);
end
end
and the main code:
clear;
X = [1 1; 1 2; 1 3];
y = [2;3;4];
theta = [0 0];
num_iters = 10;
alpha = 0.3;
thetaOut = gradientDescent(X, y, theta', 0.3, 600); % Iterate a bit more, you impatient person!
theta = pinv(X.'*X)*X.'*y; % normal equation -> works!
disp("gradient descend");
disp(thetaOut);
disp("normal equation");
disp(theta);

Spring/Damper Calculation & Plotting

Given two systems with damper/spring:
First system's simulink model with step time 2, final value 0.5:
Simulink of the second system with same input:
I have to find the code using dsolve and ode45 to generate the same graph with Simulink. Given values are:
m1 = 500
c1 = 1200
k1 = 25000
k2 = 15000
m2 = 50
I tried to find dsolve but it couldn't solve it. So I got to use ode45, and I am totally lost.
Differential equation of the first system:
syms x(t) y(t)
Dy = diff(y,t);
Dx = diff(x,t);
D2x = diff(x,2,t);
cond = [x(0)==0, y(0)==0, Dy(0)==0, Dx(0)==5];
eqn33 = D2x + (2*0.2121*0.1414*Dx) + (0.1414^2)*x==2*0.2121*0.1414*Dy+(0.1414^2)*y;
sol33 = dsolve(eqn33,cond)
pretty(sol33)
Answer updated to match Simulink model implementation
To use ode45, you first need to write a function that computes the derivative of you input vector (i.e. your differential equation), and store that function in a separate file with the function name as the filename. Please note that the ode solvers can only solve first-order differential equations, so you first need to do a bit of work to convert your second-order differential equation to a first-order one. For more details, see the documentation on ode45.
Based on what you have done in your Simulink model, D2y is known for all values of t (it's the step input), so we need to integrate it with respect to time to get Dy and y. So our state vector is X = [x; Dx; y; Dy] and our function looks like (stored in diff_eqn.m):
function dX = diff_eqn(t,X)
m1=500;
c=1200;
k1=25000;
dX(1) = X(2); % Dx
dX(2) = -(1/m1)*(c*(X(2)-X(4)/m1) + k1*(X(1)-X(3)/m1));; % D2x
dX(3) = X(4); % Dy
if t<2
dX(4) = 0; % D2y
else
dX(4) = 0.5;
end
as dX = [Dx; D2x; Dy; D2y].
In your script or your MATLAB command window, you can then call the ode solver (initial conditions all being equal to zero for Dx, x, Dy and y, as per your Simulink model):
[t,X] = ode45(#diff_eqn,[0 20],[0; 0; 0; 0]);
Adjust the ode solver options (e.g. max step size, etc...) to get results with more data points. To get the same plot as in your Simulink model, you can then process the results from the ode solver:
D2x = diff(X(:,2))./diff(t);
D2x = [0; D2x];
D2y = zeros(size(D2x));
D2y(t>=2) = 0.5;
plot(t,[D2y 500*D2x])
grid on
xlabel('Time [s]')
legend('D2y','m1*D2x','Location','NorthEast')
Which gives the following plot, matching the results from your Simulink model:

MATLAB - passing a sinusoidal forcing function to ode45

I'm new to Matlab and am really struggling even to get to grips with the basics.
I've got a function, myspring, that solves position and velocity of a mass/spring system with damping and a driving force. I can specify values for the spring stiffness (k), damping coefficient (c), and mass (m), in the command window prior to running ode45. What I am unable to do is to define a forcing function (even something simple like g = sin(t)) and use that as the forcing function, rather than having it written into the myspring function.
Can anyone help? Here's my function:
function pdot = myspring(t,p,c,k,m)
w = sqrt(k/m);
g = sin(t); % This is the forcing function
pdot = zeros(size(p));
pdot(1) = p(2);
pdot(2) = g - c*p(2) - (w^2)*p(1);
end
and how I'm using it in the command window:
>> k = 2; c = 2; m = 4;
>> tspan = linspace(0,10,100);
>> x0 = [1 0];
>> [t,x] = ode45(#(t,p)myspring(t,p,c,k,m),tspan,x0);
That works, but what I want should look something like this (I imagine):
function pdot = myspring(t,p,c,k,m,g)
w = sqrt(k/m);
pdot = zeros(size(p));
pdot(1) = p(2);
pdot(2) = g - c*p(2) - (w^2)*p(1);
end
Then
g = sin(t);
[t,x] = ode45(#(t,p)myspring(t,p,c,k,m,g),tspan,x0);
But what I get is this
In an assignment A(:) = B, the number of elements in A and B must be the same.
Error in myspring (line 7)
pdot(2) = g - c*p(2) - (w^2)*p(1);
Error in #(t,p)myspring(t,p,c,k,m,g)
Error in odearguments (line 87)
f0 = feval(ode,t0,y0,args{:}); % ODE15I sets args{1} to yp0.
Error in ode45 (line 115)
odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options, varargin);
Horchler, thank you for the reply. I can do as you suggested and it works. I am now faced with another problem that I hope you could advise me on.
I have a script that calculates the force on a structure due to wave interaction using Morison's equation. I gave it an arbitrary time span to begin with. I would like to use the force F that script calculates as the input driving force to myspring. Here is my Morison script:
H = 3.69; % Wave height (m)
A = H/2; % Wave amplitude (m)
Tw = 9.87; % Wave period (s)
omega = (2*pi)/Tw; % Angular frequency (rad/s)
lambda = 128.02; % Wavelength (m)
k = (2*pi)/lambda; % Wavenumber (1/m)
dw = 25; % Water depth (m)
Cm = 2; % Mass coefficient (-)
Cd = 0.7; % Drag coefficient (-)
rho = 1025; % Density of water (kg/m^3)
D = 3; % Diameter of structure (m)
x = 0; % Fix the position at x = 0 for simplicity
t = linspace(0,6*pi,n); % Define the vector t with n time steps
eta = A*cos(k*x - omega*t); % Create the surface elevation vector with size equal to t
F_M = zeros(1,n); % Initiate an inertia force vector with same dimension as t
F_D = zeros(1,n); % Initiate a drag force vector with same dimension as t
F = zeros(1,n); % Initiate a total force vector with same dimension as t
fun_inertia = #(z)cosh(k*(z+dw)); % Define the inertia function to be integrated
fun_drag = #(z)(cosh(k*(z+dw)).*abs(cosh(k*(z+dw)))); % Define the drag function to be integrated
for i = 1:n
F_D(i) = abs(((H*pi)/Tw) * (1/sinh(k*dw)) * cos(k*x - omega*t(i))) * ((H*pi)/Tw) * (1/sinh(k*dw)) * cos(k*x - omega*t(i)) * integral(fun_drag,-dw,eta(i));
F_M(i) = (Cm*rho*pi*(D^2)/4) * ((2*H*pi^2)/(Tw^2)) * (1/(sin(k*dw))) * sin(k*x - omega*t(i)) * integral(fun_inertia,-dw,eta(i));
F(i) = F_D(i) + F_M(i);
end
Any further advice would be much appreciated.
You can't pre-calculate your forcing function. It depends on time, which ode45 determines. You need to define g as a function and pass a handle to it into your integration function:
...
g = #(t)sin(t);
[t,x] = ode45(#(t,p)myspring(t,p,c,k,m,g),tspan,x0);
And then call it I n your integration function, passing in the current time:
...
pdot(2) = g(t) - c*p(2) - (w^2)*p(1);
...

system of differential equations with ode45 in matlab

I have got this model for glucose and insulin, and system of differential equations:
Where:
G(t) - the plasma glucose concentration at time t
I(t) - the plasma insulin concentration at time t
X(t)- the interstitial insulin at time t
Gb - the basal plasma glucose concentration
Ib - the basal plasma insulin concentration
which describe the model. I must do an algorithm to estimate parameters with use ode45 in matlab.
Test data is as follows:
I am not sure how write function for ode45, my idea is as follows:
function [] = cwiczenie3_1a(dane)
a=size(dane);
u=[];
y=[];
for i=1:a(1,1)
g(i,1)=dane(i,2);
j(i,1)=dane(i,3);
end
[x t]=ode45(#funkcjajeden,[0 100],[0,0])
end
function [dg] = funkcjajeden(t,g)
gb=350;
d=0.1;
ib=120;
k1=1;
k2=2;
k3=1;
dg=zeros(size(g));
dg(1)=(k1*(gb-g(1)))-d*g(1);
dg(2)=(k2*(g(2)-ib))-k3*d;
end
Taking a look to the documentation for ode45 to solve the system of differential equations you should write the function in a file, odefcn.m in this case:
function dg = odefcn(g,k1,k2,k3,gb,ib,d)
dg = zeros(size(g));
dg(1) = k1*(gb-g(1)) - d*g(1);
dg(2) = k2*(g(2)-ib) - k3*d;
And then in another file you solve it by doing:
gb = 350;
d = 0.1;
ib = 120;
k1 = 1;
k2 = 2;
k3 = 1;
tspan = [0 100];
g0 = [0 0];
[t,g] = ode45(#(t,g) odefcn(g,k1,k2,k3,gb,ib,d), tspan, g0);
plot(t,g(:,1),t,g(:,2))
This way you obtain the values for both G(t) an I(t) for that initial values and parameters:
Image
Then, you can compare to the test data and find the value of the parameters.

How do I solve a third order differential equation using ode23 in MATLAB and plot the step response

I have based my solution off the example provided by Matlab - solving a third order differential equation.
My problem is that I have to solve the third order differential equation, y'''+3y''+2y'+y=4u, by using the ode23 solver and plot the step response.
Here is what I have so far.
function dy = diffuy( t, y )
%Split uy into variables in equation
%y'''+3y''+2y'+y=4u
%Have to take third order equation and convert to 1st order
%y0 = y
%y1 = y0'
%y2 = y1'
%y3 = y2'
%y0' = y1
%y1' = y2
%y2' = y3
%y3' = y''' = -3*y2-2*y1-y0+4*u
%Assume that y(0)= 0, y'(0)=0, y''(0)=0, no initial conditions
u = #(t) heaviside(t);
dy = zeros(4,1);
dy(1) = y(2);
dy(2) = y(3);
dy(3) = y(4);
dy(4) = -3*y(3)-2*y(2)-y(1)+4*u(t);
end
In my main file, I have the code:
[T, Y]=ode23(#diffuy,[0 20],[0 0 0 0]);
figure(1)
plot(T,Y(:,1))
A=[0 1 0;0 0 1; -1 -2 -3]
B=[0;0;4]
C=[1 0 0]
D=[0]
sys4=ss(A,B,C,D)
figure(2)
step(sys4)
The problem I am having is that the step response produced from using the state-space representation commands in MATLAB do not match the step response produced by the ode23, so I assumed that I solved the differential equation incorrectly. Any tips or comments would be very helpful.
Step Response from ss commands:
Step Response from using ode23:
I'm not sure how the linked question got the correct answer because you're actually solving a fourth-order equation using their methodology.
The right hand-side vector given to the ODE suite should only have n entries for an n-order problem.
In your case, the change of variables
results in the third order system
with the initial conditions
.
Changing diffuy to
function dy = diffuy( t, y )
dy = zeros(3,1);
dy(1) = y(2);
dy(2) = y(3);
dy(3) = -3*y(3)-2*y(2)-y(1)+4*u(t);
end
gives a solution that matches the state-space model.