首页/新闻资讯/正文详情

用seisplotjs在浏览器中实现地震数据解析与波形可视化

发布时间:2026/9/26 5:02:04 来源:云帆数科 栏目:资讯中心
用seisplotjs在浏览器中实现地震数据解析与波形可视化
简介seisplotjs是一套面向地震数据解析、处理与可视化的JavaScript模块适合地震科研人员、地球物理方向开发者以及前端工程师学习参考。它围绕FDSN Web服务封装了事件查询、台站信息、波形数据获取与绘图等能力并内置FFT变换、日期时间选择、经纬度距离计算和数据链路协议等子模块能够在浏览器端完成从数据请求到图形渲染的完整流程。资源包共184个文件约1.02MB以JavaScript源码、HTML示例页和CSS样式为主同时包含SAC、MSEED等地震数据样例以及若干Python、JSON和配置文件便于对照教程运行和二次开发。目前已有319人学习/下载。资源内附多种访问与显示类型的示例可帮助读者快速掌握各模块的调用方式、波形处理流程及地震数据格式有效节省环境搭建与接口调试时间整体结构清晰适合按需查阅。1. seisplotjs把地震数据解析、绘制与交互全部搬到浏览器做地震数据前端展示的第一年我一直在想一个问题为什么看个波形非得后端用Python解析MiniSEED再转JSONseisplotjs这个JavaScript模块直接改变了这个局面——它把地震数据的解析、处理和绘制全部搬进浏览器掉进页面上一个script标签就能干活。它由IRIS开源维护支持MiniSEED、QuakeML、StationXML的解析能直接Fetch FDSN服务也能渲染可交互的seismogram。适合台网运维、科研可视化和教学演示不需要再架设专门的解析后端。如果你只是偶尔画一张静态波形图用ObsPy在服务端处理也不差但如果要做实时监控、交互缩放、前端深度集成seisplotjs是现在主流的选型。这篇笔记按解析→绘制→数据获取→排坑的顺序把这条路走一遍。2. JavaScript里的地震数据解析从MiniSEED二进制到可用的Seismograph2.1 为什么说MiniSEED是个二进制黑匣子MiniSEED是地震观测数据最主流的存储格式由一组固定长度的头512字节和紧跟着的数据块组成。头里编码着台网代码、台站代码、通道代码、起始时间、采样率、数据格式版本这些关键元数据实际波形数据则用Steim压缩编码存放。Steim1和Steim2的压缩方式相当不直观它把32位字拆成多种编码模式有些模式直接存原始采样值有些存差值有些还要跨字拼接。这意味着从零写解析器至少要在位操作上磨掉一晚上而且出错很难发现——解析出来的波形往往是看起来有点不对但说不出哪里不对。我并不是说seisplotjs是唯一的前端解析方案。你同样可以在服务端用ObsPy解析完再吐JSON或者用WebAssembly包装C库libmseed。但前者多一层网络转发和格式转换后者要维护编译链。seisplotjs直接在浏览器里运行输入是ArrayBuffer输出是结构化的Seismograph对象集合中间不经过任何文本转换。对做前端可视化的人来说这是最省心的一条路也是我最初选它的原因。2.2 parseMiniSeed一段代码完成解析seisplotjs里解析MiniSEED的核心入口是seisplotjs.miniseed.parseMiniSeed。它接收ArrayBuffer或Uint8Array返回一个SeisData对象。下面这段代码演示了从fetch拿到二进制流到完成解析的全过程import * as seisplotjs from seisplotjs; async function loadMiniSeed(url) { const response await fetch(url); if (!response.ok) { throw new Error(HTTP ${response.status}数据源不可用); } const arrayBuffer await response.arrayBuffer(); const seisData seisplotjs.miniseed.parseMiniSeed(arrayBuffer); console.log(解析完成, seisData); return seisData; }这里有几个需要注意的点。fetch的arrayBuffer()是异步的解析必须在它返回完整字节流之后进行不能在response拿到后立即调用parseMiniSeed。parseMiniSeed内部会把二进制流按块切分每个数据块对应一段连续波形再合并到同一SeisData下。SeisData本质上是Seismograph对象的集合每个Seismograph都带有channelCode、stationCode、sampleRate、startTime这些元数据以及一个连续的y数组——即波形幅度序列绘制阶段直接消费这个数组。有些资料会把MiniSEED解析和文档结构化解析混为一谈但前者是二进制位级解码后者是XML/JSON文本抽取思路完全不同。拿解析XML的方式去处理MiniSEED翻车几乎是必然的。parseMiniSeed的价值就在于把低层逻辑全部封装好不管是单通道文件还是多通道打包文件返回结构都一样后续可以直接交给绘制组件。2.3 QuakeML与StationXML结构化工文的解析差异除了波形数据地震事件和台站元数据分别以QuakeML和StationXML两种XML文档存在。seisplotjs单独提供了seisplotjs.quakeml.parse和seisplotjs.stationxml.parse二者接收的都是文本内容返回Promiseconst text await response.text(); const quakeml await seisplotjs.quakeml.parse(text); const events quakeml.getEvents(); console.log(events.length);两类文档的差异决定了它们在工作流里的角色QuakeML描述某时某地发生了一次地震包含震源参数、震相到时、震级、矩张量这些事件级信息StationXML描述某个台站的仪器怎么配置的包含台站坐标、通道列表、灵敏度、仪器响应这些设备级信息。实际使用时波形数据要靠StationXML做单位换算和仪器校正事件信息则用来在波形图上标注P波、S波到时。文档类型描述对象主要字段典型用途QuakeML地震事件震相到时、震级、深度、矩张量事件标记、目录查询StationXML台站设备灵敏度、响应、坐标、采样率波形单位换算、仪器校正MiniSEED波形数据采样率、通道、起止时间、幅度值波形绘制、频谱分析QuakeML、StationXML和MiniSEED三者合在一起才构成完整的地震观测数据集。seisplotjs把这三类文档的解析统一进同一个命名空间业务代码里不用为每种格式单独引入一套解析库这是我长期依赖它的一个很实际的原因。3. 波形绘制把解析结果变成可交互的Seismograph3.1 挂载波形图的基本写法Seismograph是seisplotjs的绘制核心。它接收SeisData或单个Seismograph渲染出来的波形图自带缩放、平移、鼠标悬停显示数值这些交互能力。最基本的挂载代码只需要几行const seismograph new seisplotjs.Seismograph(seisData); seismograph.height 400; seismograph.width 100%; seismograph.addToDOM(document.getElementById(waveform));addToDOM是同步调用执行后波形立刻出现在目标节点里。关于尺寸有两个细节height可以直接给数字单位是像素width则可以给百分比字符串这会映射到父容器的宽度上在响应式布局里很实用。需要区分的是Seismograph绘制组件和SeisData数据容器SeisData里放的是波形数字Seismograph里放的是视图配置。后续要更新数据只需要替换底层的SeisData再调用Seismograph的update方法不需要重新创建整个组件。3.2 时间窗与通道筛选只画你想看的那段波形真实场景里一个MiniSEED文件常常包含多个通道。直接new Seismograph(seisData)会把所有通道全部画出来如果只想看垂直分量BHZ可以在数据层面先过滤const bhzSeis seisData.filter(d d.channelCode.toUpperCase() BHZ ); if (bhzSeis.length 0) { console.warn(没有找到BHZ通道); return; } const seismograph new seisplotjs.Seismograph(bhzSeis);通道代码三位编码的语义值得多说几句第一位代表采样率与频带B是宽频带、H是高频、L是长周期第二位代表仪器类型H是高增益地震计第三位是分量方向Z垂直、N南北、E东西。这是台网行业里真正意义上的通道语义不是随意起的名字。写筛选条件时最好做大小写不敏感的匹配因为有些台网元数据里通道代码存在大小写混用的情况直接写全大写比较最省事。时间窗控制我一般分两条路走数据量小时在绘制前操作Seismograph数据数据量大时干脆在FDSN请求阶段就限定。比如想看某次地震前后十分钟的波形时间边界这样算const start new Date(eventTime.getTime() - 10 * 60 * 1000); const end new Date(eventTime.getTime() 10 * 60 * 1000);拿到震源时间eventTime后前后各开十分钟作为查询窗口。这里要强调的是start和end都必须是UTC语境下的Date对象如果eventTime本身是从QuakeML解析出来的它就是UTC毫秒值直接加减不会有问题。怕的是从后端接口拿到一个已经被转成字符串的本地时间再new Date()时区就乱了。3.3 RMS包络与震相标注可叠加的增强层给波形叠加RMS包络线是很普遍的需求。RMS包络反映的是某个时窗内信号平均能量的变化趋势地震波到达前后的包络突变比原始波形更直观。seisplotjs没有内置RMS计算但你可以直接对y数组做运算function computeRmsEnvelope(y, windowSize) { const envelope []; for (let i 0; i y.length; i windowSize) { const chunk y.slice(i, i windowSize); const rms Math.sqrt( chunk.reduce((sum, v) sum v * v, 0) / chunk.length ); envelope.push(rms); } return envelope; }windowSize建议取采样率的一半采样率40Hz时取20也就是每0.5秒一个包络点。这个参数不是越大越好——窗口太大包络会变迟钝P波到时的突变被抹平太小又跟着高频噪声起伏看不出宏观能量变化。我实际工作中会先跑一组不同windowSize的结果做对比挑出过渡最尖锐的那个。除了直观展示RMS包络还有一个用途在连续数据里做震相初至的粗筛包络超阈值的时刻往往就是震相到达点先定位再人工确认效率比逐帧拖拽高得多。震相标注的实现不复杂用SVG覆盖层在最外层叠加即可。关键是把时间值投影成像素坐标const x (time - viewStart) / (viewEnd - viewStart) * width;viewStart和viewEnd是当前视图可见区间的起止时间width是视图像素宽度。这个公式要特别注意视图一旦缩放或平移旧坐标立即失效必须在每次交互结束后重算标记位置否则P波标记会跟着波形一起漂移看着就尴尬。4. 从FDSN服务拉数据请求参数、数据量与网络边界4.1 FDSN query请求构建seisplotjs提供了fdsn.query方法对应FDSN标准的web service协议。请求一组波形数据的典型写法const seisData await seisplotjs.fdsn.query({ network: II, station: BFO, channel: BHZ, startTime: new Date(2024-01-01T00:00:00Z), endTime: new Date(2024-01-01T01:00:00Z) });参数里最关键的是台站定位五元组network、station、channel、location加上startTime和endTime。其中startTime和endTime必须是Date对象且语义是半开区间[startTime, endTime)——也就是说endTime那一秒的数据不包含在内这是波形对不齐的一个潜在来源。如果只给了网络、台站、通道而没给时间接口会直接返回错误FDSN不允许从有记录以来下载全量数据数据量太大且对服务端压力过高所以时间范围是必填项。参数类型必填说明networkstring是台网代码如II、IU、GEstationstring是台站代码如BFO、KIVchannelstring是通道代码如BHZ、HH1locationstring否位置编码默认留空startTimeDate是起始时间含该时刻数据endTimeDate是结束时间不含该时刻数据4.2 数据量估算避免一次拉爆内存FDSN返回的是二进制MiniSEED流数据量要用采样率、位深和时长来估算。BHZ通道采样率通常是20Hz或40Hz每个采样占2字节一小时单通道大约40Hz×3600秒×2字节288KB三分量Z/E/N就是864KB连续一天三分量大约20MB。20MB听起来不大但这是传输字节数。parseMiniSeed解析之后会生成带属性字段的对象数组内存占用至少翻三四倍再加上浏览器绘制SVG节点页面很快开始发烫。如果你的业务需要按天展示强烈建议分时窗拉取每次只取几小时const chunkSize 6 * 60 * 60 * 1000; // 6小时一个窗口 const start new Date(2024-01-01T00:00:00Z); const end new Date(2024-01-02T00:00:00Z); for (let t start; t end; t new Date(t.getTime() chunkSize)) { const chunkEnd new Date(Math.min(t.getTime() chunkSize, end.getTime())); const seisData await seisplotjs.fdsn.query({ network: II, station: BFO, channel: BHZ, startTime: t, endTime: chunkEnd }); // 每段数据绘制完及时释放引用 }分时窗拉取还有个附带好处单段数据解析失败不会拖垮其他时段网络超时只需要重试失败的那一段而不是重下24小时全量数据。这里再提一个浏览器侧的细节同一域名并发连接数是有限制的一次丢10个请求出去前几个很顺利后面往往开始排队超时。我一般自己维护一个简单并发池最多同时保持3个事务完成一个再递补一个。async function fetchWithConcurrency(tasks, limit 3) { const pool []; for (const task of tasks) { const p Promise.resolve().then(task); p.finally(() { const idx pool.indexOf(p); if (idx -1) pool.splice(idx, 1); }); pool.push(p); if (pool.length limit) { await Promise.race(pool); } } await Promise.all(pool); }这个fetchWithConcurrency接收一个异步任务数组和一个并发上限内部用固定大小的池子调度。核心在于每次向池子里推入新任务后如果满了就等待最先完成的那个腾出位置最后再统一等待所有剩余任务结束。参数limit根据实际数据量和带宽调3是一个比较保守的开局值。这个技巧同样适用于批量解析本地文件不只是FDSN请求。5. seisplotjs实战排查跨域、时区、单位与内存地震数据链路看起来简单真正跑起来问题不少。下面这四条是我踩得最狠的每条都按照现象→原因→解决的顺序记录供你排查时对照。5.1 跨域浏览器直连FDSN被CORS拦住现象页面里调用seisplotjs.fdsn.query控制台出现JavaScript运行时报错提示类似Access to fetch ... has been blocked by CORS policy。原因FDSN数据服务默认不允许任意跨域站点读取数据。seisplotjs在浏览器里发出的是普通fetch请求目标服务没有返回允许当前来源访问的响应头浏览器直接拦截。解决最常见的做法是做一层后端代理前端把请求发到你自己域名的代理接口由服务端转发给FDSN。服务端之间的HTTP请求不涉及浏览器CORS自然不受限制。如果数据源服务商已经开放了CORS也可以直接请求但生产环境我仍然建议保留代理一是可以缓存热点数据二是在自己这层统一控制请求频率避免被数据源限流。提示代理转发时注意保留Content-Type和Accept头FDSN服务对这两个头比较敏感头不对会直接返回406。5.2 时区时间戳没按UTC写导致波形错位现象查询某段波形返回的数据和已知事件时间对不上P波应该到达的位置一片安静波形整体偏移了几个小时。原因FDSN协议强制要求时间参数使用UTC。如果你写的是new Date(2024-01-01T00:00:00)少了结尾的ZJavaScript会按本地时区解释在东八区的机器上这个时间等于UTC前一天16:00整体偏差8小时。解决所有传给FDSN的时间参数统一加Z后缀或者用Date.UTC构造。const start new Date(2024-01-01T00:00:00Z); const end new Date(2024-01-01T01:00:00Z);这里要澄清一个容易混淆的点Date对象内部存储的是自UTC纪元起的毫秒数和本地时区无关。所以把QuakeML里的origin time直接new Date()做时间比较是安全的只有调用toString之类的方法展示给用户看时才受本地时区影响。判断依据很简单凡是作为请求参数和时间比较的值一律UTC只有显示文本才转本地时区。5.3 单位counts和物理量的换算遗漏现象波形画出来了但幅度要么小得离谱要么大得离谱和自己用ObsPy算的完全对不上。原因MiniSEED存储的原始采样值以counts为单位实际物理量等于counts除以灵敏度sensitivity而灵敏度藏在StationXML里。不同通道的灵敏度差几个数量级是常态不换算直接画出来的幅度曲线自然不对。解决先请求StationXML拿到灵敏度再画波形。const stationxml await seisplotjs.stationxml.parse(xmlText); const channel stationxml.channels.find(ch ch.networkCode II ch.stationCode BFO ch.channelCode BHZ ); const sensitivity channel.sensitivity.value; const physicalY seisData[0].y.slice().map(v v / sensitivity);这里有个容易忽略的细节sensitivity不一定是整数有些台站因为仪器标定会带小数除完后的物理量单位是速度还是加速度取决于仪器类型不能想当然。所以灵敏度值不能硬编码必须从每份StationXML里动态取。我见过有人图省事写死在配置文件里结果仪器标定更新后波形全部偏差排查了半天才意识到是灵敏度过期了。5.4 内存多通道长波形解析直接卡死页面现象按钮点下去后浏览器标签页白屏过一会儿弹出页面无响应滚动波形图掉帧严重。原因把几十MB的MiniSEED一次性parseMiniSeed同时生成大量Seismograph对象再加上SVG节点渲染浏览器主线程直接扛不住。一次查24小时三通道40Hz的数据采样点规模在百万级。解决治本方案是控制请求范围按第4章的分时窗策略处理把数据切成小段消费。视图层尽量做窗口化渲染只保留当前可视范围内的采样点绘制。seisplotjs的Seismograph内部有一定缩放优化但底层数据对象还是常驻内存所以控制数据规模才是最有效的。注意如果把SeisData保存在全局变量里做缓存要注意它不会被自动回收。用完的临时数据及时置空或者在切换台站/通道时主动清理旧引用。这一点和前端框架结合使用时尤其容易遗漏组件卸载不等于数据释放。6. 进阶技巧用seedlink拼一个实时波形监视器实时监控才是seisplotjs真正拉开差距的场景。6.1 seedlink接入实时流seedlink是地震行业通用的实时波形数据流协议。seisplotjs提供了seedlink客户端模块常见用法是建立连接后在数据回调里把新到的MiniSEED帧直接交给Seismograph更新const client new seisplotjs.seedlink.SeedlinkClient(); client.connect(seedlinkHost, seedlinkPort); client.on(data, (seisData) { seismograph.update(seisData); }); client.start();回调里拿到的seisData不需要重新创建绘制组件直接调用update刷新视图即可。实时数据展示有个关键约束不要每收到一帧就全量重绘。常见做法是只更新最近一个时窗的采样点保留已经画好的历史轨迹否则CPU会被持续重绘吃光页面交互就废了。6.2 拿已知地震事件验证实时显示验证方法其实不复杂选一个已知的强震事件时刻在同一个台站同时拉离线FDSN数据和实时seedlink数据两者在相同时间点的波形形态应该高度一致幅度差在数值误差范围内。如果实时流波形和离线数据对不上优先查时间同步实时流的起始时间戳是不是被本地时区污染了其次是通道灵敏度有没有在绘制前做换算。我从第一次做实时监视器起就把这套对比做成了固定检查项每次接入新台站数据源都强制走一遍离线FDSN与实时seedlink波形对比流程。数据源换了、采样率变了、时区设置改了任何一步出错这个对比都能第一时间暴露问题。实时流数据天然存在时间漂移没有离线基线做锚点光靠肉眼看很难发现早期偏差。希望帮到你。本文还有配套的精品资源点击获取

