1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RTL-SDRとPythonでモノラルFMラジオを聴く方法

Posted at

未完成です

はじめに

ラジオは今も多くの人々に親しまれているメディアの一つです。皆さんの中にも番組表を片手にラジオ受信機のダイヤルを回して選局する…なんて思い出のある方がいらっしゃると思います。

ラジオは、放送局が音声を電気信号に変えて電波に乗せたものを受信し、再び音声に変えることで情報や音楽などを流す仕組みになっています。放送方式は主に二種類あり、これらはAM放送とFM放送として知られています。「音声信号を電波に乗せるため、電波の振幅・周波数・位相を変化させる」ことを変調といい、AM放送とFM放送はこの変調方式が異なります。
放送局ごとに周波数が割り当てられているので、放送局は放送方式に応じてその周波数の電波を変化させて飛ばします。
「変調された電波から音声信号を取り出す」ことを復調といい(電波に限っては検波ともいう)、ラジオ受信機は復調するための機器です。目的の放送局の周波数の電波を取り出す回路や検波回路、電気信号を増幅させてスピーカーに出力する回路といったアナログ回路で構成されています。
聴取者は受信機のアンテナを伸ばし、放送方式を選んでダイヤルを回すことで放送を聴くことができます。(これはAM/FM対応の受信機の話で片方しか対応していない受信機もある)

インターネットの普及が進んだ現在では、ノートパソコンやスマートフォンを通じてラジオを聴かれる方も多くなってきています。このような環境下では、これらのデバイスがラジオ受信機と同様の仕組みでラジオ放送の電波を受信し、復調しているかのような錯覚を覚える方もいるでしょう。しかし、このようなラジオ形式では実際に飛んでいる放送局の電波を受信しているわけではありません。
上に挙げたデバイスには無線通信用電波を受信するためのアンテナはありますが、ラジオ放送用の周波数帯域を受信できるアンテナを内蔵していません。(中にはラジオの周波数帯域を受信できる機能を内蔵したノートパソコンやスマートフォンもある)このため、ラジオ放送に使われる電波を受信できません。また、変調方式においてラジオ受信機のようなアナログ回路を中心にした機器を対象にした電波の送信では電波を連続的に変調させる(アナログ変調)必要があるのに対して、デジタル回路を中心にした機器を相手するには電波を離散的に変調させる(デジタル変調)必要があります。このため、アナログ回路で復調された信号は元の情報そのものになりますが、デジタル回路では「0と1」すなわちデジタルデータになります。
では、どのようにデジタル機器でラジオを聴くことができるのかというと、配信側のサーバーとデジタルデータのやり取りをすることで音声を受信しています。このような放送形態をインターネットラジオと呼び、一般的なラジオ放送と区別されます。

インターネットラジオはインターネットに接続できる環境があれば誰でも聴取できます。また、AM・FM放送とは異なり電波の送信所の位置にあまり依存しないため、日本どころか世界中の放送局の放送をクリアな音声で聴くことができます。インターネットを介することでこのようなメリットがあります。

このように記述するとインターネットがあればラジオだけでなくSNSや動画サービスも楽しめるため、インターネットに接続するための機器さえあれば良いと感じる方もいらっしゃるかもしれません。しかし、災害が発生した時にはインターネットに接続できない可能性もあります。このような状況で情報を得るためにはラジオが最適です。ラジオは災害が発生した時に最も信頼できるメディアだからです。家庭に一つは防災用ラジオを備えておくべきですが、例えば職場にいる等の理由で災害時に手元にはノートパソコンしかないなんて状況もあると思います。本稿では、WindowsやMacからインターネットを介さずFMラジオを聴けるようにすることで災害時でも情報を得られるようにすることを目的としています。

タイトルの冒頭にある「RTL-SDR」とは、パソコンのUSBコネクターに接続して電波を受信するためのドングルです。のちに詳しく説明します。ラジオを聴くには、周波数帯域が合っているドングルと電波を拾うためのアンテナを必要とします。これらのパーツには特性があり、初心者がパーツを選定するのは難しいので、下記の「RTL-SDR Blog V3」と「ダイポールアンテナ」がセットになったキットを購入することをお勧めします。これ以降の内容は全てこのキットを使用した時の話になります。

