☰
MATLAB岩石物理计算:干燥与饱和弹性参数及Gassmann方程实现
2026/10/18 12:58:01 网站建设 项目流程

简介:这份资源面向地质勘探、地球物理及数值计算方向的学习者与研究人员,围绕地震岩石物理基本理论,用MATLAB实现干燥岩石与流体饱和岩石的弹性参数计算,涵盖纵波模量、剪切模量和泊松比三类核心指标,帮助读者理解岩石在压力与剪切力作用下的变形特性及其对地震波传播的影响。压缩包为rar格式,仅含1个m脚本文件,体积约2KB,属于轻量级算法源码,便于直接阅读、调试与二次开发。资源已有545人学习下载,说明其在相关课程与科研入门中具有一定参考价值。通过该脚本,读者可掌握弹性参数的数学建模思路与MATLAB编程实现方法,并可将计算任务迁移至云计算环境进行批量模拟,为储层评估、地震活动预测等场景提供基础工具支撑,适合具备一定岩石物理与编程基础的中级学习者使用。

1. 从一组干燥砂岩的模量算错说起:这份 MATLAB 资源到底解决什么

前阵子帮一个做储层预测的朋友看数据,他拿一组干燥砂岩的纵波模量去反演流体因子,结果饱和后的泊松比算出来是负的。翻回代码一看,他把 Gassmann 方程里的干岩石骨架模量直接填成了矿物模量,流体项整个串了。这类错误在地震岩石物理入门阶段特别常见——公式背得滚瓜烂熟,一到干燥、饱和两种状态的参数传递就翻车。这份资源就是冲着这个痛点来的:一个cementedsand.m脚本,配合一份压缩包,把干燥岩石和流体饱和岩石的纵波模量、剪切模量、泊松比从头算一遍,不依赖任何商业岩石物理软件,MATLAB 环境里跑通即可。适合刚接触岩石物理数值计算的学生、做叠前反演需要正演模量的工程师,以及想把云计算资源接进 MATLAB 做批量模拟的开发者。它不教你地震波动力学全套,只把弹性参数这条线拉直。

2. 弹性参数的计算链路:从矿物模量到饱和岩石的 Gassmann 替换

2.1 干燥岩石的纵波模量与剪切模量怎么来的

干燥岩石的弹性参数不是直接测出来的,通常是从矿物模量、孔隙度和孔隙纵横比通过等效介质模型推出来的。这份资源里cementedsand.m走的是胶结砂岩模型的路子,核心思路是先算干岩石骨架的体积模量 ( K_{dry} ) 和剪切模量 ( G_{dry} ),再往里面填流体。

干岩石体积模量的常见形式是:

[ K_{dry} = K_{mineral} \cdot (1 - \phi)^{a} ]

其中 ( \phi ) 是孔隙度,( a ) 是胶结指数,跟颗粒接触方式有关。剪切模量类似,但指数项通常不同。脚本里把这两个指数做成了可调参数,方便你按不同固结程度去试。

实际操作时,你需要在脚本开头把矿物模量、孔隙度、胶结指数这几个量填进去。常见做法是查文献取石英或方解石的 ( K ) 和 ( G ),孔隙度从测井曲线读,胶结指数先按 1.5 到 2.5 之间试。脚本里对应的变量名是K_min、G_min、phi、a_cement,改完直接运行就能得到干燥状态的 ( K_{dry} ) 和 ( G_{dry} )。

提示:胶结指数对结果影响很大,同一组孔隙度下,指数从 1.5 变到 2.5,纵波模量能差出 30% 以上。建议先固定其他参数,单独扫这个指数看敏感度。

2.2 流体饱和后的 Gassmann 方程:为什么不能直接替换

干燥岩石算完,下一步是饱和流体。Gassmann 方程是低频极限下的标准做法,它把干岩石模量、矿物模量、流体模量和孔隙度串起来:

[ K_{sat} = K_{dry} + \frac{(1 - K_{dry}/K_{mineral})^2}{\phi/K_{fluid} + (1-\phi)/K_{mineral} - K_{dry}/K_{mineral}^2} ]

