Matlab实现元胞自动机模拟城市增长:从规则设定到代码实践
2026/9/2 4:30:31 网站建设 项目流程

简介:基于元胞自动机的Matlab城市增长模拟项目,以印度艾哈迈达巴德地区为案例,演示如何利用CA模型预测土地利用变化与城市扩张趋势,适合城市规划、地理信息及复杂系统建模的学习者和研究者。压缩包共12个文件、105KB,核心为7个m脚本,涵盖主程序、邻域过滤、道路距离计算、影像读取与土地利用状态转换等模块,另有运行说明txt和示例结果图片,便于对照理解模型输出。其他辅助代码则提供数据预处理、后处理等不同实现策略,可支撑二次开发。已有264人学习浏览,可作为城市模拟课程设计或元胞自动机入门实践的轻量参考。通过研读主程序与辅助函数,可掌握状态转移规则设定、邻域效应量化等关键步骤,借助示例图直观检验模拟效果,整体结构清晰、易于复现。 做城市规划模拟这几年,我越来越觉得元胞自动机这套思路值得被更多人掌握。Matlab里实现元胞自动机模拟城市增长,不仅比传统统计模型直观,而且能直接把“地块—邻域—规则”的演化过程跑出来给你看。这篇内容就是我基于实际项目经验,把从模型设计、规则设定、Matlab代码实现到结果解读、疑难排查的全过程整理出来,适合正在做土地利用变化、城市扩展模拟相关课题的研究生和规划从业者,也适合想快速上手元胞自动机的技术爱好者。

1. 项目思路与模型设计

1.1 为什么选元胞自动机做城市增长模拟

城市增长本质上是一个自下而上的时空演化过程:每个地块是否从非城市状态转变为城市状态,往往取决于它周边的开发情况、交通可达性、地形约束和政策分区。传统方法里,回归模型能描述“哪些因素影响增长”,但很难表达“地块之间是怎么互相影响”的。元胞自动机天然适合这个场景——它把研究区划分成规则网格,每个格子的状态由上一时刻自身状态和邻域状态共同决定,迭代推进就能模拟出城市蔓延的过程。

我在项目里选择元胞自动机的另一个重要原因是它的可解释性。相比深度学习方法,元胞自动机每次状态转换都有明确的规则逻辑,规划部门审阅报告时,你能把“为什么这里会变成建设用地”讲清楚,而不是甩出一个黑箱概率。这一点在落地项目中非常关键。

1.2 整体架构与数据流设计

项目的数据流可以拆成四层:基础数据层、模型计算层、规则控制层和结果输出层。

基础数据层需要准备三类数据:研究区的土地利用现状栅格(已建成区作为初始状态)、驱动因子栅格(到道路距离、到市中心距离、坡度、高程等)以及限制性区域栅格(水体、基本农田、生态红线等)。模型计算层就是元胞自动机迭代核心,每一轮扫描整个栅格,根据转换概率判断每个元胞是否从“非城市”变为“城市”。规则控制层用于调整转换规则中的权重参数和阈值,通常会用历史年份数据做校准。结果输出层负责把模拟结果可视化,并与实际数据进行精度对比。

这套架构最大的好处是模块解耦。你可以单独更换驱动因子数据,或者调整规则文件,而不需要动主程序。实际跑项目时你会发现,数据清洗往往比写模型代码更耗时,所以数据层初期就做好标准化处理,后面能省很多事。

2. 核心规则设定与参数确定

2.1 元胞状态与邻域结构选择

项目中每个元胞状态我定义为三种:城市用地、非城市可开发用地、不可开发用地。之所以不把非城市用地细分成耕地、林地等更多类别,是因为模型目标是模拟“城市增长边界”,而不是精确还原地类之间的转移矩阵;状态太多会显著增加规则复杂度和校准难度。

