当前位置: 首页 > news >正文

元胞自动机+威尔斯-赖利模型的疾病传播仿真建模

1. 这不是一份“标准答案”,而是一次真实建模过程的复盘

2021年第十届小美赛B题——“疾病传播的风险评估与防控策略模拟”,表面看是个经典传染病建模题,但实际做下来你会发现,它根本不是套用SIR模型就能交差的作业。我带三支本科生队参赛,两支进了F奖(Finalist),一支拿了M奖(Meritorious),整个过程从选模、调试、验证到可视化,前后花了17天,光是核心代码就重写了4版。很多人搜“小美赛B题答案”想抄个现成程序,但真正跑通的没几个——因为题目里埋了三个关键陷阱:一是要求区分室内微环境(如教室、办公室)与区域宏观传播的耦合关系;二是明确限定使用基于个体的建模方法(ABM或元胞自动机),不能只用常微分方程;三是必须嵌入Wells-Riley模型对气溶胶传播路径进行量化,而不是简单设个β感染率。这三个硬性约束,直接把90%的参赛队挡在了第一关。我这篇文档不提供“万能模板”,而是完整还原我们团队如何从零开始,用Python构建一个可解释、可调参、可验证的疾病传播风险仿真系统。里面包含所有你查不到的细节:比如为什么元胞尺寸必须设为0.5米而非1米,Wells-Riley公式中呼吸频率Q取值为何要按年龄分段校准,以及如何用matplotlib动画真实还原感染者咳嗽后气溶胶扩散轨迹。如果你正在准备2026亚太杯A题、国赛C题,或者刚接触数学建模想搞懂“怎么把现实问题翻译成代码”,这篇就是为你写的——它不教你怎么拿奖,但能让你彻底明白:建模不是堆公式,而是用计算语言重新理解世界。

2. 整体设计思路:三层嵌套结构解决尺度割裂问题

2.1 为什么放弃纯SIR/SEIR模型?

很多队伍一看到“疾病传播”就本能地打开scipy.integrate.solve_ivp,写个四阶龙格-库塔解SIR方程。这在宏观人口层面没问题,但小美赛B题明确要求:“分析某高校教学楼内流感爆发风险,并提出楼层级防控建议”。注意关键词——“教学楼内”、“楼层级”。这意味着你必须处理空间异质性:同一楼层不同教室通风条件差异可能达3倍,走廊和楼梯间人流密度相差5倍以上,而SIR模型把整栋楼当做一个均质混合体,连“谁坐在谁旁边”这种基础信息都丢失了。我们实测过:用SIR拟合某高校2019年流感数据,R²=0.89;但把同样参数放进元胞自动机模拟单层教学楼,第3天就出现局部聚集性爆发,而SIR预测仍是平滑上升曲线。误差根源在于——SIR假设“每个易感者接触每个感染者概率相同”,现实中,坐在空调出风口下的人,暴露风险是背风角落学生的7.2倍(这个数字来自我们实测的CFD流场模拟)。所以第一轮淘汰的就是所有纯ODE方案。

2.2 选择元胞自动机而非Agent-Based Model的深层考量

ABM(基于智能体的建模)听起来更“高级”,每个agent自带属性、行为规则、移动路径。但B题有个致命限制:必须在48小时内完成建模+仿真+报告撰写。ABM开发成本极高——光是定义学生agent的日常行为树(上课→课间走动→去洗手间→回座位),就需要至少200行状态机代码,且每增加1个行为分支,验证复杂度呈指数增长。而元胞自动机(CA)用空间网格替代个体,把“人”抽象为“状态”,把“移动”简化为“邻域规则”,开发效率提升3倍以上。更重要的是,CA天然适配Wells-Riley模型——该模型核心是计算单位体积空气中病原体浓度(quanta/m³),而CA的每个元胞正好对应一个空间微单元(我们设为0.5m×0.5m×2.8m,即单个课桌占据空间),浓度计算可直接在元胞上积分。我们对比测试过:模拟1000人规模的教学楼,CA单次仿真耗时2.3秒(i7-10875H),ABM需47秒,且ABM结果对初始位置敏感度高(±15%波动),CA因空间离散化反而更稳定(±3.2%)。这不是技术优劣问题,而是竞赛场景下的务实选择。

2.3 三层嵌套架构:打通微观-中观-宏观尺度

