この記事はtraP Advent Calendar2018 12月10日の記事です。
計算の講義を活かして震度計を作った話の続編となっています。未読の方は前回の記事をご覧になってからお読みいただくことをおすすめします。
前回までのあらすじ
Raspberry piを使って震度計を作りました。実装はC言語です。
前回の反省
前回震度の計測はできるようになりましたが, 一方でトリガーがないので手動で計測を開始しなければなりませんでした。今回はそこについて修正を加えたいと思います。
前回の最後の実験で触れたように, 加速度センサーの精度はあまり良くなく, 平常時でも震度3程度を計測してしまうため, 常に測定し続けても意味がありません。なので震度5以上の大きな地震に絞って測定してみましょう。
ところで緊急地震速報の発表条件[1]を確認してみると, 最大震度5弱以上の地震が見込まれるときとあります。ということで今回はこれをトリガーとするものにしてみたいと思います。
情報源
ところで緊急地震速報はどうやって受信すればいいのでしょうか。気象業務支援センターによれば[2], テレビやラジオ等で入手できる他, 同センターや各配信事業者と契約を結ぶ方法があると書いてあります。
これはかなり面倒ですね。どうにかして楽に入手する方法はないのでしょうか。
電子工作では, NHKのラジオを常時受信し, チャイム音を聞き取って緊急地震速報発報を確認する方法があるようです[3]。しかし自分にはそこまでの技術力はありません。
また以前はTwitter上に緊急地震速報のデータを垂れ流してくれる素晴らしいBotがいましたが, Streaming API廃止に伴いBotも停止してしまいました[4]。
何か他に手段はないかなと探してみましたが, 次のサービスを応用すればうまく行きそうです。
防災科学研究所の提供する新強振モニタでは, 全国各地のリアルタイム震度[5]と, 緊急地震速報の確認をすることができます。
この新強振モニタですが, 検証してみると毎秒jsonを取得していることがわかります。URLにはeewの文字もあり, どうやらここから緊急地震速報の発表状況を取得しているようです。試しに気象庁の緊急地震速報の発表履歴[6]とjsonを数例突き合わせてみるとどうやらそれに間違いないようです。
ということでこのページを毎秒叩けば確認できることがわかりました。次に取得したjsonの中身について確認したいのですが, その前に緊急地震速報について概説しておきます。
緊急地震速報とは
緊急地震速報は発表要件や内容によって警報と予報の2つに分類されます。
緊急地震速報は最大震度5以上の地震が発生することが予期されるときに発表されるものと説明しましたが, 厳密にはこれは誤りで, 正確には警報の方の発表要件です。
予報の発表条件は次のとおりです[7]。
① 観測点における加速度振幅が 100gal を超えたとき(レベル法)
② 推定マグニチュードが 3.5 以上か、予想最大震度が3以上となったとき
従って警報が発表されたときには同時に予報も発表されることになります。
また, 緊急地震速報には更新があり,それぞれ発表・更新された順番に第1報, 第2報, ...... と呼ばれます。一般に報を重ねるごとに精度は向上していくようです。 そしてある程度精度が高まったら最終報を出し, 終了要件を満たした場合には緊急地震速報が終了します。
さらに, 計測機の誤検知と推定される場合にはキャンセル報が発表されることがあります。
今回は最大震度5以上であればよいので, 予報は使わず警報のみを用いることにします。
jsonの解析
どこかにjsonの中身の説明があると良いのですが, 表立って公開されているわけではないのでそのようなものはないようです。ということで先程突き合わせた結果による推察によって簡単に示しておこうと思います。
key | type | 概要 |
---|---|---|
result | object | 省略 |
report_time | string(datetime) | 取得時における最近の速報発表時刻 |
region_code | string | 不明 |
request_time | string(integer) | jsonの出力された時刻 |
region_name | string | 緊急地震速報が発表された地域名 |
longitude | string(float) | 震源の東経 |
is_cancel | string(boolean) | キャンセル報か |
depth | string | 震源の深さ |
calcintensity | string | 予測される最大震度 |
is_final | string(boolean) | 最終報か |
is_training | string(boolean) | 不明 |
latitude | string(float) | 震源の北緯 |
origin_time | string(integer) | 地震発生日時 |
security | object | 省略 |
magunitude | string(float) | 推定されるマグニチュード |
report_num | string(integer) | 本発表が第何報であるか |
request_hypo_type | string | 不明 |
report_id | string(integer) | 地震波検知時刻(?) |
alertflg | optional string("警報"or"予報") | 本発表が警報か予報か |
実装する前に
ここまで推察してみましたが,今回使うのはalertflgだけです。
実装はPythonでさっさと済ませようと思ったのですが, 実験がてらJuliaで書いてみることにしました。
Juliaとは?
ちょっとだけ紹介をしておきます。
Julialang
https://julialang.org/
公式サイトから特徴となりそうな部分を引っ張ってみると,
- Julia was designed from the beginning for high performance. Julia programs compile to efficient native code for multiple platforms via LLVM.
- dynamically-typed, feels like a scripting language
- type declarations can be used to clarify and solidify programs.
- making it easy to express many object-oriented and functional programming patterns.
つまり早くてスクリプト言語っぽさがある動的型付けだけど型の明示もできてOOっぽくも関数型っぽくも書けるという特徴を持ったコンパイル言語らしいです。
ただしコンパイル言語といってもJITコンパイラによって実行時にコンパイルが行われます。
文法はMATLABに似ているらしく(ただし筆者は書いたことがない), indexが1から始まり, 標準で行列積などがサポートされているなど応用数学などとの親和性が高い言語となっています。
ところでこれは余談なのですがjuliaを調べるときはjulialang
とかで調べると良いと思います。
Juliaのインストール
私のRaspberry PiではRaspbianを使っていますが, aptで入れようと思ったらv0.5.1
とかいう激古具合(最新の安定版はv1.0.2
)だったのでソースからビルドすることにしました。JuliaBerry[8]というサイトがあったのでそれを見ながらやってみます。
The Hard Part
The hardest part is waiting. On a Raspberry Pi 3 Model B+, the initial build takes 12+ hours. Subsequent builds after creating the Make.user file as described above should only take around two hours.[9]
は?(前日から記事を書き始めるものぐさ並の気持ち)
あ(手元のラズパイは初代model Bなので更に遅くなることを覚悟した気持ち)
実装
仕方ないので書くだけ書いておきましょう。
手始めに, 今回はHTTPクライアントとJsonのパーサが必要です。これらは公式からライブラリが公開されています。
ライブラリのインストールには, Pkgを使います。Pythonでいうpipに当たるものです。
まずJuliaを起動して次のとおり入力します。
using Pkg
Pkg.add("HTTP")
Pkg.add("JSON")
これでインストールされます。また, ライブラリの初回使用時にはプレコンパイルが入るのでさきに適当に使ってみると良いでしょう。
実際に書いてみるとだいたい次のような感じになります。
using HTTP, JSON, Dates
url = "http://www.kmoni.bosai.go.jp/new/webservice/hypo/eew/"
cexefile = ""
function getNowDateTime()
nt = now()
y = string(year(nt))
mo = lpad(month(nt), 2, "0")
d = lpad(day(nt), 2, "0")
h = lpad(hour(nt), 2, "0")
mi = lpad(minute(nt), 2, "0")
s = lpad(second(nt), 2, "0")
return y * mo * d * h * mi * s
end
function isAlertedNow(js)
p = JSON.parse(js)
return haskey(p, "alertflg") && p["alertflg"] == "警報"
end
function getJson()
return String(HTTP.request("GET", url * getNowDateTime() * ".json").body)
end
while true
if isAlertedNow(getJson())
res = ccall((:measure, cexefile), Float64, ())
println(res)
sleep(1)
end
かなり簡単にかけました。ただ本当に動くかどうかは確かめていません。実行環境がないので。
JuliaはCを呼び出すのも簡単にできます。
res = ccall((:measure, cexefile), Float64, ())
ファイルパスと関数名, 返り値と引数の型を指定してあげるだけです。
おわりに
緊急地震速報の下調べをしてデスクトップ環境にJuliaを構築しているあたりまではまだ楽しかったのですが, Raspberry pi上にてビルドが間に合わないことを理解してからは無の気持ちでやっていました。
しかしこれがうまくいけばちゃんとした震度計になります。また, JuliaBerryではGPIOPinを制御するライブラリもあるようなのでfft含めてすべての実装をJuliaで行うことも難しくはなさそうです。
機会があったらこっちにも取り組んでみようと思います。
明日の担当はyasuくんです。お楽しみに。
リアルタイム震度は前回示した算出式から求められる震度ではなく, 即時性がある方式によって計測震度を擬似的に算出したもののようです。 ↩︎
https://www.data.jma.go.jp/svd/eew/data/nc/rireki/rireki.html ↩︎