当前位置: 首页 > news >正文

石油勘探射线追踪(Ray Tracing)MATLAB 实现

面向反射/折射初至走时的 2D 射线追踪,对标井下/地面石油勘探场景:多层介质 + 层速度模型 + 射线方程(程函/哈密顿形式)+ 界面 Snell 透射/反射 + 初至走时。


一、问题建模(先对齐术语)

石油勘探语境下,射线追踪通常是速度建模 / 走时层析 / Kirchhoff 偏移的前置:

要素含义
速度模型v(x,z)v(x,z)v(x,z)层状 / 线性梯度 / 网格
射线方程drds=p, dpds=∇(ln⁡v) ⇒\frac{d\boldsymbol{r}}{ds}=\boldsymbol{p},\; \frac{d\boldsymbol{p}}{ds}=\nabla(\ln v)\;\Rightarrowdsdr=p,dsdp=(lnv)哈密顿形式
界面条件Snell:sin⁡θ1v1=sin⁡θ2v2\frac{\sin\theta_1}{v_1}=\frac{\sin\theta_2}{v_2}v1sinθ1=v2sinθ2(透射),反射同理
目标炮-检走时ttt,射线路径,覆盖分析

两套实现:

  • A 版:层状模型 + 解析 Snell
  • B 版:网格速度模型 + 哈密顿 ODE + RK4

二、A 版:层状模型 + Snell 透射/反射

2.1 速度模型定义velocity_model.m

%% 层状速度模型(石油勘探常用)% 每层: [顶深(m), 底深(m), v_top(m/s), v_bottom(m/s)]% 层内速度线性插值 v(z) = v_top + (v_bottom-v_top)*(z-top)/(bottom-top)functionv=layered_velocity(z,layers)% z: 深度(m),可标量或向量% layers: N×4 矩阵v=zeros(size(z));fori=1:size(layers,1)top=layers(i,1);bottom=layers(i,2);v_top=layers(i,3);v_bottom=layers(i,4);mask=(z>=top)&(z<bottom);ifi==size(layers,1)mask=(z>=top);% 最底层无下底endv(mask)=v_top+(v_bottom-v_top)*(z(mask)-top)/(bottom-top+eps);endend%% 示例模型(浅层沉积+基底)% 地表 z=0,深度+layers=[...0,800,1800,2200;% 表层+泥岩800,1800,2200,2800;% 砂岩1800,3000,2800,3500;% 灰岩];

2.2 单层内射线传播(常梯度,解析近似)

function[x2,z2,t12,pz2]=ray_segment_layer(z1,z2_target,x1,pz1,vtop,vbot,layer_top,layer_bottom)% 单层内射线追踪(线性梯度 v(z)=v0 + g*z)% 输入: 起点(z1,x1), 目标深度 z2_target, 入射慢度 pz1, 层参数% 输出: 出点(x2,z2), 走时 t12, 出射慢度 pz2g=(vbot-vtop)/(layer_bottom-layer_top);% 梯度v0=vtop-g*layer_top;% v(z)=v0+g*z% 慢度 p = sinθ/v, 水平慢度 px 守恒% 由 Snell: px = pz1 * (??) —— 更稳的做法是用 Hamilton:% dz/ds = pz*v, dpz/ds = -dv/dz = -g% 常梯度层内可解析:% 令 pz(z) = pz1 - g*(z-z1)/v(z)? 不,直接用慢度形式:% === 改用慢度 u=1/v 的形式(更稳)===% 程函: |∇τ|² = u², 射线: dx/dt = u*p 之类% 工程上石油界常用"梯形法则+Snell",这里给数值段(通用)px=pz1*0;% 水平慢度——等等,得从入射角来% 重新入参: 改成给入射角更直观end

上面这个函数写得太"教科书",实际石油界层内常用两段做法:

  • 层内常速 → 直线 + Snell
  • 层内线性梯度 → 圆弧形射线(解析),x(z)x(z)x(z)sin⁡\sinsin/cos⁡\coscos形式

2.3 主追踪器(层状 + 透射/反射)raytrace_2d.m