最终方案采用三级耦合结构,这是解决“尺度割裂”的关键创新:

  • 底层:元胞自动机(CA)引擎
    空间分辨率0.5m,状态包括:S(易感)、E(潜伏)、I(感染)、R(康复)、V(通风)、O(障碍物)。特别设计“气溶胶扩散核”——每个I态元胞每分钟向8邻域释放quanta,衰减系数按距离平方反比+空气沉降率修正。这部分代码仅187行,但支撑了全部空间动态。

  • 中层:Wells-Riley模块
    不是简单套公式,而是将其拆解为可调参数组:呼吸频率Q(学生取0.45 m³/h,教师取0.38 m³/h)、quanta产生率q(流感病毒取12 quanta/h,经文献校准)、通风换气率λ(实测教室取0.5 h⁻¹,实验室取2.5 h⁻¹)。关键突破是把λ从常数改为时空变量——课间开窗时λ瞬时升至3.0 h⁻¹,上课关窗后回落,这个动态过程用时间序列驱动。

  • 顶层:风险评估仪表盘
    输出不是单一R₀值,而是三维热力图:X轴时间(小时)、Y轴空间(楼层/教室编号)、Z轴风险值(定义为未来24小时新发病例期望值)。我们定义风险阈值为0.15——当某教室风险值连续2小时>0.15,触发红色预警,系统自动推荐干预措施(如“开启东侧窗户+关闭空调回风”)。

这个架构让模型既有微观机制(CA模拟传播路径),又有中观依据(Wells-Riley量化暴露),还能输出宏观决策(风险热力图)。后来我们发现,2022年国赛C题“新冠疫情下校园防控优化”几乎复刻了这个思路,只是把CA升级为多层网络。

3. 核心细节解析:那些论文里不会写的实操陷阱

3.1 元胞尺寸的物理意义与校准方法

网上教程都说“元胞越小精度越高”,但我们踩过坑:把元胞设成0.1m×0.1m,仿真跑不动(内存溢出),设成1m×1m又丢失关键细节(无法区分课桌与过道)。最终确定0.5m是黄金尺寸,理由有三:

  1. 人体尺度匹配:成年肩宽约0.45m,0.5m元胞能保证“一人一格”基本定位,避免多个学生挤进同一元胞导致状态混淆;
  2. 通风建模可行性:教室常用吊顶式空调,出风口直径0.3~0.6m,0.5m元胞恰好覆盖单个出风影响域;
  3. 计算效率平衡:某教学楼平面图120m×80m,0.5m分辨率需38400个元胞,内存占用<500MB;若用0.25m则需153600个元胞,显存直接爆掉。

校准过程很土但有效:我们打印出教室CAD图,用0.5m见方的硬纸板在实地摆位,测试学生自然站立时是否被完全覆盖——结果92%的学生能被单个纸板框住,证明尺寸合理。这个细节决定了后续所有空间计算的物理真实性。

3.2 Wells-Riley模型的本土化参数修正

原始Wells-Riley公式为:
P = 1 - exp(-q·t·Q / (N·λ))
其中P为感染概率,q为quanta产生率,t为暴露时间,Q为呼吸频率,N为空气体积,λ为通风换气率。

但直接套用文献值会出大错。我们发现三处必须修正:

  • q值不能照搬国外数据:英文文献中流感q值多为10~20 quanta/h,但中国疾控中心2020年《呼吸道传染病气溶胶传播特征》指出,北方干燥环境下病毒存活时间延长37%,q值应上调至12~25。我们取15 quanta/h,并设置±20%浮动区间供灵敏度分析。

  • Q值必须分人群:大学生久坐代谢率低,Q=0.45 m³/h;教师频繁走动,Q=0.38 m³/h;保洁人员活动量大,Q=0.52 m³/h。这个差异让同一教室不同岗位风险值相差2.3倍。

  • λ值要动态化:标准教材把λ当常数,但实测显示,教室门窗关闭时λ=0.5 h⁻¹,课间开窗5分钟可使λ峰值达4.2 h⁻¹,之后按指数衰减。我们用函数λ(t) = 0.5 + 3.7·exp(-t/8)模拟(t为开窗后分钟数),这个公式来自我们用CO₂检测仪在32间教室的实测数据拟合。

提示:所有参数修正都附原始数据来源——我们在附录放了CO₂浓度监测表、学生呼吸频率实测视频截图、病毒存活实验报告扫描件。评审专家特别看重这点,说“看到你们把公式里的每个字母都落地到了真实世界”。

3.3 潜伏期与症状期的非线性状态跃迁

SIR模型把E→I设为固定周期(如2天),但医学研究表明,流感潜伏期是1~4天的随机分布,且感染力随病程非线性变化:发病前12小时传染性最强(此时病毒载量达峰值),症状出现后24小时传染性下降50%。如果用固定时长,会严重低估“无症状传播”风险。

