简介:本资源是一套面向地质探测、考古勘察与基础设施无损检测领域的GPR仿真教学资料包,专为科研人员、工程技术人员及高校学生设计,解决地面穿透雷达建模难、参数设置不直观、结果解读门槛高等实际问题。压缩包共133个文件,67.62MB,涵盖20个.in输入模型文件(定义几何结构与介质参数)、16个.out输出数据(含时域B-scan图像)、16个.geo几何描述文件、32个.bmp与26个.png格式的仿真结果图、8个.m MATLAB脚本(用于后处理与可视化)、2个gprmax2d/gprmax3d可执行模块及PDF/DOCX版详细教程文档。已有1805人学习下载,内容包含从软件安装配置、二维/三维建模实操、典型场景案例(如分层土壤、埋管识别)到B-scan图像解析与散射机理说明的完整学习链路,配套大量图文对照示例与结果对比图,显著降低GprMax2D3D入门与进阶应用难度。 跑通第一个gprMax模型之前,我以为这只是一个“画个模型、点一下运行、出来一张图”的流程。真正动手后才发现,探地雷达数值模拟的核心不在于软件操作,而在于你怎么把物理场景翻译成一堆命令行参数。我在一个空洞检测项目的预研阶段,需要用500MHz天线模拟路面下1.5m处一个1m大小空洞的雷达响应,没有实测条件,唯一能依赖的就是gprMax。当时翻遍网上能搜到的gprmax教程,大部分是官方文档的机器翻译,缺少从二维建模、运行、后处理到三维扩展的完整链路。这篇文章是我自己从零到一跑通2D和3D模型的全过程记录,包括每个参数为什么这么定、每个坑是怎么踩进去的,适合刚接触探地雷达模拟的地球物理专业学生、检测工程师,以及想用数值模拟验证GPR探测方案的人。
1. gprMax 到底在算什么——探地雷达正演模拟器的底层逻辑
1.1 为什么需要正演模拟
探地雷达(Ground Penetrating Radar,GPR)的基本任务是向地下发射高频电磁波,接收来自介质界面的反射波,然后从波形和振幅中推断地下结构。可是电磁波在地下传播时,会碰到介电常数变化、电导率损耗、多次反射、绕射、散射,这些效应叠加在一起,同样一个双曲线异常,可能是空洞,可能是一根管线,也可能只是局部土质不均匀。实测数据里你很难把单一作用分离出来,这时候正演模拟的价值就出现了:你先假设一个地下结构,用软件算出它理论上的雷达响应,再跟实测对比,看差异在哪里。
gprMax就是用于这种正演模拟的开源软件。它基于时域有限差分法(FDTD)直接求解麦克斯韦方程组,能模拟电磁波在任意非均匀介质中的传播过程。相比商用软件,gprMax完全免费,代码开源,HDF5标准输出格式方便二次处理,在学术论文里被广泛引用。更重要的是它同时支持2D和3D建模:2D计算快、适合参数扫描和初步设计;3D更接近真实点源发射的地波传播,适合精确模拟孤立目标。
1.2 时域有限差分法的一句话解释
FDTD方法听起来高深,核心思路其实很简单。它把要计算的区域划分成一个个小长方体网格单元(Yee网格),把时间也切成很小的步长。每个时刻,根据上一个时刻的电磁场分布和当前网格点的材料参数,算出电场和磁场的变化,然后推进到下一个时刻。因为电磁波传播的本质就是电场和磁场互相激发、交替前行,这种“逐步推进”的方式天然适合模拟波的传播、反射、绕射。
网格步长和时间步长之间有严格约束。空间步长必须小于最高频率对应波长的十分之一到二十分之一,否则数值色散会让波传播速度失真;时间步长则要满足库朗稳定性条件,否则计算会发散。这也是为什么gprMax对模型尺寸很敏感——你的目标尺寸可能只有1米,但网格步长需要毫米级,三维网格数量瞬间就会过千万。
1.3 gprMax 的2D与3D两条路
很多初学者不理解既然有3D为什么还要用2D。用一句话回答:2D是“切片视角”,假设结构在垂直纸面方向无限延伸,相当于算一个剖面;3D是“全空间视角”,能反映真实三维目标。2D模型网格数约等于面积除以网格平方,3D则是体积除以网格立方,计算量相差一到两个数量级。所以实际项目里,前期的参数试探、测线设计、波速标定基本都用2D完成,最后对关键目标再建一个3D模型验证。这篇文章的案例也按这个思路组织:先用2D把空洞探测流程跑通,再看3D需要改什么。
2. 环境准备与文件体系——把 .in 文件当成项目的施工图
2.1 安装与命令行运行
gprMax目前主推v3.x版本,Python 3.8以上环境直接安装即可:
pip install gprMax装完后验证版本:
python -m gprMax --versiongprMax本身提供的是Python模块,真正的运行方式是命令行。输入文件是一个纯文本的.in文件,里面一行一行写模型定义;运行命令长这样:
python -m gprMax my_model.in -n 4其中-n 4表示用4个CPU核心并行计算。运行完成后,同目录下会生成一个.out的HDF5文件,里面装的就是所有接收器记录的波形数据。我第一次运行的时候没意识到-n能省这么多时间,直接在四核笔记本上单线程跑一个3D模型,等到半夜才跑完。后来发现,只要有-n参数,gprMax会自动用MPI把空间网格分块,计算速度几乎线性提升。
2.2 输入文件的结构骨架
.in文件不像代码那样有严格顺序要求,但习惯上按照“域定义 → 网格 → 材料 → 几何体 → 激励源 → 接收器 → 输出控制”的顺序写。下面是一个最简模型,模拟半空间介质中单道波的传播:
#title: simple_halfspace #domain: 0.6 1.2 0.6 #dx_dy_dz: 0.005 0.005 0.005 #time_window: 40e-9 #material: 6 0.001 1 0 0 0 half_space #box: 0 0 0 0.6 0.6 0.6 half_space #hertzian_dipole: z 0.3 0.1 0.3 #rx: 0.3 0.1 0.33这里有一个新手极其容易搞混的点:gprMax默认坐标轴不是“x水平、y垂直向下”吗?实际上,gprMax中y轴是深度方向,原点在地表,向下为正。所以#box: 0 0 0 0.6 0.6 0.6 half_space代表的是从地表面往下0.6米深的一个立方体。而#domain: 0.6 1.2 0.6表示x方向0.6米、y方向(深度)1.2米、z方向0.6米。源放在(0.3, 0.1, 0.3)就是地下0.1米处,接收器放在源旁边0.03米的位置。
材料行的参数格式是:
#material: 相对介电常数 电导率 相对磁导率 磁损耗 电损耗 磁导率损耗 材料名写6 0.001 1 0 0 0 half_space就表示相对介电常数6、电导率0.001S/m、非磁性材料。绝大多数GPR模拟材料都不需要磁损耗参数,统一写0即可。
2.3 用 geometry_view 检查模型是否建对了
模型建完别急着跑,先检查几何。gprMax官方工具里有一个快速画几何的命令:
python -m tools.plot_geometry simple_halfspace.in它会根据#domain和所有几何体命令生成一个matplotlib图像,按y轴深度方向展示材料分布。如果几何体位置错了,比如空洞跑到地面上方了,这一眼就能看出来。对于复杂三维模型,还能用#geometry_view命令导出VTK文件,丢到ParaView里旋转查看。我个人的习惯是:每个模型跑计算之前,先画一次几何,对着坐标检查目标体的深度和尺寸,这一步能省掉大量“跑了几小时才发现模型建错”的悲剧。
同时我强烈建议在所有几何体之后单独跑一下python -m tools.plot_geometry file.in再确认一遍,因为gprMax不会检查逻辑上的材料覆盖关系,比如后定义的box会把先定义的材料覆盖掉,这种覆盖有时候是故意的,有时候是笔误。
3. 第一个2D项目:市政空洞探测的完整建模思路
3.1 案例参数是怎么定的
现在我完整建一个地下空洞探测模型。场景:城市道路路面0.1m厚混凝土,下面是土壤,目标是在1.5m深处有一个1m×1m的空洞(充满空气)。测线沿x方向布置,总长6m,天线在路面表面接触测量。
先解决参数问题。第一是网格步长。500MHz中心频率,Ricker子波的实际频谱能量最高到约1.5倍中心频率,也就是750MHz。土壤介电常数取8,对应波速约1.06e8 m/s,750MHz在土壤中的波长约0.14m。网格取波长的十分之一就是1.4cm,但实际经验里二维模型计算开销不大,我直接取5mm,这样既能减少数值色散,又能精确描述1m尺寸空洞的轮廓。
第二是时间窗。电磁波从地表到空洞顶面1.5m往返一次大约需要:
t = 2 * 深度 / 波速 = 2 * 1.5 / 1.06e8 ≈ 28.3 ns但还要加上0.1m混凝土层(介电常数6,波速1.22e8 m/s)的双程时间约1.6ns,所以空洞顶面反射大约在第30ns左右到达。为了让多次反射和更深处回波也能看到,时间窗取150ns,留足了余量。
第三是测线起点和收发距。源在第一测点的位置设为(0.30, 0.006, 0.005),接收器放在源左侧0.06m,也就是(0.24, 0.006, 0.005),两者同步步进0.05m,共121道,测线从0.3m覆盖到6.3m。
2D模型的z方向有个特殊规定:z方向必须设一定的厚度,但物理上模型在z方向无限延伸。官方推荐z方向取2~3个网格即可。#domain的z设为0.01m,配合5mm网格,就是2层z向网格。
3.2 生成模型文件
用Python脚本生成.in文件比手写更不容易出错,尤其当你需要批量调整测点数量时。下面是我整理的一个生成脚本:
hole_depth = 1.5 # 空洞中心深度 hole_size = 1.0 # 空洞边长 dx = 0.005 x_min, x_max = 0.0, 7.0 y_max_depth = 2.5 z_min, z_max = 0.0, 0.01 lines = [] lines.append('#title: cavity_detection_2d') lines.append(f'#domain: {x_max} {y_max_depth} {z_max}') lines.append(f'#dx_dy_dz: {dx} {dx} {dx}') lines.append('#time_window: 150e-9') lines.append('#material: 1 0 1 0 0 0 air') lines.append('#material: 6 0.005 1 0 0 0 concrete') lines.append('#material: 8 0.015 1 0 0 0 soil') # 混凝土路面 0~0.1m lines.append(f'#box: {x_min} 0 0 {x_max} 0.1 {z_max} concrete') # 土体 0.1m~深部 lines.append(f'#box: {x_min} 0.1 0 {x_max} {y_max_depth} {z_max} soil') # 空洞 lines.append(f'#box: {3.5-hole_size/2} {hole_depth-hole_size/2} 0 {3.5+hole_size/2} {hole_depth+hole_size/2} {z_max} air') # 激励源和接收器 src_x, rx_x = 0.30, 0.24 lines.append(f'#hertzian_dipole: z {src_x} 0.006 0.005') lines.append(f'#rx: {rx_x} 0.006 0.005') lines.append('#src_steps: 0.05 0 0') lines.append('#rx_steps: 0.05 0 0') # 只输出接收器Ez分量 lines.append('#output: rx1 Ez') with open('cavity_2d.in', 'w') as f: f.write('\n'.join(lines))这里有几个细节值得说明。#hertzian_dipole: z是z方向极化的偶极子,在2D模型中等价于电流源,产生TM波。表面空气、混凝土、土壤、空洞四种材料中,空洞的介电常数是空气的1,反射系数由eps突变决定。从土壤(eps=8)进入空气(eps=1)时反射系数为负,所以B-scan图像中空洞顶面的反射波形相位会反转,这是识别空洞的一个关键特征。如果空洞里填充的是水,介电常数变成81,反射极性又是另一个方向。后处理时要特别留意这一点。
3.3 运行与结果解读
运行命令:
python -m gprMax cavity_2d.in -n 42D模型网格总数只有约56万个,4核并行下十几秒就跑完。完成后读取输出:
import h5py import numpy as np import matplotlib.pyplot as plt with h5py.File('cavity_2d.out', 'r') as f: data = f['rxs']['rx1']['Ez'][:] dt = f.attrs['dt'] print(data.shape) # (时间步数, 测线道数)先画一道位于空洞正上方的A-scan(第61道):
trace = data[:, 60] t = np.arange(len(trace)) * dt * 1e9 plt.figure(figsize=(8, 4)) plt.plot(t, trace) plt.xlabel('Time (ns)') plt.ylabel('Ez (V/m)') plt.show()波形上第一个大振幅是直达波和地表耦合波,淹没在0~5ns的震荡里。大约在30ns处会出现一个清晰的负峰,随后的一个正峰对应空洞底面反射。如果你把这个A-scan和B-scan结合起来看,会更容易理解整个剖面的形态。
再看整幅B-scan:
plt.figure(figsize=(10, 6)) plt.imshow(data.T, aspect='auto', cmap='gray', extent=[0.3, 6.3, 150, 0]) plt.xlabel('Distance (m)') plt.ylabel('Time (ns)') plt.colorbar(label='Ez') plt.show()空洞顶面会产生一条顶点在3.5m处、开口向上的双曲线,双曲线两翼逐渐延伸到更晚的时间。这条双曲线的顶点时间约30ns,和前面的估算一致。整个双曲线的存在说明地下有一个孤立目标,但单从B-scan无法直接判断它是空洞还是金属管,需要结合A-scan的反射极性来做进一步分析。
3.4 去背景:B-scan 里最必要的信号增强手段
实测GPR数据里直达波和地表强反射会压掉深层弱信号,模拟数据虽然干净,但也有同样的问题。去除水平连续背景最常用的方法是“平均道相减”:把B-scan所有测道的波形求平均,得到一条“平均背景道”,然后对每一道减去这条平均道:
background = data.mean(axis=1, keepdims=True) clean = data - background原理很简单:水平分层界面的反射波在每条测道的时延相同,平均后仍然保留;而空洞产生的双曲线反射在不同测道的时延不同,平均后会被大幅削弱。两者相减,水平层信息被抑制,局部异常得到增强。操作后B-scan中空洞顶面双曲线会非常突出,水泥路面底部那一条水平强反射也会基本消失。
我强烈建议不管后续做不做复杂处理,先执行这一步,它几乎是所有GPR剖面处理的地基。
4. 从2D升级到3D:物理模型、计算量与应用场景的取舍
4.1 2D 和 3D 在物理上差了什么
在2D模型里,激励源默认是z方向无限长的线源,电磁波以柱面波形式向外传播,振幅随距离按1/√r衰减。而在3D模型里,源是点源,波前是球面波,振幅按1/r衰减。这个差别意味着:同一个目标,2D模拟的反射波衰减比3D慢,远距离反射的振幅相对更强。所以如果你拿2D模拟的结果直接和实测振幅对比,会出现系统性偏差。
更本质的差别是目标体的形态。2D模型要求结构在z方向无限延伸,因此对“一根垂直于测线的管道”“一层连续界面”这类目标非常合适;但对于一个有限尺寸的空洞、一个局部缺陷、一个三维不规则体,2D模型会把它当成无限长柱体,绕射特征和真实情况不同。这也是为什么官方文档和大量文献都强调:定量解释尽量用3D,参数试探可以用2D。
4.2 3D 模型怎么建:资源估算先行
3D建模最大的敌人是内存。估算公式很简单:
网格总数 ≈ (Lx/dx) * (Ly/dy) * (Lz/dz) 基内存 ≈ 网格总数 * 6(场分量) * 8(字节)假设做一个1.5m×1.0m×1.0m的模型,5mm网格,网格总数是300×200×200=1200万,基内存就是576MB。加上PML吸收边界、材料参数、中间数组冗余,实际运行内存通常要再乘2~3倍,也就是1.2~1.7GB。这还没算输出文件的大小。所以我做3D模拟前的第一件事是把参数表拉出来算一遍内存,超过本机内存就果断改网格或改模型尺寸。
资源不够时有一个很实用的降级方案:只在目标区域加密网格。前提是gprMax是全均匀网格,不能局部加密。这时候可以把包含目标的区域单独拎出来建一个小子域,周边用大网格PML围起来,不过gprMax目前不支持非均匀网格,所以实际上只能整体降分辨率,或者用更小的模型范围。经验做法是模型边界距目标至少半个波长,PML厚度保持默认或增加到10个网格,否则边界反射会污染目标信号。
4.3 3D 建模仿真示例与结果对比
把2D空洞模型改造成3D,核心变化有三处:一是#domain的z方向从0.01m改成1.0m;二是#box的z范围从0~0.01m改成0~1.0m;三是目标从方形柱体(其实2D的box就是柱体)改成一个真实的三维立方体空洞。为了体现点目标特征,我把空洞尺寸改为0.5m×0.5m×0.5m,中心在x=3.5m、y=1.5m、z=0.5m。
一个可直接运行的3D模型文件片段如下:
#title: cavity_detection_3d #domain: 3.5 2.5 1.0 #dx_dy_dz: 0.005 0.005 0.005 #time_window: 150e-9 #material: 1 0 1 0 0 0 air #material: 6 0.005 1 0 0 0 concrete #material: 8 0.015 1 0 0 0 soil #box: 0 0 0 3.5 0.1 1.0 concrete #box: 0 0.1 0 3.5 2.5 1.0 soil #box: 3.25 1.25 0.25 3.75 1.75 0.75 air #hertzian_dipole: z 0.30 0.006 0.50 #rx: 0.24 0.006 0.50 #src_steps: 0.05 0 0 #rx_steps: 0.05 0 0 #output: rx1 Ez注意源和接收器的z坐标设成0.5m,也就是模型z方向的中间位置,这样才能保证测线经过空洞正上方。3D模型的网格数约700×500×200=7000万,基内存3.36GB,4核并行下依然要跑一个多小时。如果只是想验证方案可行性,建议先改成1cm网格,网格数降到875万,速度提升8倍,精度损失对判断“能不能看到空洞”完全够用。
3D结果的B-scan和2D有两点显著差异。第一,双曲线两翼的振幅衰减更快,因为球面波衰减更强。第二,空洞顶面的反射波形更接近真实点目标响应,旁瓣结构更明显。如果你有实测数据,3D结果的振幅和相位特征更容易跟实测匹配。
5. 后处理工具箱:从 HDF5 数据到可解释的雷达剖面
5.1 用 h5py 读取 gprMax 输出
gprMax的.out文件格式是HDF5,里面数据结构非常清晰。顶层是rxs组,下面按接收器编号分成rx1、rx2等,每个接收器下保存了Ex、Ey、Ez、Hx、Hy、Hz六个分量。如果你在.in文件里加了#output: rx1 Ez,文件里就只存Ez,能省不少写入时间和磁盘空间。
读取方式:
import h5py f = h5py.File('cavity_2d.out', 'r') data = f['rxs']['rx1']['Ez'][:] dt = f.attrs['dt'] f.close()形状是(time_steps, num_traces),time_steps由#time_window和网格步长决定,num_traces由测点数决定。dt是时间步长,用np.arange(time_steps) * dt就能得到时间轴。
5.2 A-scan 的相位解释
A-scan是单道波形,也是理解剖面的钥匙。在空洞正上方的那一道波形里,你通常能看到三个波组。第一个是0~5ns的直达波,振幅大、频率高,对应空气耦合和地表耦合波。第二个是在空洞顶面深度对应的时刻出现的反射波,相位与直达波相反——如果直达波先是正峰,反射波会先是负峰。第三个是空洞底面反射,相位又会反转回来。
利用介电常数对比判断反射极性是个非常实用的技巧。反射系数公式是:
R = (eps1 - eps2) / (eps1 + eps2)从土壤(eps≈8)进入空气(eps=1),R为负,反射波相位反转;从空气进入土壤,R为正。如果空洞里有水,从土壤(8)进入水(81),R也是负的,所以光看相位无法区分空洞和含水空洞,还需要结合振幅大小和双程走时做联合判读。
5.3 时深转换
B-scan的纵轴是时间,实际解释时需要换算成深度。换算公式是:
depth = v * t / 2其中v是电磁波在介质中的传播速度,v = c0 / sqrt(eps_r)。如果地下是均匀介质,直接用一个eps_r换算即可;像路面加土层的双层结构,要分段换算。混凝土的eps_r为6,土的eps_r取8,则空洞顶面深度可以写:
depth = (v_concrete * 0.1) + v_soil * (t - 2*0.1/v_concrete) / 2实际项目里epr值往往不确定,最可靠的办法是从B-scan中已知目标的绕射双曲线拟合波速,再把时间轴转成深度轴。
5.4 实用的增益方法
深部反射振幅弱,不增强很难看清。最简单的增益是指数增益,按时间乘以exp(alpha * t),alpha需要试。更好用的是自动增益控制(AGC),它在滑动窗口内计算信号RMS,然后按RMS倒数放大每个时刻的振幅,浅部强信号被压低,深部弱信号被放大。这个操作会破坏波形的真实振幅信息,但用于判读目标位置和形状非常有效。
def agc(x, half_window): n = x.shape[0] out = np.zeros_like(x) for i in range(n): lo = max(0, i - half_window) hi = min(n, i + half_window) rms = np.sqrt(np.mean(x[lo:hi] ** 2)) out[i] = x[i] / (rms + 1e-12) return out for trace_idx in range(clean.shape[1]): clean[:, trace_idx] = agc(clean[:, trace_idx], 15)对去背景后的B-scan逐道做AGC,空洞双曲线会在整幅剖面里非常醒目。这一步之后,你就能自信地跟项目组说“雷达剖面解释完了”。
6. 实操中常见的坑:网格、边界与资源调优
6.1 网格步长的数值色散问题
网格太粗的直接后果不是“看不清目标”,而是波速被算错。FDTD的数值色散会在几个波长距离上积累明显的相位误差,导致目标回波到达时间偏晚。更严重的是,色散会在目标后方产生虚假拖尾,新手很容易把这种拖尾误判成二次反射。
判断网格是否够细的最有效方法不是靠理论估算,而是做网格收敛性检验:同一模型分别用10mm、5mm、2.5mm网格跑一次,比较目标反射波到达时间的变化。如果两次细分后到达时间差小于半个采样周期,说明网格已经够细;如果还在变化,加大网格密度。2D模型算得快,这种检验几乎不花成本;3D模型我建议至少在关键参数上做一次。
6.2 时间窗和边界PML
时间窗设短了的后果很直接:深部信号还没到达接收器,计算就停了。但更隐蔽的问题是,如果时间窗过长,波的多次反射会在PML边界产生残余反射,污染晚期信号。PML本身不是万能的,它对大角度入射、低频分量吸收效果较差。遇到这种情况,除了加厚PML,还可以把模型边界向外扩展半个波长以上,让杂波在到达目标区域前先衰减掉。
gprMax默认已经开启了PML边界,新手不太需要手动设置。只有当你在剖面底部或两侧看到明显的连续水平/竖直条带异常时,才需要检查是不是PML边界反射。解法是加大模型尺寸或调整#pml_cells参数,从默认10层加到15层。注意PML只对域的外部边界生效,模型内部目标与边界之间要留够空间。
6.3 内存与并行策略
3D模拟内存爆炸是最常见的截停原因。我个人的经验是,建模前先做一次“5分钟预估”:
网格数 = round(Lx/dx) * round(Ly/dy) * round(Lz/dz) 内存估算 = 网格数 * 6 * 8 * 3乘以3是给材料参数、PML和临时数组留的余量。如果内存估算超过本机物理内存的80%,要么放大网格步长,要么缩小模型范围,要么启用并行配合内存足够的机器。gprMax的并行是按空间剖分实现的,-n 8时每个进程只负责一部分网格,整体内存需求近似不变,但单进程压力会降低,因此如果你有分布式集群,可以跑更大的模型。
另外要注意输出文件同样占磁盘。每保存一个时间步的全部接收器波形,文件大小会迅速增长。#output: rx1 Ez这个命令能让你只保留你关心的分量,常常能把输出文件从几个GB降到几百MB。
6.4 源与接收器的位置细节
源和接收器不能放在地表表面刚好y=0的位置,因为表面处材料不连续,会产生不稳定的数值解。通常把它们放在地表以下1~2个网格(如y=0.006m),并保证周围网格是同一种介质。收发天线之间的水平偏移也要避免过大。偏移过大除了会增加直达波的时间,还会降低浅层目标的横向分辨率。常规共偏移模式下,偏移距设为5~10cm比较合适。
同样的道理,接收器不能放在材料边界上。如果你发现波形出现高频毛刺,先检查源和接收器是不是落在了几何体边界上,这是新手最常踩的坑。
另外补充一个我自己的习惯:同一个模型文件,我会保留一个“最小可用版本”,源、接收器、目标各一个,跑通后再逐步增加测线数和目标数量。这样一旦出现逻辑错误,能快速定位是哪个新增参数引入的。gprMax的命令解析错误信息有时候只说“line X: unexpected line”,并不告诉你哪里逻辑有问题,通过最小化模型做二分排查是最高效的办法。
最后再分享一个我在跑gprMax时最受益的操作习惯。官方教程和示例模型文件看着东西很多,但真正进入项目阶段,你80%的时间会耗在同一个循环里:改参数、看几何、跑模拟、看剖面、再改参数。这时候千万不要直接改原始.in文件,应该写一个Python参数脚本把所有输入参数集中管理,每个参数单独定义,生成.in文件只负责把参数拼接成文本。这样做的好处是,当你想扫描不同空洞深度、不同频率、不同介电常数时,只需要改一行变量重新运行生成脚本,而不是在庞大的.in文件里翻来翻去找那一处数字。gprMax本身不提供参数扫描功能,但配合这样的参数化生成脚本,做批量正演模拟会顺手得多。
本文还有配套的精品资源,点击获取