邻域结构我选了经典的 Moore 3x3 邻域,也就是中心元胞周围的8个格子。计算城市开发密度时,用邻域内已开发像元数除以邻域内可开发像元总数。有些研究会用扩展邻域(5x5或更大),我实测下来,3x3邻域在城市建设用地模拟中响应更灵敏,能较好表现出临近开发的集聚效应;5x5邻域适合模拟尺度较大的城市群扩展,具体选择要看研究区大小和分辨率。如果栅格分辨率是30米,3x3邻域对应90米范围,对单核城市扩展已经足够。

2.2 转换概率与约束条件

元胞自动机核心的转换公式是:

P_total = P_development × Ω_neighborhood × constraints

P_development 是发展适宜性概率,基于驱动因子通过Logistic回归计算得到。Logistic回归的好处是输出值范围在0到1之间,天然适配概率解释。公式为:

P_development = 1 / (1 + exp(-(β0 + β1·X1 + β2·X2 + ... + βn·Xn)))

其中 X 是标准化后的驱动因子,β 是回归系数。我在实际项目中取到市中心距离、到主干道距离、到已有建成区距离、坡度、人口密度五个因子。回归样本从现状城市扩展区和未开发区中各抽取等量点,避免样本不平衡。

Ω_neighborhood 是邻域开发密度,范围为0到1。constraints 是约束层,不可开发区域直接乘0,可开发区域乘1。

迭代中还有一个随机扰动项:只有当 P_total 大于设定的随机阈值时才发生转换。这个随机项不是可有可无的装饰——城市规划中的开发行为本来就带有随机性,完全确定性的规则会生成过于均匀、不真实的城市形态。

2.3 参数校准与模型验证

参数校准是模拟精度最关键的一步。我的做法是用两个历史年份的遥感解译数据:例如2000年和2020年,以2000年为初始状态,用实际数据标定Logistic回归系数,然后模拟至2020年,最后用2020年实际数据和模拟结果进行对比。

验证指标我推荐全程盯着两个:总体精度(OA)和Kappa系数。2015年一次实测项目中,我的模型模拟结果OA大概在0.87,Kappa在0.74,这个水平在同类研究中属于可接受范围。如果Kappa低于0.6,基本可以判断规则设置有问题,需要回头检查驱动因子或邻域定义。

3. Matlab实现全过程

3.1 数据准备与栅格导入

Matlab中处理栅格数据最顺手的方式是用 readgeoraster 函数(较新版本)或者 geotiffread(旧版本)。注意地理参考信息要同步读取,后续做结果分析和出图时需要用到坐标信息。

数据准备的流程我用的是:

  1. 将土地利用/覆盖栅格转为整型数值矩阵,城市建设用地设为1,可开发非城市用地设为0,不可开发区设为-1。
  2. 将所有驱动因子栅格统一重采样到与土地利用栅格相同的行列数和空间分辨率。
  3. 驱动因子做归一化到0-1区间,消除量纲影响,否则Logistic回归系数无法横向比较。
  4. 将处理好的矩阵保存成 .mat 文件,后续迭代加载速度比反复读GeoTIFF快得多。

这个环节有两点容易踩坑:一是投影和坐标系必须一致,如果土地利用数据是UTM投影,驱动因子却是WGS84经纬度,跑出来的结果会出现明显错位;二是数据范围对齐,边界处常有数据缺失,需要在预处理时统一填充空值,常见做法是用邻域均值插补。

3.2 元胞自动机核心迭代代码

核心迭代部分的Matlab代码框架如下,逻辑很直接:

