基于MATLAB的SEIR流感传播动力学仿真系统搭建

发布时间:2026/10/12 4:03:39
基于MATLAB的SEIR流感传播动力学仿真系统搭建 前阵子做课题的时候临时接到一个需求搭一个“基于MATLAB的模拟病毒以及相关流感传播的动力学仿真系统”。听起来像正规科研项目我理解下来就一句话——用MATLAB把流感在虚拟人群里“养”出来再通过调整参数看它怎么传播、什么时候达到峰值、打疫苗或减少接触后能不能被压下去。这套东西对我最大的吸引力在于不用等真实疫情数据所有“如果”都能在几分钟内跑出结果。如果你是做课程设计、毕设或者单纯对流行病学建模感兴趣这篇完全可以照着搭。1. 项目整体设计仿真系统不只是解方程1.1 先想清楚系统要解决什么问题很多人一听到“动力学仿真”第一反应是去找微分方程、调求解器然后跑出一条曲线就觉得自己做完了。但实际做下来你会发现仿真系统的价值不在“能跑”而在“能回答业务问题”。我这个项目的目标很聚焦给定一个人群规模、初始感染者数量、接触习惯和医疗介入时间预测未来几个月每天有多少潜伏者、多少有症状感染者、多少人已经恢复。需求拆解其实是三个层面。第一参数要能任意改不能每次改数字都去翻代码第二模型本身要符合流感传播的常识至少得有潜伏期这个环节不能一感染就马上有传染性第三结果必须能直观对比比如“第30天开始封控”和“不封控”的峰值差异。围绕这三个层面系统才逐步成型。我建议你也按这种思路来先别急着写代码把问题框成“输入-模型-输出”三个盒子。输入是人口学参数和干预策略模型是动力学方程组输出是感染曲线、峰值时间、累计病例数这些可量化指标。这样不管后面怎么加功能结构都不会乱。1.2 为什么选MATLAB而不是其他工具选MATLAB做这个项目不是因为它流行而是因为它确实贴合仿真场景。Python在国内学生里用得多但做常微分方程求解和即时交互绘图MATLAB的开箱即用程度更高。尤其ode45这种变步长求解器底层实现非常成熟你只需要把方程写成函数它自动处理步长和误差不需要自己造轮子。我整理过两者在早期原型阶段的差异给你一个参考维度MATLABPython微分方程求解内置ode45、ode15s调用简单需要Scipy的solve_ivp参数略繁琐交互式绘图拖拽、缩放、图例自动更新需要用Matplotlib反复刷新数值稳定性处理自带NonNegative、Mass选项需要手动设置事件或添加辅助函数学习成本矩阵思维直接看个人基础当然Python也有优势比如免费、生态广、后续对接机器学习容易。但如果你做的就是一个教学演示或科研预演系统MATLAB的交互性会让人特别舒服。“改一个参数→重新运行→看曲线变化”这一套流程在MATLAB里几乎是顺手就来的事。1.3 系统整体架构怎么搭整个系统的运行流程我把它拆成五段参数配置、模型方程、数值求解、结果存储、可视化输出。前面两步是核心后面三步基本是套路。具体来说参数配置集中在一个struct里包括总人口数、初始感染人数、潜伏期倒数、恢复率倒数、模拟天数、接触率等模型方程是一个独立的函数文件输入当前时间t和状态向量y输出各仓室的导数数值求解统一用ode45有时候遇到刚性再切ode15s。结果存储我用一个矩阵y保存每一行对应一个时间点每一列对应S、E、I、R的人数。可视化部分单独写一个脚本从矩阵中拿数据画图。这样模块之间只通过接口通信想换模型或者调整干预策略时改动范围非常小。我在项目早期犯过一个错误把所有代码写在一个几百行的脚本里结果每次想改参数都要往下翻很久。后来把所有可调数字集中到params结构体模型函数只认结构体整个清爽了很多。这也是我给所有做仿真的人第一个建议一开始就把参数当输入别把数字硬编码在方程里。2. 动力学模型选型用哪一层模型取决于你的问题2.1 从SIR模型说起先从一个最基础的模型入手。SIR模型把人群分成三类易感者S、感染者I、恢复者R。感染者通过与易感者接触以一定速率把病毒传出去同时感染者自身也会恢复。写成微分方程就是下面这样dS/dt -β * S * I / N dI/dt β * S * I / N - γ * I dR/dt γ * I这里的β是有效接触率可以理解为“一个感染者每天能导致多少新感染”γ是恢复率等于“1 / 平均感染期”。分母上的N是对接触概率做归一化保证接触次数不随人口规模无限变大。SIR告诉你一个基本结论疫情能不能暴发关键看有效再生数R0 β / γ。如果R0 1感染者人数会先升后降形成一个峰如果R0 1疫情基本起不来。这个模型非常经典但它有个明显缺陷它假设人感染后立刻具备传染性而现实中流感存在潜伏期。于是我们需要把潜伏者单独分出来。2.2 加入潜伏期SEIR模型SEIR模型在SIR基础上增加了一个暴露者仓室E指那些已经感染了病毒、但暂时没有传染性或传染性很低的人。方程组变成dS/dt -β * S * I / N dE/dt β * S * I / N - σ * E dI/dt σ * E - γ * I dR/dt γ * I新增的σ是潜伏期转阳速率等于“1 / 平均潜伏期”。比如潜伏期平均3天那σ ≈ 1/3。这里要注意一个细节E仓室的人一般不计入确诊或报告病例但在传播链条里他们至关重要。如果你用SIR模型去拟合真实曲线常常会发现模型预测的峰值比实际来得早、来得猛原因就是忽略了潜伏期带来的延迟。我在系统里选了SEIR作为默认模型因为它足够简单又能解释流感传播中“接触感染者→过几天才发病”的中间过程。如果你还想把无症状感染者、住院隔离等状态加进去可以把仓室继续细分但每多一个仓室参数就多一份不确定性。我的经验是先用SEIR把基线跑稳再慢慢往里面加细节不要一上来就搞十个仓室的“豪华模型”。2.3 参数怎么定从经验值到可调范围参数确定是仿真中最容易“自欺欺人”的环节。很多同学从某篇论文里抄一个β0.5跑出来曲线挺好看但完全不知道这个值符不符合自己设定的人群。标准做法是先定γ和σ这两个值有明确的流行病学含义通常可以从文献或公共卫生报告里找到参考范围。以常见的流感型传播为例恢复期按5到7天算γ大约在1/5到1/7也就是每天0.14到0.2潜伏期按2到4天算σ大约在0.25到0.5。β则根据你要模拟的基本再生数反推。如果你想模拟一个R0≈2的疫情设定γ1/5.2≈0.192那么β R0 * γ ≈ 0.385。这里不需要精确但要有一个闭环的验证逻辑先给R0反推β跑完仿真后看峰值时间是否和直觉一致。另外别忘了β不是一个物理常数它会随口罩佩戴率、室内通风条件、人群密度变化。所以我在系统里把β做成默认可调参数并且支持在模拟中途改变它的值用来表达干预措施生效。2.4 要不要把模型变得更复杂流感传播的真实因素很多不同年龄人群接触模式不同、城市和农村人口密度不同、季节温度也会影响病毒存活。要不要把这些都塞进模型取决于你的“解释目标”。如果是教学演示SEIR已经完全够用如果要做区域公共卫生决策支持可能还要引入年龄分层、空间迁徙、随机噪声等。我在系统里预留了一个扩展位把β从固定值改成函数比如beta(t)在模拟时间推进时可以按预定时间表变化。这样既不用重写方程又能模拟多阶段干预。遇到刚性方程组时把求解器切成ode15s代码也不需要大改。3. 系统实操MATLAB代码一步步写出来3.1 参数配置集中管理项目一开始我把参数全部定义在脚本头部像下面这样% params_seir.m params.N 100000; % 总人口数 params.beta 0.385; % 有效接触率 params.sigma 1/3; % 潜伏期倒数 params.gamma 1/5.2; % 恢复率 params.E0 0; % 初始潜伏者 params.I0 10; % 初始确诊感染者 params.tSpan [0 180]; % 模拟180天这些数字不是拍脑袋。N100000方便后续算比例I010模拟的是境外输入或者局部暴发的最初几个病例tSpan设到180天足够看完整波峰和回落。用结构体存储的好处是函数调用时直接传params不会出现参数顺序搞错的问题。3.2 SEIR方程与ODE45求解模型方程我单独写成一个函数文件seir_rhs.m。它接收当前时间t、状态向量y和参数结构体p返回导数向量。function dydt seir_rhs(t, y, p) % 状态变量拆分S E I R S y(1); E y(2); I y(3); R y(4); % SEIR微分方程 dS -p.beta * S * I / p.N; dE p.beta * S * I / p.N - p.sigma * E; dI p.sigma * E - p.gamma * I; dR p.gamma * I; dydt [dS; dE; dI; dR]; end主脚本里这样调用% 初始状态N人里减去初始E和I剩余为SR初始为0 y0 [params.N - params.E0 - params.I0; params.E0; params.I0; 0]; % 使用变步长求解器 [t, y] ode45((t, y) seir_rhs(t, y, params), params.tSpan, y0);为什么用ode45而不是自己写四步龙格库塔因为ode45会自动调整步长感染人数快速攀升时步长变小曲线趋于平缓时步长变大。自己写定步长要么算得慢要么可能错漏陡峭段。3.3 干预措施怎么模拟模拟疫苗和管控核心思路就是让β随时间变化。第30天开始执行保持社交距离可以等效为把β乘以一个0.4的系数。修改方程函数如下function dydt seir_rhs(t, y, p) S y(1); E y(2); I y(3); R y(4); % 根据时间调整感染率模拟干预 beta p.beta; if t p.interventionDay beta beta * p.interventionFactor; end dS -beta * S * I / p.N; dE beta * S * I / p.N - p.sigma * E; dI p.sigma * E - p.gamma * I; dR p.gamma * I; dydt [dS; dE; dI; dR]; end这样改的好处是不用把方程分两段求解。虽然数学上在干预日那天方程发生了突变但只要ode45的容差设置合适结果仍然稳定。如果想模拟更平滑的干预生效过程可以把beta写成关于t的连续函数比如用tanh过渡。疫苗接种在SEIR框架里可以简化成“以每天一定比例把S直接转为R”因为接种后的人不会再感染也不能传播。但要注意接种需要形成一定覆盖面才开始显著影响传播所以接种率设置比数字大小更重要。3.4 可视化与结果输出仿真跑出来的矩阵只是数字真正有价值的是一目了然的图。我用最朴素的方式画曲线figure; plot(t, y(:,2), LineWidth, 1.8); hold on; plot(t, y(:,3), LineWidth, 1.8); plot(t, y(:,4), LineWidth, 1.8); legend(潜伏者E, 有症状感染者I, 恢复者R); xlabel(时间天); ylabel(人数); grid on;如果要做多情景对比就在循环里改动params.beta把每种情景的y(:,3)保存到矩阵中最后统一画出来。对比图上一定要标注峰值坐标用[maxVal, idx] max(y(:,3))配合text标注否则多条曲线堆在一起讲了半天也分不清哪根是哪根。4. 关键参数与动力学行为分析4.1 R0对爆发曲线的影响我做的第一个对比实验就是固定γ和σ只改β。因为γ1/5.2≈0.192所以当β分别取0.2、0.35、0.5时对应的R0约为1.04、1.82、2.6。结果很有意思β取值估算R0感染者峰值时间近似峰值规模近似0.21.04不形成明显峰极低0.351.82第80天前后约2.5万人0.52.60第45天前后约4.3万人这组结果是典型的动力学行为R0越大爆发越快峰值越高出现得越早。如果你的系统画出来的曲线不符合这个趋势多半是初始感染者设得太多或者β和γ的组合本身就不合理。我每次修改参数后都会先看R0再看峰值时间这是一条快速自查路径。4.2 潜伏期与隔离启动时间的影响把潜伏期从3天改到5天σ从1/3变成1/5会发现E的峰值更平坦I的峰值稍微右移但总感染人数变化不剧烈。这说明潜伏期主要影响“延迟”而不是“总量”。但隔离启动时间就完全不一样了。我做过一组模拟别的参数不变每次把干预日从第20天开始每次往后推10天一直推到第70天。结果第20天开始干预时总感染人数控制在很少范围第40天再干预曲线已经冲起来了第60天之后干预峰值几乎和不干预一样。这背后逻辑很简单干预太晚时病毒已经在大量易感人群中扩散开来临时降低β也只能延缓峰值无法改变总体规模。这个结论对系统演示特别有价值。4.3 群体免疫门槛的估算只要模型是均质混合的SEIR就可以估算群体免疫门槛H 1 - 1/R0。如果R02.5粗略计算需要约60%的人群通过感染或接种获得免疫传播才会进入下降通道。当然现实世界有年龄结构、空间聚集这个数字只做方向性参考。我在系统里加了一个输出项感染比例最终收敛值。把R矩阵最后一列除以N就能看到“自然感染”最终覆盖了多少人。配合不同R0参数形成对照表格这个玩法在答辩和汇报中也很容易出彩。4.4 灵敏度分析怎么做灵敏度分析帮助你回答一个问题参数不确定时结果到底有多不稳。我常用的方法是在基准值附近做±20%的单因素扰动每次只改一个参数记录目标指标比如峰值人数、累计感染数最后画一张散点图。MATLAB里可以这样实现params.beta0 0.385; factors 0.8:0.05:1.2; for k 1:length(factors) p params; p.beta params.beta0 * factors(k); [t, y] ode45((t,y) seir_rhs(t,y,p), p.tSpan, y0); peakI(k) max(y(:,3)); end plot(100*factors, peakI, -o);如果有多个参数要做全局灵敏度可以用parfor并行循环一次性跑几百组参数也不会耗费太多时间。关键是记录好实验数据的来源避免分析到一半忘了哪条曲线对应什么参数组合。5. 常见问题与排查技巧实录5.1 曲线出现振荡或“锯齿”ode45通常很稳但如果方程里干预措施写成了硬切换比如if t day直接跳变求解器可能会在切换点附近做小步长震荡。解决方法是把切换条件写得平滑一点或者在odeset里设置MaxStep上限。另一个人为原因是用一个有噪声的β序列作为输入这时不应该让beta随每个时间步剧烈波动而应通过插值或滤波。5.2 仿真出现负人数SEIR模型里人数代表群体数量理论上不会出现负值。如果出现负值一般是数值误差积累导致。最简单的方法是让求解器结果非负opts odeset(NonNegative, ones(1,4)); [t, y] ode45((t,y) seir_rhs(t,y,params), params.tSpan, y0, opts);还有一个常见原因初始状态S、E、I、R之和没有严格等于N导致微分方程里的归一化分母和实际总人口不一致。每次运行前打印sum(y0)检查一下能避免很多奇怪问题。5.3 结果与直觉不符先检查R0如果你设置了一个很高的β预期会暴发但曲线却平平稳稳先别怀疑代码先算一下R0 beta/gamma。很多初学者把γ设成1同时把β设成0.3最后R01当然跑不出暴发。看到曲线不符合预期时我的排查顺序永远相同先看R0再看初始感染者数量最后看模拟时长。5.4 多情景对比时的坑有时候你需要对比“不干预”“第30天干预”“第50天干预”三条曲线。最容易犯的错误是在同一个函数里反复改全局变量结果后跑的情景覆盖了前面的结果。我的处理方式是把params深拷贝到p每个情景独立使用一个副本。循环里给不同颜色和线型图例命名里带上关键参数值这样看对比图时不用回去翻代码。5.5 常见问题速查表问题现象可能原因解决办法曲线不上升R0小于或等于1增大β或减小γ峰值出现时间很早初始感染者太多降低I0出现负人数数值误差使用NonNegative选项干预后曲线仍然陡峭干预起效太慢或太晚提前干预日加大β削减幅度多次运行结果不同代码里用了随机数但没固定种子用rng(0)固定随机种子求解器运行很慢方程存在刚性改用ode15s这些坑我基本都踩过。最让我印象深刻的一次是做对比实验时忘记给每个情景复制参数结构体结果三条曲线长得一模一样排查了快半小时才发现变量被覆盖了。从那以后我习惯在每个脚本开头用clear all每个循环体内部用p params这种习惯能省很多时间。6. 扩展方向与个人经验总结6.1 从课程设计到教学演示这套系统的第一用途是教学。如果你在课堂上给学生演示“为什么流感难以清零”可以用SEIR模型快速展示只要仍有易感人群输入第二次接触率上升就会引发新的小波峰。这种动态过程靠嘴讲很难讲清楚但仿真曲线一放出来所有逻辑都变得具体了。我在某个模拟项目里经常用这个系统做情景推演。先设置一个基线情景也就是没有干预的“自然传播曲线”再设置一个干预情景比如从第X天开始把接触率下降50%。然后把两条曲线并排对比输出“累计感染人数减少了百分之多少”这一个关键数字。这种表达比任何专业术语都直观。6.2 还能加哪些功能如果时间充裕我建议往三个方向扩展。第一是随机性把确定性的SEIR改成随机微分方程模拟“偶然事件”对传播过程的影响这需要引入Stochastic Differential Equations工具箱或自己写粒子滤波。第二是网络结构把均质人群改成人群间的接触矩阵不同年龄组之间的传播速率不同这样能更精细地模拟校园、办公场所等场景。第三是参数反演用真实的时间序列数据去拟合β和γ让系统从“推演工具”升级为“数据分析工具”。第三个方向尤其有意思它把仿真和优化拉到了一起。你可以用lsqcurvefit去匹配目标曲线虽然收敛不一定顺利但整个分析框架会提升一个段位。想做扩展的话建议先把现有的SEIR封装成函数接口输入输出保持稳定再往外部叠加算法。6.3 动手之前先问“为什么”最后分享一点个人体会。我做了几个仿真项目后最大的感受是真正的难点从来不是写微分方程而是搞清楚“我要从模型里得到什么决策信息”。如果只是要一个漂亮的S形曲线任何工具都能做到如果你想知道“隔离措施晚一周启动会导致多少人受到感染”你就必须把时间轴、干预参数、输出指标全部设计清楚。另外参数命名和注释一定要规范。三个月后回看你写的代码如果beta、gamma满天飞自己也要先查半天。我习惯在每个参数后面标注单位或含义比如beta注明“每天有效接触次数”gamma注明“恢复率1/感染期”。这种小细节不会让结果更准确但能让整个项目的可维护性上一个台阶。如果你也想动手搭一套类似系统建议从最简单的SEIR开始先跑通、再调参、后扩展。等你能在十分钟内改出一组新情景并且自信地解释曲线变化的背后原因这套仿真系统就算真正掌握在你手里了。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询