我们的解决方案是:

  • E态元胞每小时以概率p_EI(t)跃迁至I态,其中p_EI(t) = 0.3·(1 - exp(-t/1.2)),t为潜伏时长(小时);
  • I态元胞的quanta释放率q_I(t) = 15·exp(-|t-12|/8),t为症状持续小时数(以首次发热为0点)。

这个设计让模型捕捉到关键现象:课间休息时,看似健康的E态学生(已潜伏36小时)突然转为I态,成为超级传播源。我们在仿真中重现了2019年某高校真实爆发事件——首例确诊前2天,已有3名E态学生在图书馆密集区活动,模型成功预测了后续72小时内的爆发中心。

4. 实操全过程:从零开始搭建可运行系统

4.1 环境配置与依赖包选择

我们锁定Python 3.8.10(避免新版numpy与scipy兼容问题),核心依赖如下:

包名版本选用理由
numpy1.21.6CA矩阵运算基石,比list快47倍
scipy1.7.3scipy.ndimage实现8邻域卷积,比手动循环快12倍
matplotlib3.5.2动画渲染稳定,FuncAnimation支持实时热力图更新
pandas1.3.5处理教室布局CSV数据,比openpyxl快3倍
tqdm4.64.0可视化仿真进度,避免“卡死”误判

特别说明:不用PyTorch/TensorFlow。虽然GPU加速诱人,但CA是规则驱动型计算,CPU的SIMD指令集(AVX2)已足够,强行上GPU反而因数据搬运损耗性能。我们实测:i7-10875H单核CA仿真速度1.8万步/秒,RTX3060 GPU版仅1.9万步/秒,性价比极低。

安装命令(防坑版):

conda create -n xiaomei2021 python=3.8.10 conda activate xiaomei2021 pip install numpy==1.21.6 scipy==1.7.3 matplotlib==3.5.2 pandas==1.3.5 tqdm==4.64.0

注意:不要用pip install "numpy>=1.20",版本冲突会导致scipy.linalg.eigvals报错。这是我们在第三天凌晨2点才发现的bug,重装环境花了40分钟。

4.2 教室空间数据的数字化流程

题目给的是PDF版教学楼平面图,需转化为CA可读的二维数组。步骤如下:

  1. 图像预处理:用GIMP将PDF转为PNG,去噪、二值化(阈值128),确保墙体为纯黑(0),空地为纯白(255);
  2. 坐标系标定:在图上标记两个已知距离点(如门宽1.2m),用OpenCV测量像素距离,算出缩放因子(本例为1px=0.042m);
  3. 网格生成:按0.5m元胞尺寸,计算所需行列数——120m/0.5m=240列,80m/0.5m=160行;
  4. 障碍物映射:遍历每个元胞中心坐标(x,y),用cv2.pointPolygonTest判断是否在墙体多边形内,是则设为O态(障碍物);
  5. 功能区标注:人工在CAD图上圈出教室、走廊、楼梯间,导出为CSV,字段包括room_id, type(lecture/lab), area(m2), window_count, ac_type

关键代码片段(障碍物识别):

import cv2 import numpy as np # 墙体轮廓点阵(从CAD导出) wall_contours = np.array([[[x1,y1],[x2,y2],...]], dtype=np.int32) # 创建空白地图 grid_map = np.ones((160, 240)) * 255 # 255=空地 # 填充墙体 cv2.fillPoly(grid_map, wall_contours, 0) # 0=墙体 # 转为CA状态:0->O(障碍), 255->S(易感) ca_grid = np.where(grid_map == 0, 4, 0) # 4代表O态

这个过程耗时最长(6小时),但决定了模型的空间真实性。我们发现原图有3处尺寸标注错误,通过实地照片比对修正,这个细节让我们的空间风险图比其他队更准。

4.3 Wells-Riley模块的Python实现

核心是把公式转化为可微分、可更新的动态系统。我们不预计算P值,而是实时积分quanta浓度:

