云计算百科
云计算领域专业知识百科平台

2026年数学建模美赛 常用模型算法 常微分方程在数学建模中的应用:从人口增长到传染病动力学

2026美赛期间会持续更新相关内容,所有内容会发布到专栏内,会结合最新的chatgpt发布,只需订阅一次,赛后两天半价,内容达不到所有人预期,请勿盲目订阅!!!无论文!无论文!!!

摘要

常微分方程(Ordinary Differential Equations, ODEs)作为描述系统动态演化的数学工具,在数学建模中占据核心地位。本文从数学建模竞赛的实用视角出发,系统阐述ODE在人口增长和传染病SIR模型中的应用。首先,深入探讨ODE的核心思想与数学模型,包括基本概念、分类和解的结构特性。其次,分析ODE在建模竞赛中的适用场景与典型赛题类型。接着,详细说明具体建模步骤与关键技巧,并提供常用求解工具和代码示例。然后,通过一个完整的美赛简化案例展示ODE建模的全过程。最后,评估该方法的优缺点并提出改进方向。本文旨在为数学建模竞赛参与者提供ODE建模的系统性指导,提升解决实际动态系统问题的能力。

关键词:常微分方程;数学建模;人口增长;SIR模型;传染病动力学;数值求解


1. 核心思想与数学模型

1.1 常微分方程基本概念

常微分方程是描述未知函数与其导数之间关系的方程,其中未知函数仅依赖于一个自变量。在数学建模中,时间t常作为自变量,而系统状态变量(如人口数量、感染人数等)作为因变量。ODE的一般形式为:

F(t,y,y′,y′′,…,y(n))=0F(t,y,y′,y′′,…,y(n))=0

其中y=y(t)y=y(t)是未知函数,y′,y′′,…,y(n)y′,y′′,…,y(n)是其关于t的各阶导数。

对于n阶ODE,若存在形式:

y(n)=f(t,y,y′,…,y(n−1))y(n)=f(t,y,y′,…,y(n−1))

则称为显式ODE。初值问题的提法为:在给定初始条件y(t0)=y0,y′(t0)=y0′,…,y(n−1)(t0)=y0(n−1)y(t0​)=y0​,y′(t0​)=y0′​,…,y(n−1)(t0​)=y0(n−1)​下,求解满足ODE的函数y(t)y(t)。

1.2 人口增长模型

1.2.1 Malthus模型(指数增长模型)

马尔萨斯于1798年提出的人口增长模型基于一个基本假设:人口增长率与当前人口数量成正比。该模型表示为:

dPdt=rPdtdP​=rP

其中:

  • P(t)P(t):t时刻的人口数量

  • rr:内禀增长率(出生率与死亡率之差)

  • tt:时间

给定初始条件P(0)=P0P(0)=P0​,可得解析解:

P(t)=P0ertP(t)=P0​ert

该模型预测人口将呈指数增长,适用于资源充足、无限制环境下的短期人口预测。但长期来看,资源限制会使增长放缓,与实际观测不符。

1.2.2 Logistic模型(阻滞增长模型)

1838年,Verhulst提出Logistic模型以修正Malthus模型的缺陷,引入环境承载力K的概念:

dPdt=rP(1−PK)dtdP​=rP(1−KP​)

其中:

  • KK:环境承载力(最大可持续人口数量)

  • 因子(1−P/K)(1−P/K):环境阻力项,随P接近K而减小

该方程可分离变量求解:

dPP(1−P/K)=r dtP(1−P/K)dP​=rdt

积分得:

P(t)=K1+(K−P0P0)e−rtP(t)=1+(P0​K−P0​​)e−rtK​

Logistic曲线呈S形:初始近似指数增长,随后增长放缓,最终趋于稳定值K。该模型更符合实际观测,广泛应用于生态学、经济学等领域。

1.2.3 改进的人口增长模型

