convolution integral with ode45

162 views (last 30 days)
Angie
Angie on 8 Jun 2019
Edited: Torsten 12 minutes ago
Hi guys, can someone help me solve this equation of motion using ode45 or any other way? I dont know how to approach the convolution integral. Thank you!

Accepted Answer

Star Strider
Star Strider on 8 Jun 2019
Try this:
odefcn = @(t,y,c,F,k,m,w) [y(2); -(k.*y(1) - F.*cos(t.*w) + integral(@(tau)c(t - tau).*y(2).*tau, 0, t))./m];
c = @(t) exp(-t.^2); % Make Something Up
[F,k,m,w] = deal(rand,rand,rand,rand); % Replace With Correct Values
tspan = [0 10];
ics = [1; 1];
[t,y] = ode45(@(t,y)odefcn(t,y,c,F,k,m,w), tspan, ics);
figure
plot(t, y)
hl = legend('$u(t)$', '$\dot{u}(t)$');
set(hl,'Interpreter','latex')
Noite that ‘c’ actually has to be defined as a function in order for this to work. Supply the correct one.
I derived it with the help of the Symbolic Math Toolbox.
  8 Comments
JINGYU KANG
JINGYU KANG on 12 Sep 2023
Star Strider's answer solves the different differential equation. That is,
where the desired equation to solve is as below
One can verify that by letting c(t) = 1 with k = 0, F = 0 for simplicity
David Goodmanson
David Goodmanson on 11 Dec 2025 at 1:16
Edited: David Goodmanson on 11 Dec 2025 at 7:35
Whether you include a factor of tau or not, I believe both of these solutions are incorrect, and every solution along these lines will be incorrect. The term is
Int{0,t} c(t-tau) u'(tau) dtau % u' instead of udot
i.e. a convolution that depends on the past history of u' from 0 to t. Replacing u'(tau) with u'(t) says that u' is a constant factor in the integrand (which it isn't). This gives
Int{0,t)} c(t-tau) u'(t) dtau = u'(t) Int{0,t)} c(t-tau) dtau.
If you attemp to fix this up by inserting tau or any function f(tau) inside the integral, and then do the integration you get
u'(t) Int{0,t} c(t-tau) f(tau) dtau = u'(t) g(t)
for some function g, which is a pointlike expression that does not involve past history of u' at all.
I have never unaccepted someone else's answer but would encourage Star Strider to take a hard look at that answer.

Sign in to comment.

More Answers (3)

Paul
Paul on 7 Dec 2025 at 3:05
Edited: Paul on 11 Dec 2025 at 2:18
If c(t) has a Laplace transform then we can take advantage of the convolution property and convert to the s-domain, solve for U(s), and then convert back to the t-domain. For simple c(t) we can actually get a closed form expression for u(t), though a numerical or vpa solution is more likely going to be needed.
Define the differential equation
syms m k F omega t tau real
syms u(t) c(t)
du(t) = diff(u(t),t);
z(t) = int(c(t-tau)*diff(u(tau),tau),tau,0,t);
eqn = m*diff(u(t),t,2) + z(t) + k*u(t) == F*cos(omega*t)
eqn = 
Take the Laplace transform
Leqn = laplace(eqn)
Leqn = 
Sub in U(s) and C(s)
syms U(s) C(s)
Leqn = subs(Leqn,laplace([u(t),c(t)],t,s),[U(s),C(s)])
Leqn = 
Solve for U(s)
Leqn = isolate(Leqn,U(s))
Leqn = 
At this point we need the expresion for C(s). Assume a simple form of c(t) and sub C(s) into the expression for U(s)
c(t) = exp(-t);
Leqn = subs(Leqn,C,laplace(c(t),t,s))
Leqn = 
Simplify the expression for U(s)
[num,den] = numden(rhs(Leqn));
Leqn = lhs(Leqn) == num/den
Leqn = 
Choose some arbitrary parameters for illustration and sub in
mval = 1; kval = 2; Fval = 3; omegaval = 4;
Leqn = subs(Leqn,[m,k,F,omega,u(0),du(0)],[mval,kval,Fval,omegaval,5,6])
Leqn = 
If we only want a numerical evaluation of the solution, we can just use impulse
figure
[num,den] = numden(rhs(Leqn));
impulse(tf(double(coeffs(num,'all')),double(coeffs(den,'all'))),0:.01:20);grid
Get the solution for u(t)
u(t) = ilaplace(rhs(Leqn),s,t)
u(t) = 
u(t) = rewrite(rewrite(u(t),'expandsum'),'expandroot');
The solution includes some terms in i = sqrt(-1), but we know the solution has to be real. It proved too difficult to simplify u(t) into an expression with only real terms.
Derivative of u(t)
du(t) = diff(u(t),t);
Plot the real and imaginary parts of u(t) to verify the latter is zero, and plot the derivative of u(t)
figure;
fplot([real(u(t)),imag(u(t)),real(du(t))],[0,20]);grid
legend('u(t)','imag(u(t))','du(t)');
Note that u(0) and du(0) satisfy the initial conditions assumed above.
Now verify the solution satisfies the differential equation.
z(t) actually has a closed form expression
z(t) = int(c(t-tau)*du(tau),tau,0,t)
z(t) = 
Subtract the rhs of the differential equation from the lhs and sub in the parameters
check = subs(lhs(eqn) - rhs(eqn),[m,k,F,omega],[mval,kval,Fval,omegaval]);
Sub in the expressions for u(t) and c(t), note we could just set u(t) = real(u(t)) and z(t) = real(z(t)).
check = subs(check);
Check the result at some points in time, the answer should be zero
vpa(subs(check,t,0:10)).'
ans = 
  8 Comments
