Raspberry Pi を Wi-Fi 電波強度モニターにする 【Python】

Raspberry Pi

Raspberry Pi を使って、Wi-Fi の電波強度をモニターする Python のスクリプトについてまとめておきます。Raspberry Pi を Wi-Fi の電波強度測定機にするというアイディアです。

以下の構成で動作確認をしています。
構成の一例:
・ Raspberry Pi (bullseye)
・ USB バッテリー(Raspberry Pi の電源供給用。持ち歩いて測定できると便利なため。)
・ Wi-Fi ネットワーク
・ Windows パソコン(Raspberry Pi にリモートデスクトップでアクセスするため。)
★ あらかじめ、Raspberry Pi や Windows パソコンは Wi-Fi ネットワークに接続し、リモートデスクトップなどの設定を済ませています。設定方法は、末尾の関連リンクを参照してください。

背景 ~ Wi-Fi 環境を定量的に把握したい!

Raspberry Pi やノートパソコンなどの Wi-Fi 機器を使っていると、部屋の間取りや位置関係、Wi-Fi のアクセスポイント/Wi-Fi ルーターからの距離によって、電波の状態がかなり変動します。
電波の状態がよい/悪いといったとき、感覚的なとらえ方をしていても時間の無駄です。
定量的な把握をしたい
ところです。

たまたま手元に Raspberry Pi があり、Wi-Fi 接続はすでに設定してあります。
そこで、Raspberry Pi を使って、Wi-Fi の電波強度をモニターする Python のスクリプトをまとめておきます。

Raspberry Pi をバッテリー駆動とした状態でスクリプトを実行し、部屋中/各部屋を持ち歩くと、電波の強度、電波が届く範囲を実測できます。
また逆に、無線 LAN のルーターの位置を動かしてみると、電波の強度が増減する様子がわかります。室内に各機器を設置するとき、配置を最適化することが可能になります。
スクリプトは、Wi-Fi の Linux 標準コマンド(”iwconfig wlan0″)を、一定の時間間隔で繰り返し実行している程度の内容です。

設定手順

① Raspberry Pi に電波強度測定用のフォルダを作ります。
例: /home/pi/wifi_power_tester1/
② ①のフォルダの中に “power_tester1.py” 等のファイル名でテキストファイルを作り、下記のスクリプトをコピー&ペーストして保存してください。

使い方

③ あらかじめ、Raspberry Pi を Wi-Fi ネットワークに接続しておきます。
(Raspberry Pi 上で、標準的な wlan0 で設定できているとします。)
④ Raspberry Pi のターミナルを起動し、②のスクリプトを実行してください。
例: python /home/pi/wifi_power_tester1/power_tester1.py

→ Wi-Fi の電波強度、ビットレートなどが表示されます。

★ スクリプトは、3秒間隔で 20回、測定するようにしています。
時間間隔や測定回数は、適宜、修正してください。
★ また、途中で測定を中断する場合は、[ctrl] + [c] を入力してください。
★ スクリプトを簡素化するため、ログの保存機能などは入れていませんが、ターミナルの測定データの部分をコピーしてテキストなどに貼りつけると測定結果の取得は可能です。

Wi-Fi の電波強度の表示のみかた

スクリプト実行中の表示

スクリプトを実行すると、設定した時間間隔(3秒)ごとに、以下のような結果が繰り返して表示されます。

220429 130531  Link Quality=65/70  Signal level=-45 dBm  Bit Rate=39 Mb/s  Tx-Power=31 dBm

・ Signal level のところの数値が、Wi-Fi の受信電波の強度です。
・ 0 dBm を基準とし、マイナス側(-∞ dBm)になるほど電波が弱い/プラス側ほど電波が強い、という表示になっています。

詳細

・ スクリプトでは、”iwconfig wlan0″ を繰り返し実行し、結果から文字列を引き抜いています。日付、時刻、リンクの品質、受信信号のレベル、ビットレート、送信レベルを表示するようにしています。

・ Link quality
Wi-Fi 接続全般の品質です。
・ Signal level
Wi-Fi ルーター/アクセスポイントから Raspberry Pi が受信している電波の強度です。Received Signal Strength Indicator (RSSI) に対応しています。
受信信号に対応する Signal level は、負の範囲で示されます。つまり、-∞ dBm から 0 dBm の範囲で表示されます。
・ Signal level は、負の値を取り、0 dBm に近いほど、受信できている電波強度が強いことを意味しています。いいかえると、絶対値をとったとき、値が小さなほうが受信電波が強いことになります。
・ 信号レベルの単位 dBm は、1mW を基準とした信号の相対的な強さをデシベル dB で表したものです。
式で書くと、以下のとおりです。
$$ X, dBm = 10 \log_{10} {\frac{P1}{P0}} $$
ただし、基準とする信号の強さ P0 = 1mW とし、測定値 P1 の単位系も mW に取ります。分子分母の単位系を振幅ではなくエネルギーに取っていますので、log の係数は 20 ではなく、10 となっています。
・ たとえば、受信信号の強さが P1 = 1mW のとき、P1/P0 = 1 となり、X = 0 dBm となります。
また、P1 = 0.1mW のとき、-10 dBm、P1 = 0.01mW のとき、-20 dBm となります。
・ Bit Rate の部分で、送受信データのビットレートが表示されます。
★ なお、もし表示がうまく出ない場合は、スクリプトで “# print( str2 )” となっている行の冒頭の “# ” を外してみて、コマンドが実行されているかどうかを確認してみてください。Raspberry Pi bullseye の表示に合わせて文字列を抜粋していますので、Linux のバージョンが異なる/古い等の場合は調整が必要になることがあります。また、Raspberry Pi の Wi-Fi 設定は、wlan0 で接続できていることを前提として、スクリプトを記載しています。