class WellsRileyEngine: def __init__(self, q=15.0, Q_std=0.45, lambda_base=0.5): self.q = q # quanta产生率 self.Q_std = Q_std # 标准呼吸频率 self.lambda_base = lambda_base # 基础通风率 self.quanta_conc = np.zeros((160, 240)) # 气溶胶浓度场 def update_concentration(self, ca_grid, time_step_min=1): """更新每个元胞的quanta浓度""" # 获取当前I态元胞位置 i_positions = np.where(ca_grid == 2) # 2代表I态 if len(i_positions[0]) == 0: return # 计算每个I态元胞的释放量 for i in range(len(i_positions[0])): y, x = i_positions[0][i], i_positions[1][i] # 动态通风率:课间(time%60<5)时λ=4.2,否则按基础值 current_lambda = self.lambda_base if self.current_time % 60 < 5: # 课间5分钟 current_lambda = 4.2 # 单位时间释放quanta量 release_rate = self.q * self.Q_std / (self.room_volume * current_lambda) # 向8邻域扩散(简化为高斯核) kernel = np.array([[0.0625, 0.125, 0.0625], [0.125, 0.25, 0.125], [0.0625, 0.125, 0.0625]]) # 更新浓度场 self.quanta_conc[y-1:y+2, x-1:x+2] += release_rate * kernel # 自然衰减(沉降+灭活) self.quanta_conc *= np.exp(-current_lambda * time_step_min / 60) def infection_probability(self, conc, exposure_time): """计算给定浓度下的感染概率""" return 1 - np.exp(-conc * exposure_time * self.Q_std / self.room_volume)

这个实现的关键是浓度场实时更新,而非静态P值计算。它让模型能捕捉“开窗瞬间浓度骤降”、“咳嗽后局部浓度飙升”等瞬态现象,这是纯ODE模型永远做不到的。

4.4 风险热力图的生成与解读

最终输出不是一堆数字,而是可交互的风险仪表盘。我们用matplotlib动画生成.gif:

def generate_risk_animation(ca_simulator, duration_hours=72): fig, ax = plt.subplots(figsize=(12, 8)) im = ax.imshow(np.zeros((160, 240)), cmap='RdYlBu_r', vmin=0, vmax=1) plt.colorbar(im, ax=ax, label='24h新发病例期望值') def animate(frame): # 运行1小时仿真 for _ in range(60): # 60分钟 ca_simulator.step() # 计算当前风险值 risk_map = ca_simulator.calculate_risk_map() # 自定义方法 im.set_array(risk_map) ax.set_title(f'风险热力图 - 第{frame+1}小时') return [im] anim = FuncAnimation(fig, animate, frames=duration_hours, interval=200, blit=True) anim.save('risk_animation.gif', writer='pillow') return anim

风险值定义为:未来24小时该元胞所在教室的新发病例数期望值,计算公式为:
Risk = Σ[P_infection(x,y,t) × S_count(x,y,t)]
其中P_infection由Wells-Riley模块实时输出,S_count是当前易感者数量。

解读要点:

  • 风险值>0.15:红色,需立即干预(如开窗、疏散);
  • 0.05<风险值≤0.15:黄色,加强监测;
  • 风险值≤0.05:绿色,正常状态。

我们在报告中用这个热力图定位了“高风险走廊节点”——不是教室内部,而是连接A、B教学楼的地下通道入口。仿真显示此处因气流涡旋,quanta滞留时间长达22分钟,风险值常年>0.18。这个发现被学校后勤处采纳,后续加装了定向排风扇。

5. 常见问题与排查技巧实录

5.1 仿真结果“全图变红”:通风参数设置失误

现象:运行10分钟后,整个教学楼风险值飙升至0.99,热力图一片血红,明显失真。

排查路径:

  1. 检查lambda_base是否误设为0.005(漏写小数点),正确值应为0.5;
  2. 查看room_volume计算:层高2.8m × 元胞面积0.25m² = 0.7m³,若误用教室总面积会放大1000倍;
  3. 验证q值单位:必须是quanta/小时,若用quanta/分钟会导致释放率暴涨60倍。

根因:我们在初版代码中把lambda_base写成0.05(少了个0),导致分母过小,P值趋近1。修复后风险值回归合理区间(0.01~0.25)。

5.2 动画卡顿/内存溢出:图形渲染优化

现象:生成gif时内存占用超4GB,程序崩溃。

解决方案:

  • 关闭figure默认dpi(300→100):plt.rcParams['savefig.dpi'] = 100
  • 使用blit=True只重绘变化区域;
  • FuncAnimationframes参数从range(72)改为np.arange(0, 72, 2)(每2小时一帧),文件大小减少65%;
  • PIL.Image替代matplotlib.animation直接合成gif,内存占用降至1.2GB。

实操心得:别迷信“高清”,评审专家看的是逻辑,不是像素。我们最终提交的gif分辨率为800×600,加载速度比1920×1080快3倍,且所有关键趋势清晰可见。

5.3 风险值始终为0:状态跃迁逻辑错误

现象:仿真跑完72小时,风险图全为0,没有新病例产生。

断点调试发现:ca_grid中I态(值为2)从未出现。追踪到E→I跃迁函数:

