NVIDIA Jetson Nano 開発者キットでソフトウェア無線（セットアップ編）

# はじめに

ソフトウェア無線（SDR: Software Defined Radio）をご存知でしょうか？ソフトウェア無線とは、ハードウェアを変更せずに、制御ソフトウェアにより、無線通信方式を変更できる技術と説明されています。送信側は、法令で規制されているため、気安く試すわけには行きませんが、受信側でソフトウェア無線を試すのは比較的容易です。USBドングル形状の、ソフトウェア無線用受信機は安価で販売され、ARM 64-bit 対応のデバイスドライバも提供されているので、Jetson Nano でも利用することができます。おまけに、Jetson Nano 上の GPU で、ソフトウェア無線のデジタル信号処理も高速に実行できます。

# ハードウェア

ソフトウェア無線用受信機とアンテナが必要です。私は、[RTL-SDR BLOG V.3](https://www.rtl-sdr.com/rtl-sdr-blog-v-3-dongles-user-guide/) とアンテナのセットを購入しました。アマゾンにて5千円程度の価格で購入できます。

![IMG_0862.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384208/c6771d4c-e934-ca86-cc4c-d81f824ecea9.jpeg)

この受信機はUSBドングルとしては少し大きいので、他の USB ポートと干渉します。そのため、この写真のとおり、USB エクステンダーケーブルを介して、Jetson Nano と接続しています。

# ソフトウェア

Python でプログラミングできるようにするため、以下のパッケージを利用しました。

- [RAPIDS cuSignal](https://github.com/rapidsai/cusignal)
  - GPU を利用したデジタル信号処理ライブラリ
  - [Scipy Signal](https://docs.scipy.org/doc/scipy/reference/tutorial/signal.html) 互換 API
- [SoapySDR](https://github.com/pothosware/SoapySDR)
  - ベンダーに依存しないソフトウェア無線サポート・ライブラリ
  - ライブラリ内部で、RTL-SDR 用ライブラリ librtl-sdr を呼び出している

# ソフトウェアのインストール

cuSignal, SoapySDR の順で、インストールを行います。この2つに依存関係は存在しないのですが、cuSignal は Anaconda 環境が標準なので、その環境構築が最初という意味で、この順序でのインストールに帰結します。
両方共に、配布元のドキュメントに沿ってインストールできますが、少し面倒なところもあったので、ここに記録します。

## cuSignal のインストール

[cuSignal の GitHub リポジトリ](https://github.com/rapidsai/cusignal) に [Jetson 用のインストール手順](https://github.com/rapidsai/cusignal#source-aarch64-jetson-nano-tk1-tx2-xavier-linux-os) が記載されているので、基本的にはこの手順に従います。  
**注意点は、CuPy のビルド時に、GPU の [Compute Capability](https://developer.nvidia.com/cuda-gpus#compute) を指定することです。これを行わないと、いつまでたってもビルドが完了しません。**

### Anaconda 環境の構築

まず最初に、Anaconda 環境を構築します。ドキュメントに記載どおり、[Miniforge](https://github.com/conda-forge/miniforge) をインストールします。**Linux aarch64 (arm64) Miniforge3-Linux-aarch6** を利用しました。インストーラーを実行するだけでインストールできます。最後に conda init を実行するかどうか問われますので、この後の作業のために、そこで Yes とします。

### cuSignal のインストール

```bash
export CUSIGNAL_HOME=$(pwd)/cusignal
```

```bash
git clone https://github.com/rapidsai/cusignal.git $CUSIGNAL_HOME
```

```bash
cd $CUSIGNAL_HOME
```

:point_down: 以下の環境変数設定が非常に重要です。Jetson Nano の [Compute Capability](https://developer.nvidia.com/cuda-gpus#compute) は **5.3** なので以下のように設定します。これを行わないとすべての Compute Capability に対応できるよう CuPy がビルドされるので、いつまでたってもビルドが完了しません:scream:。（私は半日放置してビルドが終わらなかったので諦め、Compute Capability を指定してのビルドへ切り替えました。）


```bash
export CUPY_NVCC_GENERATE_CODE="arch=compute_53,code=sm_53"
```

```bash
conda env create -f conda/environments/cusignal_jetson_base.yml
```

```bash
conda activate cusignal-dev
```

:point_down: CUDA Toolkit へパスを通しておかないと、CuPy のビルドに失敗します。

```bash
PATH="$PATH":/usr/local/cuda/bin
```

```bash
./build.sh
```

```bash
cd python
```

:point_down: cuSignal が正しくインストールできたかテストします。いくつかのワーニングが出ましたが、エラーは出なかったので、良しとしました。

```bash
pytest -v
```

## SoapySDR のインストール

基本的には、[SoapySDR BuildGuide](https://github.com/pothosware/SoapySDR/wiki/BuildGuide) と [Building Soapy RTL-SDR](https://github.com/pothosware/SoapyRTLSDR/wiki#building-soapy-rtl-sdr) のとおり。

### RTL-SDR と オーディオ関連のライブラリをインストール

```bash
sudo apt install rtl-sdr librtlsdr-dev portaudio19-dev
```

:point_down: pyrtlsdr と pyaudio は conda install で見つからなかったので、pip でインストールしました。

```bash
pip install pyrtlsdr pyaudio
```

:point_down: ほとんどの RTL-SDR デバイスで libdvb ドライバをブラックリスト登録してロードをされないようにする必要があるらしいです。[Please note, for most rtlsdr devices, you'll need to blacklist the libdvb driver in Linux.](https://github.com/rapidsai/cusignal#sdr-integration) 

```bash
sudo vi /etc/modprobe.d/blacklist.conf
```

最後の行に、**blacklist dvb_usb_rtl28xxu** を追加。それを反映させるため、リブート。 :point_down: 

```bash
sudo reboot
```

:point_down: swig をインストールしておかないと、SoapySDR の Python パッケージがビルドされないので。

```bash
conda install swig
```

:point_down: 後々、サンプルの Jupyter Notebook を実行するので。

```bash
conda install jupyter
```

### SoapySDR のインストール

```bash
git clone https://github.com/pothosware/SoapySDR.git
```

```bash
cd SoapySDR
```

```bash
mkdir build
```

```bash
cd build
```

:point_down: Anaconda 環境に関する理解が不足しているため、ここが苦労したところ。普通に **cmake ..** とやると、通常の Python パスに SoapySDR の Python パッケージがインストールされて、Anaconda 環境からは見えなくなってしまう。そのため Anaconda 環境のパスを指定。PYTHON_INSTALL_DIR と PYTHON3_INSTALL_DIR の両方に指定したが、PYTHON3_INSTALL_DIR だけで良いのかも知れない。

```bash
cmake -DPYTHON_INSTALL_DIR=`python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"` -DPYTHON3_INSTALL_DIR=`python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"` ..
```

```bash
make -j4
```

```bash
sudo make install
```

```bash
sudo ldconfig
```

:point_down: 以下のコマンドで SoapySDR がインストールできたことを確認。

```bash
SoapySDRUtil --info
```

:point_down: 以下のように出力されれば成功。

```
######################################################
##     Soapy SDR -- the SDR abstraction library     ##
######################################################

Lib Version: v0.8.0-gab626068
API Version: v0.8.0
ABI Version: v0.8
Install root: /usr/local
Search path:  /usr/local/lib/SoapySDR/modules0.8
Module found: /usr/local/lib/SoapySDR/modules0.8/librtlsdrSupport.so (0.3.2-53ee8f4)
Available factories... rtlsdr
Available converters...
 -  CF32 -> [CF32, CS16, CS8, CU16, CU8]
 -  CS16 -> [CF32, CS16, CS8, CU16, CU8]
 -  CS32 -> [CS32]
 -   CS8 -> [CF32, CS16, CS8, CU16, CU8]
 -  CU16 -> [CF32, CS16, CS8]
 -   CU8 -> [CF32, CS16, CS8]
 -   F32 -> [F32, S16, S8, U16, U8]
 -   S16 -> [F32, S16, S8, U16, U8]
 -   S32 -> [S32]
 -    S8 -> [F32, S16, S8, U16, U8]
 -   U16 -> [F32, S16, S8]
 -    U8 -> [F32, S16, S8]

```

### SoapyRTLSDR のインストール

```bash
git clone https://github.com/pothosware/SoapyRTLSDR.git
```

```bash
cd SoapyRTLSDR
```

```bash
mkdir build
```

```bash
cd build
```

```bash
cmake ..
```

```bash
make
```

```bash
sudo make install
```

:point_down: 最後に RTL-SDR デバイスが認識できているか確認。Jetson Nano 起動前から RTL-SDR デバイスが USB ポートに刺さっている必要があるようです。

```
SoapySDRUtil --probe
```

:point_down: 以下のように表示されれば、めでたし、めでたし。

```
######################################################
##     Soapy SDR -- the SDR abstraction library     ##
######################################################

Probe device 
Found Rafael Micro R820T tuner
[INFO] Opening Generic RTL2832U OEM :: 00000001...
Found Rafael Micro R820T tuner

----------------------------------------------------
-- Device identification
----------------------------------------------------
  driver=RTLSDR
  hardware=R820T
  index=0
  origin=https://github.com/pothosware/SoapyRTLSDR

----------------------------------------------------
-- Peripheral summary
----------------------------------------------------
  Channels: 1 Rx, 0 Tx
  Timestamps: YES
  Time sources: sw_ticks
  Other Settings:
     * Direct Sampling - RTL-SDR Direct Sampling Mode
       [key=direct_samp, default=0, type=string, options=(0, 1, 2)]
     * Offset Tune - RTL-SDR Offset Tuning Mode
       [key=offset_tune, default=false, type=bool]
     * I/Q Swap - RTL-SDR I/Q Swap Mode
       [key=iq_swap, default=false, type=bool]
     * Digital AGC - RTL-SDR digital AGC Mode
       [key=digital_agc, default=false, type=bool]
     * Bias Tee - RTL-SDR Blog V.3 Bias-Tee Mode
       [key=biastee, default=false, type=bool]

----------------------------------------------------
-- RX Channel 0
----------------------------------------------------
  Full-duplex: NO
  Supports AGC: YES
  Stream formats: CS8, CS16, CF32
  Native format: CS8 [full-scale=128]
  Stream args:
     * Buffer Size - Number of bytes per buffer, multiples of 512 only.
       [key=bufflen, units=bytes, default=262144, type=int]
     * Ring buffers - Number of buffers in the ring.
       [key=buffers, units=buffers, default=15, type=int]
     * Async buffers - Number of async usb buffers (advanced).
       [key=asyncBuffs, units=buffers, default=0, type=int]
  Antennas: RX
  Full gain range: [0, 49.6] dB
    TUNER gain range: [0, 49.6] dB
  Full freq range: [23.999, 1764] MHz
    RF freq range: [24, 1764] MHz
    CORR freq range: [-0.001, 0.001] MHz
  Sample rates: [0.225001, 0.3], [0.900001, 3.2] MSps
  Filter bandwidths: [0, 8] MHz
```

# 最後に

Jetson Nano でもソフトウェア無線を気軽に試すことができることは、先人達の努力によるもので、感謝しかありません。但し、Windows 10 や x64 Linux プラットフォームの場合ほど、Jetson Nano で試す際の情報は充実していません。私自身、このインストール手順を見出すのに何日もかかり、それが、記事にした動機です。誰かのお役に立てば幸いです。  
ところで、インストール作業をもっと簡単にするため、Dockerfile の作成を考えたのですが、Anaconda を使わないで CuPy をインストールすることが難しくて断念しました。（x64 向けは [サポート](https://github.com/rapidsai/cusignal/blob/branch-0.20/docker/Dockerfile) されているようです。）  
本記事は、[**動作確認編**](https://qiita.com/tsutof/items/966202f8c82e16846f78) へ続きます。