MATLAB 脚本,包含:
- 合成地震数据(层状模型 + Ricker 子波)
- 合成一口井的声阻抗曲线
- 设计颜色算子(频域谱比 + −90° 相位)
- 逐道卷积得到拟阻抗剖面
- 质量控制和可视化对比
1. 主脚本:colored_inversion_demo.m
matlab
%% 颜色反演(Colored Inversion)演示 --- MATLAB 实现
% 作者:教学示例
% 功能:从叠后地震数据快速估算相对波阻抗
clc; clear; close all;
%% ==================== 1. 生成合成数据 ====================
% 1.1 时间轴
dt = 0.002; % 采样间隔 2ms
nt = 512; % 时间采样点数
t = (0:nt-1)' * dt; % 时间向量 (s)
% 1.2 地下模型:三层介质,声阻抗(真实值,用于验证)
nx = 64; % 道数
x = (1:nx) * 10; % 道间距10m
% 声阻抗随深度变化(假设横向均一,但有轻微横向变化)
v0 = 2000; rho0 = 2.0;
z0 = v0 * rho0; % 上层阻抗
v1 = 2400; rho1 = 2.2; z1 = v1 * rho1; % 中层阻抗
v2 = 2200; rho2 = 2.1; z2 = v2 * rho2; % 下层阻抗
% 构造声阻抗体 (nt × nx)
AI_true = zeros(nt, nx);
for ix = 1:nx
% 两个界面:0.2s 和 0.5s,加上横向缓变
t1 = 0.2 + 0.02 * sin(ix/nx*2*pi);
t2 = 0.5 + 0.03 * cos(ix/nx*2*pi);
AI_true(:,ix) = z0 + (z1-z0)*(t >= t1) + (z2-z1)*(t >= t2);
% 加入轻微随机扰动模拟横向非均质性
AI_true(:,ix) = AI_true(:,ix) + 0.02*z0*randn(nt,1);
end
% 1.3 反射系数序列
RC = zeros(nt, nx);
for ix = 1:nx
% 反射系数 r = (Z_{i+1}-Z_i)/(Z_{i+1}+Z_i) 近似
RC(1:end-1, ix) = diff(AI_true(:,ix)) ./ (AI_true(1:end-1,ix)+AI_true(2:end,ix));
end
% 1.4 Ricker 子波(主频 30 Hz)
fm = 30; % 主频 (Hz)
tw = (-0.04:dt:0.04)'; % 子波时窗
w = (1 - 2*(pi*fm*tw).^2) .* exp(-(pi*fm*tw).^2);
w = w / max(abs(w)); % 归一化
% 1.5 合成地震记录(褶积)
seis = zeros(nt, nx);
for ix = 1:nx
seis(:,ix) = conv(RC(:,ix), w, 'same');
end
% 加入少量噪声
seis = seis + 0.01 * randn(size(seis));
% 1.6 选择一口井(例如第32道)
iw = 32;
seis_well = seis(:, iw);
AI_well = AI_true(:, iw);
%% ==================== 2. 设计颜色算子 ====================
fprintf('>>> 设计颜色算子...\n');
% 2.1 频域谱比
N = nt; % FFT点数
f = (-N/2:N/2-1)' / (N*dt); % 频率轴 (Hz)
% 地震道振幅谱
Sf = fftshift(fft(seis_well));
AS = abs(Sf);
% 井阻抗振幅谱
Zf = fftshift(fft(AI_well));
AZ = abs(Zf);
% 有效频带(5~80 Hz)
fmin = 5; fmax = 80;
fmask = (abs(f) >= fmin) & (abs(f) <= fmax);
% 谱比:|O(f)| = |Z(f)| / |S(f)| (仅在有效频带内)
eps_reg = 1e-6 * max(AS); % 正则化防除零
O_amp = zeros(N,1);
O_amp(fmask) = AZ(fmask) ./ (AS(fmask) + eps_reg);
% 在频带边界做余弦渐变(taper)避免截断效应
bw = 5; % 过渡带宽 (Hz)
taper = ones(N,1);
for edge = [fmin, fmax]
idx = find(abs(f-edge) < bw);
if ~isempty(idx)
taper(idx) = 0.5*(1+cos(pi*(abs(f(idx))-edge)/bw));
end
end
O_amp = O_amp .* taper;
% 2.2 施加 -90° 相位(积分算子)
phase = zeros(N,1);
phase(f > 0) = -pi/2; % 正频率 -90°
phase(f < 0) = pi/2; % 负频率 +90°(保证实信号)
phase(f == 0) = 0;
O_complex = O_amp .* exp(1j * phase);
% 2.3 逆FFT得到时域算子
op_full = real(ifft(ifftshift(O_complex)));
% 居中截取短算子(通常有效长度 ~100ms)
center = round(N/2);
half_len = 50; % 截取 ±50个样点(±0.1s)
op_short = op_full(center-half_len : center+half_len);
% 应用汉宁窗平滑算子两端(减少边缘振荡)
win = hann(length(op_short));
op_short = op_short .* win;
% 归一化(保持输出量级合理)
op_short = op_short / max(abs(op_short));
fprintf(' 算子长度: %d samples (%.3f s)\n', length(op_short), length(op_short)*dt);
%% ==================== 3. 应用颜色反演 ====================
fprintf('>>> 逐道卷积应用颜色算子...\n');
AI_est = zeros(nt, nx);
for ix = 1:nx
AI_est(:,ix) = conv(seis(:,ix), op_short, 'same');
end
% 对结果做最小-最大归一化到与真实阻抗相近的范围(方便对比)
% 注:颜色反演输出是相对阻抗,需要标定到绝对刻度
% 这里用井旁道做线性回归标定
coeff = polyfit(AI_est(:,iw), AI_well, 1);
AI_est_scaled = coeff(1) * AI_est + coeff(2);
%% ==================== 4. 结果可视化 ====================
figure('Position', [100 100 1400 800]);
% 4.1 地震剖面
subplot(2,4,1);
imagesc(x, t, seis); axis ij; colormap(gray);
xlabel('道号'); ylabel('时间 (s)'); title('叠后地震剖面');
colorbar; clim([-1 1]*max(abs(seis(:))));
% 4.2 颜色算子
subplot(2,4,2);
plot(op_short, (0:length(op_short)-1)*dt, 'b', 'LineWidth',1.5);
set(gca, 'YDir', 'reverse'); xlabel('振幅'); ylabel('时间 (s)');
title('颜色算子 o(t)'); grid on;
% 4.3 井旁道对比:地震、真实AI、估计AI
subplot(2,4,3);
plot(seis_well, t, 'k', 'LineWidth',1); hold on;
plot(AI_well/max(AI_well), t, 'r', 'LineWidth',1.5);
plot(AI_est_scaled(:,iw)/max(AI_est_scaled(:,iw)), t, 'b--', 'LineWidth',1.5);
set(gca, 'YDir', 'reverse');
xlabel('归一化振幅'); ylabel('时间 (s)');
legend('地震道','真实AI (归一化)','估计AI (归一化)','Location','southwest');
title('井旁道对比'); grid on;
% 4.4 估计AI剖面
subplot(2,4,4);
imagesc(x, t, AI_est_scaled); axis ij; colormap(jet);
xlabel('道号'); ylabel('时间 (s)'); title('颜色反演估计的拟阻抗');
colorbar;
% 4.5 真实AI剖面
subplot(2,4,5);
imagesc(x, t, AI_true); axis ij; colormap(jet);
xlabel('道号'); ylabel('时间 (s)'); title('真实声阻抗');
colorbar;
% 4.6 误差剖面
subplot(2,4,6);
imagesc(x, t, AI_est_scaled - AI_true); axis ij; colormap(redblue);
xlabel('道号'); ylabel('时间 (s)'); title('估计误差');
colorbar; clim([-1 1]*max(abs(AI_est_scaled(:)-AI_true(:))));
% 4.7 井轨迹处的阻抗曲线对比
subplot(2,4,[7 8]);
plot(AI_well, t, 'r', 'LineWidth',2); hold on;
plot(AI_est_scaled(:,iw), t, 'b--', 'LineWidth',2);
set(gca, 'YDir', 'reverse');
xlabel('声阻抗 (m/s*g/cm³)'); ylabel('时间 (s)');
legend('真实AI','颜色反演AI','Location','southwest');
title(sprintf('井旁道定量对比 (相关系数 r=%.3f)', ...
corr(AI_well, AI_est_scaled(:,iw))));
grid on;
sgtitle('颜色反演 (Colored Inversion) 演示');
%% ==================== 5. 质量控制 ====================
fprintf('\n========== 质量控制 ==========\n');
fprintf('井旁道相关系数: %.3f\n', corr(AI_well, AI_est_scaled(:,iw)));
fprintf('RMS误差: %.2f\n', sqrt(mean((AI_well - AI_est_scaled(:,iw)).^2)));
% 显示算子频谱
figure;
subplot(1,2,1);
plot(f, AS, 'k', 'LineWidth',1); hold on;
plot(f, AZ, 'r', 'LineWidth',1);
plot(f, O_amp*max(AS), 'b--', 'LineWidth',1.5);
xlim([0 100]); xlabel('频率 (Hz)'); ylabel('振幅');
legend('地震谱','阻抗谱','算子谱(缩放)','Location','northeast');
title('频谱对比'); grid on;
subplot(1,2,2);
plot(f, angle(O_complex)*180/pi, 'g', 'LineWidth',1.5);
xlim([0 100]); xlabel('频率 (Hz)'); ylabel('相位 (度)');
title('算子相位(期望 −90°)'); grid on;
ylim([-180 180]);
2. 运行结果解读
执行上述脚本后,你会看到:
- 合成地震剖面(灰色):两个反射同相轴对应两个界面。
- 颜色算子波形:约 100ms 长的短算子。
- 井旁道对比:红色为真实阻抗(归一化),蓝色虚线为颜色反演估计的拟阻抗,黑色为原始地震道。可见估计结果与真实阻抗趋势高度一致,但缺失低频背景(相对值)。
- 估计AI剖面:颜色反演输出的拟阻抗,清晰地显示了两个层的阻抗变化。
- 误差剖面:显示估计值与真实值的差异,主要在边界处有轻微震荡(Gibbs现象)。
- 频谱图:展示了地震谱、阻抗谱和算子谱的关系;算子相位在有效频带内约为 −90°。
参考代码 地震数据反演中的颜色反演方法 www.youwenfan.com/contentcsv/81492.html
3. 关键要点说明
| 步骤 | 说明 |
|---|---|
| 谱比设计 | 用井旁地震道振幅谱除井阻抗振幅谱,得到算子振幅谱。需限制在有效频带内,并做平滑/taper防止噪声放大。 |
| −90°相位 | 将反射系数转换为阻抗的积分操作。如果地震数据本身不是零相位,需先做相位校正。 |
| 算子截断 | 频域设计的算子理论上无限长,实际截取短时窗(约100ms)并加窗,以减少计算量且保持精度。 |
| 标定 | 颜色反演输出是相对阻抗,需要通过井旁道线性回归(或均值/方差匹配)转换到绝对刻度。本例中使用了一次多项式拟合。 |
| 适用范围 | 适用于叠后地震数据、零相位或已知相位校正后的剖面。对于复杂构造或强非平稳数据,可能需要分时窗设计多个算子。 |
4. 扩展:处理真实SEGY数据
若你有实际地震数据(SEGY格式)和井曲线,可按以下步骤替换合成数据部分:
matlab
% 读取SEGY(需SEGYMAT工具箱或自行实现)
[seis, headers] = read_segy('input.sgy');
dt = headers.dt / 1e6; % 采样间隔 (s)
nt = size(seis,1);
nx = size(seis,2);
t = (0:nt-1)' * dt;
% 读取井曲线(LAS格式或ASCII)
ai_log = load('well_ai.txt'); % 两列:时间(s), 阻抗
ai_well_interp = interp1(ai_log(:,1), ai_log(:,2), t, 'linear', 'extrap');
% 提取井旁道(根据CDP坐标匹配)
iw = find_nearest_cdp(headers, well_cdp);
seis_well = seis(:, iw);
之后的设计和应用流程完全相同。
5. 常见问题及解决
| 问题 | 可能原因 | 解决方法 |
|---|---|---|
| 输出拟阻抗与真实阻抗极性相反 | 相位处理错误(+90°而非−90°) | 检查算子相位,确认正频率相位为 −π/2 |
| 输出噪声很大 | 谱比在有效频带外放大了噪声 | 缩小 fmin/fmax 范围,加大正则化 eps_reg |
| 输出缺乏低频趋势 | 颜色反演本质是带限的 | 需后续拼接低频模型(井插值或速度模型) |
| 井旁道匹配不佳 | 地震相位不准确或子波非零相位 | 先做零相位化处理,或使用井震标定校正相位 |