Home 私って誰 Python 作ったもの 日々の雑感 リンク
English

2018.6.7 ObsPy

完全に四日坊主になっており、久しぶりに更新。

Python好きを謳う割に最新のライブラリに疎い感じがあったため、30 Amazing Python Projects for the Past Year (v.2018)を眺め、やってる感を出そうとした。

気が向けばいくつか紹介する予定である。


関係ない話であるが、地震に関する様々なデータ処理をまとめたObsPyがとても便利だという話を聞いた。

以前から存在は知っていたものの、波形データを扱わない研究をしているため、食指が動かず放置していたが、調べる機会があったのでメモ。

地震波形データはWINフォーマットやSACなど様々な種類のバイナリデータが存在し、個別にソフトウェアを用いて変換処理や解析をする必要があるらしい。普通バイナリデータにはフォーマットに対応したヘッダーや構造がある。しかし、この界隈のバイナリデータには、なぜかファイル名にフォーマットを明記していないものも多いという問題がある。

ObsPyが優れている点の一つは、フォーマットの分からないバイナリデータの先頭部分を元にフォーマットを検出し、そのフォーマットでデータを読み取ることができるというものである。読み取ったデータはNumPyのndarrayとして簡単に扱うことができる。

WINフォーマットかどうか判定する関数の実装を見ると参考になったので引用。

import warnings

import numpy as np

from obspy import Stream, Trace, UTCDateTime
from obspy.core.compatibility import from_buffer


def _is_win(filename, century="20"):  # @UnusedVariable
    """
    Checks whether a file is WIN or not.
    :type filename: str
    :param filename: WIN file to be checked.
    :rtype: bool
    :return: ``True`` if a WIN file.
    """
    # as long we don't have full format description we just try to read the
    # file like _read_win and check for errors
    century = "20"  # hardcoded ;(
    try:
        with open(filename, "rb") as fpin:
            fpin.read(4)
            buff = fpin.read(6)
            yy = "%s%02x" % (century, ord(buff[0:1]))
            mm = "%x" % ord(buff[1:2])
            dd = "%x" % ord(buff[2:3])
            hh = "%x" % ord(buff[3:4])
            mi = "%x" % ord(buff[4:5])
            sec = "%x" % ord(buff[5:6])

            # This will raise for invalid dates.
            UTCDateTime(int(yy), int(mm), int(dd), int(hh), int(mi),
                        int(sec))
            buff = fpin.read(4)
            '%02x' % ord(buff[0:1])
            '%02x' % ord(buff[1:2])
            int('%x' % (ord(buff[2:3]) >> 4))
            ord(buff[3:4])
            idata00 = fpin.read(4)
            from_buffer(idata00, native_str('>i'))[0]
    except Exception:
        return False
    return True

_is_win関数は、あるファイルがWINフォーマットかどうか判定する関数である。

24行~29行までバイナリデータを読み取っている。これらの変数は、このファイルがWINフォーマットであれば年月日時分秒を表現する値となる。

注目したいのは、31行~33行である。先ほど読み取った年月日時分秒を使ってDateTimeオブジェクトを作り出そうとするが、WINフォーマットでない場合、かなりの確率で年月日時分秒の中にふさわしくない値が一つは存在してしまう。すると、Exceptionがraiseされ、_is_win関数はfalseを返す。

こんな感じで、各フォーマットの判定を行うことで、適切なフォーマットを選択でき、データを読み取ることができるという仕組みである。

なるほど。


バイナリ関連で同じ問題が起きそうなのが、文字コードである。

おそらくブラウザの文字化けが相当減ったのも、「文字化けしているか」の判定がより正確にできるようになり、正しい文字コードを自動で選択できるからだ、と予想するがどうだろうか。