剪切模量在 Gassmann 假设下不变,( G_{sat} = G_{dry} )。泊松比则从 ( K_{sat} ) 和 ( G_{sat} ) 反算:

[ \nu = \frac{3K - 2G}{2(3K + G)} ]

脚本里把这段写成了一个独立函数gassmann_sat,输入干岩石模量、矿物模量、流体模量和孔隙度,输出饱和模量。流体模量根据你是水、油还是气,查表或按经验公式给。常见做法是水取 2.2 GPa,油取 1.0 GPa 左右,气取 0.1 GPa 量级。

这里有个容易忽略的点:Gassmann 方程要求流体压力均衡,所以只适用于低频。如果你拿它去算超声波频段的数据,饱和模量会偏高,泊松比也会偏。脚本里没有做频散校正,这是它的边界,不是 bug。

2.3 用 MATLAB 把整条链路串起来

脚本的结构很直白:参数区、干岩石计算区、Gassmann 替换区、泊松比输出区。下面这段是核心逻辑的简化版,你可以对照自己的cementedsand.m看:

% 输入参数 K_min = 36.6; % 石英矿物体积模量, GPa G_min = 45.0; % 石英矿物剪切模量, GPa phi = 0.15; % 孔隙度 a_cement = 2.0; % 胶结指数 K_fluid = 2.2; % 水体积模量, GPa % 干燥岩石模量 K_dry = K_min * (1 - phi)^a_cement; G_dry = G_min * (1 - phi)^a_cement; % Gassmann 饱和替换 K_sat = K_dry + (1 - K_dry/K_min)^2 / ... (phi/K_fluid + (1-phi)/K_min - K_dry/K_min^2); G_sat = G_dry; % 泊松比 nu_dry = (3*K_dry - 2*G_dry) / (2*(3*K_dry + G_dry)); nu_sat = (3*K_sat - 2*G_sat) / (2*(3*K_sat + G_sat)); fprintf('干燥: K=%.2f GPa, G=%.2f GPa, nu=%.3f\n', K_dry, G_dry, nu_dry); fprintf('饱和: K=%.2f GPa, G=%.2f GPa, nu=%.3f\n', K_sat, G_sat, nu_sat);

逻辑说明:先按胶结模型算干岩石,再走 Gassmann 得到饱和模量,最后统一转泊松比。参数说明:K_min和G_min按矿物类型查,phi从测井或岩心数据来,a_cement控制固结程度,K_fluid决定流体类型。跑完对比干燥和饱和两行输出,如果饱和泊松比反而比干燥低很多,大概率是流体模量填错了。

3. 把计算任务丢到云端:MATLAB 并行与批量参数扫描

3.1 为什么单机跑参数扫描会卡

岩石物理正演本身不慢,一次计算毫秒级。但如果你要做不确定性分析,比如孔隙度从 0.05 到 0.30、胶结指数从 1.0 到 3.0、流体模量分水油气三档,组合起来就是几千到几万次计算。单机 for 循环跑下来,MATLAB 的解释器开销会让总时间从几秒变成几分钟甚至更久。更别说后面还要接反演,每次迭代都调一遍正演。

云计算在这里的价值不是“算得快”,而是“同时算很多组”。把参数空间切成块,每块丢一个 worker,总时间就压下来了。这份资源本身不包含云平台配置,但cementedsand.m的写法留了并行接口——参数区是独立的,计算区没有全局依赖,可以直接套parfor。

3.2 用 parfor 做参数扫描的改法

把原来的单点计算改成扫描,核心是把参数组合展开成矩阵,然后用parfor分发。下面是一个可抄的骨架:

