📖 第15课:生态系统仿真

捕食-猎物 Lotka-Volterra 空间生态 多样性

🌿 用CA模拟生态系统

生态系统是复杂系统的经典范例——捕食者与猎物、竞争与共生、入侵与灭绝。CA提供了模拟这些现象的天然框架。

Lotka-Volterra方程与CA

经典Lotka-Volterra方程(连续):

dx/dt = αx - βxy(猎物增长 - 被捕食)

dy/dt = δxy - γy(捕食者增长 - 自然死亡)

CA离散化:每个元胞有3个状态:空(0)、猎物(1)、捕食者(2)

规则:

⚡ 生态系统CA引擎

三态生态系统CA

// ============================================================================
// ecosystem_ca.v - 三态捕食-猎物生态系统CA
// 状态: 0=空, 1=猎物(Prey), 2=捕食者(Predator)
// 使用Von Neumann邻域(4邻居),支持概率性规则
// ============================================================================
module ecosystem_ca #(
    parameter WIDTH  = 64,
    parameter HEIGHT = 64,
    parameter PREY_BIRTH_PROB  = 4'd3,   // 猎物繁殖概率 (3/16)
    parameter PRED_DEATH_PROB  = 4'd2,   // 捕食者死亡概率 (2/16)
    parameter PRED_CATCH_RANGE = 4'd1    // 捕食范围
)(
    input  wire             clk,
    input  wire             rst_n,
    input  wire             enable,
    input  wire             init,
    output wire [1:0]       grid_out [0:WIDTH*HEIGHT-1],  // 2位/元胞
    output wire [31:0]      prey_count,
    output wire [31:0]      pred_count,
    output wire [31:0]      empty_count,
    output wire [31:0]      step_count
);

    // ---- 网格状态 ----
    reg [1:0] grid_curr [0:WIDTH*HEIGHT-1];
    reg [1:0] grid_next [0:WIDTH*HEIGHT-1];

    // ---- 伪随机数 ----
    reg [15:0] rng;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) rng <= 16'hACED;
        else rng <= {rng[14:0], rng[15] ^ rng[14] ^ rng[12] ^ rng[3]};
    end

    // ---- 邻居计数 ----
    integer idx, x, y;
    reg [3:0] prey_nb, pred_nb;

    always @(*) begin
        for (idx = 0; idx < WIDTH*HEIGHT; idx = idx + 1) begin
            x = idx % WIDTH;
            y = idx / WIDTH;
            prey_nb = 0; pred_nb = 0;

            // Von Neumann邻域
            if (y > 0) begin
                prey_nb = prey_nb + (grid_curr[idx-WIDTH] == 2'd1);
                pred_nb = pred_nb + (grid_curr[idx-WIDTH] == 2'd2);
            end
            if (y < HEIGHT-1) begin
                prey_nb = prey_nb + (grid_curr[idx+WIDTH] == 2'd1);
                pred_nb = pred_nb + (grid_curr[idx+WIDTH] == 2'd2);
            end
            if (x > 0) begin
                prey_nb = prey_nb + (grid_curr[idx-1] == 2'd1);
                pred_nb = pred_nb + (grid_curr[idx-1] == 2'd2);
            end
            if (x < WIDTH-1) begin
                prey_nb = prey_nb + (grid_curr[idx+1] == 2'd1);
                pred_nb = pred_nb + (grid_curr[idx+1] == 2'd2);
            end

            // 规则应用
            case (grid_curr[idx])
                2'd0: begin  // 空
                    // 猎物繁殖:邻近有猎物 → 概率性变为猎物
                    if (prey_nb > 0 && rng[3:0] < PREY_BIRTH_PROB)
                        grid_next[idx] = 2'd1;
                    else
                        grid_next[idx] = 2'd0;
                end
                2'd1: begin  // 猎物
                    // 被捕食:邻近有捕食者 → 变为捕食者
                    if (pred_nb > 0)
                        grid_next[idx] = 2'd2;
                    else
                        grid_next[idx] = 2'd1;  // 安全存活
                end
                2'd2: begin  // 捕食者
                    // 饿死:邻近无猎物 → 概率性死亡
                    if (prey_nb == 0 && rng[7:4] < PRED_DEATH_PROB)
                        grid_next[idx] = 2'd0;
                    else
                        grid_next[idx] = 2'd2;  // 存活
                end
            endcase
        end
    end

    // ---- 状态更新 ----
    reg [31:0] step_reg;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            step_reg <= 32'd0;
        end else if (init) begin
            step_reg <= 32'd0;
            // 随机初始化
            for (idx = 0; idx < WIDTH*HEIGHT; idx = idx + 1)
                grid_curr[idx] <= rng[1:0];  // 0/1/2随机
        end else if (enable) begin
            for (idx = 0; idx < WIDTH*HEIGHT; idx = idx + 1)
                grid_curr[idx] <= grid_next[idx];
            step_reg <= step_reg + 32'd1;
        end
    end

    // ---- 种群计数 ----
    reg [31:0] pc, dc, ec;
    always @(*) begin
        pc = 0; dc = 0; ec = 0;
        for (idx = 0; idx < WIDTH*HEIGHT; idx = idx + 1) begin
            case (grid_curr[idx])
                2'd0: ec = ec + 1;
                2'd1: pc = pc + 1;
                2'd2: dc = dc + 1;
            endcase
        end
    end

    assign prey_count  = pc;
    assign pred_count  = dc;
    assign empty_count = ec;
    assign step_count  = step_reg;

    genvar gi;
    generate
        for (gi = 0; gi < WIDTH*HEIGHT; gi = gi + 1)
            assign grid_out[gi] = grid_curr[gi];
    endgenerate

endmodule

📊 生态系统动态

相图分析

Lotka-Volterra系统的典型行为是振荡

  1. 猎物增多 → 捕食者增多
  2. 捕食者增多 → 猎物减少
  3. 猎物减少 → 捕食者饿死
  4. 捕食者减少 → 猎物恢复
  5. 回到第1步

CA版本比微分方程版本多了一个关键特征——空间效应

🏋️ 练习

练习15.1:运行生态系统CA 1000步,绘制猎物和捕食者种群的时间曲线。是否出现Lotka-Volterra式振荡?
练习15.2:添加第三个物种——"植物"(猎物的食物)。构建三级食物链:植物→猎物→捕食者。
练习15.3:修改规则,使猎物有"逃跑"行为——倾向于远离捕食者移动。观察对种群动态的影响。
练习15.4:在网格中设置"地形障碍"(不可通过的元胞),观察障碍如何影响种群的空间分布和基因流。
练习15.5(挑战):实现"共生"关系——两种物种在邻近时都获得繁殖优势。观察共生如何影响生态系统的稳定性。

🏆 成就解锁

🏅 生态建筑师

人工生命阶段完成!你已经用CA模拟了生态系统的核心动态——捕食、竞争、空间效应。

📐 深入分析:空间生态学的数学模型

空间Lotka-Volterra的稳定性分析

ODE版本(无空间):共存平衡点存在但不稳定→振荡

CA版本(有空间):空间效应可以稳定共存!

机制:猎物在局部灭绝后,该区域成为"避难所",之后被邻近猎物重新殖民

这种"灭绝-殖民"循环在空间中创造了持久的异质性

空间相关性

定义空间相关函数 C(r) = ⟨n(x)n(x+r)⟩ - ⟨n⟩²

对于混沌相:C(r)指数衰减

对于结晶相:C(r)长程有序

临界点:C(r)幂律衰减 C(r) ~ r^(-η)

补充实现

// 种群统计器 - 计算生态系统CA的多种统计量
module population_stats #(
    parameter WIDTH = 64,
    parameter HEIGHT = 64
)(
    input  wire             clk,
    input  wire             rst_n,
    input  wire [1:0]       grid [0:WIDTH*HEIGHT-1],
    output wire [31:0]      prey_count,
    output wire [31:0]      pred_count,
    output wire [31:0]      prey_clusters,  // 猎物聚集区数
    output wire [31:0]      avg_cluster_size
);
    reg [31:0] pc, dc, clusters, avg_sz;
    integer idx;
    always @(*) begin
        pc = 0; dc = 0; clusters = 0;
        for (idx = 0; idx < WIDTH*HEIGHT; idx = idx + 1) begin
            case (grid[idx])
                2'd1: pc = pc + 1;
                2'd2: dc = dc + 1;
            endcase
        end
        avg_sz = (clusters > 0) ? pc / clusters : 32'd0;
    end
    assign prey_count = pc;
    assign pred_count = dc;
    assign prey_clusters = clusters;
    assign avg_cluster_size = avg_sz;
endmodule

性能与优化分析

生态系统CA的应用

1. 入侵物种建模:模拟外来物种的扩散和本地物种的响应

2. 保护区设计:确定最优的保护区形状和大小以维持生物多样性

3. 流行病学:SIR模型的CA版本,模拟疾病在空间中的传播

4. 渔业管理:模拟捕捞对鱼群空间分布的影响

📖 扩展阅读

🔬 补充专题:实验方法论

在进行CA实验时,科学的方法论至关重要。以下是一些通用的实验指导原则:

实验设计三要素

  1. 控制变量:每次只改变一个参数,保持其他不变
  2. 可重复性:记录所有参数,确保实验可以精确复现
  3. 统计显著性:多次运行取平均,避免偶然结果误导

参数扫描方法

系统性地扫描参数空间是理解CA行为的关键技术:

参数范围步长测量指标
规则号0-2551种群密度/周期
初始密度0.1-0.90.1收敛时间
网格大小16-256×2有限尺寸效应
边界条件环形/固定/镜像离散边界效应
💡 实验记录模板:每次实验记录以下信息——日期、规则号、初始条件、网格大小、边界条件、运行步数、关键观察、数据文件路径。这是科学研究的良好习惯,也使得结果可以追溯和验证。

数据可视化技巧

CA实验产生的数据通常是高维的(空间+时间+状态)。有效的可视化对于理解至关重要:

自相关分析

时间自相关:R(τ) = ⟨n(t)·n(t+τ)⟩ / ⟨n²⟩

空间自相关:C(r) = ⟨n(x)·n(x+r)⟩ / ⟨n²⟩

如果R(τ)以周期T振荡 → 系统有周期T的行为

如果C(r)幂律衰减 → 系统处于临界状态

元胞自动机课程 · 从Conway到Langton到Lattice Gas