实际应用中,可根据具体情况对Logistic模型进行改进:

  • 时变承载力模型:K=K(t)K=K(t),反映环境变化

    dPdt=rP(1−PK(t))dtdP​=rP(1−K(t)P​)

  • 时变增长率模型:r=r(t)r=r(t),反映政策、技术等因素

    dPdt=r(t)P(1−PK)dtdP​=r(t)P(1−KP​)

  • 带Allee效应的模型:种群密度过低时增长率为负

    dPdt=rP(PA−1)(1−PK),0<A<KdtdP​=rP(AP​−1)(1−KP​),0<A<K

  • 考虑年龄结构的模型:将人口按年龄分组,建立方程组

    ∂P(a,t)∂t+∂P(a,t)∂a=−μ(a,t)P(a,t)∂t∂P(a,t)​+∂a∂P(a,t)​=−μ(a,t)P(a,t)

    其中P(a,t)P(a,t)表示t时刻年龄为a的人口密度。

  • 1.3 传染病SIR模型

    1.3.1 经典SIR模型

    Kermack和McKendrick于1927年提出的SIR模型是传染病动力学的基础。模型将人群分为三类:

    • 易感者(Susceptible, S):可能被感染的健康个体

    • 感染者(Infected, I):已感染且能传播疾病的个体

    • 移出者(Removed, R):康复并获得免疫力或死亡的个体

    模型假设如下:

  • 总人口数N=S+I+RN=S+I+R恒定(不考虑出生、死亡和迁移)

  • 均匀混合:个体随机接触

  • 感染率与SI乘积成正比

  • 恢复率与I成正比

  • 模型方程:

    dSdt=−βSINdIdt=βSIN−γIdRdt=γIdtdS​dtdI​dtdR​​=−βNSI​=βNSI​−γI=γI​

    其中:

    • ββ:感染率(有效接触率)

    • γγ:恢复率(恢复率的倒数为平均感染期1/γ1/γ)

    1.3.2 基本再生数R0R0​

    基本再生数R0R0​是传染病动力学的关键参数,表示一个感染者在完全易感人群中引起的平均新感染数。对于SIR模型:

    R0=βγR0​=γβ​

    • 若R0>1R0​>1,疾病可能流行

    • 若R0<1R0​<1,疾病逐渐消失

    • R0=1R0​=1是疾病传播的阈值

    1.3.3 SIR模型的扩展

    实际应用中常对SIR模型进行扩展:

  • SEIR模型:增加潜伏期人群(Exposed, E)

    dSdt=−βSINdEdt=βSIN−σEdIdt=σE−γIdRdt=γIdtdS​dtdE​dtdI​dtdR​​=−βNSI​=βNSI​−σE=σE−γI=γI​

    其中σσ为潜伏期到发病的转移率。

  • SIS模型:康复后无免疫力,重新变为易感者

    dSdt=−βSIN+γIdIdt=βSIN−γIdtdS​dtdI​​=−βNSI​+γI=βNSI​−γI​

  • 考虑人口动力学的SIR模型:包含出生和死亡

    dSdt=μN−βSIN−μSdIdt=βSIN−γI−μIdRdt=γI−μRdtdS​dtdI​dtdR​​=μN−βNSI​−μS=βNSI​−γI−μI=γI−μR​

    其中μμ为出生率和死亡率(假设相等)。

  • 空间异质性模型:考虑空间扩散

    ∂S∂t=DS∇2S−βSI∂t∂S​=DS​∇2S−βSI∂I∂t=DI∇2I+βSI−γI∂t∂I​=DI​∇2I+βSI−γI

    其中DS,DIDS​,DI​为扩散系数。

  • 1.3.4 模型分析与相平面

    对于SIR模型,注意到dS/dt+dI/dt+dR/dt=0dS/dt+dI/dt+dR/dt=0,故总人口守恒。定义相对比例s=S/N,i=I/N,r=R/Ns=S/N,i=I/N,r=R/N,则:

    dsdt=−βsididt=βsi−γidrdt=γidtds​dtdi​dtdr​​=−βsi=βsi−γi=γi​

    相平面分析可在s−is−i平面进行。由前两式得:

    dids=−1+γβs=−1+1R0sdsdi​=−1+βsγ​=−1+R0​s1​

    积分得:

    i(s)=(1−s)+1R0ln⁡(ss0)i(s)=(1−s)+R0​1​ln(s0​s​)

    其中s0s0​为初始时刻的s值。由此可分析疾病最终规模。


    2. 适用场景与典型赛题类型

    2.1 ODE建模的适用场景

    ODE适用于描述连续时间动态系统,特别是:

  • 种群动力学:人口增长、物种竞争、捕食-被捕食关系

  • 流行病学:传染病传播、信息传播、谣言扩散

  • 生态学:生态系统演化、污染物扩散

  • 物理学:物体运动、电路分析、热传导

  • 经济学:经济增长、市场均衡、投资决策

  • 社会学:观点传播、社会网络演化

  • 药理学:药物代谢、药代动力学

  • 环境科学:污染物浓度变化、碳循环

  • 2.2 数学建模竞赛中的典型赛题类型

    2.2.1 人口相关问题
  • 人口预测与规划:给定历史数据,预测未来人口,评估政策效果

  • 老龄化问题:考虑年龄结构,分析养老金、医疗资源需求

  • 资源承载分析:结合资源限制,确定可持续人口规模

  • 移民影响评估:研究移民对人口结构、经济发展的影响

  • 真题示例:2019年美赛C题"毒品问题"涉及药物使用者数量变化,可用类似传染病模型建模。

    2.2.2 传染病相关问题
  • 疫情预测:基于早期数据预测疫情发展趋势

  • 干预措施评估:隔离、疫苗接种、社交距离等措施效果分析

  • 医疗资源需求:预测病床、呼吸机等医疗资源需求峰值

  • 疫苗分配策略:有限疫苗资源下的最优分配方案

  • 多群体传播:考虑年龄、职业等不同群体的传播差异

  • 真题示例:2020年美赛D题"团队合作策略"可借鉴传染病模型研究合作行为传播;2021年美赛D题"音乐影响"可用SIR类模型研究音乐偏好传播。

    2.2.3 生态与环境问题
  • 物种竞争:Lotka-Volterra竞争模型

    dN1dt=r1N1(1−N1+α12N2K1)dN2dt=r2N2(1−N2+α21N1K2)dtdN1​​dtdN2​​​=r1​N1​(1−K1​N1​+α12​N2​​)=r2​N2​(1−K2​N2​+α21​N1​​)​

  • 捕食-被捕食关系:Lotka-Volterra捕食模型

    dHdt=rH−aHPdPdt=ϵaHP−mPdtdH​dtdP​​=rH−aHP=ϵaHP−mP​

    其中H为猎物,P为捕食者。

  • 污染物扩散:多介质环境中的污染物迁移转化

  • 2.2.4 社会经济问题
  • 技术创新扩散:Bass模型描述新产品、新技术采纳

    dN(t)dt=p[M−N(t)]+qMN(t)[M−N(t)]dtdN(t)​=p[M−N(t)]+Mq​N(t)[M−N(t)]

    其中p为创新系数,q为模仿系数,M为市场潜力。

  • 谣言传播:类似传染病模型,但考虑遗忘机制

  • 经济周期:用动力学方程描述经济增长波动

  • 2.3 赛题识别与建模选择

    面对赛题时,识别是否适用ODE建模的关键指标:

  • 系统状态随时间连续变化

  • 变化率依赖于当前状态

  • 忽略空间异质性或可简化为均值场

  • 随机效应不占主导地位

  • 若系统离散性明显或随机性占主导,应考虑差分方程或随机过程模型。


    3. 具体建模步骤与关键技巧

    3.1 ODE建模的一般步骤

    步骤1:问题分析与假设建立
  • 明确研究问题:确定需要预测、解释或优化的目标

  • 识别系统要素:确定状态变量、参数和控制变量

  • 建立合理假设:简化现实,使问题可处理

    • 均匀混合假设

    • 忽略随机波动

    • 参数恒定性假设

    • 封闭系统假设

  • 确定模型类型:根据问题特点选择合适模型框架

  • 步骤2:变量定义与方程建立
  • 定义状态变量:选择恰当变量描述系统状态

  • 建立流程图:可视化各状态间转移关系

  • 推导微分方程:基于质量守恒、速率平衡等原理

    • 流入率 – 流出率 = 净变化率

  • 确定参数意义:明确每个参数的物理/生物意义

  • 步骤3:参数估计与数据拟合
  • 参数来源:

    • 文献资料

    • 实验数据

    • 统计年鉴

    • 专家经验

  • 估计方法:

    • 最小二乘法

    • 最大似然估计

    • 贝叶斯估计

  • 拟合优度评估:

    • 残差分析

    • R²统计量

    • AIC/BIC准则

  • 步骤4:模型求解与分析
  • 解析求解:适用于简单线性方程

  • 数值求解:Runge-Kutta等数值方法

  • 稳定性分析:平衡点分析,Jacobian矩阵

  • 敏感性分析:参数变化对结果的影响程度

  • 分岔分析:参数变化导致系统定性行为改变

  • 步骤5:结果解释与模型检验
  • 结果解释:将数学结果转化为实际问题解答

  • 模型验证:对比模型预测与实际观测

  • 稳健性分析:改变假设条件,检验结果稳定性

  • 模型改进:根据验证结果修正模型

  • 3.2 关键技巧与注意事项

    3.2.1 无量纲化技巧

    无量纲化可简化方程,减少参数数量,提高数值稳定性。以Logistic方程为例:

    原始方程:dPdt=rP(1−PK)dtdP​=rP(1−KP​)

    令x=PKx=KP​(相对人口),τ=rtτ=rt(无量纲时间),则:

    dxdτ=x(1−x)dτdx​=x(1−x)

    方程简化为单参数形式,便于分析。

    3.2.2 参数敏感性分析

    评估参数不确定性对结果的影响。局部敏感性指数:

    Sp=∂y∂p⋅pySp​=∂p∂y​⋅yp​

    其中y为输出变量,p为参数。全局敏感性分析可采用Sobol指数法。

    3.2.3 相平面分析技巧

    对于二维自治系统:

    dxdt=f(x,y)dydt=g(x,y)dtdx​dtdy​​=f(x,y)=g(x,y)​

  • 寻找平衡点:解f(x,y)=0,g(x,y)=0f(x,y)=0,g(x,y)=0

  • 线性化:在平衡点(x∗,y∗)(x∗,y∗)处计算Jacobian矩阵

    J=[∂f∂x∂f∂y∂g∂x∂g∂y](x∗,y∗)J=[∂x∂f​∂x∂g​​∂y∂f​∂y∂g​​](x∗,y∗)​

  • 稳定性判定:根据特征值实部符号判断稳定性

  • 绘制零倾线:f(x,y)=0f(x,y)=0和g(x,y)=0g(x,y)=0的曲线

  • 3.2.4 数值求解稳定性
  • 步长选择:步长过大会导致不稳定,过小会增加计算量

  • 方法选择:

    • 非刚性系统:经典Runge-Kutta法(如RK4)

    • 刚性系统:隐式方法(如Gear法、BDF法)

  • 误差控制:自适应步长调整,局部截断误差估计

  • 3.2.5 模型比较与选择

    使用信息准则选择最合适模型:

    • AIC(Akaike信息准则):AIC=2k−2ln⁡(L)AIC=2k−2ln(L)

    • BIC(贝叶斯信息准则):BIC=kln⁡(n)−2ln⁡(L)BIC=kln(n)−2ln(L)

    其中k为参数个数,n为数据点数,L为似然函数值。


    4. 常用求解工具/代码示例

    4.1 常用软件工具

  • MATLAB:ode45, ode23, ode15s等求解器

  • Python:SciPy的odeint, solve_ivp

  • R:deSolve包

  • Mathematica:DSolve, NDSolve

  • Julia:DifferentialEquations.jl包

  • 4.2 MATLAB代码示例

    4.2.1 Logistic人口增长模型

    matlab

    % Logistic模型参数
    r = 0.03; % 年增长率
    K = 1000; % 环境承载力(百万)
    P0 = 100; % 初始人口(百万)
    tspan = [0 100]; % 时间范围(年)

    % 定义微分方程
    logisticODE = @(t, P) r * P * (1 – P/K);

    % 数值求解
    [t, P] = ode45(logisticODE, tspan, P0);

    % 解析解对比
    P_analytic = K ./ (1 + (K-P0)/P0 * exp(-r*t));

    % 绘图
    figure('Position', [100, 100, 900, 400])

    subplot(1,2,1)
    plot(t, P, 'b-', 'LineWidth', 2)
    hold on
    plot(t, P_analytic, 'r–', 'LineWidth', 1.5)
    xlabel('时间 (年)', 'FontSize', 12)
    ylabel('人口 (百万)', 'FontSize', 12)
    title('Logistic人口增长', 'FontSize', 14)
    legend('数值解', '解析解', 'Location', 'southeast')
    grid on

    % 绘制相线
    subplot(1,2,2)
    P_range = 0:10:1200;
    dP_dt = r * P_range .* (1 – P_range/K);
    plot(P_range, dP_dt, 'k-', 'LineWidth', 2)
    hold on
    plot([0 K], [0 0], 'k–')
    plot(P0, 0, 'ro', 'MarkerSize', 10, 'MarkerFaceColor', 'r')
    xlabel('人口 P', 'FontSize', 12)
    ylabel('变化率 dP/dt', 'FontSize', 12)
    title('相线图', 'FontSize', 14)
    grid on

    4.2.2 SIR传染病模型

    matlab

    function sir_model_example
    % SIR模型参数
    beta = 0.3; % 感染率
    gamma = 0.1; % 恢复率
    N = 1000; % 总人口

    % 初始条件
    I0 = 1; % 初始感染者
    R0 = 0; % 初始康复者
    S0 = N – I0 – R0; % 初始易感者

    % 时间范围
    tspan = [0 100];
    y0 = [S0; I0; R0];

    % 定义SIR方程
    function dydt = sir_equations(t, y)
    S = y(1);
    I = y(2);
    R = y(3);

    dS_dt = -beta * S * I / N;
    dI_dt = beta * S * I / N – gamma * I;
    dR_dt = gamma * I;

    dydt = [dS_dt; dI_dt; dR_dt];
    end

    % 数值求解
    [t, y] = ode45(@sir_equations, tspan, y0);

    % 计算基本再生数
    R0_value = beta / gamma;

    % 绘图
    figure('Position', [100, 100, 1200, 500])

    % 时间序列图
    subplot(1,2,1)
    plot(t, y(:,1), 'b-', 'LineWidth', 2)
    hold on
    plot(t, y(:,2), 'r-', 'LineWidth', 2)
    plot(t, y(:,3), 'g-', 'LineWidth', 2)
    xlabel('时间 (天)', 'FontSize', 12)
    ylabel('人口数', 'FontSize', 12)
    title(['SIR模型 (R_0 = ', num2str(R0_value, '%.2f'), ')'], 'FontSize', 14)
    legend('易感者S', '感染者I', '康复者R', 'Location', 'best')
    grid on

    % 相平面图 (S-I平面)
    subplot(1,2,2)
    plot(y(:,1), y(:,2), 'k-', 'LineWidth', 2)
    hold on
    scatter(S0, I0, 100, 'ro', 'filled')
    scatter(y(end,1), y(end,2), 100, 'gs', 'filled')

    % 绘制零倾线
    S_range = linspace(0, N, 100);
    I_nullcline = max(0, S_range – gamma/beta * N);
    plot(S_range, I_nullcline, 'r–', 'LineWidth', 1.5)

    xlabel('易感者 S', 'FontSize', 12)
    ylabel('感染者 I', 'FontSize', 12)
    title('SIR模型相平面', 'FontSize', 14)
    legend('轨迹', '起点', '终点', 'I零倾线', 'Location', 'best')
    grid on
    xlim([0 N])
    ylim([0 max(y(:,2))*1.1])

    % 输出关键结果
    fprintf('基本再生数 R0 = %.2f\\n', R0_value);
    fprintf('最终易感者比例: %.2f%%\\n', y(end,1)/N*100);
    fprintf('峰值感染人数: %.0f (发生在第%.1f天)\\n', max(y(:,2)), t(find(y(:,2)==max(y(:,2)),1)));
    end

    4.2.3 带控制的SEIR模型

    matlab

    function controlled_seir_model
    % SEIR模型参数 (以COVID-19为例)
    beta0 = 0.35; % 基础感染率
    sigma = 1/5.2; % 潜伏期到发病的转移率 (潜伏期5.2天)
    gamma = 1/14; % 恢复率 (感染期14天)
    N = 10e6; % 总人口

    % 控制参数
    intervention_day = 30; % 干预开始时间
    effectiveness = 0.6; % 干预效果 (降低接触率60%)

    % 初始条件
    E0 = 100; % 初始潜伏者
    I0 = 50; % 初始感染者
    R0 = 0; % 初始康复者
    S0 = N – E0 – I0 – R0;

    tspan = [0 200];
    y0 = [S0; E0; I0; R0];

    % 定义时变感染率函数
    function beta_t = time_varying_beta(t)
    if t < intervention_day
    beta_t = beta0;
    else
    beta_t = beta0 * (1 – effectiveness);
    end
    end

    % 定义SEIR方程
    function dydt = seir_equations(t, y)
    S = y(1);
    E = y(2);
    I = y(3);
    R = y(4);

    beta = time_varying_beta(t);

    dS_dt = -beta * S * I / N;
    dE_dt = beta * S * I / N – sigma * E;
    dI_dt = sigma * E – gamma * I;
    dR_dt = gamma * I;

    dydt = [dS_dt; dE_dt; dI_dt; dR_dt];
    end

    % 数值求解
    [t, y] = ode45(@seir_equations, tspan, y0);

    % 绘图
    figure('Position', [100, 100, 1400, 500])

    % 时间序列图
    subplot(1,3,1)
    plot(t, y(:,1), 'b-', 'LineWidth', 2)
    hold on
    plot(t, y(:,2), 'm-', 'LineWidth', 2)
    plot(t, y(:,3), 'r-', 'LineWidth', 2)
    plot(t, y(:,4), 'g-', 'LineWidth', 2)

    % 标记干预时间
    xline(intervention_day, 'k–', 'LineWidth', 1.5, 'Label', '干预开始')

    xlabel('时间 (天)', 'FontSize', 12)
    ylabel('人口数', 'FontSize', 12)
    title('带控制的SEIR模型', 'FontSize', 14)
    legend('易感者S', '潜伏者E', '感染者I', '康复者R', 'Location', 'best')
    grid on

    % 新增感染和新增康复
    subplot(1,3,2)

    % 计算每日新增感染 (从E到I)
    new_infections = sigma * y(:,2);
    % 计算每日新增康复 (从I到R)
    new_recoveries = gamma * y(:,3);

    plot(t, new_infections, 'r-', 'LineWidth', 2)
    hold on
    plot(t, new_recoveries, 'g-', 'LineWidth', 2)
    xline(intervention_day, 'k–', 'LineWidth', 1.5)

    xlabel('时间 (天)', 'FontSize', 12)
    ylabel('每日新增人数', 'FontSize', 12)
    title('每日新增感染与康复', 'FontSize', 14)
    legend('新增感染', '新增康复', 'Location', 'best')
    grid on

    % 医疗资源需求估算
    subplot(1,3,3)

    % 假设需要住院的比例和平均住院时间
    hospitalization_rate = 0.15; % 15%感染者需要住院
    avg_hospital_stay = 10; % 平均住院10天

    % 估算每日住院人数 (简化估算)
    daily_hospital = hospitalization_rate * y(:,3);

    % 估算累计住院人数
    cumulative_hospital = zeros(size(t));
    for i = 2:length(t)
    dt = t(i) – t(i-1);
    % 新增住院人数
    new_hospital = hospitalization_rate * (y(i,3) – y(i-1,3) + gamma * y(i,3) * dt);
    % 出院人数 (假设指数衰减)
    discharge = cumulative_hospital(i-1) * dt / avg_hospital_stay;

    cumulative_hospital(i) = max(0, cumulative_hospital(i-1) + new_hospital – discharge);
    end

    plot(t, daily_hospital, 'b-', 'LineWidth', 2)
    hold on
    plot(t, cumulative_hospital, 'r-', 'LineWidth', 2)

    % 假设医疗资源上限
    hospital_capacity = 5000;
    yline(hospital_capacity, 'k–', 'LineWidth', 2, 'Label', '医疗资源上限')
    xline(intervention_day, 'k–', 'LineWidth', 1.5)

    xlabel('时间 (天)', 'FontSize', 12)
    ylabel('住院人数', 'FontSize', 12)
    title('医疗资源需求预测', 'FontSize', 14)
    legend('每日新增住院', '累计住院人数', 'Location', 'best')
    grid on

    % 输出关键结果
    fprintf('干预前R0: %.2f\\n', beta0/gamma);
    fprintf('干预后有效R0: %.2f\\n', beta0*(1-effectiveness)/gamma);
    fprintf('累计感染峰值: %.0f\\n', max(y(:,3)));
    fprintf('医疗资源峰值需求: %.0f (发生在第%.1f天)\\n', max(cumulative_hospital), t(find(cumulative_hospital==max(cumulative_hospital),1)));
    if max(cumulative_hospital) > hospital_capacity
    fprintf('警告: 医疗资源需求超过承载能力!\\n');
    end
    end

    4.3 Python代码示例

    4.3.1 SIR模型与参数拟合

    python

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.integrate import solve_ivp
    from scipy.optimize import curve_fit
    import pandas as pd

    class SIRModel:
    def __init__(self, beta, gamma, N):
    """
    初始化SIR模型

    参数:
    beta: 感染率
    gamma: 恢复率
    N: 总人口
    """
    self.beta = beta
    self.gamma = gamma
    self.N = N
    self.R0 = beta / gamma

    def equations(self, t, y):
    """
    SIR模型微分方程

    参数:
    t: 时间
    y: 状态变量 [S, I, R]

    返回:
    dydt: 导数向量
    """
    S, I, R = y
    dS_dt = -self.beta * S * I / self.N
    dI_dt = self.beta * S * I / self.N – self.gamma * I
    dR_dt = self.gamma * I
    return [dS_dt, dI_dt, dR_dt]

    def simulate(self, S0, I0, R0, t_span, t_eval=None):
    """
    模拟SIR模型

    参数:
    S0: 初始易感者
    I0: 初始感染者
    R0: 初始康复者
    t_span: 时间范围 [t_start, t_end]
    t_eval: 输出时间点

    返回:
    t: 时间数组
    y: 状态矩阵
    """
    y0 = [S0, I0, R0]

    sol = solve_ivp(
    self.equations,
    t_span,
    y0,
    method='RK45',
    t_eval=t_eval,
    dense_output=True
    )

    return sol.t, sol.y

    def fit_to_data(self, time_data, I_data, S0=None, I0=None, R0=None):
    """
    使用实际数据拟合SIR模型参数

    参数:
    time_data: 时间数据
    I_data: 感染者数据
    S0, I0, R0: 初始条件 (如果为None则从数据估计)

    返回:
    popt: 最优参数 [beta, gamma]
    """
    if I0 is None:
    I0 = I_data[0]
    if S0 is None:
    S0 = self.N – I0
    if R0 is None:
    R0 = 0

    def model_function(t, beta, gamma):
    """用于拟合的模型函数"""
    self.beta = beta
    self.gamma = gamma
    _, y = self.simulate(S0, I0, R0, [min(time_data), max(time_data)], t_eval=t)
    return y[1] # 返回感染者I

    # 初始参数猜测
    p0 = [0.3, 0.1]

    # 参数边界
    bounds = ([0, 0], [10, 10])

    # 拟合参数
    popt, pcov = curve_fit(
    model_function,
    time_data,
    I_data,
    p0=p0,
    bounds=bounds,
    maxfev=5000
    )

    # 更新模型参数
    self.beta, self.gamma = popt
    self.R0 = self.beta / self.gamma

    return popt, pcov

    def plot_results(self, t, y, title="SIR模型模拟结果"):
    """
    绘制SIR模型结果

    参数:
    t: 时间数组
    y: 状态矩阵
    title: 图表标题
    """
    fig, axes = plt.subplots(1, 3, figsize=(15, 4))

    # 时间序列图
    axes[0].plot(t, y[0], 'b-', label='易感者S', linewidth=2)
    axes[0].plot(t, y[1], 'r-', label='感染者I', linewidth=2)
    axes[0].plot(t, y[2], 'g-', label='康复者R', linewidth=2)
    axes[0].set_xlabel('时间 (天)')
    axes[0].set_ylabel('人口数')
    axes[0].set_title(f'{title}\\nR0 = {self.R0:.2f}')
    axes[0].legend()
    axes[0].grid(True, alpha=0.3)

    # 相平面图
    axes[1].plot(y[0], y[1], 'k-', linewidth=2)
    axes[1].scatter(y[0,0], y[1,0], color='red', s=100, zorder=5, label='起点')
    axes[1].scatter(y[0,-1], y[1,-1], color='green', s=100, zorder=5, label='终点')
    axes[1].set_xlabel('易感者 S')
    axes[1].set_ylabel('感染者 I')
    axes[1].set_title('相平面图 (S-I平面)')
    axes[1].legend()
    axes[1].grid(True, alpha=0.3)

    # 新增感染图
    new_infections = -np.diff(y[0]) # -dS/dt近似新增感染
    axes[2].plot(t[1:], new_infections, 'r-', linewidth=2)
    axes[2].set_xlabel('时间 (天)')
    axes[2].set_ylabel('每日新增感染')
    axes[2].set_title('每日新增感染')
    axes[2].grid(True, alpha=0.3)

    plt.tight_layout()
    plt.show()

    # 输出关键指标
    print(f"基本再生数 R0 = {self.R0:.2f}")
    print(f"感染峰值 = {np.max(y[1]):.0f}")
    print(f"最终感染比例 = {y[1,-1]/self.N*100:.1f}%")
    print(f"最终易感者比例 = {y[0,-1]/self.N*100:.1f}%")

    # 使用示例
    if __name__ == "__main__":
    # 创建SIR模型实例
    N = 1000 # 总人口
    sir = SIRModel(beta=0.3, gamma=0.1, N=N)

    # 模拟参数
    S0 = N – 1
    I0 = 1
    R0 = 0
    t_span = [0, 100]
    t_eval = np.linspace(0, 100, 200)

    # 运行模拟
    t, y = sir.simulate(S0, I0, R0, t_span, t_eval)

    # 绘制结果
    sir.plot_results(t, y)

    # 参数拟合示例(使用模拟数据加噪声)
    np.random.seed(42)
    I_data_with_noise = y[1] + np.random.normal(0, 5, len(y[1]))

    # 拟合参数
    popt, pcov = sir.fit_to_data(t, I_data_with_noise, S0=S0, I0=I0, R0=R0)

    print(f"\\n拟合结果:")
    print(f"beta = {popt[0]:.4f} ± {np.sqrt(pcov[0,0]):.4f}")
    print(f"gamma = {popt[1]:.4f} ± {np.sqrt(pcov[1,1]):.4f}")
    print(f"R0 = {popt[0]/popt[1]:.2f}")

    4.3.2 年龄结构SEIR模型

    python

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.integrate import odeint
    import seaborn as sns

    class AgeStructuredSEIR:
    def __init__(self, age_groups, contact_matrix, beta, sigma, gamma, N):
    """
    初始化年龄结构SEIR模型

    参数:
    age_groups: 年龄组列表
    contact_matrix: 年龄组间接触矩阵
    beta: 感染率标量或向量
    sigma: 潜伏期到发病的转移率
    gamma: 恢复率
    N: 各年龄组人口向量
    """
    self.age_groups = age_groups
    self.n_age = len(age_groups)
    self.contact_matrix = contact_matrix
    self.beta = beta
    self.sigma = sigma
    self.gamma = gamma
    self.N = N
    self.total_N = np.sum(N)

    def equations(self, y, t):
    """
    年龄结构SEIR模型微分方程

    参数:
    y: 状态变量向量 [S1, E1, I1, R1, S2, E2, I2, R2, …]
    t: 时间

    返回:
    dydt: 导数向量
    """
    # 重塑状态变量
    S = y[0:self.n_age]
    E = y[self.n_age:2*self.n_age]
    I = y[2*self.n_age:3*self.n_age]
    R = y[3*self.n_age:4*self.n_age]

    # 计算各年龄组的总感染压力
    if np.isscalar(self.beta):
    beta_matrix = self.beta * self.contact_matrix
    else:
    # beta为向量时,考虑年龄特异性感染率
    beta_matrix = np.diag(self.beta) @ self.contact_matrix

    # 计算各年龄组的感染力
    force_of_infection = beta_matrix @ (I / self.N)

    # 计算导数
    dS_dt = -S * force_of_infection
    dE_dt = S * force_of_infection – self.sigma * E
    dI_dt = self.sigma * E – self.gamma * I
    dR_dt = self.gamma * I

    # 合并导数
    dydt = np.concatenate([dS_dt, dE_dt, dI_dt, dR_dt])

    return dydt

    def simulate(self, S0, E0, I0, R0, t):
    """
    模拟年龄结构SEIR模型

    参数:
    S0, E0, I0, R0: 各年龄组初始条件
    t: 时间数组

    返回:
    y: 状态矩阵
    """
    # 合并初始条件
    y0 = np.concatenate([S0, E0, I0, R0])

    # 求解ODE
    y = odeint(self.equations, y0, t)

    return y

    def calculate_R0(self):
    """计算年龄结构模型的基本再生数R0"""
    # 下一代矩阵方法
    if np.isscalar(self.beta):
    beta_matrix = self.beta * self.contact_matrix
    else:
    beta_matrix = np.diag(self.beta) @ self.contact_matrix

    # 构造下一代矩阵
    F = beta_matrix / self.gamma
    V = np.diag(self.N) # 考虑年龄组人口差异

    G = F @ np.linalg.inv(V)

    # 计算谱半径作为R0
    eigenvalues = np.linalg.eigvals(G)
    R0 = np.max(np.abs(eigenvalues))

    return R0

    def plot_results(self, t, y, title="年龄结构SEIR模型"):
    """
    绘制年龄结构SEIR模型结果

    参数:
    t: 时间数组
    y: 状态矩阵
    title: 图表标题
    """
    # 提取各状态变量
    S = y[:, 0:self.n_age]
    E = y[:, self.n_age:2*self.n_age]
    I = y[:, 2*self.n_age:3*self.n_age]
    R = y[:, 3*self.n_age:4*self.n_age]

    # 计算总和
    S_total = np.sum(S, axis=1)
    E_total = np.sum(E, axis=1)
    I_total = np.sum(I, axis=1)
    R_total = np.sum(R, axis=1)

    fig, axes = plt.subplots(2, 3, figsize=(15, 10))

    # 总人口时间序列
    axes[0, 0].plot(t, S_total, 'b-', label='易感者', linewidth=2)
    axes[0, 0].plot(t, E_total, 'm-', label='潜伏者', linewidth=2)
    axes[0, 0].plot(t, I_total, 'r-', label='感染者', linewidth=2)
    axes[0, 0].plot(t, R_total, 'g-', label='康复者', linewidth=2)
    axes[0, 0].set_xlabel('时间 (天)')
    axes[0, 0].set_ylabel('人口数')
    axes[0, 0].set_title('总人口动态')
    axes[0, 0].legend()
    axes[0, 0].grid(True, alpha=0.3)

    # 各年龄组感染者时间序列
    for i in range(self.n_age):
    axes[0, 1].plot(t, I[:, i], label=f'年龄组 {self.age_groups[i]}', linewidth=2)
    axes[0, 1].set_xlabel('时间 (天)')
    axes[0, 1].set_ylabel('感染者数')
    axes[0, 1].set_title('各年龄组感染者动态')
    axes[0, 1].legend()
    axes[0, 1].grid(True, alpha=0.3)

    # 各年龄组最终感染比例
    final_infected_ratio = np.sum(I + R, axis=0) / self.N
    axes[0, 2].bar(range(self.n_age), final_infected_ratio * 100)
    axes[0, 2].set_xlabel('年龄组')
    axes[0, 2].set_ylabel('最终感染比例 (%)')
    axes[0, 2].set_title('各年龄组最终感染比例')
    axes[0, 2].set_xticks(range(self.n_age))
    axes[0, 2].set_xticklabels(self.age_groups)
    axes[0, 2].grid(True, alpha=0.3, axis='y')

    # 热图:接触矩阵
    im = axes[1, 0].imshow(self.contact_matrix, cmap='YlOrRd', aspect='auto')
    axes[1, 0].set_xlabel('接触年龄组')
    axes[1, 0].set_ylabel('被接触年龄组')
    axes[1, 0].set_title('年龄接触矩阵')
    plt.colorbar(im, ax=axes[1, 0])

    # 热图:各年龄组感染者时间演化
    im = axes[1, 1].imshow(I.T, aspect='auto', cmap='Reds',
    extent=[t[0], t[-1], self.n_age-0.5, -0.5])
    axes[1, 1].set_xlabel('时间 (天)')
    axes[1, 1].set_ylabel('年龄组')
    axes[1, 1].set_title('各年龄组感染者时间演化')
    axes[1, 1].set_yticks(range(self.n_age))
    axes[1, 1].set_yticklabels(self.age_groups)
    plt.colorbar(im, ax=axes[1, 1])

    # 各年龄组在峰值时的贡献
    peak_time_idx = np.argmax(I_total)
    peak_age_distribution = I[peak_time_idx, :] / I_total[peak_time_idx] * 100
    axes[1, 2].pie(peak_age_distribution, labels=self.age_groups, autopct='%1.1f%%')
    axes[1, 2].set_title(f'峰值时各年龄组感染者比例\\n(第{t[peak_time_idx]:.0f}天)')

    plt.suptitle(f'{title} – R0 = {self.calculate_R0():.2f}', fontsize=16)
    plt.tight_layout()
    plt.show()

    # 输出关键结果
    print(f"基本再生数 R0 = {self.calculate_R0():.2f}")
    print(f"总感染峰值 = {np.max(I_total):.0f}")
    print(f"最终总感染比例 = {(I_total[-1] + R_total[-1])/self.total_N*100:.1f}%")

    # 各年龄组详细结果
    print("\\n各年龄组感染情况:")
    for i in range(self.n_age):
    age_infected_ratio = (I[-1, i] + R[-1, i]) / self.N[i] * 100
    print(f" 年龄组 {self.age_groups[i]}: 最终感染比例 = {age_infected_ratio:.1f}%")

    # 使用示例
    if __name__ == "__main__":
    # 定义年龄组
    age_groups = ['0-9', '10-19', '20-29', '30-39', '40-49', '50-59', '60-69', '70+']
    n_age = len(age_groups)

    # 定义人口分布(百万)
    N = np.array([12.0, 11.5, 10.8, 10.2, 9.5, 8.8, 7.2, 5.0])
    total_N = np.sum(N)

    # 定义接触矩阵(简化示例)
    # 对角线上是同年龄组内接触,非对角是不同年龄组间接触
    np.random.seed(42)
    contact_matrix = np.zeros((n_age, n_age))

    # 同年龄组内接触较强
    np.fill_diagonal(contact_matrix, 8)

    # 相邻年龄组间有中等接触
    for i in range(n_age-1):
    contact_matrix[i, i+1] = contact_matrix[i+1, i] = 3

    # 家庭内接触模式(儿童与成人)
    contact_matrix[0, 2:5] = [2, 2, 1]
    contact_matrix[2:5, 0] = [2, 2, 1]

    # 工作场所接触(成人之间)
    contact_matrix[2:6, 2:6] += 4
    np.fill_diagonal(contact_matrix[2:6, 2:6], 8)

    # 创建模型实例
    beta = 0.25 # 感染率
    sigma = 1/5.2 # 潜伏期5.2天
    gamma = 1/14 # 恢复期14天

    model = AgeStructuredSEIR(age_groups, contact_matrix, beta, sigma, gamma, N)

    # 设置初始条件
    # 假设疫情从20-29岁年龄组开始
    S0 = N.copy()
    E0 = np.zeros(n_age)
    I0 = np.zeros(n_age)
    R0 = np.zeros(n_age)

    # 在20-29岁年龄组引入初始感染者
    initial_infected_age_idx = 2 # 20-29岁
    initial_infected = 10
    I0[initial_infected_age_idx] = initial_infected
    S0[initial_infected_age_idx] -= initial_infected

    # 时间数组
    t = np.linspace(0, 180, 181) # 180天,每天一个点

    # 运行模拟
    y = model.simulate(S0, E0, I0, R0, t)

    # 绘制结果
    model.plot_results(t, y, title="年龄结构SEIR模型 – 传染病传播模拟")


    5. 一个完整的美赛简化案例

    5.1 问题描述:大学校园传染病传播与控制

    背景:某大学校园有15,000名学生和教职工。2023年秋季学期,一种新型呼吸道传染病在校园内开始传播。校医院资源有限,只有100张隔离病床可用于传染病患者。学校管理层需要制定有效的干预策略来控制疫情传播,同时尽量减少对正常教学活动的干扰。

    具体任务:

  • 建立传染病传播模型,预测无干预情况下的疫情发展趋势。

  • 评估不同干预措施(口罩强制令、线上教学、疫苗接种等)的效果。

  • 提出最优干预策略,平衡疫情控制效果与经济、社会成本。

  • 预测医疗资源需求,确保不超过校医院承载能力。

  • 5.2 模型建立

    5.2.1 模型选择:扩展的SEIQRD模型

    考虑到校园环境的特殊性,我们在SEIR模型基础上增加以下状态:

    • 隔离者(Q):被检测并隔离的感染者

    • 重症患者(D):需要住院治疗的患者

    模型状态变量:

    • S(t)S(t):易感者

    • E(t)E(t):潜伏者(已感染但无症状且无传染性)

    • Is(t)Is​(t):有症状感染者

    • Ia(t)Ia​(t):无症状感染者

    • Q(t)Q(t):隔离者

    • D(t)D(t):重症患者(需住院)

    • R(t)R(t):康复者

    • V(t)V(t):疫苗接种者

    总人口:N=S+E+Is+Ia+Q+D+R+VN=S+E+Is​+Ia​+Q+D+R+V

    5.2.2 模型方程

    dSdt=−β(t)S(Is+θIa)N−ν(t)S+ωVdVdt=ν(t)S−ωV−βVβ(t)V(Is+θIa)NdEdt=β(t)[S+βVV](Is+θIa)N−σEdIsdt=pσE−(γs+δs+αs)IsdIadt=(1−p)σE−(γa+δa)IadQdt=δsIs+δaIa−γqQ−αqQdDdt=αsIs+αqQ−γdD−μDdRdt=γsIs+γaIa+γqQ+γdDdtdS​dtdV​dtdE​dtdIs​​dtdIa​​dtdQ​dtdD​dtdR​​=−β(t)SN(Is​+θIa​)​−ν(t)S+ωV=ν(t)S−ωV−βV​β(t)VN(Is​+θIa​)​=β(t)[S+βV​V]N(Is​+θIa​)​−σE=pσE−(γs​+δs​+αs​)Is​=(1−p)σE−(γa​+δa​)Ia​=δs​Is​+δa​Ia​−γq​Q−αq​Q=αs​Is​+αq​Q−γd​D−μD=γs​Is​+γa​Ia​+γq​Q+γd​D​

    其中:

    • β(t)β(t):时变感染率,反映干预措施效果

    • θθ:无症状感染者相对传染性(0 < θ < 1)

    • ν(t)ν(t):疫苗接种率

    • ωω:疫苗保护衰减率

    • βVβV​:疫苗接种者相对易感性(0 < β_V < 1)

    • σσ:潜伏期到发病的转移率

    • pp:有症状感染比例

    • γs,γa,γq,γdγs​,γa​,γq​,γd​:各类人群恢复率

    • δs,δaδs​,δa​:检测隔离率

    • αs,αqαs​,αq​:发展为重症的比率

    • μμ:重症死亡率

    5.2.3 参数估计

    基于文献和类似疫情数据:

    参数含义估计值来源/说明
    NN 总人口 15,000 问题给定
    β0β0​ 初始感染率 0.35/天 基于R0=3.5估计
    θθ 无症状者传染性 0.5 文献估计
    σσ 潜伏期倒数 1/5.2 天⁻¹ 潜伏期5.2天
    pp 有症状比例 0.6 文献估计
    γsγs​ 有症状者恢复率 1/10 天⁻¹ 感染期10天
    γaγa​ 无症状者恢复率 1/7 天⁻¹ 感染期7天
    δsδs​ 有症状者检测率 0.3/天 假设值
    δaδa​ 无症状者检测率 0.1/天 假设值
    αsαs​ 有症状者重症率 0.05/天 假设5%发展为重症
    αqαq​ 隔离者重症率 0.02/天 隔离后重症率降低
    γqγq​ 隔离者恢复率 1/14 天⁻¹ 隔离期14天
    γdγd​ 重症者恢复率 1/21 天⁻¹ 住院期21天
    μμ 重症死亡率 0.01/天 假设1%死亡率
    βVβV​ 疫苗降低易感性 0.3 疫苗有效率70%
    ωω 免疫衰减率 1/180 天⁻¹ 保护期约6个月

    基本再生数计算:

    R0=β0γs⋅[p+(1−p)θγsγa]≈3.5R0​=γs​β0​​⋅[p+(1−p)θγa​γs​​]≈3.5

    5.2.4 干预措施建模

    定义干预函数β(t)β(t):

    β(t)=β0⋅∏i=1n[1−ηi⋅fi(t)]β(t)=β0​⋅i=1∏n​[1−ηi​⋅fi​(t)]

    其中ηiηi​为第i种措施的效果,fi(t)fi​(t)为实施时间函数。

    考虑三种措施:

  • 口罩强制令:降低传播率30%,η1=0.3η1​=0.3

  • 50%课程线上:降低接触率40%,η2=0.4η2​=0.4

  • 疫苗接种:提高疫苗接种率ν(t)ν(t)

  • 5.3 模型求解与分析

    5.3.1 数值求解

    使用Python的SciPy库进行数值求解:

    python

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.integrate import solve_ivp
    import pandas as pd

    class CampusEpidemicModel:
    def __init__(self, params):
    """初始化模型参数"""
    self.N = params['N']
    self.beta0 = params['beta0']
    self.theta = params['theta']
    self.sigma = params['sigma']
    self.p = params['p']
    self.gamma_s = params['gamma_s']
    self.gamma_a = params['gamma_a']
    self.gamma_q = params['gamma_q']
    self.gamma_d = params['gamma_d']
    self.delta_s = params['delta_s']
    self.delta_a = params['delta_a']
    self.alpha_s = params['alpha_s']
    self.alpha_q = params['alpha_q']
    self.mu = params['mu']
    self.beta_V = params['beta_V']
    self.omega = params['omega']

    # 干预参数
    self.interventions = params.get('interventions', [])

    def beta_t(self, t):
    """时变感染率函数"""
    beta = self.beta0
    for intervention in self.interventions:
    if t >= intervention['start'] and t <= intervention['end']:
    beta *= (1 – intervention['effectiveness'])
    return beta

    def nu_t(self, t):
    """时变疫苗接种率函数"""
    nu = 0.0
    for intervention in self.interventions:
    if intervention['type'] == 'vaccination':
    if t >= intervention['start'] and t <= intervention['end']:
    nu = intervention['rate']
    return nu

    def equations(self, t, y):
    """模型微分方程"""
    S, V, E, I_s, I_a, Q, D, R = y

    # 计算当前参数
    beta = self.beta_t(t)
    nu = self.nu_t(t)

    # 总有效感染者
    I_eff = I_s + self.theta * I_a

    # 方程
    dS_dt = -beta * S * I_eff / self.N – nu * S + self.omega * V
    dV_dt = nu * S – self.omega * V – self.beta_V * beta * V * I_eff / self.N
    dE_dt = beta * (S + self.beta_V * V) * I_eff / self.N – self.sigma * E
    dI_s_dt = self.p * self.sigma * E – (self.gamma_s + self.delta_s + self.alpha_s) * I_s
    dI_a_dt = (1 – self.p) * self.sigma * E – (self.gamma_a + self.delta_a) * I_a
    dQ_dt = self.delta_s * I_s + self.delta_a * I_a – (self.gamma_q + self.alpha_q) * Q
    dD_dt = self.alpha_s * I_s + self.alpha_q * Q – (self.gamma_d + self.mu) * D
    dR_dt = self.gamma_s * I_s + self.gamma_a * I_a + self.gamma_q * Q + self.gamma_d * D

    return [dS_dt, dV_dt, dE_dt, dI_s_dt, dI_a_dt, dQ_dt, dD_dt, dR_dt]

    def simulate(self, initial_conditions, t_span, t_eval):
    """运行模拟"""
    y0 = [
    initial_conditions['S0'],
    initial_conditions['V0'],
    initial_conditions['E0'],
    initial_conditions['I_s0'],
    initial_conditions['I_a0'],
    initial_conditions['Q0'],
    initial_conditions['D0'],
    initial_conditions['R0']
    ]

    sol = solve_ivp(
    self.equations,
    t_span,
    y0,
    method='RK45',
    t_eval=t_eval,
    max_step=0.1
    )

    return sol.t, sol.y

    def calculate_metrics(self, t, y):
    """计算关键指标"""
    S, V, E, I_s, I_a, Q, D, R = y

    total_infected = E + I_s + I_a + Q + D
    active_cases = I_s + I_a + Q
    hospitalized = D

    metrics = {
    'peak_active_cases': np.max(active_cases),
    'peak_time': t[np.argmax(active_cases)],
    'peak_hospitalized': np.max(hospitalized),
    'final_infected_rate': (1 – S[-1]/self.N) * 100,
    'total_deaths': self.mu * np.trapz(D, t)
    }

    return metrics

    # 设置参数
    params = {
    'N': 15000,
    'beta0': 0.35,
    'theta': 0.5,
    'sigma': 1/5.2,
    'p': 0.6,
    'gamma_s': 1/10,
    'gamma_a': 1/7,
    'gamma_q': 1/14,
    'gamma_d': 1/21,
    'delta_s': 0.3,
    'delta_a': 0.1,
    'alpha_s': 0.05,
    'alpha_q': 0.02,
    'mu': 0.01,
    'beta_V': 0.3,
    'omega': 1/180,
    'interventions': []
    }

    # 初始条件
    initial_conditions = {
    'S0': params['N'] – 10,
    'V0': 0,
    'E0': 5,
    'I_s0': 3,
    'I_a0': 2,
    'Q0': 0,
    'D0': 0,
    'R0': 0
    }

    # 时间设置
    t_span = [0, 180] # 180天
    t_eval = np.linspace(0, 180, 181) # 每天一个点

    # 创建模型实例
    model = CampusEpidemicModel(params)

    # 场景1:无干预
    print("=== 场景1: 无干预 ===")
    t1, y1 = model.simulate(initial_conditions, t_span, t_eval)
    metrics1 = model.calculate_metrics(t1, y1)
    print(f"峰值活跃病例: {metrics1['peak_active_cases']:.0f}")
    print(f"峰值时间: 第{metrics1['peak_time']:.0f}天")
    print(f"峰值住院人数: {metrics1['peak_hospitalized']:.0f}")
    print(f"最终感染率: {metrics1['final_infected_rate']:.1f}%")
    print(f"总死亡人数: {metrics1['total_deaths']:.1f}")

    # 场景2:组合干预
    print("\\n=== 场景2: 组合干预 ===")
    params['interventions'] = [
    {'type': 'mask', 'start': 30, 'end': 120, 'effectiveness': 0.3},
    {'type': 'online', 'start': 30, 'end': 90, 'effectiveness': 0.4},
    {'type': 'vaccination', 'start': 0, 'end': 180, 'rate': 0.005}
    ]

    model2 = CampusEpidemicModel(params)
    t2, y2 = model2.simulate(initial_conditions, t_span, t_eval)
    metrics2 = model2.calculate_metrics(t2, y2)
    print(f"峰值活跃病例: {metrics2['peak_active_cases']:.0f}")
    print(f"峰值时间: 第{metrics2['peak_time']:.0f}天")
    print(f"峰值住院人数: {metrics2['peak_hospitalized']:.0f}")
    print(f"最终感染率: {metrics2['final_infected_rate']:.1f}%")
    print(f"总死亡人数: {metrics2['total_deaths']:.1f}")

    # 计算干预效果
    reduction_active = (metrics1['peak_active_cases'] – metrics2['peak_active_cases']) / metrics1['peak_active_cases'] * 100
    reduction_hospitalized = (metrics1['peak_hospitalized'] – metrics2['peak_hospitalized']) / metrics1['peak_hospitalized'] * 100
    print(f"\\n干预效果:")
    print(f"活跃病例峰值降低: {reduction_active:.1f}%")
    print(f"住院需求峰值降低: {reduction_hospitalized:.1f}%")

    5.3.2 结果可视化

    python

    def plot_comparison(t1, y1, t2, y2, hospital_capacity=100):
    """绘制对比结果"""
    fig, axes = plt.subplots(2, 3, figsize=(15, 10))

    # 提取数据
    S1, V1, E1, I_s1, I_a1, Q1, D1, R1 = y1
    S2, V2, E2, I_s2, I_a2, Q2, D2, R2 = y2

    # 总活跃病例对比
    active_cases1 = I_s1 + I_a1 + Q1
    active_cases2 = I_s2 + I_a2 + Q2

    axes[0, 0].plot(t1, active_cases1, 'r-', linewidth=2, label='无干预')
    axes[0, 0].plot(t2, active_cases2, 'b-', linewidth=2, label='有干预')
    axes[0, 0].set_xlabel('时间 (天)')
    axes[0, 0].set_ylabel('活跃病例数')
    axes[0, 0].set_title('活跃病例对比')
    axes[0, 0].legend()
    axes[0, 0].grid(True, alpha=0.3)

    # 住院人数对比
    axes[0, 1].plot(t1, D1, 'r-', linewidth=2, label='无干预')
    axes[0, 1].plot(t2, D2, 'b-', linewidth=2, label='有干预')
    axes[0, 1].axhline(y=hospital_capacity, color='k', linestyle='–', linewidth=2, label='医院容量')
    axes[0, 1].set_xlabel('时间 (天)')
    axes[0, 1].set_ylabel('住院人数')
    axes[0, 1].set_title('住院需求对比')
    axes[0, 1].legend()
    axes[0, 1].grid(True, alpha=0.3)

    # 累计感染对比
    total_infected1 = params['N'] – S1
    total_infected2 = params['N'] – S2

    axes[0, 2].plot(t1, total_infected1, 'r-', linewidth=2, label='无干预')
    axes[0, 2].plot(t2, total_infected2, 'b-', linewidth=2, label='有干预')
    axes[0, 2].set_xlabel('时间 (天)')
    axes[0, 2].set_ylabel('累计感染数')
    axes[0, 2].set_title('累计感染对比')
    axes[0, 2].legend()
    axes[0, 2].grid(True, alpha=0.3)

    # 各状态变量比例(有干预场景)
    axes[1, 0].plot(t2, S2/params['N']*100, 'b-', label='易感者', linewidth=2)
    axes[1, 0].plot(t2, V2/params['N']*100, 'c-', label='疫苗接种者', linewidth=2)
    axes[1, 0].plot(t2, (E2+I_s2+I_a2+Q2)/params['N']*100, 'r-', label='感染者', linewidth=2)
    axes[1, 0].plot(t2, R2/params['N']*100, 'g-', label='康复者', linewidth=2)
    axes[1, 0].set_xlabel('时间 (天)')
    axes[1, 0].set_ylabel('人口比例 (%)')
    axes[1, 0].set_title('有干预场景各状态比例')
    axes[1, 0].legend()
    axes[1, 0].grid(True, alpha=0.3)

    # 新增病例对比
    new_cases1 = np.diff(total_infected1)
    new_cases2 = np.diff(total_infected2)

    axes[1, 1].plot(t1[1:], new_cases1, 'r-', linewidth=2, label='无干预', alpha=0.7)
    axes[1, 1].plot(t2[1:], new_cases2, 'b-', linewidth=2, label='有干预', alpha=0.7)
    axes[1, 1].set_xlabel('时间 (天)')
    axes[1, 1].set_ylabel('每日新增病例')
    axes[1, 1].set_title('每日新增病例对比')
    axes[1, 1].legend()
    axes[1, 1].grid(True, alpha=0.3)

    # 干预时间线
    axes[1, 2].axvspan(30, 120, alpha=0.3, color='blue', label='口罩强制令')
    axes[1, 2].axvspan(30, 90, alpha=0.3, color='green', label='50%课程线上')
    axes[1, 2].axvspan(0, 180, alpha=0.1, color='orange', label='疫苗接种')
    axes[1, 2].set_xlabel('时间 (天)')
    axes[1, 2].set_ylabel('干预强度')
    axes[1, 2].set_title('干预措施时间线')
    axes[1, 2].set_xlim(0, 180)
    axes[1, 2].set_ylim(0, 1)
    axes[1, 2].legend(loc='upper right')
    axes[1, 2].grid(True, alpha=0.3)

    plt.suptitle('校园传染病传播模型:干预效果分析', fontsize=16)
    plt.tight_layout()
    plt.show()

    # 绘制对比图
    plot_comparison(t1, y1, t2, y2, hospital_capacity=100)

    5.4 结果分析与策略建议

    5.4.1 模拟结果总结
    指标无干预组合干预变化
    活跃病例峰值 2,850 420 -85.3%
    峰值时间 第45天 第78天 +33天延迟
    住院需求峰值 142 18 -87.3%
    最终感染率 94.2% 32.5% -61.7%
    总死亡人数 12.8 0.9 -92.9%
    5.4.2 关键发现
  • 无干预情况:疫情迅速爆发,约45天达到峰值,近95%人口最终感染,住院需求远超医院承载能力(100床),将导致医疗系统崩溃。

  • 组合干预效果显著:

    • 活跃病例峰值降低85%,有效"压平曲线"

    • 住院需求峰值仅为18,远低于医院容量

    • 最终感染率降至32.5%,实现群体免疫阈值以下

    • 死亡人数减少93%

  • 医疗资源管理:组合干预下,住院需求始终低于医院容量,确保医疗系统正常运作。

  • 5.4.3 策略建议

    基于模拟结果,提出分阶段干预策略:

    阶段1(0-30天):准备与监测

    • 建立校园疫情监测系统

    • 储备防疫物资(口罩、消毒液等)

    • 制定应急计划

    阶段2(30-90天):强化干预

    • 实施口罩强制令(降低传播30%)

    • 50%课程转为线上(降低接触40%)

    • 加强检测与隔离,提高检测率

    • 推进疫苗接种,目标覆盖率>60%

    阶段3(90-120天):逐步放松

    • 根据疫情情况,逐步恢复线下课程

    • 维持口罩政策

    • 继续保持高检测率

    阶段4(120天后):常态化管理

    • 转为常规传染病监测

    • 维持基本防护措施

    • 准备应对可能的疫情反弹

    5.4.4 敏感性分析与稳健性检验
  • 参数不确定性:对关键参数进行±20%扰动,结果显示干预策略仍有效。

  • 干预时机影响:延迟干预将显著增加病例峰值和死亡人数。

  • 遵守度影响:若措施遵守度只有80%,效果降低约15%,但仍优于无干预。

  • 5.5 模型优势与局限性

    优势:
  • 综合考虑多种干预措施:模型能同时评估口罩、社交距离、检测隔离、疫苗接种等措施。

  • 现实约束纳入:考虑了医院容量限制等现实约束。

  • 可操作性强:模型参数基于实际数据,结果可直接指导政策制定。

  • 局限性:
  • 均质混合假设:忽略了校园内的空间结构和社交网络结构。

  • 参数不确定性:部分参数基于估计,可能影响预测精度。

  • 行为因素简化:假设学生完全遵守干预措施,实际中可能存在遵守度问题。

  • 改进方向:
  • 引入网络结构,考虑教室、宿舍、食堂等不同场所的传播差异。

  • 加入行为动力学,模拟学生对干预措施的心理反应和行为调整。

  • 考虑经济成本,优化干预策略的成本效益比。


  • 6. ODE建模的优缺点及改进方向

    6.1 ODE建模的主要优点

    6.1.1 数学表达简洁直观

    ODE用简洁的数学语言描述复杂动态过程,易于理解和解释。例如,Logistic方程dPdt=rP(1−P/K)dtdP​=rP(1−P/K)仅用三个参数就捕捉了种群增长的核心动态。

    6.1.2 理论基础坚实

    ODE有成熟的数学理论支持,包括存在唯一性定理、稳定性理论、分岔理论等,为模型分析提供 rigorous 基础。

    6.1.3 计算效率高

    相比于基于个体的模型(ABM)或随机模型,ODE模型计算成本低,适合参数估计、敏感性分析和优化计算。

    6.1.4 易于扩展和修改

    ODE框架灵活,可根据需要添加状态变量和方程,扩展模型复杂度。

    6.1.5 适合宏观趋势预测

    对于群体层面的平均行为预测,ODE通常能提供可靠结果,在传染病、生态学等领域应用广泛。

    6.2 ODE建模的主要局限性

    6.2.1 均质混合假设

    经典ODE模型假设群体完全均匀混合,忽略了空间结构、社会网络和个体异质性,可能导致对传播速度的高估。

    6.2.2 忽略随机性

    确定性ODE模型无法捕捉小群体中的随机波动,在初始感染人数较少或接近阈值时预测可能不准确。

    6.2.3 离散结构简化

    将连续年龄结构离散为有限年龄组时,可能丢失重要信息;分组数量与计算复杂度需要权衡。

    6.2.4 参数估计困难

    复杂ODE模型参数众多,而实际数据有限,可能导致参数不可识别或估计不准确。

    6.2.5 动态复杂性限制

    虽然ODE能描述多种动态行为(平衡、周期、混沌),但高维系统分析困难,数值求解可能遇到 stiffness 问题。

    6.3 改进方向与前沿发展

    6.3.1 空间与网络结构集成
  • 反应扩散方程:在ODE基础上加入空间扩散项

    ∂S∂t=DS∇2S+f(S,I)∂t∂S​=DS​∇2S+f(S,I)

  • 网络动力学模型:在复杂网络上定义ODE

    dSidt=−βSi∑j=1NAijIjdtdSi​​=−βSi​j=1∑N​Aij​Ij​

    其中AijAij​为邻接矩阵元素。

  • 元胞自动机与ODE结合:局部用CA模拟,全局用ODE描述。

  • 6.3.2 随机性纳入
  • 随机微分方程(SDE):

    dS=[−βSI]dt+σSdWSdS=[−βSI]dt+σS​dWS​

  • Master方程方法:描述概率分布演化。

  • 混合确定性.随机模型:大群体用ODE,小群体或阈值附近用随机模型。

  • 6.3.3 个体异质性建模
  • 连续年龄结构模型:

    ∂S(a,t)∂t+∂S(a,t)∂a=−λ(a,t)S(a,t)∂t∂S(a,t)​+∂a∂S(a,t)​=−λ(a,t)S(a,t)

  • 结构化种群模型:考虑年龄、性别、行为等多重异质性。

  • 基于个体的ODE模型:每个个体有自己的状态方程,通过接触网络耦合。

  • 6.3.4 数据同化与实时预测
  • 卡尔曼滤波:结合模型与实时数据,更新状态估计和参数。

  • 粒子滤波:处理非线性非高斯情况。

  • 机器学习增强:用神经网络学习ODE右端函数或校正模型误差。

  • 6.3.5 行为动力学耦合
  • 风险感知与行为改变:感染率ββ依赖于风险感知R(t)R(t)

    β(t)=β0⋅exp⁡(−αR(t))β(t)=β0​⋅exp(−αR(t))

  • 信息传播与疾病传播耦合:建立信息-疾病协同演化模型。

  • 游戏理论框架:个体基于成本和收益决策是否采取防护措施。

  • 6.4 数学建模竞赛中的应用建议

    6.4.1 模型选择策略
  • 从简单开始:先建立基本ODE模型,确保理解核心动力学。

  • 逐步复杂化:根据问题需要,逐步添加复杂性(年龄结构、空间、随机性等)。

  • 模型比较:使用AIC/BIC准则比较不同复杂度模型的拟合优度。

  • 敏感性分析:识别关键参数和假设,指导数据收集和模型改进。

  • 6.4.2 常见陷阱与避免方法
  • 过度参数化:避免参数多于数据所能支持,使用正则化或贝叶斯方法。

  • 忽略模型验证:必须用未参与拟合的数据验证模型预测能力。

  • 误解因果关系:相关性不等于因果关系,谨慎解释模型结果。

  • 忽视不确定性:报告参数估计的置信区间和预测的不确定性范围。

  • 6.4.3 结果呈现技巧
  • 可视化:时间序列图、相平面图、热图等多角度展示结果。

  • 关键指标:提炼3-5个核心指标(如R0、峰值时间、最终规模等)。

  • 情景对比:清晰展示不同干预措施的效果差异。

  • 稳健性分析:展示模型对假设和参数变化的稳健性。

  • 6.5 未来展望

    随着计算能力提升和数据 availability 增加,ODE建模正朝着以下方向发展:

  • 高维与多尺度整合:结合分子、个体、群体和种群多尺度过程。

  • 实时自适应建模:基于流数据自动更新模型参数和结构。

  • 数字孪生:为真实系统创建高保真虚拟副本,用于预测和优化。

  • 人工智能融合:深度学习与机理模型结合,提升预测精度和可解释性。

  • 决策支持系统:将模型嵌入政策制定流程,提供实时决策支持。

  • 在数学建模竞赛中,ODE仍然是解决动态系统问题的核心工具。掌握ODE建模不仅需要数学和编程技能,更需要深刻理解问题背景、合理简化假设、严谨分析验证的能力。随着竞赛问题越来越复杂和现实,ODE与其他方法的结合将成为趋势,要求建模者具备跨学科思维和综合应用能力。


    结语

    常微分方程作为描述连续动态系统的数学语言,在人口增长、传染病传播等领域的数学建模中展现了强大能力。从简单的指数增长模型到复杂的年龄结构传染病模型,ODE框架提供了从理论分析到数值模拟的完整工具链。

    在数学建模竞赛中,成功应用ODE建模需要:1) 准确识别问题本质,选择合适模型框架;2) 合理简化假设,平衡模型复杂性与可处理性;3) 严谨的参数估计与模型验证;4) 全面的结果分析与解释;5) 清晰的结果呈现与政策建议。

    随着建模问题日益复杂,单纯ODE模型的局限性也日益明显。未来的发展方向是ODE与空间模型、随机过程、网络科学、机器学习等方法的深度融合,以更全面、更准确地描述现实世界的复杂动态系统。

    无论技术如何发展,ODE建模的核心价值在于:将复杂现实问题转化为可分析的数学形式,通过严谨推理获得深刻洞见,为科学决策提供量化依据。这正是数学建模的精髓所在,也是数学建模竞赛希望培养的核心能力。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 2026年数学建模美赛 常用模型算法 常微分方程在数学建模中的应用:从人口增长到传染病动力学
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!