Using ode45 in Matlab - matlab

I'm trying to simulate the time behavior for a physical process governed by a system of ODEs. When I switch the width of the input pulse from 20 to 19, there is no depletion of the y(1) state, which doesn't make sense physically. What am I doing wrong? Am I using ode45 incorrectly?
function test
width = 20;
center = 100;
tspan = 0:0.1:center+50*(width/2);
[t,y] = ode45(#ODEsystem,tspan,[1 0 0 0]);
plot(t,y(:,1),'k*',t,y(:,2),'k:',t,y(:,3),'k--',t,y(:,4),'k');
hold on;
axis([center-3*(width/2) center+50*(width/2) -0.1 1.1])
xlabel('Time')
ylabel('Relative values')
legend({'y1','y2','y3','y4'});
function dy = ODEsystem(t,y)
k1 = 0.1;
k2 = 0.000333;
k3 = 0.1;
dy = zeros(size(y));
% rectangular pulse
I = rectpuls(t-center,width);
% ODE system
dy(1) = -k1*I*y(1);
dy(2) = k1*I*y(1) - k2*y(2);
dy(3) = k2*y(2) - k3*I*y(3);
dy(4) = k3*I*y(3);
end
end

You are changing the parameters of your your ODEs discontinuously in time. This results in a very stiff system and less accurate, or even completely wrong, results. In this case, because the your ODE is so simple when I = 0, an adaptive solver like ode45 will take very large steps. Thus, there's a high probability that it will step right over the region where you inject the impulse and never see it. See my answer here if you're confused as to why the code in your question misses the pulse even though you've specified tspan to have (output) steps of just 0.1.
In general it is a bad idea to have any discontinuities (if statements, abs, min/max, functions like rectpuls, etc.) in your integration function. Instead, you need to break up the integration and calculate your results piecewise in time. Here's a modified version of your code that implements this:
function test_fixed
width = 19;
center = 100;
t = 0:0.1:center+50*(width/2);
I = rectpuls(t-center,width); % Removed from ODE function, kept if wanted for plotting
% Before pulse
tspan = t(t<=center-width/2);
y0 = [1 0 0 0];
[~,out] = ode45(#(t,y)ODEsystem(t,y,0),tspan,y0); % t pre-calculated, no need to return
y = out;
% Pulse
tspan = t(t>=center-width/2&t<=center+width/2);
y0 = out(end,:); % Initial conditions same as last stage from previous integration
[~,out] = ode45(#(t,y)ODEsystem(t,y,1),tspan,y0);
y = [y;out(2:end,:)]; % Append new data removing identical initial condition
% After pulse
tspan = t(t>=center+width/2);
y0 = out(end,:);
[~,out] = ode45(#(t,y)ODEsystem(t,y,0),tspan,y0);
y = [y;out(2:end,:)];
plot(t,y(:,1),'k*',t,y(:,2),'k:',t,y(:,3),'k--',t,y(:,4),'k');
hold on;
axis([center-3*(width/2) center+50*(width/2) -0.1 1.1])
xlabel('Time')
ylabel('Relative values')
legend({'y1','y2','y3','y4'});
function dy = ODEsystem(t,y,I)
k1 = 0.1;
k2 = 0.000333;
k3 = 0.1;
dy = zeros(size(y));
% ODE system
dy(1) = -k1*I*y(1);
dy(2) = k1*I*y(1) - k2*y(2);
dy(3) = k2*y(2) - k3*I*y(3);
dy(4) = k3*I*y(3);
end
end
See also my answer to a similar question.

Related

Plot step response without using step function

I want to plot the step response. I know that I can use step function with state space equations, but I try to get same results using plot function. Here is my sample of code:
for i=1:201
u(i) = 1;
x1(i+1) = (-(b/J)*x1(i) + (K/J)*x2(i));
x2(i+1) = (-(K/L)*x1(i) - (R/L)*x2(i) + (1/L)*u(i));
y(i) = x1(i);
end
and this is the state space equations:
A = [-b/J K/J
-K/L -R/L];
B = [0
1/L];
C = [1 0];
D = 0;
If i do:
t = 0:1:200;
plot(t, y)
it is not working and I want to have the same results like the step function below:
sys = ss(A,B,C,D);
step(sys)
You can find my state space equation here.
The reason for the mismatch is that sys is a continuous time model, whereas the computation of y treats it as a discrete-time system.
The following is a way of estimating the step-response of a continuous-time system in the discrete-time domain:
% Given from the problem statement
A = [-b/J K/J
-K/L -R/L];
B = [0
1/L];
C = [1 0];
D = 0;
% this is your continuous-time model
sys = ss(A,B,C,D);
% define the sample rate of the equivalent discrete-time model
Ts = 1/10;
% this needs to be something smaller than the time-constants in your model,
% so that you have enough resolution to represent the continuous-time
% signal.
% convert the system to the equivalent discrete-time model
sysd = c2d(sys,Ts);
% define how long a step response you'd like to compute
T = 7;
% this should be long enough to cover the length of the step response
t = 0:Ts:T; % time-grid for the plot
nSmp = length(t); % total number of samples to be computed
% initializations
y = NaN(1, nSmp); % output vector
u = ones(1, nSmp); % unit step input
X = [0; 0]; % state vector, initialized to 0
% compute the samples of the step-response
% (i prefer to use vectorized form to keep the code concise)
for i=1:nSmp
y(i) = sysd.C * X + sysd.D * u(i);
X = sysd.A * X + sysd.B * u(i);
end
% plot continous-time step response
figure;
step(sys);
% plot simulated discrete-time step response
figure;
plot(t, y, 'r')
xlabel('Time (s)');
ylabel('Amplitude');
title('Simulated Step Response');

Mass spring damper calculation in Matlab using Runge Kutta

I get always an Error: Index exceeds matrix dimensions.
Error in rhs (line 13)
xdot_2 = -(b/m)*x(2) - (k/m)*x(1) + force(t)/m;
Error in FinalProject2 (line 20)
result = rhs(100,x0);
I have a mass spring damper system with this to achieve:
Initially releasing it is release and just once it touch the ground, to see what is it’s initial poistion. Then a force is introduced to see how much it compress and reacts. Finally this force is released to see how much time it will take to recover.
Calculate the potential, and kinetic energy of the system (spring gravity and mass)
once the force is removed and until the system stops
Calculate the energy lost by the damping once the force is removed and until the
system stops.
Get the characteristic function of damping of the damper, ie, the function describing
the motion as it decays
Calculate as accurately as posible the crossing points by y (substract the initial
compresion) of the final position y once the force is removed and until the system
stops.
this is my code:
clc, close all, clear *
t_start = 0;
t_end = 1000; %final time in seconds.
t =t_start:0.001:t_end;
k = 1500.0; % as spring constant N/m,
b = 30; %the damping constant Ns/m,
m = 10.0; %the mass of the device,
F = 0.0; %as the input force N
g = 9.81; %as the gravity constant m/s^2
initial_position = 0;
initial_speed = 0;
x0 = [initial_position initial_speed];
result = rhs(100,x0);
with this as my rhs function:
function xdot=rhs(t,x)
k = 1500.0; % as spring constant N/m,
b = 30; %the damping constant Ns/m,
m = 10.0; %the mass of the device,
force = 0.0; %as the input force N
%g = 9.81; %as the gravity constant m/s^2
xdot_1 = x(2);
xdot_2 = -(b/m)*x(2) - (k/m)*x(1) + force(t)/m;
xdot = [xdot_1 ; xdot_2 ];
end
so what I am doing wrong? Can someone help me by calculating those values? Would be a great help :)
EDIT: my RK function:
% Classical fourth-order Runge-Kutta method
function [t,y] = rk(yprime, tspan, y0, h)
t0 = tspan(1); tfinal = tspan(end);
% set up the t values at which we will approximate the solution
t = [t0:h:tfinal]';
% include tfinal even if h does not evenly divide tfinal-t0
if t(end)~=tfinal, t=[t tfinal]; end
m = length(t);
y = [y0 zeros(length(y0), length(t)-1)];
for i=1:(m-1)
k1 = feval(yprime,t(i),y(:,i));
k2 = feval(yprime,t(i)+0.5*h, y(:,i)+(h.*k1)/2);
k3 = feval(yprime,t(i)+0.5*h, y(:,i)+(h.*k2)/2);
k4 = feval(yprime,t(i)+h, y(:,i)+h.*k3);
y(:,i+1) = y(:,i)+(h*(k1+2*k2+2*k3+k4))/6;
end
and I call it with this:
yprime=rk(#(t,x) rhs(t,x,force));
tspan = [0 10];
y0 = 0;
h = 0.1;
[t,y] = rk(yprime, tspan, y0, h);
figure(1), clf
plot(t,y,'b.','markersize',15);

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);
...

Implement finite difference method in matlab

I am trying to implement the finite difference method in matlab. I did some calculations and I got that y(i) is a function of y(i-1) and y(i+1), when I know y(1) and y(n+1). However, I don't know how I can implement this so the values of y are updated the right way. I tried using 2 fors, but it's not going to work that way.
EDIT
This is the script and the result isn't right
n = 10;
m = n+1;
h = 1/m;
x = 0:h:1;
y = zeros(m+1,1);
y(1) = 4;
y(m+1) = 6;
s = y;
for i=2:m
y(i) = y(i-1)*(-1+(-2)*h)+h*h*x(i)*exp(2*x(i));
end
for i=m:-1:2
y(i) = (y(i) + (y(i+1)*(2*h-1)))/(3*h*h-2);
end
The equation is:
y''(x) - 4y'(x) + 3y(x) = x * e ^ (2x),
y(0) = 4,
y(1) = 6
Thanks.
Consider the following code. The central differential quotient is discretized.
% Second order diff. equ.
% y'' - 4*y' + 3*y = x*exp(2*x)
% (y(i+1)-2*y(i)+y(i-1))/h^2-4*(y(i+1)-y(i-1))/(2*h) + 3*y(i) = x(i)*exp(2*x(i));
The solution region is specified.
x = (0:0.01:1)'; % Solution region
h = min(diff(x)); % distance
As said in my comment, using this method, all points have to be solved simultaneously. Therefore, above numerical approximation of the equation is transformed in a linear system of euqations.
% System of equations
% Matrix of coefficients
A = zeros(length(x));
A(1,1) = 1; % known solu for first point
A(end,end) = 1; % known solu for last point
% y(i) y'' y
A(2:end-1,2:end-1) = A(2:end-1,2:end-1)+diag(repmat(-2/h^2+3,[length(x)-2 1]));
% y(i-1) y'' -4*y'
A(1:end-1,1:end-1) = A(1:end-1,1:end-1)+diag(repmat(1/h^2+4/(2*h),[length(x)-2 1]),-1);
% y(i+1) y'' -4*y'
A(2:end,2:end) = A(2:end,2:end)+diag(repmat(1/h^2-4/(2*h),[length(x)-2 1]),+1);
With the rhs of the differential equation. Note that the known values are calculated by 1 in the matrix and the actual value in the solution vector.
Y = x.*exp(2*x);
Y(1) = 4; % known solu for first point
Y(end) = 6; % known solu for last point
y = A\Y;
Having an equation to approximate the first order derivative (see above) you can verify the solution. (note, ddx2 is an own function)
f1 = ddx2(x,y); % first derivative (own function)
f2 = ddx2(x,f1); % second derivative (own function)
figure;
plot(x,y);
saveas(gcf,'solu1','png');
figure;
plot(x,f2-4*f1+3*y,x,x.*exp(2*x),'ko');
ylim([0 10]);
legend('lhs','rhs','Location','nw');
saveas(gcf,'solu2','png');
I hope the solution shown below is correct.

Solving ODEs with Matlab, with varying Parameters

Lets say I have a simple logistic equation
dx/dt = 2ax(1 - x/N)
where N is the carrying capacity, a is some growth rate, and both a and N are parameters I'd like to vary.
So what I want to do is to plot a 3D graph of my fixed point and the two parameters.
I understand how to find a fixed point of a single parameter.
Here is my sample code
function xprime = MyLogisticFunction(t,X) %% The ODE
% Parameters
N = 10 % Carrying Capacity
a = 0.5 % Growth Rate
x1prime = 2*a*X(1)*(1 - X(1)/N );
xprime = [x1prime ]';
end
Next my solver
% Initial Number
x0 = 0.4;
%Time Window
tspan=[0 100];
[t,x]=ode45(#MyLogisticFunction,tspan,x0);
clf
x(end,1) % This gives me the fixed point for the parameters above.
So my real question is, how do I put a for loop across two functions, that allows me to vary a and N, so that I can plot out a 3D graph of a and N and my fixed point x*.
I've tried combining both functions into one .m file but it does not seem to work
You need to pass the parameters to your function:
function xprime = MyLogisticFunction(t,X,a,N) %% The ODE
% Parameters (passed as function arguments)
% N = 10 % Carrying Capacity
% a = 0.5 % Growth Rate
x1prime = 2*a*X(1)*(1 - X(1)/N );
xprime = [x1prime ]';
end
and then when you call the ode solver:
% Initial Number
x0 = 0.4;
%Time Window
tspan=[0 100];
a = 0.1:0.1:1; % or whatever
N = 1:10; % or whatever
x_end = zeros(length(a),length(N));
for ii = 1:length(a)
for jj = 1:length(N)
[t,x]=ode45(#(t,X)MyLogisticFunction(t,X,a(ii),N(jj)),tspan,x0);
x_end(ii,jj) = x(end,1);
end
end