Paul
Paul 11 minutes ago
I had been thinking about this approach but wanted to avoid having to define the vector of output times a-priori. I'd rather let the solver figure it out (in general, but there could be exceptions). Of course, the approach I illustrated has the same concern if the user wants to specify a full tspan vector. In that case, maybe better to use 2-element tspan and the structure output from ode45 with subesquent calls to deval, but I didn't check into that option.
In the numerical solutions posted in this thread, the convolution in the derivative function assumes linear interpolation of something. Do you think that more accuracy could be obtained by storing the history of u(t), its derivatives, and any other information and somehow using all of that to get better estimates of udot(t) between the stored points for the convolution operation?
Torsten
Torsten about 2 hours ago
Edited: Torsten 19 minutes ago
Do you think that more accuracy could be obtained by storing the history of u(t), its derivatives, and any other information and somehow using all of that to get better estimates of udot(t) between the stored points for the convolution operation?
"trapz" on an equidistant grid has integration order 2.
Maybe "interp1" with the "spline" option if you want to use "integral" for the convolution integral ?
And of course the absolute and relative tolerances for ode45 will influence the number of output points, thus the size of the history vector and thus the accuracy of the convolution integral.

Sign in to comment.


David Goodmanson
David Goodmanson on 13 Dec 2025 at 10:37
Edited: David Goodmanson on 13 Dec 2025 at 10:51
Hi Paul, Torsten et. al.
The code below saves the history of udot in ode45 and then does the convolution. I used delt = 1e-2 as Matt did and the plot is pretty similar. Taking delt down to 1e-4 does not change things very much.
A more accurate method might be available and I will add it to this answer if I can get it to work.
One thing I don't like about the ode solvers is that for e.g a second order ode you get back y and y' but not y'' which you have calculated at great expense in the odefun but can't get to. With this method you could save up the calculated y'' values. The code below just used the saved stuff internally, so accss wasn't a problem. But to get the y'' vales out I can't think of a way other than using a global variable, which is not great, but it would be possible to have a wrapper function that contains the global and then passes the values out from there, so you wouln't have to have a global mucking up the command window.
m = 1;
k = 2;
F = 3;
wF = 4;
a = 1; % c = exp(-a*t)
delt = 1e-2; % step size for the convolution integration
tspan = [0 20];
icond = [5;6];
[t u] = ode45(@(t,u) fun(t,u,m,k,a,delt,F,wF,tspan,icond), tspan, icond);
figure(3); grid on
plot(t,u)
function udot = fun(t,u,m,k,a,delt,F,wF,tspan,icond)
persistent udotstore
persistent tstore
if t == tspan(1)
udotstore = icond(2);
tstore = tspan(1);
G = 0;
else
udotstore = [udotstore u(2)];
tstore = [tstore t];
% sort the times, toss out near-duplcate times
[t1 ind] = sort(tstore);
udot1 = udotstore(ind);
fin = find(diff(t1)<1e-7); % judgment call here
t1(fin) = [];
udot1(fin) = [];
% set up equally spaced time array, do the convolution G
t2 = t1(1):delt:t1(end);
udot2 = interp1(t1,udot1,t2);
c = exp(-a*t2);
G = trapz(t2,flip(c).*(udot2));
end
udot = [0 1; (-k/m) 0]*u -(G/m)*[0;1] + (F/m)*cos(wF*t)*[0;1];
end
  4 Comments