相关推荐

仿QQ音乐静态网页实战:HTML+CSS+JS布局与踩坑排查
仿QQ音乐静态网页实战:HTML+CSS+JS布局与踩坑排查

简介:仿QQ音乐的HTML静态网页项目是一份面向前端初学者与开发者的实践案例,以纯HTML和CSS还原音乐播放器界面,重点展示高复用布局结构的设计思路。压缩包内共20个文件,包含1个HTML主入口、2个CSS样式文件以及17张JPG/PNG图片素材&… · 2026/9/26 5:02:04

CLI驱动的工程级代码模板系统:可离线、可定制、可复用
CLI驱动的工程级代码模板系统:可离线、可定制、可复用

1. 这不是另一个“AI代码助手”,而是一套可复用、可定制、可离线的工程级代码模板系统你有没有遇到过这样的场景:刚接手一个新项目,光是搭环境就花了两小时——装Node、配TypeScript、写webpack配置、初始化ESLint规则、补.gitignore、建src/… · 2026/9/26 5:02:04

GitHub热点项目实战:从收藏到跑通的选型与避坑指南
GitHub热点项目实战:从收藏到跑通的选型与避坑指南

这期是 2026 年 9 月 20 日的 GitHub 热点项目精选。本来想按老规矩先把 Trending 页面刷一遍,再把群里讨论度最高的仓库拎出来,结果越翻越觉得,GitHub 上的热点其实早就分成两个完全不同的物种:一种是"看一眼就想收藏"… · 2026/9/26 5:01:57