% 参数网格 phi_vec = 0.05:0.01:0.30; a_vec = 1.0:0.1:3.0; fluid_vec = [2.2, 1.0, 0.1]; % 水, 油, 气 % 展开所有组合 [PHI, A, FLUID] = ndgrid(phi_vec, a_vec, fluid_vec); params = [PHI(:), A(:), FLUID(:)]; n = size(params, 1); % 预分配输出 K_dry_out = zeros(n,1); K_sat_out = zeros(n,1); nu_sat_out = zeros(n,1); % 并行扫描 parfor i = 1:n phi = params(i,1); a = params(i,2); Kf = params(i,3); Kd = K_min * (1 - phi)^a; Gd = G_min * (1 - phi)^a; Ks = Kd + (1 - Kd/K_min)^2 / ... (phi/Kf + (1-phi)/K_min - Kd/K_min^2); Gs = Gd; K_dry_out(i) = Kd; K_sat_out(i) = Ks; nu_sat_out(i) = (3*Ks - 2*Gs) / (2*(3*Ks + Gs)); end

逻辑说明:ndgrid把三个参数展成全组合,parfor把循环体分发到多个 worker。参数说明:phi_vec和a_vec的步长决定扫描密度,fluid_vec对应不同流体。注意parfor里不能有依赖上一次迭代的变量,所以所有输出都预分配成数组,按索引写。

注意:parfor启动并行池有开销,如果总计算量不到几百次,单机 for 循环反而更快。一般组合数超过 1000 再考虑并行。

3.3 云端部署时容易忽略的路径与许可问题

把 MATLAB 放到云服务器上跑,第一道坎不是代码,是许可。MATLAB 的并行计算工具箱需要额外的 license,云厂商的镜像里不一定带。常见做法是先用ver命令确认Parallel Computing Toolbox在不在,不在的话要么换镜像,要么改用parfeval配合本地 worker。

第二道坎是路径。cementedsand.m里如果写了相对路径读数据,云端工作目录和本地不一样,会报文件找不到。稳妥的做法是在脚本开头用fullfile拼绝对路径,或者把数据文件跟脚本放同一目录,用mfilename('fullpath')取脚本位置再拼。

第三道坎是结果回传。批量扫描的输出可能有几十万行,直接save成 mat 文件再下载,比在云端做可视化更省事。如果非要画图,建议只回传抽样后的散点数据,别把整个网格传回来。

4. 避坑与排查:弹性参数计算里最容易翻车的五个点

4.1 饱和泊松比出现负值

现象:跑完脚本,饱和岩石的泊松比小于 0,甚至到 -0.5。

原因:Gassmann 方程里 ( K_{sat} ) 算出来比 ( K_{dry} ) 还小,或者流体模量填成了负数。最常见的是把K_fluid和K_min的变量名写反了,或者孔隙度填成了百分数(15 而不是 0.15)。

解决:先检查phi是否在 0 到 1 之间,再检查K_fluid是否为正。如果都正常,打印K_dry和K_sat对比,正常情况 ( K_{sat} > K_{dry} )。如果反了,说明 Gassmann 分母里的符号错了,对照公式逐项核对。

4.2 干燥和饱和剪切模量不一致

现象:脚本输出里 ( G_{dry} ) 和 ( G_{sat} ) 不相等。

原因:Gassmann 理论假设剪切模量不受流体影响,所以 ( G_{sat} ) 必须等于 ( G_{dry} )。如果代码里给 ( G_{sat} ) 单独套了一个公式,或者并行扫描时索引串了,就会出现不一致。

解决:在脚本里强制G_sat = G_dry;,不要给剪切模量做任何流体替换。如果用了并行,检查G_sat_out(i)的赋值是否误写成了G_dry_out(i+1)之类的越界索引。

4.3 胶结指数取值的玄学

现象:同一组孔隙度,别人算出来的纵波模量跟你差一倍。

原因:胶结指数没有唯一标准,不同文献给的取值范围从 1.0 到 3.0 都有。取 1.0 接近临界孔隙度模型,取 3.0 接近高固结砂岩。如果没说明取值依据,结果没法对比。

解决:在脚本注释里写清楚a_cement的来源,比如“按某地区砂岩岩心拟合值取 1.8”。做敏感度分析时,把a_cement作为扫描变量,输出模量随它的变化曲线,而不是只报一个数。

