How to fix the time step in ODE45
222 vues (au cours des 30 derniers jours)
Afficher commentaires plus anciens
Vahid Jahangiri
le 6 Juil 2018
Commenté : Abla Nevame Edzenunye
le 12 Oct 2022
I want to fix the time step for my ode45 function. The code which I am using is as follows:
dt = 0.02;
tf = 600;
t = dt:dt:tf;
y0 = zeros(14,1);
[tout,yout] = ode45(@OC3_odefull,t,y0);
When I run my code, I have no control over the time step size and ode45 uses an adaptive time step. Is there any way that I can force ode45 to use the time step that I want?
2 commentaires
Jan
le 8 Juil 2018
The "45" means, that each step is calculated with an order 4 and order 5 method. The difference between the results is used to control the step size. It is not meaningful to run an ODE45 method with a fixed step size.
Réponse acceptée
Steven Lord
le 8 Juil 2018
Why do you want to fix the time step?
If you want to find the solution of the system of ODEs at specific times, you don't need to control the time step to do that. Specify the time span vector as a vector with more than two elements and the ODE solver will return the solution at the specified times. [Note that this affects the times at which the solver returns the solution, not the times used by the solver internally.]
If you have a differential equation where the value of the right-hand side depends upon the value of the solution at earlier times (and you're trying to ensure the solver computes the solution at those earlier times) you don't want to use the ordinary differential equation solvers. Use the delay differential equation solvers instead, like dde23 or ddesd.
If there's a different reason you want to control the time step, please say more about that reason.
9 commentaires
Vishesh Mangla
le 18 Juin 2020
Modifié(e) : Vishesh Mangla
le 18 Juin 2020
v 2018a
This is the whole code and you can replicate by just copying. Just try obj.temperature function which takes argument as a vector, so try linspace or [0 .1 .2 ] but still instead of 3 points on the time axis there is all that stuff making the plot dirty.
FiniteElement.m a class
classdef FiniteElement
%FINITEELEMENT Summary of this class goes here
properties
simpson_nodes
N%number of nodes
H% step in x direction
domain % 0 to 1
beta% hyperparameter
%initial conditions
alpha
%analytic solution
exact
f%f(x, t)
%Define boundary conditions
g0 % alpha0
g1 %alphaN
g0dash %alpha'0
g1dash %alpha'N
%stiffness matrices
A
D
% time to calculate at
time_at
end
methods
function obj = FiniteElement(N, beta)
% Constructor initialize all variables
%Parameters Initialization
obj.N = N;
obj.beta = beta;
obj.H = 1 / N; % step in x direction
obj.domain = linspace(0, 1, N + 1);
obj.f = @(x, t) (1 - pi^2 * obj.beta ) * exp(t) * sin(pi * x);
%Set initial conditions here
obj.alpha = sin(pi * obj.domain(2:end - 1));
%Set exact solution here
obj.exact = @(t) exp(t) * obj.alpha;
obj.simpson_nodes = 3*20*obj.N; % number of nodes to be used for
%Define boundary conditions
obj.g0 = @(t) 0;
obj.g1 = @(t) 0;
obj.g0dash = @(t) 0;
obj.g1dash = @(t) 0;
obj = obj.matrices_req();
end
function output = phi(obj, i, x)
% basis functions see live script for better representation
if i == 0
if x >= 0 && x <= obj.H
output = -(x - 1 * obj.H) / obj.H;
else
output = 0;
end
elseif i == obj.N
if x >= (obj.N - 1) * obj.H && x <= obj.N * obj.H
output = (x - (obj.N - 1) * obj.H) / obj.H;
else
output = 0;
end
else
if x >= (i - 1) * obj.H && x <= i * obj.H
output = (x - (i - 1) * obj.H) / obj.H;
elseif x >= i * obj.H && x <= (i + 1) * obj.H
output = -(x - (i + 1) * obj.H) / obj.H;
else
output = 0;
end
end
end
function output = phidash(obj, i, x) % derivative
%derivative of phi
if i == 0
if x >= 0 && x <= obj.H
output = -1 / obj.H;
else
output = 0;
end
elseif i == obj.N
if x >= (obj.N - 1) * obj.H && x <= obj.N * obj.H
output = 1 / obj.H;
else
output = 0;
end
else
if x >= (i - 1) * obj.H && x <= i * obj.H
output = 1 / obj.H;
elseif x >= i * obj.H && x <= (i + 1) * obj.H
output = -1 / obj.H;
else
output = 0;
end
end
end
function output = const(obj, i, t)
% constant in the matrix equation
output = obj.g0dash(t) * simpsons(@(x) obj.phi(i, x) * obj.phi(0, x), 0, 1, obj.simpson_nodes) + ...
obj.g1dash(t) * simpsons(@(x) obj.phi(i, x) * obj.phi(obj.N, x), 0, 1, obj.simpson_nodes) ...
-obj.beta * obj.g0(t) * simpsons(@(x) obj.phidash(i, x) * obj.phidash(0, x), 0, 1, obj.simpson_nodes) + ...
-obj.beta * obj.g1(t) * simpsons(@(x) obj.phi(i, x) * obj.phi(obj.N, x), 0, 1, obj.simpson_nodes)...
+obj.beta*obj.phi(i, 1)*obj.phidash(obj.N, 1)*obj.g1(t)-obj.beta*obj.phi(i, 0)*obj.phidash(0, 0)*obj.g0(t) ;
end
function obj = matrices_req(obj)
% stiffness matrices
obj.A = zeros(obj.N - 1);
obj.D = zeros(obj.N - 1);
for i = 1:obj.N - 1
for j = 1:obj.N - 1
if ismember(abs(i - j), [0, 1])
obj.A(i, j) = simpsons(@(x) obj.phi(i, x) * obj.phi(j, x), 0, 1, obj.simpson_nodes);
obj.D( i, j) = simpsons(@(x) obj.phidash(i, x) * obj.phidash(j, x), 0, 1, obj.simpson_nodes);
end
end
end
end
function derivative_ = dydx(obj, t, y)
% derivative used in ode45
C = zeros(obj.N - 1, 1);
F = zeros(obj.N - 1, 1);
for i = 1:obj.N - 1
C(i) = obj.const(i, t);
F(i) = simpsons(@(x) obj.phi(i, x) * obj.f(x, t), 0, 1, obj.simpson_nodes);
end
derivative_ = obj.A \ (-(-obj.beta * obj.D * y + C) + F);
end
function output = exactsoln(obj, time)
% give exactsolution the same structure as output from ode45
output.x = time;
output.y = [];
for t =output.x
output.y = [output.y obj.exact(t)'];
end
end
function [ApproxTemp, ExactTemp] = temperature(obj, time_at)
% main function to be called to get temperatures
ApproxTemp = ode45(@(t, y) obj.dydx(t, y), time_at, obj.alpha);
ExactTemp = obj.exactsoln(ApproxTemp.x);
end
end
end
simpsons.m
function I = simpsons(f,a,b,n)
h=(b-a)/n;
s = f(a) + f(b);
for i=1:2:n-1
s = s+ 4*f(a+i*h);
end
for i=2:2:n-2
s = s + 2*f(a+i*h);
end
I = h/3 * s;
end
run.m
obj = FiniteElement(8, -1);
[A, E] = obj.temperature([0 .1 .2]);
x = obj.domain;
y = A.x;
[xx, yy] = meshgrid(x, y);
subplot(2, 1, 1);
z = vertcat(arrayfun(obj.g0, A.x), A.y,arrayfun(obj.g1, A.x) )';
heatmap(x, y, z);
colormap(flipud(hot));
title("Approximate Solution");
xlabel("The rod as x-axis");
ylabel("Time");
subplot(2, 1, 2);
z = vertcat(arrayfun(obj.g0, E.x), E.y,arrayfun(obj.g1, E.x) )';
heatmap(x, y, z);
colormap(flipud(hot));
title("Exact Solution");
xlabel("The rod as x-axis");
ylabel("Time");
Run run.m
Vishesh Mangla
le 18 Juin 2020
Sorry, mb. I just saw that there are couple of output formats and the one I was using was the structure output one. My apologies. I should have read the docs more thoroughly.
Plus de réponses (1)
Walter Roberson
le 7 Juil 2018
No, you cannot do that.
Officially, Mathworks only provides variable step solvers for MATLAB use.
Unofficially, see https://www.mathworks.com/matlabcentral/answers/98293-is-there-a-fixed-step-ordinary-differential-equation-ode-solver-in-matlab-8-0-r2012b#answer_107643 for the fixed step routines ode1 through ode5 .
0 commentaires
Voir également
Catégories
En savoir plus sur Ordinary Differential Equations dans Help Center et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!