convolution integral with ode45

214 ビュー (過去 30 日間)
Angie
Angie 2019 年 6 月 8 日
コメント済み: Paul 約6時間 前
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!

採用された回答

Star Strider
Star Strider 2019 年 6 月 8 日
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 件のコメント
JINGYU KANG
JINGYU KANG 2023 年 9 月 12 日
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 2025 年 12 月 11 日 1:16
編集済み: David Goodmanson 2025 年 12 月 11 日 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.

サインインしてコメントする。

その他の回答 (4 件)

Paul
Paul 2025 年 12 月 7 日 3:05
編集済み: Paul 2025 年 12 月 11 日 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 件のコメント
Paul
Paul 2025 年 12 月 15 日 14:55
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 2025 年 12 月 15 日 15:12
編集済み: Torsten 2025 年 12 月 15 日 16:48
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.

サインインしてコメントする。


David Goodmanson
David Goodmanson 2025 年 12 月 13 日 10:37
編集済み: David Goodmanson 2025 年 12 月 16 日 9:19
******************** MODIFIED ******(**************
because the method suggested here does not work. I took out some useless text but left the basic idea as an example of what not to do.
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 it works.
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
  5 件のコメント
Paul
Paul 2025 年 12 月 13 日 22:17
編集済み: Paul 2025 年 12 月 13 日 22:46
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.
David Goodmanson
David Goodmanson 2025 年 12 月 16 日 9:11
I see that persistent is not going to work. Thanks to Torsten and especially Paul for taking the time to point out the flaws in that idea.
Going back somewhere on this thread I mentioned Matt in conndection with delta t = .01 but I meant to say Torsten.

サインインしてコメントする。


Sam Chak
Sam Chak 2025 年 12 月 15 日 18:56
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
  2 件のコメント
Torsten
Torsten 2025 年 12 月 15 日 20:05
編集済み: Torsten 2025 年 12 月 15 日 20:17
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 ?
Sam Chak
Sam Chak 2025 年 12 月 17 日 13:38
This high-school integration technique clearly does not work for arbitrary functions. If this technique cannot be applied, then the convolution must be evaluated numerically while integrating the ODE function, as demonstrated by @Paul using the OutputFcn method. In theory, this should be analogous to solving a Volterra integral equation. Are there any examples available in the MathWorks Help Center or official documentation?

サインインしてコメントする。


David Goodmanson
David Goodmanson 2025 年 12 月 16 日 9:04
編集済み: David Goodmanson 2025 年 12 月 16 日 22:43
This is a very interesting problem! Convolution of the loss term for the harmonic oscillator. I had been working on some extensions of the same approach that Sam posted so I will post these. If
c = b e^(-at)
G = Int{0,t} b e^(-a(t-tau)) u'(tau) dtau
then
(d/dt + a) G(t) = b u'(t)
and the system consists of that result combined with
mu'' + G + ku = F cos(wt)
Let
y = [u u' G]' % two different uses of '
The odefun is
ydot = [ 0 1 0
-k/m 0 -1/m
0 b -a ] y + (F/m) cos(wt) [0 1 0]'
with initial condition G(0) = 0, all of which was covered by Sam. An advantage of this method is that as well as u and u' you get the convolution integral as a function of time.
In everything below, the initial condition for every G is zero.
Some generalizations of c are possible. These are sums of functions of the form
% b t^n e^(-at)
which include e.g.
% b1 e^(-a1 t) + b2 e^(-a2 t) + b3 e^(-a3 t) .... sum of exponentials b)
% ( ... b3 t^3 + b2 t^2 + b1 t + b0 ) e^(-a t) polymomials a)
and mixtures of those. If additional easily calculated c functions don't come around, then one task would be to fit an arbitrary c function to sums of these functions There are more possibilites for success there than it might seem. For example in addition to [ t e^(-at) ], the function [ e^(-a1 t) - e^(-a2 t) ] also equals 0 at the origin and has one peak.
a) For polynomials you can define the convolutions
G_n = Int{0,t} b (t-tau)^n e^(-a(t-tau)) u'(tau) dtau
in which case
(d/dt + a) G_n) = n G_(n-1)
(d/dt + a) G_0) = b u' % as before
For a fourth degree polynomial with
y = [u u' G4 G3 G2 G1 G0]'
then after a straightforward process the odefun looks like
ydot= [ 0 1 0 0 0 0 0
-k/m 0 -1/m 0 0 0 0
0 b4 -a 1 0 0 0
0 b3 0 -a 1 0 0
0 2b2 0 0 -a 1 0
0 6b1 0 0 0 -a 1
0 24b0 0 0 0 0 -a] y + (F/m) cos(wt) [0 1 0 0 0 0 0]'
A better loooking result is obtained by rescaling the G's with
Gnew_n = Gold_n / (4-n)!
in which case
ydot= [ 0 1 0 0 0 0 0
-k/m 0 -1/m 0 0 0 0
0 b4 -a 1 0 0 0
0 b3 0 -a 2 0 0
0 b2 0 0 -a 3 0
0 b1 0 0 0 -a 4
0 b0 0 0 0 0 -a] y + (F/m) cos(wt) [0 1 0 0 0 0 0]'
b) An easier process is the sums of terms of the same type. For e.g. three exponentials the odefun is
ydot = [ 0 1 0 0 0
-k/m 0 -1/m -1/m -1/m
0 b1 -a1 0 0 ]
0 b2 0 -a2 0 ]
0 b3 0 0 -a3 ] y + (F/m) cos(wt) [0 1 0 0 0]'
  4 件のコメント