次に「Python」という点です。ドングルをただパソコンに挿すだけでは音声を出力することはできません。それどころか挿したものが何なのかすらパソコンはよくわかっていません。ここでソフトウェアが必要になります。ドングルのドライバやCUIで通信するためのコマンド群を含めたソフトウェアは公開されていて、その大元はC言語で作成されています。C言語は比較的高速に動作するのが特徴ですが、ハードウェア、主にメモリの管理を自分で行う必要があるため、C言語での開発は容易ではありません。それに対してPythonは初心者にもわかりやすい言語であるのに加えてライブラリが豊富であるため、独自のアプリケーションを作るのに適しています。GUIを開発するライブラリを使って周波数や音量を調節できるようにしたり、APIを活用してSNSと連携させたり、AIを使って全自動字幕機能を搭載したりなどが考えられ、既存のラジオ放送以上に便利で付加価値のあるサービスをPythonで実現できます。このことから本稿ではPythonを使っています。
世の中には様々なドングルに対応したGUIソフトウェアが出ていているので、ただ電波を受信する、ラジオを聴くことをされたいのであればそれらを活用するだけで大丈夫です。

最後に「FMラジオ」という点です。昨今、AM方式の廃止も検討されているようで放送をFM方式に代替するという流れが出てきています。本稿ではFMラジオを対象にしているので幅広い放送局に対応できます。

RTL-SDR

RTL-SDRは、ソフトウェア無線の一種で、主にUSB接続の受信機を使用して無線信号を受信し、デジタル処理を行うことができます。RTL-SDRは、RealTek社製のRTL2832Uチップをベースにしたデバイスで、元々はテレビ受信用のチューナーとして設計されましたが、オープンソースのソフトウェアを利用することで幅広い周波数帯域の無線信号を受信できるようになりました。