信号強度のめやす

信号強度のめやすを、RSSI に関するサイトから引用しておきます(外部リンク参照)。

Signal Strength TL;DR Required for
-30 dBm Amazing Max achievable signal strength. The client can only be a few feet from the AP to achieve this. Not typical or desirable in the real world. N/A
-67 dBm Very Good Minimum signal strength for applications that require very reliable, timely delivery of data packets. VoIP/VoWi-Fi, streaming video
-70 dBm Okay Minimum signal strength for reliable packet delivery. Email, web
-80 dBm Not Good Minimum signal strength for basic connectivity. Packet delivery may be unreliable. N/A
-90 dBm Unusable Approaching or drowning in the noise floor. Any functionality is highly unlikely. N/A

★ -70 dBm 以上であれば使用が可能であって、-67 dBm を超えると動画のストリーミングも扱えるレベルといった理解でよいかと思います。

測定事例

実際に測定した事例を挙げておきます。

220429 130531  Link Quality=65/70  Signal level=-45 dBm  Bit Rate=39 Mb/s  Tx-Power=31 dBm
220429 130535  Link Quality=61/70  Signal level=-49 dBm  Bit Rate=24 Mb/s  Tx-Power=31 dBm
220429 130538  Link Quality=67/70  Signal level=-43 dBm  Bit Rate=24 Mb/s  Tx-Power=31 dBm
220429 130541  Link Quality=70/70  Signal level=-40 dBm  Bit Rate=24 Mb/s  Tx-Power=31 dBm
220429 130544  Link Quality=49/70  Signal level=-61 dBm  Bit Rate=24 Mb/s  Tx-Power=31 dBm
220429 130547  Link Quality=43/70  Signal level=-67 dBm  Bit Rate=24 Mb/s  Tx-Power=31 dBm
220429 130550  Link Quality=40/70  Signal level=-70 dBm  Bit Rate=24 Mb/s  Tx-Power=31 dBm
220429 130553  Link Quality=32/70  Signal level=-78 dBm  Bit Rate=24 Mb/s  Tx-Power=31 dBm
220429 130556  Link Quality=41/70  Signal level=-69 dBm  Bit Rate=24 Mb/s  Tx-Power=31 dBm
220429 130559  Link Quality=46/70  Signal level=-64 dBm  Bit Rate=24 Mb/s  Tx-Power=31 dBm
220429 130602  Link Quality=31/70  Signal level=-79 dBm  Bit Rate=39 Mb/s  Tx-Power=31 dBm
220429 130605  Link Quality=25/70  Signal level=-85 dBm  Bit Rate=26 Mb/s  Tx-Power=31 dBm
220429 130608  Link Quality=30/70  Signal level=-80 dBm  Bit Rate=26 Mb/s  Tx-Power=31 dBm
220429 130611  Link Quality=14/70  Signal level=-96 dBm  Bit Rate=19.5 Mb/s  Tx-Power=31 dBm
220429 130614  Link Quality=19/70  Signal level=-91 dBm  Bit Rate=12 Mb/s  Tx-Power=31 dBm
220429 130617  Link Quality=19/70  Signal level=-91 dBm  Bit Rate=12 Mb/s  Tx-Power=31 dBm
220429 130620  Link Quality=18/70  Signal level=-92 dBm  Bit Rate=12 Mb/s  Tx-Power=31 dBm
220429 130623  Link Quality=15/70  Signal level=-95 dBm  Bit Rate=12 Mb/s  Tx-Power=31 dBm
220429 130626  Link Quality=17/70  Signal level=-93 dBm  Bit Rate=12 Mb/s  Tx-Power=31 dBm
220429 130629  Link Quality=16/70  Signal level=-94 dBm  Bit Rate=12 Mb/s  Tx-Power=31 dBm

測定手順の一例

・ まず、Raspberry Pi を USB バッテリーで起動します(末尾の関連リンクで、USB バッテリーの写真をアップしています)。
・ つぎに、Windows パソコンから Raspberry Pi にリモートデスクトップでログインし、スクリプトを実行します。
・ スクリプトの実行開始後、測定期間中に、まず、Raspberry Pi を Wi-Fi のアクセスポイントから 10cm 程度となるよう近づけます。
・ その後、Raspberry Pi をだんだんアクセスポイントから離していき、アクセスポイントから一番離れた部屋に入ります。
※ この時点で、測定時間の1分が経過し、3秒おき×20回の測定を終えました。測定データの部分をコピーし、テキストで保存しました。