Torsten
Torsten on 13 Dec 2025 at 13:56
Edited: Torsten on 13 Dec 2025 at 13:56
As said: not the ODE function, but an OutputFcn function should be used to store the values for u.
OutputFcn is called for increasing values of t and only after a basic integration steps has successfully finished (thus when u really contains the solution of the ODE at time t).
Paul
Paul about 4 hours ago
Edited: Paul about 4 hours ago
I didn't see this comment before I prepared and submitted mine. I see that we both have the same fundamental concern (I think).
I did not think of using an OutputFcn.
I think the derivative function can include additional arguments, which won't be used by the ode solver, but can be used in a call from the OutputFcn to pass data from the OutputFcn to the derivative function for the derivative function to store persistently. Don't see why that wouldn't work.
Or the state data could be stored persistently in the OutputFcn and it could be called from the derivative function with an optional second argument and specific value of flag or a fourth argument to return the stored state data. I think that should work too.

Sign in to comment.


Sam Chak
Sam Chak about 1 hour ago
In the past few days, I have been closely following the discussions on this intriguing topic of solving the integro-differential equation that involves a convolution integral term using the ode45 solver. It seems challenging to define the time-shifted dummy variable τ, which serves as a temporary placeholder for integration in the ODE function, as pointed out by @Star Strider.
I commend everyone for their contributions, including @JINGYU KANG, who revived this unsolved problem, and @David Goodmanson, who initially implemented storing the historical solutions from ode45 needed to perform the convolution. I would also like to especially recognize @Paul for developing solutions using the Laplace transform method, the fixed-step RK4 method, and the OutputFcn method (under @Torsten's insightful suggestion).
Here is my take: I initially wondered if the product of functions in the convolution integral term could be decomposed using integration by parts, a common mathematical technique that we all learned in high school calculus.
The idea eventually evolved into a mathematical technique inspired by integration by substitution.
Methodology:
The mass-spring-damper system is given by:
where is the convolution integral term.
If the damping function, is differentiable or Laplace transformable, we can introduce an auxiliary variable y to define that
Next, applying Leibniz integral rule for differentiating , we obtain
where the kernel function is
.
Evaluating the two terms:
and
.
Since
it can be rewritten simply as a coupled ODE:
.
Essentially, the integro-differential equation is converted into a coupled ODE system, allowing the ode45 solver to adaptively solve the system.
% Parameters
m = 1; % mass
k = 2; % stiffness
F = 3; % amplitude of the sinusoidal Force
w = 4; % natural angular frequency
% Call ode45 solver
tspan = [0, 20]; % simulation time
icond = [5 % u(0) = 5
6 % u'(0) = 6
0]; % y(0) = 0
[tu, u] = ode45(@(t, u) odefcn(t, u, m, k, F, w), tspan, icond);
% Compare with impulse response
[v, tv] = impulse(tf([5, 11, 94, 179, 176], conv([1, 0, 16], [1, 1, 3, 2])), tspan(2));
% Plot results
figure
hold on
plot(tu, u(:,1), '.')
plot(tv, v)
hold off
grid on
xlabel('Time')
ylabel('Amplitude')
legend('Adaptive ode45', 'Impulse response')
%% Transform the integro-differential equation into a coupled ODE system
function du = odefcn(t, u, m, k, F, w)
du = zeros(3, 1);
du(1) = u(2);
du(2) = 1/m*(F*cos(w*t) - k*u(1) - u(3)); % convolution integral is substituted by u(3) = y
du(3) = u(2) - u(3); % dy/dt = du/dt - y, after applying Leibniz rule
end
  1 Comment
Torsten
Torsten 15 minutes ago
Edited: Torsten 3 minutes ago
Very nice solution.
What a luck that
d/dt (c(t-tau)) = -c(t-tau)
in this specific case :-)
Can you think of a similar approach for a general convolution integral
int_{tau = 0}^{tau = t} c(t-tau) * u(tau) d(tau)
with an arbitrary function c ?

Sign in to comment.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!