# 错误写法(概率恒为0) p = 0.3 * (1 - np.exp(-t/1.2)) # t初始为0,p=0 # 正确写法(t从1开始计) if t >= 1: p = 0.3 * (1 - np.exp(-(t-1)/1.2)) else: p = 0

原来t是潜伏小时数,初始为0,exp(0)=1,导致p=0。修正后,E态元胞在t=1小时后开始以概率跃迁,问题解决。

5.4 与真实数据偏差大:初始感染源定位不准

现象:用某高校2019年流感数据验证,模型预测爆发时间比实际晚36小时。

根因分析:我们把首例患者设在“教室中心”,但校医院记录显示首例在“图书馆二楼阅览区”。重新导入图书馆CAD图,将初始I态设在阅览区靠窗座位(通风好但人流大),预测时间误差缩小至±6小时。

这个教训告诉我们:初始条件不是技术问题,而是调研问题。我们后来增加了“数据溯源”章节,列出所有参数的来源(校医院年报、后勤处通风记录、学生体质报告),让模型可信度大幅提升。

6. 从B题到2026亚太杯A题:可迁移的核心能力

做完小美赛B题,我带学生复盘时总结出三条硬核能力,这些能力在2026亚太杯A题(“城市暴雨内涝风险动态评估”)中直接复用:

  • 空间离散化思维:把城市划分为100m×100m网格,每个网格的状态包括水深、流速、建筑密度、排水能力,用CA规则模拟积水扩散——和B题的元胞设计逻辑完全一致;
  • 多物理场耦合意识:B题耦合了流体力学(Wells-Riley)与流行病学(SEIR),A题要耦合水文学(降雨径流)、地理学(地形坡度)、交通工程(道路通行能力),建模框架一脉相承;
  • 决策导向输出设计:B题输出风险热力图指导防控,A题输出“交通中断概率图”指导应急调度,本质都是把复杂计算转化为可操作的决策信号。

最后分享一个小技巧:所有数学建模竞赛,先花2小时做“失败预演”——假设你的模型完全失效,最可能在哪一步崩?然后针对那个点设计验证方案。B题我们预判“通风参数失真”是最大风险,所以专门做了λ值灵敏度分析(±50%变化下风险值波动<12%),这个分析成了报告中最受好评的部分。建模不是追求完美,而是让每个环节都经得起质疑。

http://www.cnnetsun.cn/news/4243816.html

相关文章:

  • 主动推理:让AI智能体按需获取上下文,优化Token成本
  • 基于微信小程序的大学生心理健康系统的设计与实现毕业设计项目源码
  • AI编码代理的隐性成本:“氛围税”如何悄悄拖慢你的团队
  • 深度强化学习在电力系统机组组合优化中的应用与实践
  • C++11核心特性深度解析:从auto到移动语义的现代编程实践
  • 两位图形行业领袖加入AMD RTG,GPU软硬件生态战升级
  • 3U cPCI板卡式工业以太网交换机设计与实现
  • FigmaCN Figma 中文插件:三步把 Figma 界面变成中文
  • 为什么2026年必须全站HTTPS?拆解慢贵难谣言+标准化迁移步骤
  • 共享缓冲与操作系统缓存如何配合——读密集系统内存调优实践
  • 机器人8小时工作制:从融资热潮到稳定落地的工程考验
  • 面向空间应用的新型抗辐射MOSFET加固技术与选型解析
  • 图生3d img2threejs 相机3d重建
  • 组合数计算全解:从定义到算法,一张图掌握核心方法与实战策略
  • 4000流明LED光引擎深度解析:散热、驱动与选型全指南
  • 渲染引擎实践 - UnrealEngine Render 介绍
  • 回源慢3秒,AI直接跳过你
  • 汽车制造缓存区调度优化:灰狼算法与动态规划在排序与路径规划中的应用
  • 蓝桥杯国赛Python攻略:从算法思维到工程实践的能力跃迁
  • VSCode如何配置LlamaIndex RAG(检索增强生成)应用开发环境
  • 从大厂到创业公司,管理上需要怎样转变?
  • Matlab优化用户侧储能配置:峰谷套利与辅助服务经济性分析
  • MATLAB fmincon函数实战:从建模到求解约束优化问题
  • 从Token到Next Token:一文读懂大语言模型生成原理
  • Muon优化器与Mamba:状态空间模型的谱优化实战
  • Matlab/Simulink 二维查表导入Excel表格数据的方法总结
  • 智能体测开Day59
  • 用AssetStudio快速解包Unity资源
  • 基于MATLAB的储药柜多目标优化设计:数学建模与遗传算法实践
  • 机器人百米破纪录背后:高速奔跑的运动控制与工程实践