SORACOM Onyx LTE USB ドングルの電波状況を SORACOM に保存する


:::note info
この記事は [SORACOM Advent Calendar 2022](https://qiita.com/advent-calendar/2022/soracom) の17日目の記事です
:::

みなさん、こんにちは。
本日は、Raspberry Pi と [SORACOM Onyx LTE USBドングル](https://soracom.jp/store/7326/) の組み合わせで、ドングルから AT コマンドを使って電波状況を取得し、さらに結果を SORACOM に保存してみるという内容です。Raspberry Pi などの Linux 上で実行できる Python のサンプルスクリプト付きです。全体の構成は下の図の通り。

![Screenshot from 2022-12-17 16-37-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960954/1e93ff0f-4a2a-d696-70e9-30a09d99d8b7.png)

細けえこたぁいいから、さっさとそのスクリプトを見せてくれよ！という方は、[サンプルPythonスクリプト](#サンプルpythonスクリプト) の節から読み始めていただいて大丈夫なはずです。AT コマンドって何？という方には、[SORACOM で学ぶATコマンド入門](https://zenn.dev/bearmini/books/12ebf8331d6f9ea1d90d) がおすすめです。入門からあっという間にエキスパートになれます（個人の見解です）。

# はじめに

IoT デバイスからのデータの送信が時々失敗するという場合、原因の一つとしてそのデバイスと基地局との間の電波状況がよくないという可能性が考えられます。電波状況は移動しないデバイスであっても周辺の影響で変化することがあり、また、取り付け位置の工夫などで改善できることもあるため、電波状況の問題が疑われる場合まずは把握することが必要です。

そこで参考になる記事として、『[IoTデバイスの電波状況をSORACOMに保管し、SORACOM ユーザーコンソールで一覧する方法](https://blog.soracom.com/ja-jp/2021/08/12/show-signal-qualities-on-soracom-webconsole/)』 という記事が、[SORACOM 公式ブログ](https://blog.soracom.com/ja-jp/) の中に掲載されています。こちらの SORACOM 公式ブログの記事は、デバイスからATコマンドを使って取得した電波状況を、SORACOM Air のメタデータサービスに保存するという内容になっています。この方法を使えば SORACOM ユーザーコンソールの SIM 一覧画面上にデバイスから取得された電波状態を並べて表示することができて、とっても便利です。

ところで、SORACOM 公式ブログの記事では電波状況の指標として多くの種類のデバイスで取得可能な RSSI (Received Signal Strength Indicator) 値のみを紹介しています。ですが、デバイスを特定機種に限定すれば、RSSI の他にも有益な指標が取得できる場合があります。

そこで本記事では、『[IoTデバイスの電波状況をSORACOMに保管し、SORACOM ユーザーコンソールで一覧する方法](https://blog.soracom.com/ja-jp/2021/08/12/show-signal-qualities-on-soracom-webconsole/)』 の内容を下敷きとしつつ、デバイスに Raspberry Pi と [SORACOM Onyx LTE USBドングル SC-QGLC4-C1](https://soracom.jp/store/7326/) を用いた場合に限定して、ATコマンドの操作方法と、取得できる情報の少し詳しい解説を加えます。そして、これら電波状況を取得して SORACOM に保存する Python のサンプルスクリプトを提供します。

それでは、いってみましょう。

:::note warn
SORACOM Onyx LTE USBドングルはモデムデバイスとして [Quectel EG-25G](https://www.quectel.com/ja/product/lte-eg25-g) を内部に組み込んだ製品です。この記事の内容の一部は他のデバイスにも応用可能ですが、情報取得に使用できる AT コマンドの仕様はベンダや機種によって異なる可能性があります。
:::

# 用意するもの

- [SORACOM Air for セルラー SIMカード](https://soracom.jp/services/air/cellular/)
- [SORACOM Onyx LTE USB ドングル SC-QGLC4-C1](https://soracom.jp/store/7326/)
- [Raspberry Pi](https://www.raspberrypi.org/) (筆者はRaspberry Pi 3 Model Bを使いました)


# SORACOM Onyx LTE USBドングルで通信できるようにする

まずは、Raspberry Pi と SORACOM Onyx LTE USBドングルの組み合わせで SORACOM Air for セルラーを使った通信が行える状態にしておきます。この手順については SORACOM 公式サイトの以下のページに詳しい解説があるため、本記事では割愛します。

- [SORACOM Onyx LTE USB ドングルをセットアップする (日本語)](https://users.soracom.io/ja-jp/guides/usb-dongles/soracom-onyx/)
- [Soracom Onyx LTE Dongle Setup Guide (英語)](https://developers.soracom.io/en/start/connect/soracom-onyx-lte/)

:::note warn
ちなみに、[英語版](https://developers.soracom.io/en/start/connect/soracom-onyx-lte/)のガイドにはPPP接続 (wvdial) を用いる方法と NetworkManager を用いる方法との2通りの方法が掲載されています（[日本語版](https://users.soracom.io/ja-jp/guides/usb-dongles/soracom-onyx/)は本記事公開時点（2022/12/17）でPPP接続のみの掲載）。NetworkManager を用いる方法は、内部的には NetworkManager が ModemManager を制御し、ModemManager が QMI というインターフェース経由でモデムを制御するという仕組みで成り立っています。
本記事は、PPP接続と ModemManager での接続とどちらにも対応するように意図していますが、個人的な好みの問題で動作確認は ModemManager を利用する環境だけで行いました。もし PPP接続を用いる環境でうまく動作しなかったらごめんなさい。
:::

# ATコマンドを使えるようにする

SORACOM Onyx LTE USB ドングルでATコマンドを使う方法です。

### SORACOM Onyx LTEドングルのポート構成

最初に、ATコマンドに使用するシリアルポートを確認します。

ドングルを Raspberry Pi (Pi OS) に接続すると、`/dev/`以下にデバイスファイルとして、`cdc-wdm0`、`ttyUSB0`、`ttyUSB1`、`ttyUSB2`、`ttyUSB3`が追加されます。`ttyUSBn`がシリアル（tty）ポートです。

:::note info
これらのポートのうち、 `/dev/ttyUSB3` が通信中の電波状況などの取得のために使用できる ATコマンド用ポートです。最低限その点のみ把握いただければ、この節の残りは参考情報ですので読まずに [次の節](#atコマンド用ポートをmodemmanagerによる管理から除外する) に進んでいただいても大丈夫です。
:::

```shell-session
$ ls -la /dev/cdc-*
crw-------   1 root  root    180, 176 Dec 13 20:55 /dev/cdc-wdm0

$ ls -la /dev/ttyUSB*
crw-rw----   1 root  dialout 188,   0 Dec 13 20:55 /dev/ttyUSB0
crw-rw----   1 root  dialout 188,   1 Dec 13 20:55 /dev/ttyUSB1
crw-rw----   1 root  dialout 188,   2 Dec 13 20:55 /dev/ttyUSB2
crw-rw----   1 root  dialout 188,   3 Dec 13 20:55 /dev/ttyUSB3
```

ttyに加えて、ネットワークインターフェースとして `wwan0` も追加されます。
```shell-session
$ ip l show wwan0
5: wwan0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000
    link/none 
```

:::note warn
cdc-wdm, tty および wwan デバイス名の末尾の数字の部分は、同じホストに同時に別のシリアルデバイスやネットワークアダプタが接続されている場合など別の番号になることもありますので、適宜読み替えてください。
:::


ModemManager を使用して接続を管理している場合は、`mmcli` を使用してデバイスを確認することもできます。まず`mmcli -L`で接続されているモデムの番号（以下の`/Modem/`の後ろの数字）を確認します。
```shell-session
$ mmcli -L
    /org/freedesktop/ModemManager1/Modem/0 [QUALCOMM INCORPORATED] QUECTEL Mobile Broadband Module
```
`-m` オプションのあとに、先に確認したモデムの番号をつけて `mmcli`  を実行すると、モデムのステータスが表示されます。この中に、ModemManager が認識しているポートの情報もあります。

```shell-session
$ mmcli -m 0
(抜粋)
  -----------------------------------
  System   |                  device: /sys/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3
           |                 drivers: qmi_wwan, option1
           |                  plugin: quectel
           |            primary port: cdc-wdm0
           |                   ports: cdc-wdm0 (qmi), ttyUSB0 (qcdm), ttyUSB1 (gps), 
           |                          ttyUSB2 (at), ttyUSB3 (at), wwan0 (net)
  -----------------------------------
```

ポートの構成をざっくりまとめたものが以下の表です。参考まで、同じ Onyx ドングルを Windows 11 の PC に接続した場合のデバイスマネージャ上での表示名も記載しました。

| Linuxデバイス名 | (参考) Windowsデバイス名       | 役割                             |
|---------------|------------------------|---------------------------------|
| ttyUSB0       | Quectel USB DM Port    | デバッグ (DM) ポート |
| ttyUSB1       | Quectel USB NMEA Port  | GNSS (NMEA) ポート　※ OnyxではGNSS使用不可      |
| ttyUSB2       | Quectel USB Modem      | ATコマンド/PPP接続ポート          |
| ttyUSB3       | Quectel USB AT Port    | ATコマンドポート                  |
| cdc-wdm0, wwan0 | Quectel Wireless Ethernet Adapter |  ネットワークインターフェース (QMI/USBNET) |

:::note info
DM (Diagnostic Monitor) と QMI (Qualcomm MSM Interface) はどちらも Qualcomm が開発したプロプライエタリな仕様のインターフェースで、DMはモデムのデバッグ用、QMIはホストとモデム間の通信／制御用インターフェースです。ATコマンド用のポートはこれらとは独立です。
:::

SORACOM Onyx LTE USB ドングルでATコマンドが利用できるのは `/dev/ttyUSB2` と `/dev/ttyUSB3` の2つのポートです。ただし、ネットワーク接続に `wvdial` などによるPPP接続を利用する場合には `/dev/ttyUSB2` がIPデータ通信に占有されるため、PPP 接続中のATコマンドの送受信ができません。よって、**電波状態などのステータス取得のためのATコマンドには `/dev/ttyUSB3` を使用すると良いでしょう。**

この節の冒頭の`ls`コマンドの結果から、`/dev/ttyUSB3` ファイルの所有者は `root:dialout` となっているため、ATコマンドを利用するユーザを `dialout` グループに所属させておきます。シェルにログインし直すと反映されます。

```shell
sudo usermod -aG dialout $USER
```

### ATコマンド用ポートをModemManagerによる管理から除外する

:::note warn
この節の内容は、 ModemManager を使用していない（インストールしていない or サービスを無効にしている）場合は不要ですので読み飛ばして[次の節](#atコマンドの動作確認)に進んでください。
:::

ModemManager のデーモンは、ホストに接続されたセルラーモデムの可能性のあるデバイスを常時スキャンし検出しようとしています。これによって、ATコマンド用ポートが ModemManager にロックされ、他のプログラムからのアクセスができなくなったり、ATコマンドの送受信が競合したりする可能性があります。そこで、ATコマンド用ポートをModemManagerによる管理の対象から除外します。

ModemManager には、Linuxのデバイス管理の仕組みであるudev上のタグにしたがって管理対象のデバイスをフィルタする仕組み（[Modem filter](https://www.freedesktop.org/software/ModemManager/doc/latest/ModemManager/ref-overview-modem-filter.html)）があるので、これを利用します。具体的には、`/etc/udev/rules.d/` の下に以下の内容のudev設定ファイルを置くことで、SORACOM Onyx LTE USB ドングルのATコマンド用ポート（`/dev/ttyUSB3`）だけを ModemManager の管理対象から除外できます。

```:/etc/udev/rules.d/31-mm-ignore-onyx-at-port.rules
KERNEL=="ttyUSB*", ATTRS{../idVendor}=="2c7c", ATTRS{../idProduct}=="0125", ATTRS{bInterfaceNumber}=="03", ENV{ID_MM_DEVICE_IGNORE}="1"
```

以下をシェルにコピペして実行すれば、同じ内容の設定ファイルを作成できます。
```shell
sudo tee /etc/udev/rules.d/31-mm-ignore-onyx-at-port.rules << EOF
KERNEL=="ttyUSB*", ATTRS{../idVendor}=="2c7c", ATTRS{../idProduct}=="0125", ATTRS{bInterfaceNumber}=="03", ENV{ID_MM_DEVICE_IGNORE}="1"
EOF
```

反映には udev のリロードと ModemManager の再起動が必要です。手っ取り早く Raspberry Pi 自体を再起動してしまっても良いでしょう。`mmcli -m 0` でモデムのステータスを確認した際に、`ttyUSB3 (at)` が `ports` の項から無くなっていれば成功です。

:::note info
AT コマンドポートが ModemManager の管理下にある場合の別のアプローチとして、ModemManager デーモンを経由してATコマンドを送受信するという手もあります。
まず、`/lib/systemd/system/ModemManager.service` の中の `ExecStart=` の行で、ModemManager の起動オプションに `--debug`を追加しておきます。こうすると、ModemManager デーモンがデバッグモードで動作します。

```:/lib/systemd/system/ModemManager.service
(抜粋)
ExecStart=/usr/sbin/ModemManager --debug
```

設定を反映させるため、ModemManager を再起動します。

```shell
sudo systemctl daemon-reload
sudo systemctl restart ModemManager
```

そうすると、ModemManager を制御する CLI である `mmcli` に `--command=COMMAND` オプションを付けて、ATコマンドを実行できます。

```shell-session
$ mmcli -m 0 --command='AT+GMM'
response: 'EG25'
```

ただし、デバッグモードでは ModemManager の LOGLEVEL が `DEBUG` に設定され大量のログが syslog に吐かれるようになります。よって、ログの出力先やローテーションを工夫する必要があるかもしれません。

:::


### ATコマンドの動作確認

ATコマンドに使用するポートがの準備ができたところで、実際にATコマンドを実行してみましょう。ひとまずは `minicom` あたりのターミナルを使って接続してみます。

```shell-session
$ sudo apt-get install -y minicom
$ minicom -D /dev/ttyUSB3
```

`AT`と打ち込んで`OK`が返れば大丈夫です。自分が打ち込んだ文字が表示されなくてやりづらいというときは、`ATE1`でエコーバックを有効にしましょう。minicom の終了は `Ctrl-A Z Q` です。

```
Welcome to minicom 2.8

OPTIONS: I18n
Port /dev/ttyUSB3, 19:51:04

Press Ctrl-A Z for help on special keys

AT
OK
ATE1
OK
AT+GMM
EG25
```

# 電波状況の取得に使えるATコマンド

ここでは、SORACOM Onyx LTE USB ドングルで電波状況の取得に利用できる、代表的なATコマンドを紹介します。

SORACOM Onyx LTE USB ドングルで利用可能な AT コマンドについての詳細は、Quectel EG25-G の AT Commands Manual を参照してください。Quectel 社の[LTE EG25-G のプロダクトページ](https://www.quectel.com/product/lte-eg25-g) 内の Documentation and Resources から取得できます。取得に際しては、Quectel 社のアカウントを作成しサイトにログインしておく必要があります。

:::note warn
ファームウェアのバージョンの違いなどにより、Quectel 社が提供している最新のマニュアルの記載と SORACOM Onyx LTE USB ドングルの動作には差分が生じる可能性があります。
:::

### AT+CSQ

受信信号品質を取得するコマンドです。こちらは ITU-T や ETSI および 3GPP の標準仕様で定められている歴史あるコマンドのため、SORACOM Onyx LTE USBドングルに限らず多くのモデムでサポートされています。成功時の結果のフォーマットは以下のとおりです。

```
+CSQ: <rssi>,<ber>

OK
```

| 項目 | 説明 |
|----|----|
| `rssi` | 受信信号強度を表す指標 (Received Signal Strength Indicator: RSSI) です。 |
| `ber` | 誤り率(bit error rate) を表す指標ですが、LTEでは利用できず、常に無効値 (99) となります。 |

実行例を以下に示します。
```console
AT+CSQ
+CSQ: 31,99

OK
```

RSSIの値の定義については、[アットマークテクノさんの Web サイト上の解説](https://armadillo.atmark-techno.com/howto/armadillo_3g-lte_installation-location) が詳しいです。


### AT+QENG="servingcell"

セルラーネットワークに関する詳しい情報を取得するコマンドです。Quectel 社独自の拡張コマンドのため、他社モデムでは利用できません。ちなみに Quectel 社独自のATコマンドは原則 `AT+Q` で始まるものになっているようです。成功時の結果のフォーマットは以下のとおりです。モデムが利用中の無線アクセス技術（3G、LTE等）によってフォーマットが異なるのですが、現在日本で主流のLTEの場合のみ示します。

```
+QENG: "servingcell",<state>,"LTE",<is_tdd>,<mcc>,<mnc>,<cellID>,<pcid>,<earfcn>,<freq_band_ind>,<ul_band
width>,<dl_bandwidth>,<tac>,<rsrp>,<rsrq>,<rssi>,<sinr>,<srxlev>

OK
```

| 項目 | 説明 |
|----|----|
| `state` | 端末のネットワーク接続状態を示します。 |
| `is_tdd` | 利用中のバンド（周波数帯域）の複信方式（FDD: 周波数分割多重 / TDD: 時分割多重）を示します。 |
| `mcc`, `mnc` | 基地局の通信事業者を示す識別符号です。mcc が国番号 (Mobile Country Code: MCC) 、mnc がネットワーク番号 (Mobile Network Code: MNC) です。 |
| `cellID` | 同一の通信事業者（MCC-MNC）内でセル（基地局）を一意に識別するセルIDです。LTEの場合は E-UTRAN Cell Identity (ECI) という長さ 28-bit の値です。 |
| `pcid` | 物理層のセルID (Physical cell ID: PCI) です。値の範囲が 0 - 503 のみのため、地理的に離れているなどして干渉の生じない基地局どうしで同じ値が再利用されます。 |
| `earfcn` | 基地局の中心周波数を示す番号（E-UTRA Absolute Radio Frequency Channel Number: EARFCN) です。FDD の場合は下りの値 (DL EARFCN) が出力されるようです。[3GPP TS 36.101](https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=2411) で規定されています。 |
| `freq_band_ind` | 利用中のバンドを示す番号 (E-UTRA Operating Band) です。こちらも [3GPP TS 36.101](https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=2411) での規定ですが、巨大な Word ファイルで開くのがちょっと大変なので、[Wikipedia上の表](https://ja.wikipedia.org/wiki/LTE%E3%83%90%E3%83%B3%E3%83%89) などを見るとよいです。 |
| `ul_bandwidth`, `dl_bandwidth` | 上り、下りそれぞれの周波数帯域幅を表します。0: 1.4 MHz / 1: 3 MHz / 2: 5 MHz / 3: 10MHz / 4: 15 MHz / 5: 20 MHz です。 |
| `tac` | 端末の位置登録に用いられる、端末が在圏しているエリアを識別する番号（Tracking Area Code: TAC) です。|
| `rsrp` | 基地局からの受信電力の強さを示す指標 (Reference Signal Received Power: RSRP) です。[3GPP TS 36.214](https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=2428) で規定されています。 |
| `rsrq` | RSRP の値を RSSI で除算して正規化した値で、基地局からの受信電力の質を示す指標 (Reference Signal Received Quality: RSRQ) です。[3GPP TS 36.214](https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=2428) で規定されています。 |
| `rssi` | 測定対象の周波数帯域の範囲内で観測された全受信電力の合算値です。すなわち、接続している基地局からの信号電力のほかに、隣接する基地局からの干渉電力や、熱雑音電力を含む値です。[3GPP TS 36.214](https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=2428) で規定されています。 |
| `sinr` | 基地局からの信号電力と、干渉雑音電力との比 (Signal to Interference plus Noise Ratio: SINR) です。
| `srxlev` | 基地局からの受信信号電力に補正係数をかけた値 (Cell Selection RX level value) で、基地局の再選択動作を開始するトリガーに用いる指標です。 |

実行例を以下に示します。

```console
AT+QENG="servingcell"
+QENG: "servingcell","NOCONN","LTE","FDD",440,10,2845B61,211,9510,28,3,3,1229,-73,-8,-47,16,56

OK
```

:::note info
本記事では電波状況の取得にATコマンドを使用しましたが、これとは別に、Qualcommモデムの制御インターフェースである QMI を経由してモデムの情報を取得することもできます。QMIに対応したライブラリ libqmi のフロントエンドである `qmicli` を使用します。ModemManagerと併用する場合は、`-p` オプションを付けてプロキシ（`qmi-proxy`) 経由でデバイスにアクセスします。簡単な実行例を以下に示します。

```shell-session
$ sudo apt-get install -y libqmi-utils
$ sudo qmicli -p -d /dev/cdc-wdm0 --nas-get-signal-info
[/dev/cdc-wdm0] Successfully got signal info
LTE:
	RSSI: '-50 dBm'
	RSRQ: '-8 dB'
	RSRP: '-74 dBm'
	SNR: '11.8 dB'
$ sudo qmicli -p -d /dev/cdc-wdm0 --nas-get-cell-location-info
[/dev/cdc-wdm0] Successfully got cell location info
Intrafrequency LTE Info
	UE In Idle: 'yes'
	PLMN: '44010'
	Tracking Area Code: '4649'
	Global Cell ID: '42228577'
	EUTRA Absolute RF Channel Number: '9510' (E-UTRA band 28: 700 APT)
	Serving Cell ID: '211'
	Cell Reselection Priority: '4'
	S Non Intra Search Threshold: '44'
	Serving Cell Low Threshold: '20'
	S Intra Search Threshold: '46'
	Cell [0]:
		Physical Cell ID: '211'
		RSRQ: '-9.2' dB
		RSRP: '-74.6' dBm
		RSSI: '-48.4' dBm
		Cell Selection RX Level: '55'
(以下略)
```

詳しいオプションについては `man qmicli` を参照ください。こちらの方法であれば、SORACOM Onyx LTE USB ドングル (Quectel製モジュール) に限らず、Qualcomm のQMIインターフェースを備えた一般的なモデムで利用できる可能性があります。
:::

# 電波状況に関する指標の読み方

いろいろ情報があるのはわかったけれど、電波状況って具体的にどれをどう見ればいいのか？と思われた方もおられるかと思います。例えばですが、同じ IoT システムの中で特定の端末だけが通信が安定せず、電波状況がどうも怪しいといったときにどのあたりを見るべきか、あくまで個人的見解になりますが書いてみます。ここ間違っているとか、こういう視点でも見たらどうかといった情報があればぜひお知らせください。

:::note info
もうええからスクリプトはよ、という方は [サンプルPythonスクリプト](#サンプルpythonスクリプト) へ。
::: 

### 通信事業者 (MCC-MNC)

複数の通信事業者が利用可能なサブスクリプションの場合において、ご利用の場所などの関係によって、ある通信事業者では通信が安定するが別の事業者では安定しないといったことが起こりえます。特定のデバイスだけ安定しないといった場合、同じ場所の他のデバイスと比較して同じ通信事業者に接続されているかどうかも確認してみるとよいでしょう。
もっとも、接続中の通信事業者についてはデバイスでの AT コマンド等を利用しなくても、SORACOM のユーザコンソールや API からセッションのステータス情報として取得できます。

### 周波数帯（バンド）

特定の周波数帯の基地局に接続されると通信の安定性が低下するという事象も、稀ではありますが端末の機種や場所によって起こることがあります。この症状が疑われる場合、デバイスの設定で特定のバンドの使用を無効にするといった対策も考えられます。

### 信号品質（RSRP, RSRQ, RSSI, SINR)

電波の質が良好かどうかという指標です。似たような指標がたくさんあって混乱される方もおられるかもしれませんので、解説を加えておきます。

無線通信システムにおいて最終的に通信の質といいますか伝送レート（スループット）に影響するのは、所望する基地局からの受信信号電力(_S_) と、伝送の妨げになる干渉電力(_I_) および雑音電力(_N_) との比、すなわち SINR = _S_ / (_I_+_N_) です。実用上は _I_ と _N_ を区別して測定することは難しいので、干渉 (_I_) が存在する伝送路であっても _I_ を _N_ の中に含めてしまって SNR = _S_ / _N_ と書いてしまうことも多いです。

それなら SINR だけを唯一の品質指標にすれば良いじゃないかと思ってしまうところですが、SINR は短時間で正確に測定することが難しく、変動が大きな値となってしまうことがあります。このような値を基地局の選択基準にしてしまうと、変動に合わせてあちこちの基地局を行き来するピンポン現象が生じたりといった問題があります。また、SINR が高い（品質が良い）方にも測定の上限があり、SINR が高い基地局がたくさんあった時にどれが最も近い基地局かわからなくなります。こうした理由で（他にもあるかもしれません）、基地局の選択には様々な指標を組み合わせて用いているというわけです。

若干不正確ではあるのですが、ざっくり雑に解説しますと以下のようになります。

- SINR : 信号電力と雑音干渉電力の比 ・・・ _S_ / (_I_ + _N_)
- RSSI : 測定対象の帯域内の全電力 ・・・ _S_ + _I_ + _N_
- RSRP : 所望基地局の信号電力 ・・・ _S_
- RSRQ : _n_ * RSRP / RSSI ・・・ _S_ / (_S_ + _I_ + _N_)

   S: 信号電力, I: 干渉電力, N: 雑音電力
<font color="gray">※　RSRQ の式にある _n_ はRSSI の測定時の帯域幅に対応する係数です。RSSIはもともとある帯域幅で電力を積分した測定値になっているのに対して、RSRPは帯域幅あたりで正規化された測定値なので、分子と分母の関係を合わせるためにRSRPの方に帯域幅をかけています。</font>

それぞれ数値がどのぐらいだったら良いのかについて、[Twillio のサイトに掲載されていた表](https://www.twilio.com/docs/iot/supersim/how-determine-good-cellular-signal-strength)がわかりやすく見えましたので、以下に引用させてもらいます（ちなみにTwillioのサイト内には Quectel の定義を元にしたと記載されていたのですが、元ネタはわかりませんでした）。右端の SNR の列は付け足しました。

| RF Quality | RSRP (dBm)   | RSRQ (dB)  | SNR (dB) |
|------------|--------------|------------|----------|
| Excellent  | >= -80       | >= -10     |   >= 20  |
| Good       | -80 to -90   | -10 to -15 | 13 to 20 |
| Mid cell   | -90 to -100  | -15 to -20 | 0 to 13  |
| Cell edge  |  <= -100     |   < -20    |  <=0     |


RSRP は直接に基地局からの受信信号電力を表す指標であり、同一周波数内でのセル選択基準として用いられます。大雑把に基地局からの距離感を把握するためにも使えます（基地局自体の送信電力や、遮蔽物の影響も大きく受けますが）。例えば同じ場所に置いてあるデバイスの中で 1 台だけ RSRP が妙に低いといったことがあれば、アンテナの不良や断線などを疑うと良いかもしれません。

周波数や無線アクセス技術(3G, LTE等)の異なるセルの再選択には、RSRQ も用いられます。RSRP と RSRQ の違いは RSSIで除算しているかどうかだけの違いでした。同一周波数内ではどのセルでも RSSI　は共通なので RSRP だけで判断すればよく、周波数が変わると干渉電力も変わりうるのでその成分が考慮される RSRQ で評価するというわけです。

最終的に伝送レート（スループット）の決め手になるのは SINR です。基地局からの受信電力 (RSRP) は高いのに、SINRは何故か低いといったことがもしあれば、干渉雑音電力が高いということになります。デバイスの近くになにか強いノイズを発する電子機器がないかなど、疑ってみるとよいかもしれません。


# サンプルPythonスクリプト

SORACOM Onyx LTE USB ドングルから ATコマンドを用いて電波状況を取得するスクリプトを Python で書いてみました。取得した情報は、JSON 形式に変換してシェルの標準出力に出すほかに、SORACOM Air メタデータサービスのタグとして設定したり、Unified endpoint に向けてUDPで送信したりできます。下の図は記事の冒頭と同じものですが再掲します。

![Screenshot from 2022-12-17 16-37-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960954/1e93ff0f-4a2a-d696-70e9-30a09d99d8b7.png)

### 事前準備

Python3 および pySerial を使用しますので、これらをインストールします。Pi OS や Ubuntu など Debian 系の Linux では以下のコマンドでインストールできます。

```shell
sudo apt-get install -y python3 python3-serial
```

ATコマンド用ポートは `/dev/ttyUSB3` とします。ご使用の環境でデバイスファイル名が異なる場合は適宜読み替えてください。スクリプトを一般ユーザ権限で実行する場合、実行ユーザを `/dev/ttyUSB3` と同じ `dialout` グループに所属させておきます。（これらは前の節にも書きましたが、この節だけを読む読者のためということでご容赦ください）

```shell
sudo usermod -aG dialout $USER
```
minicom など、ほかにポートを開いているプログラムがあれば終了しておきます。

### スクリプト本体のダウンロード

以下リンクの GitHub 上のリポジトリで公開しています。ここから、[get-onyx-signal-info.py](https://raw.githubusercontent.com/shozoo/soracom-onyx-signal-info/main/get-onyx-signal-info.py) をダウンロードして、`/usr/local/bin` などの適当なディレクトリに配置します。
[https://github.com/shozoo/soracom-onyx-signal-info/](https://github.com/shozoo/soracom-onyx-signal-info/)

### 基本的な使い方

実行時のオプションは以下のとおりです。

```console
get-onyx-signal-info.py [-h] [-d DEVICE] [-i INCLUDE] [--json] [--metadata] [--udp-endpoint]
```

- `-h` : ヘルプを表示します
- `-d DEVICE` : ATコマンドポートを指定します。省略すると、`-d /dev/ttyUSB3` と同一の結果になります。
- `-i INCLUDE` : モデムから取得した情報のうち、出力に含める項目名をカンマ区切りのリストで指定します。`-i any` で取得できた全項目を出力します。
- `--json` : 結果をJSON形式で標準出力に表示します。ほかに `--metadata` と `--udp-endpoint` のどちらも設定しなかった場合にもこの動作となります。
- `--metadata` : 結果を、SORACOM Air メタデータサービスのタグとして送信します。
- `--udp-endpoint` : 結果を、Unified endpointに向けてUDPパケットとして送信します。

例えば以下のコマンドで、`band`、`rsrp`、`rsrq` 、`sinr` を取得できます。
```shell-session
$ ./get-onyx-signal-info.py -d /dev/ttyUSB3 -i band,rsrp,rsrq,sinr
{"band": 28, "rsrp": -75, "rsrq": -10, "sinr": 13}
```

取得可能な全項目を出力するには、`-i any` を指定します。
```shell-session
 $ ./get-onyx-signal-info.py -d /dev/ttyUSB3 -i any
{"state": "NOCONN", "rat": "LTE", "duplex": "FDD", "mcc": "440", "mnc": "10", "cellid": "2845B61", "pcid": 211, "earfcn": 9510, "band": 28, "ul_bandwidth": 3, "dl_bandwidth": 3, "tac": "1229", "rsrp": -75, "rsrq": -10, "rssi": -47, "sinr": 12, "rxlev": 54}
```

### SORACOM Air メタデータサービスに送信する

取得した電波状況を SORACOM Air メタデータサービスのタグに反映できます。

まず、SORACOM ユーザーコンソール上で対象の SIM が所属するグループのメタデータサービスを有効にし、読み取り専用のチェックを解除しておきます。変更後は「保存」ボタンのクリックをお忘れなく。
![Screenshot from 2022-12-17 09-47-47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960954/a408309f-bb06-9e0d-d0c7-dff6f5a8e001.png)

コマンドラインオプションに `--metadata` を付けて実行すると、結果を SORACOM Air メタデータサービスに送信してタグに保存します。

```shell
./get-onyx-signal-info.py -d /dev/ttyUSB3 -i band,rsrp,rsrq,sinr --metadata
```

送信に成功すると、SORACOM ユーザコンソールの SIM 詳細画面内のタグの項に、結果が登録されます。
![Screenshot from 2022-12-17 10-11-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960954/20a8ac8b-2f6a-d132-ea23-3c4cd6220558.png)

SIM 一覧画面のテーブル設定で、タグをカラムの項目として登録することができます。
![Screenshot from 2022-12-17 10-15-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960954/c054b306-d815-5ec9-863f-acc88c0f02c1.png)

これにより、 SIM 一覧画面上でも電波状況を確認できるようになります。
![Screenshot from 2022-12-17 10-18-48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960954/37d19b6c-3381-1217-acb0-a8745d7fffc4.png)

### SORACOM Harvest Data に送信する

取得した電波状況を Unified endpoint 経由で SORACOM Harvest Data に保存できます。

まず、SORACOM ユーザーコンソール上で対象の SIM が所属するグループの SORACOM Harvest Data 設定を on にしておきます。
![Screenshot from 2022-12-17 10-41-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960954/93581b95-e94b-0bfa-991b-cb7c58514cda.png)

コマンドラインオプションに `--udp-endpoint` を付けて実行すると、結果を Unified endpoint に向けてUDPパケットとして送信します。

```shell
./get-onyx-signal-info.py -d /dev/ttyUSB3 -i band,rsrp,rsrq,sinr --udp-endpoint
```

送信に成功すると、SORACOM Harvest Data に結果が保存されます。
![Screenshot from 2022-12-17 10-51-35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960954/84f02b8f-0a57-caae-c43b-37350dfdb7e0.png)

データの送信はスクリプトの実行ごとに1度だけのため、継続的にデータを取得するには cron などを用いてスクリプトを定期的に実行する必要があります。例えば、 `/etc/cron.d/` の下に以下の内容のファイルを配置すると、10分おきにスクリプトを実行して取得結果を送信します。

```:/etc/cron.d/onyx-signal-info
*/10 * * * * root /usr/local/bin/get-onyx-signal-info.py -d /dev/ttyUSB3 -i band,rsrp,rsrq,sinr --udp-endpoint
```

これにより、時系列での変化を確認できます。
![Screenshot from 2022-12-17 11-03-42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960954/089d0974-17b3-5ffb-d322-78eecd7639ba.png)

# おわりに

本記事では、SORACOM Onyx LTE USB ドングルから取得できる電波状況に関する情報の一部を紹介し、また、取得した結果を SORACOM に送信するサンプルスクリプトを提供しました。

SORACOMへの送信に関しては、取得の都度セルラー通信で送信する仕組みですので、そもそもセルラー通信が成立しない状況では送信できないという課題があります。このような状況で電波状況を分析するには、タイムスタンプ付きでログとしてデバイスに保存するとか、デバイス内でキューイングしておいてセルラー接続が復旧したタイミングでまとめて送信するといった工夫が本記事の内容に追加して必要となります。

セルラーモデムの内部では、本記事で紹介した他にもネットワークや周辺の無線基地局に関する様々な情報を常に受信し計測しています。これらの情報は、デバイスの移動や周辺状況の変化に関わらず、できる限り皆さんに安定した通信を提供するために、収集されているものです。それぞれの値の意味や変化を詳しく見てゆくと、複雑なセルラーシステムの内部で行われていることの一端が垣間見れて面白いかもしれません。

ここまで読んでいただきありがとうございました。

:::note info
こちらは [SORACOM Advent Calendar 2022](https://qiita.com/advent-calendar/2022/soracom) に向けて書いた記事ですが、全体のボリュームを考えずに思いつくまま書いた結果長文になってしまいました。要点を絞ればもっと簡潔な記事にできたかと思いますが、断捨離がどうも苦手です（そういえば大掃除の季節ですね）。3つぐらいに分割してもいいかなとも思いましたが、もうすぐ担当の日が終わろうとしており時間切れになるので、長文のまま公開しました。締切に追われがちな師走のこととして、どうかご容赦いただけますと幸いです。
:::