SG2格式解析:SEG-D地震数据解码与Python实践
发布时间:2026/9/16 19:22:52 作者:尧图编辑部 阅读量:1,286

简介一个专注地震数据格式转换的MATLAB工具包用来解决SG2二进制格式与DAT文本格式之间的数据互通问题面向地震行业从业者、科研人员以及高校相关专业学生。压缩包内仅含1个m源文件segdat.m整体大小约1KB结构精简便于直接查阅、运行和二次修改。SG2格式通常由地震传感器或数据采集系统生成适合高密度时间序列的实时存储DAT格式则以ASCII文本保存整理后的波形和参数可读性强便于在多种软件中交换。代码按“解析SG2结构—提取时间序列与元数据—完成数值到文本转换—写入DAT文件”的流程组织涵盖采样率、通道信息、时间戳以及振幅、震级等关键字段的处理可帮助读者理解二进制文件解析和文本输出的完整思路。目前已有607人学习下载适合需要批量转换地震记录、搭建数据处理流程或通过实际代码学习地震数据格式转换逻辑的入门及进阶用户。1. 为什么地震道数据要绕着 SG2 打转做地面地震采集的人拿到野外队交上来的数据最常见的不是漂亮的剖面图而是几个 G 的 .dat 文件和一叠说明不清的格式文档。segdat 这个名字在物探数据处理圈子里几乎成了「SEG-D 数据现场预处理」的代名词而 SG2 则是 SEG-D 标准里一个绕不开的子格式标识。简单说SEG-D 是地震数据记录的国际通用磁带格式SG2 是其中按时序组织地震道的一种记录类型文件里每道除了采样值还带着道头、坐标、时间标签。搞清楚 SG2 格式才能真正读懂仪器吐出来的 .dat 文件才能用 Python、C 或者现成工具做后续的解编、动校正和叠加。这篇文章写给两类人一类是刚接手野外地数据、被字节序和道头字逼疯的物探工程师另一类是给物探项目做数据管道的 IT 人。你不需要 SEG-D 全标准在手按下面几章走一遍,基本能应付八成以上的现场数据。2. SG2 在 SEG-D 格式里的定位先分清卷、文件和道SG2 不是一个完全独立的格式它依附在 SEG-D 标准框架下。野外仪器采集完地震数据输出的 .dat 文件里有三类东西卷头卷标签、文件头文件标签和数据道。SG2 标识的数据道是核心它们才是你最终要用来做处理的波形数据。很多人把 SEG-D 和 SG2 混为一谈实际上 SG2 是 SEG-D 记录格式中的一个数据格式代码表示这一卷数据的道结构、时序方式和采样字长已经按标准写死。换言之见到 SG2 标识你至少能确定数据按道组织、每道有固定道头、采样值紧随其后且大概率使用 32 位浮点或 16 位整型存储。2.1 卷头、文件头与道头三个结构体的字节偏移关系野外仪器写文件时卷头在文件最前面长度通常 3200 字节之后是文件头SEG-D 标准里也叫文件标签长度可变。再往后才是一道接一道的数据道。每道数据道都以 32 字节的道头开始道头里存道号、采样点数、坐标信息等道头之后才是采样数据。因为文件头可能因厂商扩展而变化解析 SG2 时最稳妥的路径是先读卷头拿到文件头偏移量再读文件头拿到首道偏移量然后按道头长度加数据长度循环前进直到文件尾。import struct def find_first_trace_offset(file_path: str) - int: with open(file_path, rb) as f: # SEG-D 卷头占前 3200 字节其中第 25 字节对应卷头所在块大小 # 这里按多数厂商实现卷头按 256 字节为一个块block f.seek(0) volume_header f.read(3200) general_block_size volume_header[24] # 多个实现中此位置描述块大小 if general_block_size 0: general_block_size 256 # 文件头偏移量 卷头字节数 卷头总块数 * 每块字节数 # SEG-D rev1 常见写法卷头紧跟文件头 file_header_offset 3200 f.seek(file_header_offset) file_header f.read(1600) # 文件头里记录第一道道头的位置通常以字节为单位 trace_pointer_offset struct.unpack(I, file_header[48:52])[0] if trace_pointer_offset 0: trace_pointer_offset 3200 1600 return trace_pointer_offset # 这个函数只做一件事找到第一道数据的起点 # 参数 file_path 指向 .dat 文件返回值为第一道偏移量字节这段代码先把卷头读到内存再从固定偏移读文件头最后取出首道偏移。segdat 这类工具在快速质检时也是同样的逻辑只是它把偏移计算藏在了 GUI 后面。字节序采用大端是 SEG-D 标准规定的但厂商实现经常无视这一点所以碰到解析出来的道数荒谬的时候先把改成再试一次这是最经济的一步调试。2.2 SG2 记录的时序特征固定采样间隔与多道交织SG2 标识的另一个关键含义是时序组织方式每一道内部是一个连续的时间序列采样间隔在整个文件内全局一致。多道数据在物理文件里按道号顺序排列第一道的所有采样点写完才写第二道。这与 SEG-Y 的写法一样但和某些连续记录格式CFS、CSP按时间切片存储的机制截然不同。所以解析 SG2 时随机访问某一道数据非常容易首道偏移 道序号 x (道头长度 采样点数 x 采样字长)时间复杂度 O(1)不需要从头到尾扫描。下表列出了 SG2 文件里最常用的几个字段及其在道头中的典型偏移方便手动排错时直接对照。字段含义常见偏移字节长度说明扫描类型号02标识道属性如地震道、时间道道号202当前道序号用于道编辑时追踪采样点数242每道采样样本数解码时算数据长度用采样间隔262单位微秒注意有些厂商存的是 1/16 微秒坐标 X284炮点或检波点坐标端到端校验时用采样格式3221 代表 16 位整型2 代表 32 位浮点道头各字段偏移在不同版本 SEG-D 标准rev0、rev1、rev2里略有差异但采样点数和采样格式的位置相对稳定。真正确认厂商实现的唯一办法是打开第一道道头看一眼字节值是否符合你预期的范围。采样点数一般几百到几千格式代码就在 1 和 2 之间。超出这个范围基本可以断定偏移没对准或者字节序反了。3. 用 Python 手工解码 SG2从字节流到可绘图地震道原理只能帮你找到偏移量真正动手时还得靠代码把数据变成能看到的波形。这一章给出一个最小可用的 SG2 解码流程读取道头、解析采样值、组装成 numpy 数组、把数据写进 SEG-Y 或者直接画图。为减少依赖全程只用标准库和 numpy这样可以放在任何一台没有图形界面的服务器上跑。3.1 道循环根据首道偏移和道长度迭代读取解码 SG2 其实就三个动作循环读道头、算采样长度、跳转到下一道。先把文件指针定位到首道偏移然后进入 for 循环每轮读 32 字节道头解出采样点数和采样格式再读采样数据并解释为数值数组。segdat 在批量转储时核心逻辑也是这套只是它还加入了坐标重排和噪声统计。import numpy as np import struct def decode_sg2(file_path: str, trace_offset: int, num_traces: int): traces [] with open(file_path, rb) as f: for tr in range(num_traces): f.seek(trace_offset) trace_header f.read(32) ns struct.unpack(H, trace_header[24:26])[0] # 采样点数 fmt struct.unpack(H, trace_header[32:34])[0] # 采样格式 if ns 0 or ns 100000: break # 防御性检查越界立即停止 if fmt 1: arr np.frombuffer(f.read(ns*2), dtypei2) elif fmt 2: arr np.frombuffer(f.read(ns*4), dtypef4) else: break traces.append(arr.copy()) # 下一道偏移 当前道偏移 32 字节道头 数据字节数 trace_offset f.tell() return traces # 返回一个列表每个元素是一道完整的采样值数组 # 调用前先确定 num_traces 上限避免野值导致死循环注意代码里的f.tell()是获取当前文件指针位置天然等于下一道起始偏移不需要手动计算数据字节数。这里默认道头没有扩展区如果厂商在道头后加了扩展道头Extended Header要在下一次 seek 时补上扩展偏移否则每道数据都会错位。碰到这种情况解码结果会出现「所有道看起来都一样」的规律性错误因为指针串到了采样值中间误把别处的字节当成了道头。3.2 参数调优采样格式误判时如何自动兜底实际文件里采样格式字段有时会被厂商写成 0 或 3不按 SEG-D 标准来。segdat 的做法是提供一个「自动探测」开关先按 16 位整型解码算一遍数据的均方根振幅再按 32 位浮点解码比较物理范围。地震道的真实振幅一般在几十到几万微米/秒之间如果解码出来的数值动辄 1e9几乎可以断定格式选错了。def auto_detect_format(file_path: str, trace_offset: int): with open(file_path, rb) as f: f.seek(trace_offset 32) # 读 2000 字节数据做判断 raw_data f.read(2000) int_vals np.frombuffer(raw_data[:len(raw_data)//2*2], dtypei2) float_vals np.frombuffer(raw_data[:len(raw_data)//4*4], dtypef4) if np.max(np.abs(float_vals)) 1e6: return 2 if np.max(np.abs(int_vals)) 32767: return 1 return 2 # 默认优先按浮点处理避免大值截断 # 自动探测原理浮点解释得到的量级更符合地震信号范围 # 若数据本身是整型强解释为浮点会得到极小的大众值振幅远超物理限这个探测函数只取文件开头的一段数据速度快但可能受第一道噪声影响。稳妥做法是取文件中部三道数据分别判断投票决定采样格式。投票逻辑在批处理场景里很有用因为一个 SEG-D 卷内的道通常格式统一但不同卷之间可能不同。4. 实战质检SG2 文件里的数据可信度检查与常见坑解析出波形只是第一步接下来要做的是判断这堆数据能不能进入后续处理流。SG2 文件常出现的三个问题文件截断、道头坐标错位、极性反转。坐标错位往往意味着解释人员拿到的炮检距是错的直接影响速度分析极性反转则会导致叠加时信号抵消。4.1 基于 SG2 道头关键字的完整性校验解完所有道之后做一次完整性校验比对文件大小与按道头计算的期望大小是否一致检查道号列是否连续检查采样点数是否恒定。现场采集时有的仪器会在一炮结束后写一条 0 振幅的道做标记这种道在显示时就该剔除。python -c import struct, sys # 命令行快速检查计算期望文件大小与实际大小差 # 用法python check_sg2.py 观测文件.dat 3200 1600 32 fname, vol_len, fh_len, th_len sys.argv[1], int(sys.argv[2]), int(sys.argv[3]), int(sys.argv[4]) import os actual os.path.getsize(fname) with open(fname,rb) as f: f.seek(vol_len fh_len) h f.read(32) ns struct.unpack(H, h[24:26])[0] fmt struct.unpack(H, h[32:34])[0] bytes_per_sample 2 if fmt 1 else 4 expected vol_len fh_len ns * bytes_per_sample print(单道大小:, expected, 文件大小:, actual, 误差:, actual - expected) 单道大小计算出来之后用「文件大小 ÷ 单道期望大小」得到的整数就是这道文件应有的总道数。如果相除结果不是整数说明文件截断或道数统计错误这时再回到 §2.2 核对采样点数读取是否有问题。这个命令在没有完整解析脚本的应急场景下特别管用配合dd和hexdump就能定位损坏位置。4.2 字节序、坐标单位与静校正三个需要警惕的厂商习惯厂商实现 SEG-D 最常见的「非标」操作有三个。第一是字节序标准规定大端但有一批国产仪器按小端写。第二是坐标单位标准规定是米但有些系统输出的是度经纬度导致后续 CMP 道集分选时坐标跨度异常。第三是记录延迟record delay即触发时刻和实际记录起点之间的时间差处理时要统一减掉才能让初至对齐。这三个问题单靠格式文档没法确认需要用已知炮点位置的数据反推验证。5. 把 SG2 转成更适合后续处理的格式SEG-Y 与内存映射提速处理中心通常希望数据以 SEG-Y 格式落地因为主流商业软件对 SEG-Y 的适配成本最低。将 SG2 转为 SEG-Y 的实质就是重新组装道头把采样值原样拷贝再按 SEG-Y 规范写文件。工程上有一个更快的做法不需要等到转完 SEG-Y 才看数据直接用 numpy 的np.memmap对原始 .dat 文件做只读映射按道头偏移切片即可完成随机访问处理速度远高于逐道读取文件。import numpy as np def sg2_memmap_decoder(file_path: str, first_trace: int, ns: int, fmt: int): # 建立整个文件的内存映射不会把大文件完整载入 RAM # 按大端解释采样点数为 ns采样格式为 int16 或 float32 dtype i2 if fmt 1 else f4 mmap np.memmap(file_path, dtypenp.uint8, moder) dt np.dtype(dtype) byte_len ns * dt.itemsize # first_trace 是首道偏移实际生产中常用 3328即 3200128 简化场景 data_start first_trace 32 # 跳过道头 n_traces (mmap.size - data_start) // byte_len # reshape 成 (道数, 采样点数) 的二维数组方便后续按道检索 sg2_array np.ndarray(shape(n_traces, ns), dtypedt, buffermmap, offsetdata_start) return sg2_array # 返回一个二维数组sg2_array[i] 就是第 i 道的全部分采样值 # 内存映射模式下访问任意一道只读相应页不触发全盘 I/O5.1memmap方式下处理大数据集的两个限制内存映射也不是万能的两个限制要提前说。第一个是文件系统的页缓存压力频繁随机访问整个文件会导致内存页换入换出反而比顺序读慢。应对方法是预处理阶段只做一遍顺序读把采样值或抽稀后的特征写入二进制缓存第二个限制是字节序不匹配的机器上如果不使用i2这类显式大端 dtype解释出来的数据会前后颠倒做 FFT 检查时会看到镜像频率。5.2 转换之后的交叉验证用已知正弦信号复核采样格式转完 SEG-Y 后最怕的是格式对了、数据反了。可以构造一个简单验证在原 .dat 文件里找一道已知初至比较陡的地震道画出波形后检查初至方向向上还是向下再和仪器手册里的极性定义对照。若方向反了在转 SEG-Y 的道头里调整极性标志位通常是一个 2 字节的极性字段置 1 或 2具体值视处理软件而定。现场操作中竖井微测井数据是最理想的验证样本因为到达时初至方向唯一且容易判断。本文还有配套的精品资源点击获取