数学建模里,种群竞争模型是我每次带学生备赛时都会反复强调的一个经典模型。它看似只是两个微分方程,但背后牵扯到的参数设计、稳定性分析、数值求解、结果解释,几乎覆盖了建模竞赛从建模到论文的全部核心环节。这篇文章是我自己梳理的一份完整学习笔记,从建模思路讲到代码实现,再到竞赛论文里容易翻车的细节,争取让零基础的同学也能照着推一遍、跑一遍、改一遍就上手。
1. 先看建模思路:竞争模型到底在模拟什么现象
种群竞争模型不是凭空造出来的,它是从单种群增长模型自然扩展出来的。很多教材直接甩出两个微分方程,但没有说清楚这些项为什么长这样。如果只背公式,遇到竞赛题稍微变个背景就麻了。
1.1 从 Logistic 单种群模型说起
单种种群在有限环境下的增长,经典方程是 Logistic 模型:
[ \frac{dN}{dt}=rN\left(1-\frac{N}{K}\right) ]
这里面 (N) 是种群数量,(r) 是内禀增长率,也就是在资源无限时的最大增长速度,(K) 是环境容纳量,也就是这个环境最多能养活多少个个体。(\frac{N}{K}) 可以理解成“已经被占用的资源比例”,(1-\frac{N}{K}) 就是“还没有被占用的资源比例”。种群数量越接近环境容量,增长越慢,最终稳定在 (N=K)。
这个方程自己已经能解释很多生态现象。但自然界里很少有物种真正单独生活,两个物种如果吃同样的食物、占据同样的空间,就存在竞争关系。于是问题就变成了:两个物种能不能共存?谁能活下来?结局是有条件的吗?这些就是竞争模型要回答的核心问题。
1.2 双物种竞争方程的建立
先直接写出两个物种竞争的标准形式:
[ \frac{dx}{dt}=r_1 x\left(1-\frac{x}{K_1}-\alpha_{12}\frac{y}{K_1}\right) ]
[ \frac{dy}{dt}=r_2 y\left(1-\frac{y}{K_2}-\alpha_{21}\frac{x}{K_2}\right) ]
记号说明:(x(t)) 和 (y(t)) 是两个物种种群数量,(r_1,r_2) 是各自的增长率,(K_1,K_2) 是各自单独存在时的环境容纳量,(\alpha_{12}) 是物种 2 对物种 1 的竞争系数,(\alpha_{21}) 是物种 1 对物种 2 的竞争系数。
这里最关键的就是竞争系数。它的含义要特别讲清楚:(\alpha_{12}) 表示一个物种 2 个体对资源的消耗相当于 (\alpha_{12}) 个物种 1 个体的消耗。比如说 (\alpha_{12}=0.5),意味着一个 y 物种个体吃掉的资源只相当于半个 x 物种个体。所以原本 x 物种自己能用的资源比例是 (1-\frac{x}{K_1}),现在还要把 y 带来的资源占用扣掉,就变成了 (1-\frac{x}{K_1}-\alpha_{12}\frac{y}{K_1})。
这类方程也叫 Lotka-Volterra 竞争方程。形式对称,含义清楚,是生态学里最基础的竞争框架,也是竞赛题喜欢拿来改编的原型。
1.3 参数到底该怎么理解
很多同学写模型的时候把参数当成摆设,这是大忌。建模竞赛里,模型的价值不在于方程多复杂,而在于每一个参数都能和实际问题对应。比如两个企业在争夺同一批客户,(x) 和 (y) 可以是两个平台的活跃用户数,(K_1,K_2) 是整个市场对两个平台各自能容纳的最大用户规模,(\alpha_{12}) 可以理解成平台 2 的一个用户对平台 1 用户资源的挤占程度。
如果是两个农作物品种争抢同一块地的养分和光照,(\alpha) 就代表了品种间的竞争强度。参数有了现实解释,后面的灵敏度分析和结论才有意义。
2. 无量纲化:让模型少两个参数,也让你看清本质
第一次看到上面的方程,会觉得参数太多了:两个增长率、两个容纳量、两个竞争系数,一共六个参数。直接分析会非常繁琐。数学建模里处理这类问题有一个很标准的操作,无量纲化。它不只是简化符号,更能把控制模型行为的因素压缩到最核心的几个组合参数上。
2.1 无量纲化的具体步骤
设:
[ u=\frac{x}{K_1},\quad v=\frac{y}{K_2},\quad \tau=r_1 t ]
这样 (u,v) 变成了两只种群分别占自己环境容量比例的无量纲量,(\tau) 是新的时间尺度。代入原方程并整理,令 (\rho=\frac{r_2}{r_1}),(\alpha=\alpha_{12}\frac{K_2}{K_1}),(\beta=\alpha_{21}\frac{K_1}{K_2}),方程就变成:
[ \frac{du}{d\tau}=u(1-u-\alpha v) ]
[ \frac{dv}{d\tau}=\rho v(1-v-\beta u) ]
新的组合参数 (\alpha,\beta,\rho) 比原来直观很多,模型的行为主要就由 (\alpha) 与 (1) 的关系、(\beta) 与 (1) 的关系来区分。后面的稳定性分析可以完全基于这个简化形式进行,结果再反推回原参数即可。
2.2 无量纲化为什么重要
第一,它减少了参数数量,分析难度直接下降。第二,它让“量纲不同不能直接比较”的问题消失,不同物种的竞争关系可以在同一尺度上比较。第三,在写论文时,这一步能体现建模功底的严谨性,评审老师看到这个操作,通常会认为你对模型有过深入思考。
我之前见过有队伍的论文,从头到尾守着六个参数硬算平衡点,算到最后表达式已经是一大串代号,特征值判断根本做不下去。而做了无量纲化的队伍,两三页就把稳定性分析讲清楚了。差距就是这么拉开的。
3. 稳定性分析:四种结局背后的数学逻辑
竞争模型的最终结局,完全由平衡点的稳定性决定。而平衡点的稳定性,又完全由参数 (\alpha,\beta) 落在哪个区间决定。这部分是模型的核心数学论证,也是竞赛论文中必须写清楚的部分。
3.1 平衡点求解
令方程组右边等于零,也就是种群数量不再改变:
[ u(1-u-\alpha v)=0 ]
[ \rho v(1-v-\beta u)=0 ]
解得四类平衡点:
- (E_1=(0,0)):两个物种都灭绝。
- (E_2=(1,0)):物种 1 达到环境容量,物种 2 灭绝。
- (E_3=(0,1)):物种 2 达到环境容量,物种 1 灭绝。
- (E_4=\left(\frac{1-\alpha}{1-\alpha\beta},\frac{1-\beta}{1-\alpha\beta}\right)):两物种共存,但只在这两个坐标都为正且有实际意义时存在。
其中 (E_4) 的存在条件很关键,需要分子分母同号,即 ((1-\alpha)(1-\alpha\beta)>0) 且 ((1-\beta)(1-\alpha\beta)>0)。后面会看到,这个条件会直接影响最终是哪一方胜出。
3.2 用雅可比矩阵判断稳定性
对无量纲化后的方程,计算雅可比矩阵 (J):
设
[ f(u,v)=u(1-u-\alpha v) ]
[ g(u,v)=\rho v(1-v-\beta u) ]
则
[ J= \begin{bmatrix} \frac{\partial f}{\partial u} & \frac{\partial f}{\partial v} \ \frac{\partial g}{\partial u} & \frac{\partial g}{\partial v} \end{bmatrix}
\begin{bmatrix} 1-2u-\alpha v & -\alpha u \ -\rho\beta v & \rho(1-2v-\beta u) \end{bmatrix} ]
把每个平衡点代入,考察矩阵特征值实部的符号。若两个特征值实部都为负,则该平衡点是局部渐近稳定的;若存在正实部特征值,则不稳定。
以 (E_2=(1,0)) 为例,代入后:
[ J(E_2)= \begin{bmatrix} -1 & -\alpha \ 0 & \rho(1-\beta) \end{bmatrix} ]
特征值就是主对角线上的 (-1) 和 (\rho(1-\beta))。因为 (-1<0) 恒成立,所以 (E_2) 稳定与否取决于 (1-\beta) 的符号。若 (\beta<1),即物种 1 对物种 2 的竞争压力不够大,则 (E_2) 稳定,意味着物种 1 胜出、物种 2 被排挤掉。
3.3 四种典型结局及其参数条件
汇总起来,整个系统的行为可以分为四类:
| 参数条件 | 稳定平衡点 | 生态结局 |
|---|---|---|
| (\alpha<1,\ \beta<1) | (E_4) | 两物种共存 |
| (\alpha>1,\ \beta<1) | (E_2=(1,0)) | 物种 1 胜出,物种 2 灭绝 |
| (\alpha<1,\ \beta>1) | (E_3=(0,1)) | 物种 2 胜出,物种 1 灭绝 |
| (\alpha>1,\ \beta>1) | (E_2) 或 (E_3),取决于初值 | 竞争排斥,强者胜出 |
注意最后一行的“取决于初值”。当双方竞争都比较激烈时,共存不可能,谁赢取决于一开始谁的数量优势大,历史路径在这里起了决定性作用。这个结论放在经济竞争背景里特别有意思,先发优势、市场占有率领先会产生根本性影响。
4. 上机实操:用 MATLAB 和 Python 把模型跑起来
数学推导再漂亮,最终要在论文里放图表,要展示不同参数下的动态过程。数值模拟是不可跳过的一步。我习惯用 MATLAB 做演示,用 Python 做批量参数扫描,两个都值得掌握。
4.1 MATLAB 实现
使用ode45求解微分方程的标准代码:
% population_competition.m % 无量纲化的 Lotka-Volterra 竞争模型 clear; clc; % 参数设置 alpha = 0.5; % 物种2 对物种1 的竞争作用 beta = 0.5; % 物种1 对物种2 的竞争作用 rho = 1.0; % 增长率之比 r2/r1 % 定义微分方程 f = @(tau, z) [ z(1) * (1 - z(1) - alpha * z(2)); rho * z(2) * (1 - z(2) - beta * z(1)) ]; % 初始条件:u0, v0 z0 = [0.4; 0.6]; % 时间范围 tspan = [0, 50]; % 求解 [tau, z] = ode45(f, tspan, z0); % 绘图:时序图 figure; plot(tau, z(:,1), 'b-', 'LineWidth', 1.5); hold on; plot(tau, z(:,2), 'r--', 'LineWidth', 1.5); xlabel('无量纲时间 \tau'); ylabel('种群比例 u, v'); legend('物种 1 (u)', '物种 2 (v)', 'Location', 'best'); grid on; title(['\alpha = ', num2str(alpha), ', \beta = ', num2str(beta)]); % 绘图:相图 figure; plot(z(:,1), z(:,2), 'k-', 'LineWidth', 1.5); xlabel('u'); ylabel('v'); grid on; title('相图轨迹');这段代码跑出来,时序图展示两个种群随时间从初值演化到平衡点,相图展示系统状态在 (u-v) 平面上的运动轨迹。建议每个参数组合都跑一遍,观察四类结局的曲线形态差异,这样对模型的理解会直观很多。
4.2 Python 实现
用scipy.integrate.solve_ivp实现同样功能:
import numpy as np import matplotlib.pyplot as plt from scipy.integrate import solve_ivp # 参数定义 alpha = 0.5 beta = 0.5 rho = 1.0 # 微分方程 def competition(t, z): u, v = z du_dt = u * (1 - u - alpha * v) dv_dt = rho * v * (1 - v - beta * u) return [du_dt, dv_dt] # 初始条件与时间区间 z0 = [0.4, 0.6] t_span = (0, 50) t_eval = np.linspace(0, 50, 500) # 求解 sol = solve_ivp(competition, t_span, z0, t_eval=t_eval, method='RK45') # 绘图 fig, axes = plt.subplots(1, 2, figsize=(12, 4)) axes[0].plot(sol.t, sol.y[0], label='物种 1 (u)') axes[0].plot(sol.t, sol.y[1], label='物种 2 (v)') axes[0].set_xlabel('无量纲时间') axes[0].set_ylabel('种群比例') axes[0].legend() axes[0].grid(True) axes[1].plot(sol.y[0], sol.y[1], 'k-') axes[1].set_xlabel('u') axes[1].set_ylabel('v') axes[1].grid(True) plt.tight_layout() plt.show()我建议把 (\alpha,\beta) 做成循环参数,批量画出九宫格图,一组画时序图,一组画相图。这样论文里的参数分析部分图文并茂,同时也方便自己对全部情况有整体把握。
4.3 参数组合设计策略
做参数分析时,不建议随机取值,要对着稳定性结论表设计:
- 第一组:(\alpha=0.5,\beta=0.5),对应两物种共存。
- 第二组:(\alpha=1.5,\beta=0.5),对应物种 1 胜出。
- 第三组:(\alpha=0.5,\beta=1.5),对应物种 2 胜出。
- 第四组:(\alpha=1.5,\beta=1.5),再分别取初值 ((0.2,0.8)) 和 ((0.8,0.2)),观察竞争排斥中初值的作用。
每一组跑完,记录平衡点、收敛时间、曲线形态,这些记录最后可以整理成论文里的数值实验表格。
5. 一个完整案例:从参数设定到论文结论
理论学习容易飘,我带你完整走一个案例。假设要研究同一片草原上两个食草动物种群的数量演变,物种 1 体型小、繁殖快,物种 2 体型大、繁殖慢,但单个体对牧草的消耗更大。
5.1 参数还原
设物种 1 的环境容纳量为 1000 只,物种 2 为 500 只。增长率 (r_1=0.8) 每年,(r_2=0.4) 每年。一个物种 2 个体的采食量相当于 1.2 个物种 1 个体的采食量,即 (\alpha_{12}=1.2);一个物种 1 个体对物种 2 的资源挤占相对较小,取 (\alpha_{21}=0.4)。
按照前面的组合公式:
[ \alpha=\alpha_{12}\frac{K_2}{K_1}=1.2 \times \frac{500}{1000}=0.6 ]
[ \beta=\alpha_{21}\frac{K_1}{K_2}=0.4 \times \frac{1000}{500}=0.8 ]
判断条件,(\alpha<1) 且 (\beta<1),理论预测两物种共存。
5.2 数值模拟结果
取初值 ((x_0,y_0)=(300,200)),运行代码后,两个种群都会先经历一段增长,之后逐渐向某个平衡比例靠拢。最终平衡点用公式计算:
[ u^*=\frac{1-\alpha}{1-\alpha\beta}=\frac{1-0.6}{1-0.6\times 0.8}\approx 0.7143 ]
[ v^*=\frac{1-\beta}{1-\alpha\beta}=\frac{1-0.8}{1-0.6\times 0.8}\approx 0.3571 ]
换算回原始数量:(x^=u^\times K_1 \approx 714) 只,(y^=v^\times K_2 \approx 179) 只。
这个结果可以直接写进论文:在给定参数下,物种 1 与物种 2 能够在同一环境中长期共存,但稳定数量比例约为 4 比 1,说明该环境下体型小、繁殖快的物种在资源竞争中占据明显优势。
5.3 从模拟到论文的语言转换
很多队伍模拟做完了,但不会写进论文。我建议按这个顺序组织段落:第一段说明参数来源和取值依据,第二段展示稳定条件判定,第三段给出模拟误差验证。把数值解与解析平衡点做对比,比如验证一下最终解是否落在 (u^,v^) 上,这个“模型检验”环节在竞赛评分里非常加分。
6. 竞赛论文必看:灵敏性分析与模型扩展方向
种群竞争模型是基础模型,竞赛题通常不会要求你只列个方程就交差,而是需要在此基础上做深入分析。哪些方向最常用,我总结几个。
6.1 灵敏性分析怎么做
灵敏性分析本质上是考察参数变化对结论的影响。最简单实用的做法是参数扫描。以竞争系数为例,固定 (\rho=1),让 (\alpha) 和 (\beta) 分别从 0.2 变化到 2.0,每次改变 0.2,共 100 组参数组合,每组都跑一遍模拟并判断平衡点的位置。然后把 ((u^,v^)) 画成热力图或等值线图。
在论文里,灵敏性分析的核心不是“我画了很多图”,而是给出管理对策或生态解释。举例来说,如果发现 (\alpha) 从 0.9 变为 1.1 时系统从共存跳到物种 1 胜出,说明系统在这个参数附近非常脆弱,微小的环境变化可能导致物种灭绝。这种结论比单纯展示图表更有价值。
6.2 模型扩展之一:时变环境容纳量
现实中的环境容纳量不是常数,季节变化、自然灾害都会改变 (K)。可以把 (K) 改写成时间的函数,例如:
[ K(t)=K_0\left(1+\epsilon\sin(\omega t)\right) ]
代入原始方程后,再用数值方法求解。这个扩展会让论文从静态分析升级到环境变化下的动态响应分析,尤其是可以研究环境波动会不会让本来稳定的共存变得不稳定。
6.3 模型扩展之二:多物种竞争
竞赛题如果涉及三种以上物种,可以直接把方程组推广到 (n) 个物种:
[ \frac{dx_i}{dt}=r_i x_i\left(1-\frac{x_i}{K_i}-\sum_{j\neq i}\alpha_{ij}\frac{x_j}{K_i}\right) ]
矩阵形式的竞争系数 (\alpha_{ij}) 可以展开非常丰富的分析,比如食物网结构、竞争网络拓扑对系统稳定的影响。建模深度会明显提升,但计算量也大幅增加。
6.4 模型扩展之三:延迟与随机扰动
有些物种繁殖存在明显的时间滞后,例如昆虫从产卵到成虫有一个发育周期,这时可以引入延迟微分方程。而随机扰动则对应着极端天气、突发灾害等随机因素,需要引入随机微分方程。
这两类扩展都适合作为高难度题的加分点,但要注意控制篇幅和难度。竞赛时间有限,过度扩展导致模型无法求解是最大的风险。我的建议是选择一个扩展方向做深做透,比贪多嚼不烂要有效得多。
7. 踩坑记录:调试种群模型时我反复遇到的几个问题
这部分是真正从实操里积累出来的。几乎每次有同学跑这个模型,都会在下面几个环节卡一下,提前对照可以省不少时间。
7.1 参数单位与数量级不匹配
最典型的错误是直接把 (K) 设置为 1000,把 (\alpha) 设置为 0.5,不加换算就塞进无量纲化方程。但如果你用的是无量纲化后的方程,(u,v) 必须是在 0 到 1 附近的数。直接把 1000 和 500 代进去,数值积分很容易出现病态甚至溢出。
解决办法是先做无量纲化再写代码,或者在原始方程中保持单位一致。代码里的变量含义要非常清楚:是原始数量还是无量纲比例,必须写注释。
7.2 初值设置不当导致数值发散
无量纲方程的合理初值应该在 0 到 1 之间。如果初值写成了 10 或者负数,数值积分很容易在早期就产生震荡,然后系统发散。虽然这个模型本身在正锥上是耗散的,但积分器在初值不合理时仍然可能出现数值爆掉。最简单的方法是把初值设置在平衡点附近,再逐渐扩大范围。
7.3 绘图缺少关键信息
竞赛论文里图的质量直接影响第一印象。很多图的横纵坐标不标物理量、没有图例、曲线颜色难以区分。我做这部分内容时,要求自己每张图必须有完整坐标标签,两物种曲线要用不同线型和颜色区分,图上要标注参数数值。另外一个容易被忽视项是时间范围,模拟时间不能太短,否则还没收敛到平衡点,看起来就像系统持续振荡。
7.4 特征值符号判断误用
判断平衡点稳定性时,要代入雅可比矩阵后看特征值实部,而不是看特征值本身。有的同学算出复数特征值就慌了,以为不稳定。实际上只要实部为负,即使是复数特征值,平衡点依然是稳定的,只是收敛过程会带有振荡特征。
7.5 相图画反了方向
相图故意展示轨线从初值走向平衡点的过程,方向必须与时间演化一致。建议在曲线上用箭头标注时间方向,或者用颜色渐变表示时间推进。这个细节做好了,论文的专业质感会提高一个档次。
8. 一点个人的经验总结
我做了这么多年建模相关的东西,最深的体会是:种群竞争模型之所以值得认真掌握,不只是因为它本身是经典,更因为它的分析套路可以迁移到大量其他问题中。判断取舍、分析多重因子影响、寻找稳定状态,这些思路在资源配置、市场争夺、舆情扩散、甚至一些工程优化问题里都是通用的。
实际操作中还有一个小技巧是,在正式求解前先用代数方法求出所有平衡点,再通过数值模拟验证。这样一旦数值结果和理论结果对不上,能立刻意识到可能存在问题,而不是盲目相信一个肉眼看着合理的曲线。这个习惯帮我避免过好几次重大失误,希望你也能用得上。