4.4 parfor 里变量切片报错

现象:parfor循环报“无法分类变量”或“无效索引”。

原因:parfor要求循环内的变量要么是广播变量(不随迭代变),要么是切片变量(按索引写)。如果代码里出现了K_dry_out = [K_dry_out; Kd];这种动态增长,就会报错。

解决:所有输出数组提前用zeros(n,1)预分配,循环内只写K_dry_out(i) = Kd;。如果需要在循环内累加,改用parfeval或把累加拆成两阶段。

4.5 云端跑完结果对不上本地

现象:同样的参数,本地跑出来 ( \nu_{sat} = 0.28 ),云端跑出来 0.31。

原因:最常见的是 MATLAB 版本不同,parfor的归约顺序有差异,导致浮点累加结果有微小偏差。如果偏差大到 0.03,那更可能是云端脚本读到了旧版参数文件,或者并行池里某个 worker 的路径指向了另一个副本。

解决:在脚本开头打印version和pwd,确认云端和本地一致。批量扫描时,把参数矩阵和结果一起存成 mat 文件,回本地用isequal对比关键列。如果只是浮点末位差异,可以忽略;如果量级不对,先查文件路径。

5. 进阶技巧:用干燥模量反推流体因子与敏感度矩阵

5.1 从饱和模量反推流体模量的迭代写法

正演是已知流体算饱和模量,反演是已知饱和模量反推流体。Gassmann 方程对 ( K_{fluid} ) 没有解析解,得用数值迭代。常见做法是二分法或牛顿迭代,把 ( K_{fluid} ) 限制在 0.01 到 3.0 GPa 之间。

function Kf = invert_fluid(K_sat_obs, K_dry, K_min, phi) % 二分法反推流体模量 lo = 0.01; hi = 3.0; for iter = 1:50 mid = (lo + hi) / 2; Ks = K_dry + (1 - K_dry/K_min)^2 / ... (phi/mid + (1-phi)/K_min - K_dry/K_min^2); if Ks < K_sat_obs lo = mid; else hi = mid; end end Kf = (lo + hi) / 2; end

逻辑说明:二分法每次把区间折半,50 次迭代后精度足够。参数说明:K_sat_obs是观测到的饱和模量,K_dry和K_min从干燥计算和矿物查表来,phi是孔隙度。这个函数可以嵌在parfor里,对每个观测点单独反推。

5.2 敏感度矩阵:哪个参数对泊松比影响最大

做正演的人经常被问“泊松比变了,到底是孔隙度变了还是流体变了”。回答这个问题需要敏感度矩阵,也就是 ( \partial \nu / \partial \phi )、( \partial \nu / \partial K_{fluid} ) 这些偏导。不用解析求导,数值差分就行:

参数扰动方式泊松比变化量(典型值)
孔隙度0.15 → 0.16+0.008
流体模量2.2 → 1.0 GPa-0.015
胶结指数2.0 → 2.1-0.003
矿物模量36.6 → 37.0 GPa+0.001

这张表是用脚本跑出来的,每行只改一个参数,其他固定。从量级看,流体模量的影响最大,孔隙度次之,胶结指数再次,矿物模量最小。这意味着如果你要反演流体,泊松比是比纵波模量更敏感的量。

5.3 我自己的习惯:每次改参数前先存一份基准

从那以后我每次动cementedsand.m的参数区之前,都强制走一遍基准测试:把默认参数跑一遍,把K_dry、K_sat、nu_dry、nu_sat四个数存到一个baseline.mat里。改完参数再跑,用isequal或max(abs(diff))对比,确认只有目标参数在变,其他没被误改。这个习惯帮我逮住过好几次变量名手滑——有一次把K_fluid改成了K_fluid_new,结果脚本里另一处还在引用旧名,跑出来饱和模量根本没变,差点把错误结论写进报告。希望帮到你。

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

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

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

立即咨询