測定結果について

・ 上記の測定データで、4行目の Signal level = -40 dBm となっているところで、受信電波の強度が最大となっています。アクセスポイントに最も近づいた状態での実測値となっています。
・ その後、次第に Signal level = -40 dBm → -90 dBm 前後となり受信電波が弱くなっています。
・ Signal Level = -80 dBm ~ -90 dBm となっているあたりでは、Raspberry Pi の実機としては、電波強度の取得はしているものの、Wi-Fi 接続はできなくなっています。Windows からのリモートデスクトップの画面は、止まった状態/フリーズした状態となります。
ここで、直線的な移動ではなく部屋に入ると受信電波が急に弱くなることから、Wi-Fi 電波は(携帯やラジオとは異なり)、回り込みに弱いことがわかります。Wi-Fi の電波の波長は、1cm ~ 10cm 程度とのことです。この程度の波長では光の性質に似ていることになり、直進性が強く、影に入ると届きにくくなる/極端に信号が弱くなることを確認できます。
・ その後、測定が完了したのち、Raspberry Pi を Wi-Fi の電波が届く位置に戻しました。すると、Wi-Fi 接続が自動で復帰し、Windows からのリモートデスクトップも、フリーズした状態から画面操作が機能する状態に戻りました。
・ Link Quality を見ると、いったんは最大となる 70/70 まで上昇したものの、距離が離れるにつれ、14/70 前後にまで通信接続の品質が落ちています。
・ Tx-Power は、Raspberry Pi の出力信号に対応しています(Tx: transmitter 送信、Rx: Receiver 受信)。Raspberry Pi が一方的に出している出力値なので、電波環境には依存せず、値はつねに一定(31 dBm)となっています。また、負ではなく正の値となっていることから、Raspberry Pi の出力電波の設定としては 1mW を超える値としていることがわかります。
・ Wi-Fi の通信速度に関して、正確には、実際にデータを転送してみて確認するのがよさそうです。コマンド上では、Bit Rate の部分で確認ができます。Bit Rate は、最大で 39 ~ 24 Mb/s となっています。距離が離れて電波環境が悪くなると、1/3 以下程度まで落ち、通信できなくなることがわかります。
最大ビットレート 39Mb/s という値自体については、IEEE 802.11 の通信規格での自動設定の影響や、Wi-Fi ルーター側の制限の影響もあるのかなという印象を受けますが、ライブ画像を扱ったりデータ転送を行う場合など、データ量が多い処理を扱う際に、また検討してみようと思います。

まとめ

Raspberry Pi を電波強度モニターにする Python のスクリプトについてまとめました。
また、関連コマンド、単位系、RSSI、Wi-Fi の通信速度など、Wi-Fi に関連する情報についても1か所に集約しました。

各部屋を持ち歩いて電波強度や通信速度を計測し、Wi-Fi 環境を確認、改善してみてください。
たかだか 20 行程度のプログラムですが、かなりのレベルまで把握できるものです。

なお、今回の Python のスクリプトは、測定値を表示するのみとしています。
うまく動いたら、表示を見やすくする、ログを残すようにしてみるなど、カスタマイズしてみてください。

関連リンク
・ Raspberry Pi にリモートデスクトップで接続する
・ Raspberry Pi の Wi-Fi がつながりにくくなったとき
・ LED を ON/OFF する 【Raspberry Pi & Python】
  ★ 今回、Raspberry Pi をモバイルにするために使っている USBバッテリーの写真・構成はこちらのページと同じものです。
・ 音声データの音量レベルを一括で変換する
  ★ デシベルの換算表を、こちら↑にまとめています。(20 log_10 P1/P0 での表示のため、係数2倍が異なりますが。。)

外部リンク
・ What is RSSI and what does it mean for a Wi-Fi network?
・ iwconfig: configure a wireless network interface – Linux Man Pages (8) (systutorials.com)
・ Raspberry Pi 4 Model B 8GB
・ Raspberry Pi 4 Model B 4GB

サンプルスクリプト

import subprocess as sp1 
import shlex as sl1 
import datetime as dt1 
import time as tm1 

def get_signal_level1(): 
    str1 = dt1.datetime.now().strftime( "%y%m%d %H%M%S" )
    cmd1 = "iwconfig wlan0" 
    str2 = sp1.run( cmd1.split( " " ), encoding='utf-8', stdout=sp1.PIPE ).stdout 
    # print( str2 ) 
    a1 = str2.split( "\n" ) 
    str3 = ( a1[5].strip() + "  " + a1[2].strip() ).replace( "   ", "  " ) 
    str4 = str1 + "  " + str3 
    return str4 

print( "Press [ctrl]+c to quit." ) 

for _ in range( 20 ): 
    try: 
        str1 = get_signal_level1() 
        print( str1 ) 
        tm1.sleep( 3 ) 
    except: 
        break 

タイトルとURLをコピーしました