David Goodmanson
David Goodmanson 約8時間 前
編集済み: David Goodmanson 約7時間 前
Adding the 1 to make c positive seems like a good idea since if c has some negative regions one might run the risk that the convolution goes negative and sets the oscillator into exponential growth.
I wasn't sure if you mean you used the complex form and combined terms within the odefun, or whether you ran the original ode with a force of (F/m)*exp(i*w*t) and took the real part afterwards, which is legit since all the operations in the set of equations are real.
Paul
Paul 約6時間 前
I used the complex form of c(t) = 1 + cos(t). Even though c(t) has two exponential terms that correspond to two G states, those G states are conjugates so the ode only needs to be augmented with one additional (complex-valued) state variable. The constant in c(t) can be handled explicitly.
Code below is for c(t) = 1 + cos(2*t) and includes commented lines for an earlier version that computed both G states.
m = 1; k = 2; F = 3; omega = 4;
u0 = 5; udot0 = 6;
syms t tau
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);
syms U(s) C(s)
Leqn = laplace(eqn);
Leqn = subs(Leqn,laplace([u(t),c(t)],t,s),[U(s),C(s)]);
Leqn = subs(Leqn,[u(0),du(0)],[u0,udot0]);
Leqn = isolate(Leqn,U(s));
[num,den] = numden(rhs(Leqn));
Leqn = lhs(Leqn) == num/expand(den);
c(t) = (1 + cos(2*t));
C(s) = laplace(c(t),t,s);
Leqn = subs(Leqn);
[num,den] = numden(rhs(Leqn));
Leqn = lhs(Leqn) == num/den;
[num,den] = numden(rhs(Leqn));
[uimp,timp] = impulse(tf(double(coeffs(num,'all')),double(coeffs(den,'all'))),20);
[t,u] = ode45(@(t,u) odefun(t,u,m,k,F,omega,u0),[0,20],[u0;udot0;0]);
figure
plot(timp,uimp,t,u(:,1),'.'),grid
legend('Laplace','ode45')
function udot = odefun(t,u,m,k,F,omega,u0)
% c(t) = 1 + cos(2*t)
% exponential form of cos(2*t)
% cos(2*t) = exp(-t*2i)/2 + exp(t*2i)/2
a1 = -2i; b1 = 1/2;
%a2 = 2i; b2 = 1/2;
% convolution with constant term
% int(1*udot(tau),tau,0,t) = u(t) - u(0)
udot = zeros(3,1);
udot(1) = u(2);
%udot(2) = (F*cos(omega*t) - k*u(1) - (u(1)-u0) - real(u(3) + u(4)))/m;
udot(2) = (F*cos(omega*t) - k*u(1) - (u(1)-u0) - 2*real(u(3)))/m;
udot(3) = -a1*u(3) + b1*u(2);
%udot(4) = -a2*u(4) + b2*u(2);
end

サインインしてコメントする。

カテゴリ

Help Center および File ExchangeEquation Solving についてさらに検索

Community Treasure Hunt

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

Start Hunting!

Translated by