%% 2D 射线追踪 —— 层状模型,shooting 法% 炮 (xs, zs), 检波器 (xr, zr),多层常速层,界面 Snell 透射% 这里做: 直达 + 折射(临界) + 反射 三类function[rays]=raytrace_2d_shot(xs,zs,xr_arr,zr_arr,layers)% xs,zs: 炮坐标% xr_arr,zr_arr: 检波器数组% layers: N×4 层定义nc=length(xr_arr);rays=cell(nc,1);forir=1:nc xr=xr_arr(ir);zr=zr_arr(ir);% ===== 先试: 直达波(同一层内)=====iffloor(zs/layers(1,2))==floor(zr/layers(1,2))% 粗糙同层判v=layered_velocity((zs+zr)/2,layers);L=sqrt((xr-xs)^2+(zr-zs)^2);t_direct=L/v;ray.type='direct';ray.path=[[xs,zs];[xr,zr]];ray.tt=t_direct;rays{ir}=ray;continue;end% ===== 透射波(射线穿过界面)=====% shooting: 从炮出发,猜入射角,追到检波器深度,看水平偏差% 这里给简化版: 假设垂直层状,射线只在界面处偏折(层内直线)% 找出炮→检经过哪些界面z_interface=[layers(:,1);layers(end,2)];% 所有界面深度z_pts=unique(sort([zs;zr;z_interface]));z_pts=z_pts(z_pts>=min(zs,zr)&z_pts<=max(zs,zr));% 每段: 常速, Snell 在界面处% 入射角 θ1: sinθ1/v1 = sinθ2/v2 = p (射线参数, 守恒)% shooting: 搜 p (水平慢度)p_candidates=linspace(1e-6,1/min(layers(:,3))*0.99,200);% p < 1/v_maxbest_err=inf;best_p=NaN;best_path=[];best_tt=inf;forip=1:length(p_candidates)p=p_candidates(ip);% 水平慢度, 守恒% 从炮出发x_cur=xs;z_cur=zs;tt=0;path=[x_cur,z_cur];ok=true;% 向下追界面foriz=2:length(z_pts)z_next=z_pts(iz);% 当前所在层ilayer=find(z_cur>=layers(:,1)&z_cur<[layers(2:end,1);inf],1);ifisempty(ilayer),ilayer=size(layers,1);endv_layer=layered_velocity((z_cur+z_next)/2,layers);% 由 p 求垂直慢度: pz = sqrt(u² - p²), u=1/vu=1/v_layer;ifp>=u ok=false;break;% 全反射/临界endpz=sqrt(u^2-p^2);% 层内 dz, dxdz=abs(z_next-z_cur);ds=dz/(v_layer*pz*v_layer);% 错——ds = dz/(v*cosθ), cosθ = pz*u? 重算:% 慢度矢量 p⃗ = (px, pz) = (p, pz)% dx/ds = v * px = v*p, dz/ds = v*pz% 所以 dz = v*pz * ds → ds = dz/(v*pz)% 但 pz = √(u²-p²)ds=dz/(v_layer*pz);dx=v_layer*p*ds;ifz_next>z_cur,x_cur=x_cur+dx;elsex_cur=x_cur-dx;endz_cur=z_next;tt=tt+ds;path=[path;x_cur,z_cur];endif~ok,continue;end% 看水平偏差err=abs(x_cur-xr);iferr<best_err best_err=err;best_p=p;best_path=path;best_tt=tt;endend% 收敛判据ifbest_err<5% 5m 以内算追到ray.type='transmitted';ray.path=best_path;ray.tt=best_tt;ray.p=best_p;rays{ir}=ray;elserays{ir}=[];% 没追上,可能是反射/临界,这里略endendend

2.4 主脚本seismic_raytrace_demo.m

