我在 C 中实现了一个 Matlab 脚本的等效版本。为了运行 ode45,我选择了 GNU 科学库。但是 ode45 为每个版本生成不同的输出。我已经工作了一段时间,但我无法找到问题所在。我使用 gsl_odeiv2_driver_apply_fixed_step 进行与 Matlab 中相同的步骤。
Matlab 脚本
function ExpoGrowthEqn
% code to solve the exponential growth equation
% dN/dt = r*N, N(0)=N0
% parameter values
r=0.2;
N0=10;
% numerical parameters
step=0.25;
tspan=[0:step:10];
% EXACT solution is: N(t)=N0 * exp(r*t)
for i=1:length(tspan)
N(i,1)=N0*exp(r*tspan(1,i));
end
plot(tspan,N,'ob') %plots EXACT solution
hold on
% solve ODE using ode45
options = odeset('RelTol',1e-12,'AbsTol',1e-12);
[t y] = ode45( @growth_eqn, tspan, N0, options, r);
plot(t,y,'-r') %plot APPROXIMATE solution
solutions=[t N y]
end
function dy = growth_eqn(t, y, r)
N=y(1)
dy=r*N;
end
C代码
void fixed_step(void) {
PARAM parameters;
parameters.N = 11500000;
parameters.beta = 0.1;
parameters.gamma = 1/2;
double I0=500.0/parameters.N;
double R0=9000000.0/parameters.N;
double S0=1-I0-R0;
double y[3] = {S0, I0, R0};
gsl_odeiv2_system sys = {func, NULL, 3, ¶meters};
gsl_odeiv2_driver * d = gsl_odeiv2_driver_alloc_y_new (&sys, gsl_odeiv2_step_rkf45, 1e-12, 1e-12, 0);
printf ("=== Initial values ===\n");
printf ("y[0]=%6.15lf y[1]=%6.15lf y[2]=%6.15lf\n", y[0], y[1], y[2]);
int length = 53;
const double step = 0.25;
double ti; double t = 0.0, tant = t;
int i;
for (i = 0; i <= length*(1/step); i++)
{
printf ("%.2f(%3.d) -> t=%.2f %6.15lf %6.15lf %6.15lf\n", (float)tant, i, (float)t, y[0], y[1], y[2]);
tant = t;
int status = gsl_odeiv2_driver_apply_fixed_step (d, &t, step/8, 8, y);
if (status != GSL_SUCCESS)
{
printf ("error, return value=%d\n", status);
}
}
gsl_odeiv2_driver_free (d);
}
Matlab 输出
S I R
------------------------------------------------------------------
0.217347826086956 0.000043478260870 0.782608695652174
0.217347603416592 0.000038578485741 0.782613818097667
0.217347405784518 0.000034229664122 0.782618364551360
0.217347230418583 0.000030370797298 0.782622398784119
0.217347074884551 0.000026948321844 0.782625976793605
...
0.217345850226451 0.000000000007068 0.782654149766481
0.217345850226413 0.000000000006234 0.782654149767354
0.217345850226380 0.000000000005510 0.782654149768110
0.217345850226351 0.000000000004888 0.782654149768761
0.217345850226327 0.000000000004356 0.782654149769316
0.217345850226307 0.000000000003903 0.782654149769790
0.217345850226289 0.000000000003514 0.782654149770197
0.217345850226273 0.000000000003172 0.782654149770554
0.217345850226259 0.000000000002859 0.782654149770881
0.217345850226245 0.000000000002556 0.782654149771198
C 输出
=== Initial values ===
y[0]=0.217347826086956 y[1]=0.000043478260870 y[2]=0.782608695652174
0.00( ) -> t=0.00 0.217347826086956 0.000043478260870 0.782608695652174
0.00( 1) -> t=0.25 0.217347589196436 0.000043715151390 0.782608695652174
0.25( 2) -> t=0.50 0.217347351015482 0.000043953332344 0.782608695652174
0.50( 3) -> t=0.75 0.217347111537070 0.000044192810757 0.782608695652174
0.75( 4) -> t=1.00 0.217346870754133 0.000044433593694 0.782608695652174
...
51.00(205) -> t=51.25 0.217258883883215 0.000132420464611 0.782608695652174
51.25(206) -> t=51.50 0.217258162689554 0.000133141658272 0.782608695652174
51.50(207) -> t=51.75 0.217257437570519 0.000133866777307 0.782608695652174
51.75(208) -> t=52.00 0.217256708504771 0.000134595843055 0.782608695652174
52.00(209) -> t=52.25 0.217255975470856 0.000135328876970 0.782608695652174
52.25(210) -> t=52.50 0.217255238447202 0.000136065900623 0.782608695652174
52.50(211) -> t=52.75 0.217254497412123 0.000136806935703 0.782608695652174
52.75(212) -> t=53.00 0.217253752343811 0.000137552004014 0.782608695652174
在第二列的末尾,数据有很大不同。在 Matlab 中几乎是 0 但不是 C 代码。
Matlab 时间戳
t =
0
0.250000000000000
0.500000000000000
0.750000000000000
1.000000000000000
1.250000000000000
1.500000000000000
1.750000000000000
...
52.250000000000000
52.500000000000000
52.750000000000000
53.000000000000000