Fluentd Dashboard + SDR デバイスで周囲の電波状況を可視化してみる


まず前提として以下の文章を読みましょう。

> [Fluent Dashboard＋Norikraでリアルタイムダッシュボードを7分で作る話 #dockerjp](http://qiita.com/kazunori279/items/6329df57635799405547)

こちらで紹介されているように、なんらかグラフを描画 & 公開したい場合に Fluent Dashboard (GoogleSpreadSheet)を使うと手軽でよさそうです。また紹介されている例では時系列データをプロットしていますが、"横並びのデータが順に繰り返し出てくるもの"を横並びのまま扱うのにこのセルというのが向いていそうです。
本稿ではこれをSDRデバイスで取得した電波状況の可視化、スペクトラムアナライザっぽい表示に応用してみます。

# SDRデバイスからの情報取得

SDRデバイスから、特定の周波数間での電波強度を取得するためのコマンドとして osmocom_spectrum_sense が存在します。gnuradioのインストール時に併せてgr-osmosdrパッケージを導入することでインストールされます。

このコマンドは、指定された周波数間をループしながらそれぞれの周波数帯での状況を一定の書式で出力・表示します。以下はその出力例(78.5〜83.0MHz間)です。

```
$ osmocom_spectrum_sense  -s 3200000 --dwell-delay=0.25 --tune-delay=0.25 -b 100000.0 78500000 83000000
(中略)
2016-09-13 22:24:35.941527 center_freq 79700000.0 freq 78500000.0 power_db 1.96513647574 noise_floor_db -80.7667250073
2016-09-13 22:24:35.941602 center_freq 79700000.0 freq 78600000.0 power_db 1.49557885312 noise_floor_db -80.7667250073
2016-09-13 22:24:35.941643 center_freq 79700000.0 freq 78700000.0 power_db 1.43733536577 noise_floor_db -80.7667250073
2016-09-13 22:24:35.941675 center_freq 79700000.0 freq 78800000.0 power_db 0.714014848917 noise_floor_db -80.7667250073
2016-09-13 22:24:35.941702 center_freq 79700000.0 freq 78900000.0 power_db 0.0 noise_floor_db -80.7667250073
(以降続き)
```

この出力を取得しやすく & 扱いやすくするために、fluentdのプラグインとして以下を用意しました。実際にはin_execに同様の整形を行うラッパースクリプトを噛ますでも良いような気はしますが、オプション等を簡単に渡せるようにプラグイン化しています。

> [fluent-plugin-osmocom-spectrum-sense](https://rubygems.org/gems/fluent-plugin-osmocom-spectrum-sense)

設定例は以下の通りです。

```
<source>
  @type osmocom_spectrum_sense

  tag osmocom
  minfreq 78500000
  maxfreq 83000000
  sample_rate 3200000
  channel_bandwidth 10000
</source>
```

- 周波数範囲は 78.5MHz - 83.0MHz (この間を繰り返し)
- サンプルレートは 3.2Msps
- チャネル帯域幅は100KHz (100KHz刻みでpower_dbを取得)

最終的な出力としてはosmocom_spectrum_senseの要素名をそのままキーにしたハッシュになります。以下の例では時刻が丸められていますが、内部的にはマイクロ秒のオーダーでの取り扱いが可能です。

```
2016-09-13T21:45:00+09:00      	osmocom	{"center_freq":79700000.0,"freq":78500000.0,"power_db":0.319440100129,"noise_floor_db":-80.5206848485}
2016-09-13T21:45:00+09:00      	osmocom	{"center_freq":79700000.0,"freq":78600000.0,"power_db":1.1783839666,"noise_floor_db":-80.5206848485}
2016-09-13T21:45:00+09:00      	osmocom	{"center_freq":79700000.0,"freq":78700000.0,"power_db":0.107644707085,"noise_floor_db":-80.5206848485}
2016-09-13T21:45:00+09:00      	osmocom	{"center_freq":79700000.0,"freq":78800000.0,"power_db":0.0,"noise_floor_db":-80.5206848485}
2016-09-13T21:45:00+09:00      	osmocom	{"center_freq":79700000.0,"freq":78900000.0,"power_db":0.197514552631,"noise_floor_db":-80.5206848485}
```

# GoogleSpreadSheetのスクリプト

受け側となるGoogleAppScriptは、もともとのFluentd Dashboardのスクリプトを大幅に流用しています。ただし、対象のデータの形式および系列が異なるためデータの挿入やグラフの描画部分に変更が入っています。

> [freqqie.gs](https://gist.github.com/enukane/72dfa374d689e7102225babef21d954b)

先のosmocom_spectrum_senseコマンドの出力結果にもあるように、時刻に従って対象周波数(freq)が順にかつ繰り返し動きながらデータが出てくるため挿入方法が異なっています。またグラフとしては横軸が周波数、縦軸が電波強度としスペクトラムアナライザのように見せるというのが理想です。

データを保持するシートにはそれぞれのカラムに周波数(freq)と電波強度(power_db)を周波数順に保存していきます。周波数系列は順繰りであること、一定の刻みであることを前提に後ろに追加するか既存のpower_dbを更新するかの二択というロジックになっています(このため、設定を変えた場合にはシートまたは中身をいったん消す必要があります)。

グラフは散布図(ScatterChart)で、これらのカラムを描画します。本来は、元のFluentDashboardの例にもあるように、折れ線グラフで描画したほうがそれっぽいです。が、第１カラムに時刻が入っていない系列を簡単に描画する方法がなかったためこの方式を採用しています。誰か教えて...


# fluentd で Fluentd Dashboardに流し込み

入力側のosmocom_spectrum_senseプラグインの設定は上記で述べた通り可視化したい周波数帯を、Fluentd Dashboardへの流し込みは引用元のページにあるのをそのまま用います。

```
<source>
  @type osmocom_spectrum_sense

 tag osmocom
  minfreq 78500000
  maxfreq 83000000
  sample_rate 3200000
  channel_bandwidth 10000
</source>

<match osmocom>
  @type https_json

  use_https true
  buffer_path /tmp/buffer
  buffer_chunk_limit 256m
  buffer_queue_limit 128
  flush_interval 3s
  endpoint https://script.google.com/macros/s/HOGEHOGE/exec #FIXME!
</match>
```

osmocom_spectrum_senseではこのほかに tune_delay や dwell_delay も設定可能です。中長期にわたって安定して運用するのではれば、これらをある程度長めにし channel_bandwidth も可能な限り広めにすると良いようです。あるいは、https_json の buffer 周りのパラメータを調整することで対処可能かもしれませんが、osmocom_spectrum_senseの出力はバンド幅や待ち時間を細かくすればするほど出力データ数が増し、GoogleSpreadSheetへの出力が詰まったりタイムアウトが発生する傾向にあるようです。また一方的にバッファに溜まっていくばっかりになるので、POSTのスループットとのバランスを上手く取る必要があります。

# 電波状況の見え方

前述の設定でfluentdを回すと、以下の様なテーブルを含むシートがタグ名で作成されます。この場合は、"osmocom"となっています。

![スクリーンショット 2016-09-13 21.50.30.png](https://qiita-image-store.s3.amazonaws.com/0/2226/074efe19-2282-048b-3792-0405356013a2.png)

第１シートには、上記データに従ってスペクトラムアナライザ(ただし散布図...)っぽく、各周波数の電波強度をプロットしたグラフが表示されます。

![スクリーンショット 2016-09-13 21.54.53.png](https://qiita-image-store.s3.amazonaws.com/0/2226/36d382ea-c18d-b520-692b-e3cf2cbd2239.png)

この周波数帯は東京でFMラジオが放送されている箇所です。TOKYO FM(80.0MHz)やJ-WAVE(81.3)、NHK FM(82.5MHz) などが割当たっている周波数の電波強度が強くなっており、それっぽく情報が可視化できています。