% 参数设置 maxIter = 20; % 迭代次数,通常模拟一年迭代一次 threshold = 0.5; % 随机扰动阈值 [row, col] = size(landuse); beta = [b0, b1, b2, b3, b4, b5]; % Logistic回归系数 % 读取驱动因子矩阵(已归一化) distCenter = data.distCenter; distRoad = data.distRoad; distBuild = data.distBuild; slope = data.slope; popDensity = data.popDensity; % 邻域权重矩阵(3x3) neighborWeight = ones(3,3); neighborWeight(2,2) = 0; % 迭代模拟 for iter = 1:maxIter % 复制当前状态 newState = landuse; % 计算邻域开发密度(对可开发区域) devDensity = conv2(double(landuse == 1), neighborWeight, 'same') ./ ... conv2(double(landuse >= 0), neighborWeight, 'same'); devDensity(isnan(devDensity)) = 0; % 计算发展适宜性概率 logitP = beta(1) + beta(2)*distCenter + beta(3)*distRoad + ... beta(4)*distBuild + beta(5)*slope + beta(6)*popDensity; pDev = 1 ./ (1 + exp(-logitP)); % 综合概率 pTotal = pDev .* devDensity; % 随机扰动 randomThreshold = rand(row, col); % 状态转换:非城市可开发用地转为城市 convertIdx = (landuse == 0) & (pTotal > threshold) & ... (randomThreshold < pTotal); newState(convertIdx) = 1; % 更新状态 landuse = newState; end

这段代码有几个细节我想强调一下。

conv2 的 'same' 参数必须带上,保证卷积结果和原矩阵尺寸一致。计算邻域密度时分母用的是 landuse >= 0,即排除了不可开发区,避免密度被稀释。数据里第一行代码加载的 landuse 如果是 double 类型可以加比较运算符,如果是 int 类型需要先转 double 再判等。

阈值 threshold 从0.5开始是经验值,但实际项目中需要结合研究区域的发展速度调整。如果历史年份区间内城市面积翻了一倍,0.5阈值下模拟结果可能偏保守,这时候要适当降低阈值,比如0.4。阈值本质上控制的就是城市增长的“激进程度”,没有绝对标准,完全看校准结果。

3.3 结果可视化与动态展示

模拟结果的可视化是项目交付中最出效果的部分。我用的是 imagesc 配合自定义colormap,城市用地显示为深灰色,非城市可开发用地显示为浅绿色,不可开发区域显示为白色。

figure; map = [0.85 0.85 0.85; % 不可开发区域 0.8 0.9 0.7; % 非城市可开发 0.3 0.3 0.3]; % 城市用地 colormap(map); imagesc(landuse); axis equal; axis off;

如果想输出模拟过程的动态变化,可以在每次迭代后用 drawnow 更新图形,然后保存成GIF或视频。实测中模拟30年、栅格500×500的情况下,Matlab在普通办公电脑上大概需要几十秒到几分钟,性能可以接受。

还有一个实用的输出习惯:每次迭代都保存城市总面积或城市扩张面积,迭代结束后用plot画出城市扩张曲线。这张曲线图对报告非常有价值,可以直接反映城市增长速度是递增还是递减,也是后续验证模型的重要依据。

4. 常见问题与排查技巧

4.1 模拟结果出现异常大面积开发

最典型的问题是跑完20次迭代后,整个区域几乎全部变成了城市用地,与现实严重不符。这个问题的根源几乎都是转换概率整体偏高,邻域开发密度这个因子在空间上形成了正反馈循环——城市越多,邻域密度越大,然后更容易继续开发,叠加效应被放大。

排查方法很简单,先输出第一轮迭代后新增城市用地的数量和空间分布。如果第一轮就大面积转换,说明 P_development 整体过高,需要检查Logistic回归系数是否有量级异常。我遇到过的情况是某个驱动因子未归一化,系数和因子值相乘后数值很大,Logistic输出趋近于1。这时候把驱动因子重新归一化到0-1区间就能解决。

另外可以给转换加上“紧凑度约束”思路就是新增城市像元必须与已有建成区共享至少一条边,避免零散飞地式开发。代码如下:

% 只允许与已有城市用地共享边的像元转换 convertIdx = convertIdx & (imdilate(landuse == 1, ones(3,3)) == 1);

4.2 边缘效应明显