IDEA中配置JDK与Tomcat:版本匹配、环境变量与报错排查全攻略
IDEA中配置JDK与Tomcat:版本匹配、环境变量与报错排查全攻略

把JDK装好、Tomcat解压好、IDEA也打开之后,很多人遇到的第一道坎就是:在IDEA里配好环境,点了运行,结果浏览器要么半天不弹出来,弹出来就是404,或者Tomcat启动日志直接一片红。我见过太多次这种场景——旁边… · 2026/9/26 5:36:42

个人的初想法
个人的初想法

1.自我介绍:我叫谢智敏,来自广东湛江,今年18岁,喜欢打羽毛球和听歌,对阅读比较感兴趣,读过《人性的弱点》、《认知觉醒》、《戒掉你的弱者气息》等 2.学习编程的目标:我希望通过编程技术来培养我… · 2026/9/26 5:36:36

红外技术彻底讲透:从电磁波原理到遥控测温与循迹实战
红外技术彻底讲透:从电磁波原理到遥控测温与循迹实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 5:36:30

CodeBuddy CLI不是命令行工具,而是对话式编程会话协议
CodeBuddy CLI不是命令行工具,而是对话式编程会话协议

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 5:36:30

工科生的多元微积分实战指南:从几何直觉到物理建模
工科生的多元微积分实战指南:从几何直觉到物理建模

简介:本资源是面向高校数学专业学生及多元微积分初学者的系统性学习笔记,聚焦MTH008课程核心内容,覆盖前12章关键知识点与配套例题,助力期末冲刺80成绩。笔记采用英文撰写(适配原课程教学语言),… · 2026/9/26 5:36:24

WLAN基础概念实战指南:从信道干扰到速率协商
WLAN基础概念实战指南:从信道干扰到速率协商

简介:本资源是一份面向网络初学者与IT运维人员的WLAN基础入门文档,系统梳理无线局域网核心概念与技术要点,助力读者建立清晰的知识框架并理解实际部署逻辑。文档以WLAN基本定义为起点,横向对比PAN、MAN、WAN等七类网络的覆盖范围与… · 2026/9/26 5:36:24

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21

OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40

向下兼容与向上兼容:接口设计中的兼容性策略与工程实践
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践

一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码