资讯动态

基于MATLAB的FK变换原理与地震数据去噪实践

发布时间:2026/9/8 10:20:38 来源:尧图企业网站定制
简介基于MATLAB的FK变换傅里叶-基尔霍夫变换完整资源包面向光学成像、遥感图像处理、医学成像等方向的学习者与开发者旨在解决复杂光学系统成像特性的分析与仿真问题。资源共10个文件总大小仅926KB类型覆盖4个docx文档、3个mat数据文件、1个m脚本、1个txt说明及1张运行结果图片。docx文档系统梳理FKT概述、程序手册与使用说明m脚本fktran.m提供核心算法实现mat文件保存处理所需数据txt与jpg则可快速核对代码运行流程与结果。目前已有1779人学习。借助这套资源读者可快速理解FK变换中二维傅里叶变换、光瞳函数卷积与逆变换的完整链路直接运行脚本复现成像效果并可根据文档示例将方法迁移到遥感图像理解、光学系统设计或OCT图像重建等实际任务中兼具理论参考与工程实践价值也可结合自身光学系统参数进行二次开发。 我们直接进入正题。1. 为什么要从FK变换开始聊做地震数据处理、探地雷达分析甚至实验力学振动信号整理的朋友大概率都绕不过FK变换这个坎。我第一次接触FK变换是在处理二维地震记录时目标很单纯把斜向传播的干扰波比如面波、声波干掉把同相轴更平缓的反射波保留下来。当时我用的就是matlab一条fish命令来回试最后跑通了也踩了不少坑。先说清楚FK变换到底处理的是什么问题。常规的FFT处理一维信号只有时间轴t得到的是频率fFK变换处理的是二维信号除了记录时间t还有个空间轴x比如检波点道号、测线位置两个方向都做傅里叶变换后得到的就是频率f和波数k空间频率代表波数即每公里/每米有多少个波长构成的谱。所以FK变换本质上是二维傅里叶变换帮助我们把信号放到频率-波数平面上去区分波场。为什么要在频率-波数域做因为地震记录里的不同波场在f-k平面里的分布区域有明显差异。反射波视速度大同相轴平缓能量集中在靠近k轴的小斜率区域面波视速度低同相轴陡峭能量集中在斜率较大的锥形区域。两者在时间-空间域可能重叠得很厉害但在f-k域可以分开于是就可以用滤波算子在f-k平面上做切除然后再逆变换回t-x域。这就是FK滤波“治“波场分离的最常见用法。如果你正在做数据预处理、去噪、插值或者只是想搞清楚二维阵列数据的频率成分这篇内容应该能帮你少走不少弯路。我们以下都用matlab为操作环境从物理原理讲到实际代码再到排错经验一步步拆开说。2. FK变换的物理意义与matlab实现前的准备2.1 直观理解f-k域里的“一个点代表一种波”先做个简化比喻。一维信号FFT后某个频率f上的能量大小说明信号里这个快慢变化的成分有多强二维数据FK变换后某个fk坐标上的能量说明的是这个数据里有多少能量是以“传播速度为f/k”这种特定的时空模式在移动。因为速度v 频率f / 波数k。于是在f-k平面上从原点出发的任意一条射线的斜率就代表了波场的视速度。斜率越陡速度越低斜率越缓速度越快。例如水平反射波同相轴在时空域是近水平的FFT之后能量集中在k≈0附近对应视速度接近无穷大在f-k图上就是贴着f轴的一条窄带。而倾斜干扰波同相轴例如线性面波视速度是固定的几百米每秒它的能量会沿一条射线分布。有了这个图像我们就能设计扇形滤波器把不需要的射线区域切掉。这里必须提一个容易混淆的点不要以为f-k域和t-x域是割裂的两个空间。事实上它们只是同一份波场数据的两种正交展开方式。你做的任何f-k域操作都会影响到时空域的结果所以理解“域里面切了什么域外面改了什么”很重要。2.2 matlab实现前必备的三个基础操作在写任何代码前有准备工作要做。第一步数据摆放格式。FK变换要求输入是二维矩阵而且建议是空间轴按行排列、时间轴按列排列或者反过来但必须保持恒定因为它直接影响fft2输出的含义。习惯上地震行业用nt时间采样点数×nx空间道数的矩阵行是固定一道的时间序列列是固定时刻的各道振幅。绝大多数Segy读取工具导出的就是这种格式。第二步了解fft2的输出布局。matlab的fft2对矩阵做二维FFT默认输出的第一个维度对应矩阵的行方向即时间方向第二个维度对应列方向即空间方向。很多坑都是这里产生的。如果你习惯用imagesc直接看abs(fft2(data))会发现低频在四角零频在左上角视觉上反直觉。建议用fftshift做一次移位把零频挪到矩阵中心再显示否则后面画扇形滤波边界的时候坐标关系很容易搞乱。第三步搞清坐标轴。显示f-k谱时横轴是波数k纵轴是频率f或者采样点数。需要根据采样间隔dt、道间距dx把数组坐标换算成物理坐标频率轴f (0 : nt-1) / (nt * dt)单位Hz波数轴k (0 : nx-1) / (nx * dx)单位1/m或者换算成cycles/m如果用fftshift需要生成从负到正的物理坐标范围f (-nt/2 : nt/2-1) / (nt*dt)k同理。这一步很多人偷懒不做直接拿索引坐标去设计滤波器结果滤波边界完全对不上波场位置导致该去的没去掉不该削的反射波反而被削了。2.3 为什么有人用f-k插值而不是单纯去噪除了压制干扰波FK变换还有一个高频用法数据规则化与插值。规则化是要把不规则采样的道间距变成等间距插值是要把缺道补出来。时间域直接插值容易破坏波场的动力学特征而f-k域可以利用波场的可预测性在k方向做带宽限制或者反泄露处理后再反变换。简单说原理如果原始空间采样不足存在空间假频见后面第5节插值算法在f-k域能识别哪些是假频能量、哪些是真实信号能量通过迭代或者抗泄露算子把落在假频区的信号重建出来。这种用法在处理地面地震数据、GPR探地雷达数据甚至麦克风阵列信号时都非常常见。3. matlab中FK变换的核心代码与参数设计这部分我们写一个可以直接运行的示例流程。假设数据data变量是一个nt×nx的矩阵代表了某个时刻采集的多道信号。% 参数 dt 0.002; % 时间采样间隔单位秒 dx 5; % 道间距单位米 [nt, nx] size(data); % 1. 二维傅里叶正变换 spec fft2(data); % 2. 将零频移到中心便于显示和设计滤波算子 spec_shift fftshift(spec); % 3. 构建物理坐标轴 f_axis (-nt/2 : nt/2-1) / (nt*dt); k_axis (-nx/2 : nx/2-1) / (nx*dx); % 4. 显示f-k谱注意转置为了符合imagesc显示习惯 figure; imagesc(k_axis, f_axis, abs(spec_shift)); xlabel(波数 k (1/m)); ylabel(频率 f (Hz)); axis xy; % 让y轴从小到大显示这段代码是基础中的基础。显示之后你能直观看到面波的能量团通常是一个以原点为顶点、向高低频两侧扩展的扇形或V形区域。找到它的边界斜率就是计算视速度范围的开始。3.1 扇形滤波器设计参数选择是关键面波压制最常见的是扇形切除把f-k平面中超过某个速度界限的能量置零。实现方式有两种思路。第一种直接在f-k域生成一个二维掩膜mask。比如我要保留视速度大于等于1500 m/s的成分那么在f-k平面上每个点对应的视速度v f / k我把|v| 1500的点设为0其余保留。这里注意k的正负都要考虑因为波可以向左传也可以向右传所以滤波器必须关于k0对称如果只是去除某个方向传播的波则只保留一翼。% 用meshgrid生成二维网格 [K, F] meshgrid(k_axis, f_axis); % 视速度计算注意避免除以零 V zeros(size(K)); idx abs(K) 1e-10; V(idx) F(idx) ./ K(idx); V(~idx) sign(F(~idx)) * 1e10; % 近似无穷大速度 % 设计低切滤波器只保留速度绝对值大于等于vmin的信号 vmin 1500; % 米/秒 mask ones(size(K)); mask(abs(V) vmin) 0; % 保留近零波数区间即垂直入射波附近这在很多情况是必要的 k_zero_band abs(K) 0.01 / dx; % 归一化阈值根据数据调整 mask(k_zero_band) 1; % 加一点平滑过渡避免吉布斯效应见第5节 mask imgaussfilt(mask, 1.5); % 5. 应用滤波 spec_filtered spec_shift .* mask; % 6. 反变换 data_filtered real(ifft2(ifftshift(spec_filtered)));这里有几个坑要单独说明。第一直接硬截断会产生严重的吉布斯效应表现为时间域信号上出现振荡拖尾、空间域出现条带状伪影。所以上面用imgaussfilt对mask做了一次轻度高斯平滑让过渡带不要过于陡峭。平滑的程度要控制太缓会把有效波也削掉一点太陡又振铃这个需要根据实际数据摸索。第二速度下限vmin的选取不能拍脑袋要根据面波最大视速度和有效波最小视速度来定。如果目标反射波速度本来就低例如浅层低速层里的折射波vmin太高会伤害有效信号。我习惯先把f-k谱显示出来用探针工具量出干扰波的视速度边界再去填vmin不要凭感觉。第三k_zero_band的处理。很多人在低频段保留全部信号原因是浅层多次波、直达波通常都在低频小波数区切太狠会影响后续反演。这个带保留的宽度我这里用的是0.01/dx属于经验值如果你只关心深部中高频反射可以把带设得更窄。3.2 非扇形陷波处理已知速度的规则干扰有时候干扰波不是扇形铺满而是事先知道它是某个固定视速度的声波比如空气中传播的声波在地震记录上表现为直线同相轴这时我倾向于做窄带陷波而不是整个扇形切除。做法是构造一个带阻掩膜把落在v≈v_noise附近的窄带区域置零同时保留其余区域。具体操作计算v_fk F ./ K的矩阵注意K0的置大值然后设定一个速度带宽v_tol比如噪声速度是340 m/s带宽设为±30 m/s把|V - 340| 30的点置零。同样建议加高斯过渡。这种做法比扇形切除更精细副作用也更小。但要注意如果干扰波速度随时间变化比如地形起伏导致视速度变化这种固定速度陷波就不太行了应回到扇形切除路线或用自适应方法。3.3 空间抽稀问题不充分空间采样该怎么办无论如何有一点必须在matlab代码里主动检查空间方向的Nyquist波数。空间采样率dx决定了最大不混叠波数k_Nyquist 1 / (2 * dx)如果某频率f下存在波数绝对值大于k_Nyquist的成分那这部分就是空间假频。假频在f-k谱上表现很具迷惑性它不会出现在正确的速度射线位置而是由于采样不够被“折叠”到低波数区域也就是看起来像是低速度能量。这与时间域的频率混叠是同一个道理。如果你用滤波直接切掉假频区会丢失真实信息如果不切它又会污染有效信号。最彻底的办法是空间重采样或道距加密采集但数据已经到手了所以现实做法是如果假频不严重且目标频段不在假频区可以考虑直接用带通滤波把假频频段的能量一并压制如果假频严重那常规FK滤波解决不了要改用f-k反假频插值比如基于抗泄露的迭代插值但那是另一个话题这里不展开。4. 一个从数据构建到滤波的完整案例为了让你直观看到整个过程我构造一个合成的二维地震记录包含一条水平反射同相轴和一组线性面波干扰。这样你可以自己跑一遍看看f-k谱长什么样滤波前后变化多明显。% 参数 dt 0.002; dx 5; nt 512; nx 64; t (0:nt-1)*dt; x (0:nx-1)*dx; % 构建水平反射时间方向子波 空间方向水平展布 w ricker(30, dt, 25); % 自己实现的Ricker子波峰值频率25Hz ref zeros(nt, nx); t_ref 0.25; % 反射波到达时刻 i_ref round(t_ref/dt); ref(i_ref:i_reflength(w)-1, :) repmat(w(:), 1, nx); % 构建线性面波斜率对应速度500 m/s slope 1/500; % 每米延迟秒数 noise zeros(nt, nx); for ix 1:nx t_noise 0.05 x(ix) * slope; % 道间延迟 i_noise round(t_noise/dt) 1; if i_noise length(w) - 1 nt noise(i_noise:i_noiselength(w)-1, ix) 0.8 * w(:); end end % 混合 data ref noise;这里我用了自定义的ricker子波你可以写一个简单函数function w ricker(fdom, dt, T) t -T/2 : dt : T/2; w (1 - 2*pi^2*fdom^2*t.^2) .* exp(-pi^2*fdom^2*t.^2); w w / max(w); end接下来就是显式地进行FK变换、滤波、反变换。把这套流程跑下来你会在f-k谱上清楚地看到反射波能量贴f轴且一般在较低频率面波能量沿600 m/s速度射线分布是一个V形或窄带区域。设计mask时保留|V|800 m/s的成分面波被有效压制反射波基本保留。这个案例虽然合成数据很干净但跑通它以后换成真实Segy数据无非就是多一步读数据、多一步道编辑。逻辑和代码大部分可以复用。5. 常见问题与排查技巧实录FK变换本身不复杂但实际用起来几乎每个环节都有坑。这里把我在matlab里踩过的典型问题整理成一张速查表再单独挑几个细说。现象常见原因首选检查项f-k谱显示四角亮、中心暗没做fftshift低频分布在角落检查是否对fft2输出做了fftshift滤波后时间域出现横纹/拖尾掩膜边界太陡吉布斯效应使用imgaussfilt或斜坡过渡反变换后信号幅度整体变小滤波器把有效成分也切了一部分重新审视vmin和k_zero_band参数面波滤除不干净掩膜速度边界偏低或空间方向分辨率不足查看f-k谱里干扰波的边界再做调整反变换结果出现负值放大频域中保留了直流/零频附近异常值检查零频分量的处理适当做直流压制数据非等间距采样导致的全谱混乱未做数据规则化直接FFT先用插值法将道间距规整到等间距滤波器对复杂地形数据失效视速度随偏移距变化明显改用分频段分偏移距区处理局部FK细说三个高频问题。第一个就是吉布斯效应。很多新手觉得掩膜是逻辑判断直接maskzeros/ones然后一顿切就完事了。这样做在f-k谱上确实能看到干扰波被切掉了但时间域里全是振铃。我建议无论如何都要加一点过渡带哪怕只有几个像元的平滑。如果用imgaussfilt比如σ取1.52个网格对于道间距5米的勘探数据实测下来既保住了主频能量拖尾也明显减少。如果你想要更精确控制也可以自己做斜坡在掩膜边界附近定义一个过渡带宽Δv用线性或余弦过渡把0和1连接起来。第二个容易忽略的是f-k谱中的直流分量。matlab的fft2会把零频和零波数处的绝对值放到11位置如果你在显示时没处理好可能看到一片巨大的亮斑。滤波时如果对零频附近做硬置零反变换出来信号整体均值会偏移造成每道出现常数偏差。我的习惯是如果不需要研究低频背景保持零频附近一个很小的矩形区域不变而不是置零。第三个高频问题真实数据往往不是纯二维均匀采样比如弯线采集、变观测系统它们的道间距不规则。直接塞进fft2会引入人为的采样不均匀噪声。我处理这种数据的做法是先用matlab自带的scatteredInterpolant插值到均匀网格上再做FK变换。但要注意插值会改变波场的频率成分最好是先做带限插值插值后做FK变换只用于分析不在这个域直接做滤波而是把滤波设计信息拿回时间域应用。再说一个经验性技巧f-k谱的线性干扰边界经常不是一条干净直线因为振幅随频率有衰减谱上能量看起来是“一头粗一头细”的形状。这时不要只用一个vmin去切我常用两段式滤波先做f-k扇形初滤把强能量去掉然后对剩余数据做一次自适应噪声压制比如在时间域做预测反卷积效果往往比单靠FK一步到位好。原因在于FK滤波是全局算子无法很好处理时空变化的噪声背景而组合策略可以弥补这个盲区。另一个实战提示在做FK滤波前不要忘记先对数据做常规预处理比如去均值、去线性趋势、带通滤波。否则低频漂移会严重影响f-k谱的显示比例真实反射波能量在谱图里会被“淹没”你根本看不清有效的速度区间。这个过程我每次都会做算是固定前置流程。6. 参数敏感性分析与个人调试心得回到文章开头的那句话FK变换的关键在于f-k谱上能量团的位置和边界。所以调试流程我一般这样走先显示原始数据的f-k谱把坐标轴物理单位标好标注干扰波边界。选一个保守的vmin先做一次滤波对比时间域的残差原数据减滤波数据看残差里是否还有明显相干能量。逐步调整vmin和过渡带宽度直到残差里大部分是非相干的随机噪声而有效波的同相轴连续不破碎。如果同相轴出现“搓板状”振幅抖动多半是滤波器过渡带过宽或者vmin太接近有效波速度下限。这时要回看f-k谱重新确定两者的分离点。关于vmin的具体取值经验上我习惯取有效波最小视速度的0.70.9倍。为什么不是直接取有效波速度因为f-k谱里速度是一个斜线能量分布有一定宽度如果直接卡在有效波边界附近滤波器会切掉一部分有效波的低频或高频边缘。留出余量配合过渡带的平滑能大大减小损伤。这个系数看起来不起眼但值得专门记录。另外我强烈建议把参数值固定为脚本开头的变量不要散落在代码里乱改。因为滤波参数往往要做敏感性测试场景比如vmin1200/1500/2000用变量名定义好改起来安全很多。我早期经常在mask代码里直接写数字后来一个数字填错整个结果就废了排查半天才发现是滤波器边界变量被覆盖了。再补充一个道上平均法trace averaging和f-k域做互补的小技巧如果面波速度不太低可以先在时间域做相邻道相减相当于空间高通滤波把低速的水平相关噪声压掉剩余数据再做f-k域低切这种组合能大幅提升高速度弱信号的可见度。类似思路可以衍生出很多变体核心原则是在处理流程中把线性算子和非线性算子比如中值滤波搭配起来往往能比单一域处理更稳健。还有就是如果数据量很大比如上千道、上万时间采样点fft2本身并不慢但显示f-k谱的大矩阵会占很多内存。我一般先decimate或者分频段处理把数据降到可交互的规模设计好滤波参数后再对原始数据整体执行一次滤波。注意分频段处理时要保证各频段滤波器过渡带连续否则整体反变换后可能出现频段接缝处的不自然起伏。最后再分享一次真实数据调试的体会。当时的数据里面波速度大概在400600 m/s反射波有效速度在2000 m/s以上两者在f-k谱上离得很开按理说非常好切。但实际滤波后反射波同相轴出现了明显的横向振幅波动检查发现是道间存在振幅不一致导致f-k滤波后横向道间差异被放大。解决方法是滤波前先做一道振幅均衡AGC或道间能量归一化处理后再恢复原始振幅关系。这个坑不在FK变换本身却在工程链路里非常现实。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价