
简介本资源是一套面向计算机、电子信息工程及应用数学等专业学习者的地震波传播仿真教学工具包聚焦地震射线追踪算法实现与多层介质地层模型构建适用于地球物理正演模拟入门与Matlab数值计算实践。压缩包共116个文件主体为107个Matlab函数.m涵盖射线路径求解如main.m、fun_calmod.m、速度模型构建fun_txin_maker.m、走时计算fun_set_timegroup.m、横波可视化fun_vin_Swave_plot.m等核心模块另含5个Markdown说明文档与4个文本配置文件结构清晰、注释完整便于分步调试与功能拓展。资源包仅330KB轻量易部署已有224人下载学习。使用者可直接运行主程序观察不同地层参数下的射线弯曲路径理解Snell定律在非均匀介质中的数值实现并基于现有框架快速修改模型参数、添加新层位或集成反演逻辑是理论学习与代码实操结合的高价值参考范例。1. 地震射线追踪不是画几条线——它是在Matlab里用数值方法“听清”地下结构的物理过程你拿到一份地质勘探数据想确认某条断层是否真实存在、某个储层厚度是否达到开发阈值但手头只有地表接收的地震波走时记录。这时候单纯拟合曲线或调用黑箱函数远远不够——你需要知道哪条射线路径真正对应这个走时它穿过了哪些速度层在哪个界面发生了反射/折射这正是地震射线追踪要解决的核心问题从给定速度模型出发求解满足费马原理最短走时的波传播路径。而地层模型仿真不是画个彩色分层图就完事它是构建一个可计算、可扰动、可与实测走时反演耦合的物理载体。本项目提供完整Matlab实现覆盖从分层速度模型定义、射线方程数值积分4阶Runge-Kutta、多段射线拼接临界角判断Snell定律迭代、到可视化路径与走时曲面的全链路。它不依赖任何商业地球物理插件所有代码基于原生Matlab语法R2018b兼容适合地球物理方向研究生快速复现基础算法也适合作为高年级本科生《地震勘探原理》课程设计的可调试底座。2. 用Matlab构建可计算的地层模型从分层定义到速度场网格化地层模型是射线追踪的物理基础。本项目采用“分层横向变化”双模结构纵向按深度划分为N个均匀层每层内速度可设为常数或线性梯度横向则支持沿x方向的速度缓变如沉积盆地边缘速度渐变。这种设计平衡了物理合理性与计算效率——既避免了全空间三维速度场带来的巨大内存开销又比纯一维模型更能反映实际地质构造。2.1 分层模型参数化layer_model.m的核心字段解析模型由结构体model定义关键字段如下代码中已预置华北平原典型浅层模型示例model struct(... n_layers, 5, ... % 总层数含基底 depths, [0, 200, 500, 1200, 2500], ... % 各层顶界深度m首项为0 velocities, [1500, 1800, 2300, 3100, 4200], ... % 各层P波速度m/s gradients, [0, 0.5, 0.3, 0.8, 0], ... % 各层速度垂向梯度s⁻¹0表示常速 x_variation, (x) 1 0.0002*x, ... % 横向速度修正函数v(x,z) v0(z) * x_variation(x) x_range, [-5000, 5000], ... % 模型横向范围m z_range, [0, 3000]); % 模型垂向范围m注意gradients单位为 s⁻¹即每米速度变化量而非 m/s/m。这是为后续射线方程中dv/dz项直接代入做准备。若某层设为常速gradients(i)0若需线性增加如2000m/s增至2500m/s跨越300m则梯度500/300≈1.67 s⁻¹。2.2 速度场网格化build_velocity_grid.m的离散策略射线追踪需在连续空间求解微分方程但计算机只能处理离散点。本项目采用自适应网格垂向分辨率随深度增加而降低因深层速度变化平缓横向保持均匀。核心逻辑如下function [V, X, Z] build_velocity_grid(model, nx, nz) % nx: x方向采样点数默认201 % nz: z方向采样点数默认151 X linspace(model.x_range(1), model.x_range(2), nx); Z zeros(1, nz); % 垂向非均匀采样前50%点覆盖0-1000m高分辨率后50%覆盖1000-3000m低分辨率 Z(1:floor(nz/2)) linspace(model.z_range(1), 1000, floor(nz/2)); Z(floor(nz/2)1:end) linspace(1000, model.z_range(2), ceil(nz/2)); % 构建网格 [Xg, Zg] meshgrid(X, Z); % 计算每点速度先查层再应用梯度和横向修正 V zeros(size(Xg)); for i 1:nz for j 1:nx z Zg(i,j); % 查找z所在层索引 layer_idx find(model.depths z, 1, last); if layer_idx model.n_layers, layer_idx model.n_layers; end v0 model.velocities(layer_idx); grad model.gradients(layer_idx); v_z v0 grad * (z - model.depths(layer_idx)); % 层内线性插值 v_xz v_z * model.x_variation(Xg(i,j)); % 横向修正 V(i,j) max(v_xz, 1500); % 速度下限保护避免零速导致除零 end end end2.2.1 网格精度与计算开销的权衡表参数组合内存占用单精度射线追踪单次耗时i7-11800H适用场景nx101, nz76~230 KB~0.8 ms快速验证、教学演示、初筛参数nx201, nz151~900 KB~3.2 ms标准科研仿真、走时反演初值生成nx401, nz301~3.5 MB~12.5 ms高精度成像、复杂构造如逆冲断层提示build_velocity_grid输出的V是(nz×nx)矩阵Z和X是向量。后续所有插值如射线位置查速度均使用interp2(V, X, Z, x, z, linear, extrap)避免重复计算。3. 实现地震射线追踪从费马原理到4阶Runge-Kutta数值积分射线追踪的本质是求解程函方程Eikonal Equation的特征线其微分形式为dx/dt p_x * v², dz/dt p_z * v², dp_x/dt -v * ∂v/∂x, dp_z/dt -v * ∂v/∂z其中(p_x, p_z)是射线参数slowness vectorv是局部速度。本项目采用四阶龙格-库塔RK4法对上述方程组进行步进积分因其在精度与稳定性间取得最佳平衡——相比欧拉法RK4在相同步长下误差降低两个数量级相比更高阶方法它无需额外导数计算更适合速度场梯度变化剧烈的近地表区域。3.1 射线起始条件与边界处理ray_trace.m的初始化逻辑一次追踪需明确从哪发射向哪发射到哪终止项目通过结构体ray_opts控制ray_opts struct(... source_x, 0, ... % 源点x坐标m source_z, 0, ... % 源点z坐标m通常为地表 init_angle, 30, ... % 初始出射角°从水平轴逆时针计 max_range, 5000, ... % 最大水平传播距离m max_depth, 3000, ... % 最大垂向探测深度m step_size, 5, ... % RK4初始步长m自动调整 min_step, 0.1, ... % 最小允许步长m防陷入奇点 tolerance, 1e-4); % 位置收敛容差m关键步骤在于将角度转换为初始慢度矢量theta0 deg2rad(ray_opts.init_angle); p0_x cos(theta0) / v_source; % v_source interp2(V,X,Z, source_x, source_z) p0_z sin(theta0) / v_source; y0 [ray_opts.source_x; ray_opts.source_z; p0_x; p0_z]; % 初始状态向量3.2 RK4核心迭代rk4_step.m的四次斜率计算每一步RK4需计算四个斜率k1,k2,k3,k4对应不同位置的速度梯度。核心函数如下function y_next rk4_step(y_curr, h, V, X, Z, model) % y_curr [x; z; px; pz] 当前状态 % h: 步长 x y_curr(1); z y_curr(2); px y_curr(3); pz y_curr(4); v interp2(V,X,Z,x,z,linear,extrap); % 计算当前点速度梯度∂v/∂x 和 ∂v/∂z [~, dVdx, dVdz] gradient_interp2(V,X,Z,x,z); % 自定义插值梯度函数 % 斜率函数 f(y) [dx/dt; dz/dt; dpx/dt; dpz/dt] f (x,z,px,pz) [px*v^2; pz*v^2; -v*dVdx; -v*dVdz]; % 四次斜率计算省略中间变量k2,k3定义仅展示k1和k4 k1 f(x, z, px, pz); k2 f(x h/2*k1(1), z h/2*k1(2), px h/2*k1(3), pz h/2*k1(4)); k3 f(x h/2*k2(1), z h/2*k2(2), px h/2*k2(3), pz h/2*k2(4)); k4 f(x h*k3(1), z h*k3(2), px h*k3(3), pz h*k3(4)); y_next y_curr h/6*(k1 2*k2 2*k3 k4); end3.2.1 梯度插值函数gradient_interp2的实现要点由于interp2不直接提供梯度需手动计算function [v, dvdx, dvdz] gradient_interp2(V,X,Z,x,z) % 先双线性插值得到v v interp2(V,X,Z,x,z,linear,extrap); % 在(x,z)邻域取4点(x±dx, z±dz)dxdz1m保证精度且避开奇点 dx 1; dz 1; v_xp interp2(V,X,Z,xdx,z,linear,extrap); v_xm interp2(V,X,Z,x-dx,z,linear,extrap); v_zp interp2(V,X,Z,x,zdz,linear,extrap); v_zm interp2(V,X,Z,x,z-dz,linear,extrap); dvdx (v_xp - v_xm)/(2*dx); dvdz (v_zp - v_zm)/(2*dz); end注意dvdx和dvdz的符号直接影响射线弯曲方向。若dvdx0东侧速度更快射线将向东偏折类似光在密度梯度介质中的折射。3.3 多段射线拼接处理反射与折射的临界角判断单一RK4积分只能处理透射射线。要模拟反射/折射需在每步后检测是否到达层界面并应用斯涅尔定律Snells Law。项目采用“界面碰撞检测参数重置”策略% 在RK4步进循环中插入 z_curr y_curr(2); % 查找当前z所在层及下一层界面 layer_idx find(model.depths z_curr, 1, last); if layer_idx model.n_layers abs(z_curr - model.depths(layer_idx1)) 0.5 % 接近下界面容差0.5m触发反射/折射判断 v_upper interp2(V,X,Z,x_curr,model.depths(layer_idx1),linear,extrap); v_lower interp2(V,X,Z,x_curr,model.depths(layer_idx1),linear,extrap); theta_i atan2(abs(y_curr(4)), abs(y_curr(3))); % 入射角 theta_c asin(v_upper / v_lower); % 临界角 if theta_i theta_c v_lower v_upper % 全反射重置pz符号保持px不变 y_curr(4) -y_curr(4); else % 折射根据Snell定律更新px, pz p_new y_curr(3:4) * v_upper / v_lower; % 慢度缩放 y_curr(3) p_new(1); y_curr(4) p_new(2); end end4. 可视化与验证从射线路径图到走时残差分析可视化不是为了好看而是为了快速诊断模型与算法的合理性。本项目提供三类核心图件射线路径叠加在速度模型上、单炮记录的走时曲线、以及与理论解的残差热力图。它们共同构成验证闭环。4.1 射线路径图plot_ray_path.m的分层着色逻辑速度模型用伪彩色显示射线用不同颜色区分类型红色透射、蓝色反射、绿色折射并标注关键点figure(Name,Ray Path in Velocity Model); imagesc(X, Z, flipud(V)); % V需上下翻转以匹配z轴正向向下 axis xy; colorbar; xlabel(X (m)); ylabel(Z (m)); hold on; % 绘制各射线段 for i 1:length(rays) x_ray rays{i}.x; z_ray rays{i}.z; if isfield(rays{i}, type) strcmp(rays{i}.type, reflected) plot(x_ray, z_ray, b-, LineWidth, 1.5); % 蓝色反射 elseif isfield(rays{i}, type) strcmp(rays{i}.type, refracted) plot(x_ray, z_ray, g-, LineWidth, 1.5); % 绿色折射 else plot(x_ray, z_ray, r-, LineWidth, 1.2); % 红色透射 end % 标注源点与接收点 plot(x_ray(1), z_ray(1), ro, MarkerSize, 8, MarkerFaceColor, r); plot(x_ray(end), z_ray(end), ks, MarkerSize, 6); end title(sprintf(Ray Tracing: %d Rays, %d Layers, length(rays), model.n_layers));4.1.1 关键验证点路径弯曲方向必须与速度梯度一致若某层速度随深度增加gradients0射线应向下弯曲凸向高速区若某层速度随x增加x_variation递增射线应向右偏折若在界面处发生反射路径应满足入射角反射角。提示运行demo_simple_reflection.m可立即看到单层模型下的标准反射路径这是检验算法正确性的第一道关卡。4.2 走时曲线生成generate_shot_gather.m的批量计算单炮记录是多个接收点检波器的走时集合。项目通过循环调用ray_trace并行计算function [times, positions] generate_shot_gather(model, ray_opts, rec_x, rec_z) % rec_x, rec_z: 接收点坐标向量长度N times zeros(size(rec_x)); positions [rec_x; rec_z]; parfor i 1:length(rec_x) % 使用并行计算加速 ray_opts.rec_x rec_x(i); ray_opts.rec_z rec_z(i); [~, ~, t] ray_trace(model, ray_opts); % 返回走时t times(i) t; end end输出times可直接用于绘制经典“香蕉曲线”时间-距离图并与野外采集的初至时间对比。4.3 残差分析用解析解验证数值精度对于简单模型如半空间常速存在解析解。项目内置analytic_time_1D函数计算直达波走时function t_analytic analytic_time_1D(x_src, z_src, x_rec, z_rec, v) % 直达波t sqrt((x_rec-x_src)^2 (z_rec-z_src)^2) / v t_analytic sqrt((x_rec-x_src)^2 (z_rec-z_src)^2) / v; end然后计算数值解与解析解的相对误差t_num generate_shot_gather(model, ray_opts, rec_x, rec_z); t_ana arrayfun((x) analytic_time_1D(0,0,x,0,1500), rec_x); residuals abs(t_num - t_ana) ./ t_ana * 100; % 百分比误差 figure; plot(rec_x, residuals, k-o); xlabel(Receiver Offset (m)); ylabel(Relative Error (%)); title(Numerical vs Analytical Traveltime Residual);合格标准在step_size5m下大部分接收点误差应 0.5%若出现 2% 的尖峰说明该位置步长不足或界面附近插值失真需启用自适应步长调整。5. 进阶技巧用射线追踪结果驱动地层模型优化与不确定性量化射线追踪本身是正演工具但其输出走时、射线密度、路径弯曲度可作为反演的敏感核。本项目提供两个即用型技巧基于射线覆盖的模型分辨率评估和蒙特卡洛走时扰动分析帮助用户跳出“能跑通”的初级阶段进入“结果可信度如何”的工程实践层面。5.1 射线覆盖图识别模型中的“盲区”并非所有地下区域都被射线充分照亮。覆盖不足的区域反演结果必然不可靠。项目通过ray_coverage_map.m生成二维覆盖密度图function coverage ray_coverage_map(rays, X, Z, bin_size) % rays: 射线路径列表每个rays{i}包含.x和.z字段 % X,Z: 速度模型网格坐标 [nz, nx] size(X); coverage zeros(nz, nx); for i 1:length(rays) x_ray rays{i}.x; z_ray rays{i}.z; % 将射线路径离散化为点集步长bin_size points [x_ray; z_ray]; for j 1:size(points,1) % 找到points(j,:)最近的网格点索引 [~, idx_x] min(abs(X(1,:) - points(j,1))); [~, idx_z] min(abs(Z(:,1) - points(j,2))); coverage(idx_z, idx_x) coverage(idx_z, idx_x) 1; end end % 归一化为每平方米射线数需换算网格面积 dx X(1,2)-X(1,1); dz Z(2,1)-Z(1,1); coverage coverage / (dx * dz); end5.1.1 覆盖图解读指南覆盖密度射线/m²地质解释建议操作 0.1严重照明不足反演结果无意义增加炮点/检波点密度或调整观测系统0.1–1.0中等覆盖可用于粗略构造解释结合其他信息如测井约束该区域 1.0充分覆盖反演结果可靠性高可进行精细速度建模实战案例运行demo_coverage_analysis.m加载提供的华北平原模型设置10个炮点x-4km到4km间隔1km生成覆盖图。你会发现在1500–2500m深度、x±2km区域出现明显低覆盖带——这提示该区域需要补充垂直地震剖面VSP数据。5.2 蒙特卡洛走时扰动量化速度模型不确定性的传播实际速度模型存在测量误差如测井采样间隔、实验室标定偏差。本项目通过随机扰动模型参数观察走时变化从而评估结果鲁棒性function [t_mean, t_std] monte_carlo_traveltime(model_base, ray_opts, n_samples) t_all zeros(n_samples, 1); for i 1:n_samples % 随机扰动各层速度±3%符合典型测井误差 model_pert model_base; model_pert.velocities model_base.velocities .* (1 0.03 * randn(size(model_base.velocities))); % 保持梯度和横向变化不变 [~, ~, t] ray_trace(model_pert, ray_opts); t_all(i) t; end t_mean mean(t_all); t_std std(t_all); end调用示例[t_mean, t_std] monte_carlo_traveltime(model, ray_opts, 200); fprintf(Mean traveltime: %.4f s, Std: %.4f s (%.2f%%)\n, ... t_mean, t_std, t_std/t_mean*100);关键结论若某接收点走时标准差 5ms对应距离误差约7.5m则该点的反演结果应被降权处理。项目uncertainty_weighting.m提供了基于t_std的走时权重矩阵可直接输入到最小二乘反演流程中。最后一句技术内容在run_full_workflow.m中你将看到如何串联build_velocity_grid→generate_shot_gather→ray_coverage_map→monte_carlo_traveltime形成一条从模型构建、正演计算、质量评估到不确定性量化的完整技术流水线——这不是一个孤立的“射线追踪演示”而是一个可嵌入实际地球物理工作流的计算模块。本文还有配套的精品资源点击获取