主な特徴としては:

  1. 高帯域受信:約500kHzから1.7GHzまでの周波数帯を受信可能
  2. コスト効率:比較的安価に入手できるため、無線通信の学習や趣味に最適
  3. 柔軟性:ソフトウェアを変更することで、さまざまなプロトコルやモードに対応できる
  4. オープンソースサポート:多くのソフトウェア(例えば、GNU Radio、SDR#など)が利用可能で、ユーザーコミュニティも活発

RTL-SDRは、無線通信の実験や解析、または気象データの受信、航空機のADS-B信号の受信などさまざまな用途に利用されています。

SDRは、Software Defined Radioの略語で従来のハードウェアベースの回路を使わず、ソフトウェアを用いて無線信号の生成、変調、復調を行うシステムです。デジタル処理が普及する以前では各プロトコルやモードに特化した機器が必要で、後から変更やアップグレードしようと考えた場合ハードウェアを再構築する必要がありましたが、現在ではソフトウェア上の設定を変更するだけで様々な無線処理が行えます。

RTL-SDR Blog V3の特徴は以下のユーザーガイドを参照してください。

今回はQuadratureサンプリングモードでの受信となり、ホストのパソコンにはI-Q信号が送信されます。(Iが実数、Qが虚数)

今回はRTL-SDR Blog V3という製品を使っていますが、別のチップを搭載したデバイスであれば周波数帯域や分解能などの性能も変わるので注意が必要です。2023年の8月にはV4も出ていますがV3と同様に動作するか不明であることにも注意してください。バージョン違いによる性能の差は次のサイトが参考になると思います。

おまけとして以下にRTL-SDR Blog V3の中身の写真を示します。
RTL-SDR Blog V3

わかりやすい回路の概略図がありましたのでその画像と掲載元のサイトを紹介します。

R820T2-RTL2832U

pyrtlsdr

pyrtlsdrはRTL-SDRプロジェクトでサポートされているデバイスへのシンプルなPythonインタフェースです。非同期読み取りサポートを含むlibrtlsdrライブラリの関数の多くをラップしています。
librtlsdrとはRTL2832をもとにしたドングルをSDRレシーバーに変えるほぼC言語で書かれたソフトウェアです。
pyrtlsdrだけでなくその他必要なツールのインストール方法について記していきます。

librtlsdrのGitHub:

pyrtlsdrのGitHub:

Windowsにインストールする方法

Macにインストールする方法

信号処理 〜FM復調〜

FMとはFrequency Modulationの略語で周波数変調を表します。周波数変調は音波の強弱を周波数の変化で表した方式です。

信号波の振幅がゼロの時の搬送周波数を基準として

  • 信号波の振幅がゼロ
    搬送周波数は変化しない  
  • 信号波の振幅がプラス方向
    搬送周波数は高くなる
  • 信号波の振幅がマイナス方向
    搬送周波数は低くなる

といった特徴を持っています。搬送波の周波数の変化量は使用する無線設備で決められていて、FM放送では最大75kHzと定められています。

本稿ではデジタル機器を用いたアナログFM復調に関する処理になります。

FM復調のプログラムに関しての着想は以下のサイトから得ました。

搬送波を

S_c \left( t \right)=A_c\cos\left( \omega_c t+ \phi_c \right)

とします。
信号波の単位時間あたりの振幅を

S_s \left( t \right)=A_s

とします。

ある時刻$t$に搬送波の位相角を$\theta_c$だったとします。

\Delta \theta=\int A_s dt
\Delta \omega = \frac{\Delta \theta}{\Delta t} =A_s

実際に作成したプログラム

このプログラムをファイルにコピーしてターミナルやコマンドプロンプト等から実行するとスピーカーからラジオ放送を聴くことができます。今回は東京FMの80.0MHzに設定しています。お住まいの地域や聴く場所によって受信できる電波の状況が異なるかもしれないので適宜sdr.center_freqの値を変更してください。

from rtlsdr import RtlSdr
import numpy as np
import asyncio
import pyaudio
from scipy import signal

sdr = RtlSdr()

sdr.sample_rate = 2.048e6  # サンプルレートの設定
sdr.center_freq = 80e6     # Hz
sdr.freq_correction = 60   # PPM
sdr.gain = 'auto'         # ゲインの設定

audiofreq = 48e3
audioobj = pyaudio.PyAudio()
audiostream = audioobj.open(format=pyaudio.paInt16, channels=1, rate=int(audiofreq), output=True)

Fs = 2.048e6
Ft = 192e3

async def demodulation(samples):
        d1data = signal.resample(samples, int(len(samples) * Ft / Fs))
        demodulated = np.angle(d1data[1:] * np.conj(d1data[:-1]))
        d2data = signal.resample(demodulated, int(len(demodulated) * audiofreq / Ft))
        audiodata = ((d2data / np.pi) * (2 ** 15)).astype(np.int16)
        return audiodata
    
    
async def sound(pri):
    audiostream.write(pri, num_frames=len(pri))

async def streaming():
   #sdr = RtlSdr()

   async for samples in sdr.stream(num_samples_or_bytes=64*1024):
       # do something with samples
        audiodata = await demodulation(samples)
        await sound(audiodata)
       # ...

   # to stop streaming:
   await sdr.stop()

   # done
   sdr.close()

loop = asyncio.get_event_loop()
loop.run_until_complete(streaming())

このプログラムにはユーザーから終了を受け付ける機能が存在しないため、ターミナルやコマンドプロンプト等で実行する際にはCtr+Cで強制終了させてください

実際に動作している様子

セットアップ

実際に動作している様子

プログラムの解説

asyncio

非同期処理ができる。サンプリングをループで取得するコードはpyrtlsdrのgithubをそのまま使った。追加でFM復調とオーディオ出力の非同期処理を行うための関数を書いた。書き方がわからず結構失敗した。最後に詰まったところはpyaudioのバッファサイズの指定をFM復調処理したデータ数にしなければならなかったところ。

次の目標

RTL-SDRの部分をFPGAに実装したい
PyQtを使ってGUIを作りたい

付録

世の中にあるSDRソフトウェアの一部ですが、RTL-SDR BLOG V3でFMラジオを聴く際に使用したものを紹介しようと思います。

SDR#

Airspyの公式サイトからSDR#をインストールできます。ダウンロードページはこちらになります。SDR#は無料のソフトウェアツールで、PCで無線信号を受信、解析、操作するために使用されます。主にWindows環境で動作します。僕の方ではWindows 11 Pro 64bit版とWindows 11 Home 64bit版で動作することは確認できました。多くの受信機と互換性を持つため、SDR#だけで様々な受信機・受信方法に対応できます。
2024年8月あたりにインストールした時と記事の執筆用に2025年1月にインストールした時では少し仕様が異なる部分もありましたので、インストールする時期によっては下記の方法とは異なる可能性があることにご注意ください。

・インストール方法

  1. ダウンロードページの「Software Defined Radio Package(Change log)」の右側にある「Download」をクリックして「sdrsharp-x86.zip」をダウンロードします
  2. ZIPファイルを解凍します(デフォルトでZIPファイルと同階層にフォルダーが展開されます)
  3. 生成されたフォルダー「sdrsharp-x86」内のバッチファイル「install-rtlsdr.bat」をダブルクリックします。(この時、「windowsによってPCが保護されました」とメッセージが出るかもしれません。その場合「詳細情報」をクリックして、下に表示される「実行する」をクリックすれば大丈夫です)すると、CUI画面が表示されて、RTL-SDR Driverに関するソフトウェアがインストールされていきます。インストールが終わると「続行するには何かキーを押してください・・・」と表示されるので任意のキーを押すとCUI画面は消えます

・ドライバのインストール

RTL-SDR系はここまでの流れで専用のドライバが存在していないため、USBドングルをPCに接続するとOS側が自動で標準ドライバをインストールします。この場合でも設定次第でラジオが聞こえるとは思いますが、専用のドライバをインストールした場合の方が使いやすくなるかもしれません。比較してみるのも良いでしょう。

  1. 用意したUSBドングルをPCのUSBソケットに接続します
  2. デバイスマネージャーを確認すると、USBドングルが「ほかのデバイス」のツリー内にWARNING SIGN付きで「Bulk-In, Interface」と表示されているのがわかります

デバイス名の表記は同名称のドングルでも変わる場合があるらしいので必ず確認する必要があります

  1. 「sdrsharp-x86」フォルダー内の「zadig.exe」をダブルクリックして実行します

zadigに関する説明
zadig.exeはUSBデバイスへのアクセスを支援するWindowsアプリケーション

  1. ユーザーアカウント制御のダイアログが表示された場合は「はい」をクリックします
  2. インストーラーが立ち上がり、ドライバーインストール用のダイアログが表示されるので、デバイスマネージャーで記憶したUSBドングル用のデバイス名を選択します(デフォルトで「Bulk-In, Interface(Interface 0)」となっていたのでそのままにします)

間違って他のデバイスを選択してしまうと選択したデバイスまたはPCが動作不能になる恐れがあるため注意する必要がある

  1. 「Install Driver」をクリックし、インストールが完了するとダイアログが開くので「Close」をクリックしてインストーラーを終了させます
  2. デバイスマネージャーを立ち上げると「ユニバーサル シリアル バス デバイス」のツリー内に「Bulk-In, Interface」が確認できます(環境によって異なりますが「RTL2838UHIDIR」、「RTL2832U」、「Blog V4」と表示された方は正しくRTL-SDR系が認識されていることを表しているので大丈夫です。ここから先は、「Bulk-In, Interface」と認識されている状態での動作確認になります。後に「Bulk-In, Interface」を「RTL2838UHIDIR」に置き換える作業をします。)

・SDR#の起動と受信設定

  1. アンテナをUSBドングルのコネクタソケットに同軸ケーブルで接続し、受信したい電波の周波数に合わせてアンテナを伸ばします
  2. 「sdrsharp-x86」内の実行ファイル「SDRSharp.dotnet9.exe」をダブルクリックします(SDR#のバージョンによっては「SDRSharp.exe」の表記かも?)
  3. 「You must install .NET Desktop Runtime to run this application.」とダイアログが表示されるので「Download it now」をクリックします
  4. 「Microsoft Windows Desktop Runtime - 9.0.1」のインストーラーが表示されるので「インストール」をクリックしてインストールし、終了したら「閉じる」をクリックします(バージョンはインストールのタイミングによって異なる可能性があります)
  5. 再度「SDRSharp.dotnet9.exe」をダブルクリックしてSDR#を起動します
  6. SDR#のデフォルト画面から左上の「Main Menu」をクリックし、メニュー内の「Source」をクリックします
  7. デフォルトで「AIRSPY R2/Mini」となっているのでプルダウンメニューから「RTL-SDR USB」をクリックしてセットします
  8. 上部にある数字は受信周波数となっていて、矢印をクリックして受信したい周波数を選択します(必要であれば隣のスピーカーマークから音量調節ができます)
  9. 左側にある復調方式を「WFM」にします
  10. ノイズしか聞こえない場合は「RF Gain」のスライドバーを調整すると音声が聞こえる可能性があります

・ドライバの再インストール

  1. USBドングルをPCに挿した状態でzadigを起動します
  2. 上にある「Options」をクリックして「List All Devices」のチェックを入れ、「Ignore Hubs or Composite Parents」のチェックを外します
  3. プルダウンリストから「RTL2832U」または「RTL2838UHIDIR」を選択します
  4. 「Replace Driver」をクリックします
  5. 警告が出たら「はい」をクリックします
  6. インストールが終了したらデバイスマネージャーを立ち上げ、「ユニバーサル シリアル バス デバイス」内のツリー内に「RTL2838UHIDIR」などの表記が変わった状態で表示されていれば再インストールに成功したことが確認できます

後は先程と同様にSDR#の起動と設定の変更をすればラジオを聴くことができます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?