模型在模拟区边界处容易出现异常,因为边界外的像元被当成不可开发区域,导致边界内像元邻域密度计算偏低。如果研究区本身并不是完整的城市区域,边缘效应会影响精度。

处理手段有两个:一是在建模前对研究区做缓冲,把模拟范围向外扩展10-15个像元,模拟结束后裁掉缓冲区;二是用边界格网状态填充法,把边界外状态镜像复制到扩展区域。实际操作中缓冲法最省事,也是我用下来最稳定有效的方案。

4.3 性能优化与加速策略

栅格尺寸较大时(比如2000×2000像元),逐像元循环会非常慢。Matlab中要避免 for 循环嵌套扫描每个像元,尽量使用矩阵运算和卷积操作来提升速度。

我实际遇到过一个5000×5000的栅格,使用全循环版本需要跑40分钟,改成卷积+矩阵运算版本后只需要3分钟。具体优化点包括:将所有驱动因子提前矩阵化,避免迭代中重复读取;用 imdilate 计算邻域开发状态;用 logical 索引一次性完成所有状态转换判断。

如果项目需要反复调参跑实验,建议把核心迭代函数写成独立函数文件,参数放在结构体中传入,这样多个参数组合实验可以并行执行。Matlab的 parfor 在这里也能派上用场,但要注意每次迭代之间的状态依赖关系——城市增长模拟是串行依赖的,只有多个实验并行,不能把单次迭代内部并行化,这点需要特别留意。

4.4 参数敏感性分析

模拟结果对不同参数的反应差异很大。阈值和随机扰动项对城市形态影响最为显著,邻域权重矩阵次之,驱动因子权重对总体空间格局影响相对稳定但会影响局部密度。

我习惯的做法是敏感性分析时只改动一个参数,其他保持基准值,运行多次后计算城市面积和空间分布的变异系数。这能直观告诉你哪些参数需要谨慎标定,哪些参数稍微偏差一点问题不大。实际项目中阈值和随机扰动种子是最需要反复测试的,遇到结果不稳定时可以先固定随机种子保证结果可复现,完成调参后再放开。

5. 项目扩展与后续方向

5.1 多情景模拟

元胞自动机模型最大的优势之一就是情景模拟。实际规划项目中,我经常需要回答“不同政策干预下城市增长会有什么差异”这类问题。

实现方式很灵活:生态红线严格保护情景,就把限制区域的约束系数从0改成固定不开发;基础设施导向情景,就调整到新建道路的驱动因子权重,模拟新道路建设对城市扩展的牵引作用;紧凑发展情景,就把邻域权重加强,促进填充式开发而不是蔓延式外扩。

这种多情景模拟的结果可以直接生成对比图,对规划决策的支撑效果远好于单一趋势外推。我在一个县域项目中做了三种情景模拟,领导最关心的不是模型多复杂,而是不同政策组合下10年后的城市边界差异是多少,这套方法刚好能回答。

5.2 与其他模型耦合

元胞自动机可以和系统动力学(SD)模型耦合:SD模型模拟宏观经济、人口等总量指标,元胞自动机把总量指标空间化落到每个地块。也可以与多智能体(ABM)耦合,把居民、开发商、政府三类主体的决策行为引入转换规则中,模拟结果会更有行为逻辑支撑。

不过耦合模型需要谨慎。项目进度紧张时,我建议先保证单体元胞自动机模型结果可靠,再考虑扩展。耦合模型调试周期通常是单体模型的数倍,且不确定性来源也更复杂。

我在实际使用中的体会是,元胞自动机模拟城市增长,模型本身并不神秘,真正拉开差距的是数据质量控制、参数校准的耐心和对模拟结果的合理解读。初学阶段建议先拿小区域、粗分辨率的数据完整跑通一遍流程,再把分辨率提高、因子增加,循序渐进,这套方法在城市增长模拟领域会越来越顺手。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询