MATLAB - passing a sinusoidal forcing function to ode45 - matlab

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

Related

Slow time integration of system ODE under specific conditions

I am trying to solve the system of ODEs below. I am applying the finite differences to z, so I get a system of ODE that I can solve with a solver like ode45.
The problem is that under the conditions that interest me integration is too slow (time step is very small) and I get no result. I would like to know what is the underlying problem and if there is any way to solve it. I have tried:
using different solvers (tried all of them)
using dimensionless variables
using the pdepe function of Matlab to solve the PDE system directly without applying finite differences myself. Same problem occurs.
Full code (using the parameters that do not work)
function transport_model()
global parameter L Di epsb Q Cfeed K tfinal npz npt F ui h
parameter = [0.044511*432.75 432.75]; % isotherm parameters
L = 0.4; % m, column length
epsb = 0.367; % column bulk porosity
ui = 4e4; % m/s, velocity
Cfeed = 200; % feed concentration
K = 0.0782 % s-1, mass transfer coefficient
tfinal = 400; % min, final time for calculation
npz = 50; % number of discretization points in z
npt = 20;
F = (1-epsb)/epsb;
tspan = 0:tfinal/(npt-1):tfinal;
y0 = zeros(2*npz,1);
h = L/(npz-1);
sol = ode15s(#sedo, tspan, y0);
t = sol.x;
C1 = sol.y(1:npz,:);
q1 = sol.y((npz+1):end,:);
plot(t, C1(end,:))
xlim([0 tfinal])
ylim([0 Cfeed])
function DyDt = sedo(t,y)
global Cfeed K npz F ui h
N = npz;
y(1) = Cfeed;
DyDt = zeros(2*N,1);
% Forward finite differences
DyDt(1) = -ui * 1/(2*h)*(-y(3)+4*y(2)-3*y(1)) - F * K * (y(1) - ilangmuir(y(N+1)));
DyDt(N+1) = K * (y(1) - ilangmuir(y(N+1)));
% Central finite differences
for i=2:N-1
DyDt(i) = -ui * 1/(2*h)*(y(i+1)-y(i-1)) - F * K * (y(i) - ilangmuir(y(N+i)));
DyDt(N+i) = K * (y(i) - ilangmuir(y(N+i)));
end
% Backward finite differences
DyDt(N) = -ui * 1/(2*h)*(3*y(N)-4*y(N-1)+y(N-2)) - F * K * (y(N) - ilangmuir(y(N+N)));
DyDt(2*N) = K * (y(N) - ilangmuir(y(N+N)));
function c = ilangmuir(q)
% langmuir solved for c
global parameter
a = parameter(1);
b = parameter(2);
c = q /(a - b * q);
However, if I try to model a different case (different conditions) I get the correct response. So I am assuming this is a numerical problem caused by the conditions I am trying to model and not an error in the model. For instance, if I use the conditions below I get the correct response.
parameter = [0.044511*432.75 432.75]; % isotherm parameters
L = 0.4; % m, column length
epsb = 0.367; % column bulk porosity
ui = 0.0056; % m/s, velocity
Cfeed = 0.0025; % feed concentration
K = 0.0782 % s-1, mass transfer coefficient
tfinal = 4000; % min, final time for calculation
npz = 50; % number of discretization points in z
npt = 20;

Solving the Damped Harmonic Oscillator ODE as a first order system using midpoint methods

The exact solution of the damped harmonic oscillator
$$x'' + 2\gamma x' + \omega^2 x = 0, \quad x(0)=x_0, \quad x'(0)=-\gamma x_0$$
with $0 < \gamma < \omega$ is
$$x(t)= x_0 e^{-\gamma t} \cos(\beta t) \quad \text{where} \quad \beta:=\sqrt{\omega^2 - \gamma^2}$$
Notice that this second order ODE can be written as a first order system by making the substitutions:
$x' = y$ and,
$y' = -2\gamma y - \omega^2 x$
I want to solve the system using the method:
$$\dfrac{ x_{n+1} - x_{n-1} }{2h} = y_n \quad \quad \dfrac{y_{n+1} - y_{n-1}}{2h} = -2\gamma y_n - \omega^2 x_n.$$
which is an explicit midpoint rule. This is the code that I constructed for the problem, but it is not giving me the correct result. My plot has no harmonic behavior as I would anticipate.
function resonance
omega = 1; % resonant frequency = sqrt(k/m)
a = 0.2; % drag coeficient per unit mass
b = 0.1; % driving amplitude per unit mass
omega0 = 1.2; % driving frequency
tBegin = 0; % time begin
tEnd = 80; % time end
x0 = 0.2; % initial position
v0 = 0.8; % initial velocity
a = omega^2; % calculate a coeficient from resonant frequency
% Use Runge-Kutta 45 integrator to solve the ODE
[t,w] = ode45(#derivatives, [tBegin tEnd], [x0 v0]);
x = w(:,1); % extract positions from first column of w matrix
v = w(:,2); % extract velocities from second column of w matrix
plot(t,x);
title('Damped, Driven Harmonic Oscillator');
ylabel('position (m)');
xlabel('time (s)');
% Function defining derivatives dx/dt and dv/dt
% uses the parameters a, b, A, omega0 in main program but changeth them not
function derivs = derivatives(tf,wf)
xf = wf(1); % wf(1) stores x
vf = wf(2); % wf(2) stores v
dxdt = vf; % set dx/dt = velocity
dvdt = xf + 2 * b * vf + a * tf; % set dv/dt = acceleration
derivs = [dxdt; dvdt]; % return the derivatives
end
end
Also, my apologies about the formatting. I am use to math stackexchange, and the LaTeX style formatting doesn't seem to be applicable here and I do not know how to put my math in the math environment.
You missed a sign, it should be
dvdt = - ( xf + 2 * b * vf + a * tf ); % set dv/dt = acceleration
However, the whole expression is at odds with the previously stated equation,
x'' + 2*b*x' * a*x = 0
should result in
dvdt = - ( 2*b*vf + a*xf ); % set dv/dt = acceleration
But then again you have defined a twice, so change w2=omega^2 to get
dvdt = - ( 2*b*vf + w2*xf + a ); % set dv/dt = acceleration

How to debug this Matlab code to model glider descent?

I have this Matlab project but for some reason I just cannot stop thinking about it because I could not get it to work.
Objective:
This is a MATLAB script that would calculate the change of pressure, temperature and density of a glider that is being dropped from 10000 feet. As it falls, we want to use those new values calculated and then plugged in a function that has 4 equations that need to be differentiated at every point using ode45 as well as the new values of P T and Rho.
Here is the main code:
% HouseKeeping:
clc
clear all
close all
% Constants:
S = 232; % ft^2
Cd0 = 0.02;
K = 0.07;
W = 11000; % lbf
Cl_max = sqrt(Cd0/K);
Cd_max = 2*K*Cl_max^2;
Rho_10000 = .001756; % slugs/ ft^3
%Initial conditions:
t = 0; % Sec
x = 0; % ft
h = 10000; % ft
v = sqrt((2*W)/(Rho_10000*S*Cl_max)); %ft/s
gamma = -Cd_max/Cl_max;
% Find Endurance:
V_RD= sqrt((2*W)/(S* Rho_10000* sqrt(3*Cd0/K)));
RD= V_RD/((sqrt(3*Cd0/K))/(2*Cd0)) ; % ft/s
Endurcance= h/RD; % 958.3515 sec
% Sea Level values:
TSL = 518.69; % Rankine
PSL = 2116.199414; % lbs/ft^2
RhoSL = 0.0023769; % slugs/ft^3
while h > 0
tspan = [t t+1];
i=1;
X = [x;h;v;gamma;Rho_10000];
Time(i)= t;
% Calling ODE45:
[F] = ode45(# D,tspan, X)
% Hight Varying Parameters:
T = TSL - 0.00356616*h;
P = (1.137193514E-11)*(T)^5.2560613;
Rho = (RhoSL * TSL / PASL)*(P / T);
a = 49.0214 * (T)^.5;
H_Del(i) = (-Cd_max/Cl_max)*(plotted_x(i))+10000;
V_Del(i) = sqrt((2*W)/(Rho*S*Cl_max));
Gamma_Del(i) = -Cd_max/Cl_max;
i= i+1;
X = [ x ; H_Del(i); V_Del(i); Gamma_Del(i); Rho];
end
% Plots:
%1
figure (1)
plot(F(:,1),'-r',F(:,3),'-b')
title('Velocity vs Distance');
xlabel('x (ft)');
ylabel('v (ft/s)');
%2
Figure (2)
plot(F(:,1),'-r',F(:,2),'-b')
title('Altitude vs Distance ');
xlabel('x (ft)');
ylabel('h (ft)');
%3
figure (3)
plot(F(:,1),'-r',F(:,4),'-b')
title('Gamma vs Distance');
xlabel('x (ft)');
ylabel('Gamma (rad)');
%4
figure (4)
plot(t,'-r',F(:,3),'-b')
title('Velocity vs Time');
xlabel(' t (s)');
ylabel('v (ft/s)');
%5
figure (5)
plot(t,'-r',F(:,1),'-b')
title(' Distance vs Time ');
xlabel('t (s)');
ylabel('x (ft)');
%6
figure (6)
plot(t,'-r',F(:,4),'-b')
title('Gamma vs Time ');
xlabel('t (s)');
ylabel('Gamma (rad)');
%7
figure (7)
plot(t,'-r',F(:,3),'-b')
title('Velocity vs Time');
xlabel('t (s)');
ylabel('V (ft/s)');
Here is the Function
function [F] = D(X)
% Constants:
S = 232; % ft^2
Cd0 = 0.02;
K = 0.07;
W = 11000; % lbf
Cl_max = sqrt(Cd0/K);
Cd_max = 2*K*Cl_max^2;
Rho_10000 = .001756; % slugs/ ft^3
% Initial conditions:
t = 0; % Sec
x = 0; % ft
h = 10000; % ft
v = sqrt((2*W)/(Rho_10000*S*Cl_max)); % ft/s
gamma = -Cd_max/Cl_max;
g= 32.2; % ft/s^2
% Equations:
X_Pr = X(3)*cos(X(4));
H_Pr = X(3)*sin(X(4));
V_Pr = (-32.2./W)*(0.5*X(5)*Cd_max*S*X(3)^2 + W*sin(X(4)));
G_Pr = (32.2./(W*X(3)))*(0.5*X(5)*Cl_max*S*X(3)^2 - W*cos(X(4)));
F = [X_Pr;H_Pr;V_Pr;G_Pr];
I am not very good with Matlab but I did my very best! I went to my professors for help but they said they were too busy. I even stalked every senior I knew and they all said they did not know how to do it. My next project will be assigned soon and I think that if I cannot do this then I would not be able to do the next one.
Your code produces the following error:
Error using main>D
Too many input arguments.
This means that ode45 tries to call your provided function D with too many input arguments. You should check the desired odefun format in the ode45 documentation: dydt = odefun(t,y)
So, you should change your function declaration of D to
function [F] = D(t, X)
This should solve your first problem, but a following error pops up:
D returns a vector of length 4, but the length of initial conditions
vector is 5. The vector returned by D and the initial conditions
vector must have the same number of elements.
Again, you should check the ode45 documentation. Your function should return the derivatives of all your input variables X: F = dX/dt. You should also return the derivate of the fifth element Rho_10000.
Next, I got some error about undefined variables such as PASL. Probably because you did not post your full code.
Besides of the errors, you should really check your code again. You have written an infinite while loop while h > 0. You never change h in the loop, nor you use the output of ode45 in your loop. Furthermore you always overwrite your i and X value at the beginning of the loop, which is probably not what you want.
This is not a full answer to your question, but I hope you will be able to continue and post smaller, well defined problems, instead of one big problem which is very difficult to answer completely.

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

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.