%% 石油勘探 2D 射线追踪 democlear;clc;close all;%% 1. 速度模型layers=[...0,800,1800,2200;% 表层800,1800,2200,2800;% 砂岩1800,3000,2800,3500;% 灰岩];%% 2. 观测系统xs=0;zs=0;% 地表炮xr=0:50:2000;zr=zeros(size(xr));% 地表检波器% 也可以加井下: zr = 1000*ones(size(xr));%% 3. 追踪rays=raytrace_2d_shot(xs,zs,xr,zr,layers);%% 4. 走时曲线tt=zeros(size(xr));fori=1:length(xr)if~isempty(rays{i})tt(i)=rays{i}.tt;elsett(i)=NaN;endend%% 5. 可视化figure('Color','w','Position',[1001001200500]);% 速度剖面subplot(1,2,1);hold on;grid on;box on;% 画层fori=1:size(layers,1)plot([02500],[layers(i,1)layers(i,1)],'k-','LineWidth',1.5);plot([02500],[layers(i,2)layers(i,2)],'k--','LineWidth',1);% 速度填充(示意)zz=linspace(layers(i,1),layers(i,2),100);vv=layered_velocity(zz,layers);yy=vv*ones(size(zz'))? 不对——换思路:用 contourfend% 画几条射线colors=parula(length(rays));cnt=0;fori=1:5:length(rays)% 稀疏画if~isempty(rays{i})cnt=cnt+1;r=rays{i};plot(r.path(:,1),r.path(:,2),'-','Color',colors(cnt,:),'LineWidth',1);plot(r.path(:,1),r.path(:,2),'.k','MarkerSize',3);endend% 炮检plot(xs,zs,'r*','MarkerSize',14,'LineWidth',2);plot(xr,zr,'kv','MarkerSize',8,'LineWidth',1);xlabel('x (m)');ylabel('z (m)');title('射线追踪(层状模型)');axis ij;ylim([30000]);xlim([-1002100]);% 走时曲线subplot(1,2,2);hold on;grid on;plot(xr,tt,'bo-','LineWidth',1.5);xlabel('偏移距 (m)');ylabel('走时 (s)');title('初至走时曲线 (t-x)');% 画 v(z) 示意axes('Position',[0.70.150.10.6]);hold on;zz=linspace(0,3000,200);vv=layered_velocity(zz,layers);plot(vv,zz,'r-','LineWidth',2);set(gca,'YDir','reverse');ylim([30000]);xlabel('v (m/s)');ylabel('');title('v(z)');sgtitle('石油勘探 2D 射线追踪 Demo','FontSize',14,'FontWeight','bold');

参考代码 raytrace石油勘探的射线追踪程序www.youwenfan.com/contentcsw/82208.html

三、B 版:网格速度模型 + 哈密顿 ODE

A 版够教学,但真做走时层析一般用网格v(x,z)v(x,z)v(x,z)+ 最短路径法(SPM)或 Runge-Kutta 追射线。给你 RK 版骨架:

%% 哈密顿射线追踪(网格速度模型)% 射线方程(慢度形式):% dx/dt = v² * px% dz/dt = v² * pz% dpx/dt = -v * ∂v/∂x% dpz/dt = -v * ∂v/∂z% 其中 p = ∇τ(慢度矢量), v = 1/ufunction[x_ray,z_ray,t_ray]=hamilton_raytrace(x0,z0,px0,pz0,v_grid,xvec,zvec,dt)% v_grid: 网格速度 (Nz×Nx)% xvec, zvec: 网格坐标% dt: RK 步长% 初始x=x0;z=z0;px=px0;pz=pz0;t=0;x_ray=x;z_ray=z;t_ray=t;whilet<1e4% 追到检波器逻辑外面包% 插值 v, dv/dx, dv/dzv=interp2(xvec,zvec,v_grid,x,z,'linear',2000);[dvdx,dvdz]=gradient(v_grid,mean(diff(xvec)),mean(diff(zvec)));dvdx_i=interp2(xvec,zvec,dvdx,x,z,'linear',0);dvdz_i=interp2(xvec,zvec,dvdz,x,z,'linear',0);% RK4% k1k1x=v^2*px;k1z=v^2*pz;k1px=-v*dvdx_i;k1pz=-v*dvdz_i;% k2, k3, k4 略(模板化写)...% 这里给欧拉示意(想稳就用 RK4)x=x+dt*k1x;z=z+dt*k1z;px=px+dt*k1px;pz=pz+dt*k1pz;t=t+dt;x_ray=[x_ray;x];z_ray=[z_ray;z];t_ray=[t_ray;t];% 出口判(追到检波器)ifz>zvec(end)-10,break;endendend

工程上更稳的是最短路径法(SPM)/ Fast Marching,网格上直接解程函方程得 τ(x,z),再插射线(∇τ 方向)。石油界商业 code(Hampson-Russell, Omega)底层都是这个思路。

http://www.jsqmd.com/news/1083462/

相关文章:

  • AI智能DDoS防护:从行为分析到实战部署
  • 7分钟高效掌握:为什么DLSS Swapper能彻底解决游戏画质升级难题
  • 技术好,为什么常常不被重用
  • 扩展-Agent Loop:自主执行的工程哲学
  • 终极指南:5分钟掌握HS2-HF_Patch,让《Honey Select 2》焕然新生
  • 终极指南:如何在Revit中无缝集成Rhino进行BIM参数化设计
  • 短视频矩阵系统哪个品牌好
  • 美光与Anthropic签署AI内存供应协议并投资H轮融资
  • Ark事件
  • 免费开源AMD处理器调试工具SMUDebugTool:硬件爱好者的终极掌控指南
  • qmc-decoder完全指南:3步解锁QQ音乐加密音频,释放你的音乐自由
  • Mermaid Live Editor:3分钟学会实时图表编辑的终极解决方案
  • AICoverGen:三步轻松制作AI翻唱,无需高端设备的语音转换神器
  • 奥运会数据分析实战:从数据清洗到可视化洞察
  • 为什么你的 RS-485 设备实验室好好的,一到现场就出问题?
  • 专业Cookie管理指南:本地化处理的完整实践方法
  • 【JAVA毕设源码分享】基于SpringBoot的日用品仓储管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)
  • 2026网络安全就业全景:缺口百万、薪资领跑,普通人如何抓住黄金赛道?
  • 【RV1126B 实战连载 03】从YOLOv5到YOLO26,RV1126B 通用目标检测模型部署实测
  • 【JAVA毕设源码分享】基于SpringBoot的食物节约盲盒系统的设计与实现(程序+文档+代码讲解+一条龙定制)
  • 杭州本地生活精准运营:GEO优化的流量逻辑与消费特征
  • 【2026实测】薅千问新用户8元券,千问APP输入:千问新用户专属220372,会弹出8元无门槛立减券
  • 计算机毕业设计之宠物平台的设计与实现
  • 如何用FeHelper前端工具箱解决开发中的三大效率瓶颈
  • 室外越野赛题优化建议
  • 撰写SKILL的哲学
  • HarmonyOS7 动画做不出高级感?animateTo 和共享元素转场够你用了
  • 世界杯巴拉圭VS澳大利亚袋鼠军团纸面占优或可小胜
  • 如何用Mermaid Live Editor实现5分钟完成复杂图表设计?
  • 31.TIA/Codesys 通用工业 PID 工程|模拟量滤波 + 手动自动切换 + 故障保护