ソフトウェア無線(SDR: Software Defined Radio)は、従来ASICやFPGAなどの専用ハードウェアで処理していた無線信号の変復調・フィルタリングなどを、ソフトウェアで実現する技術です。
同一のハードウェアで様々な変調方式や通信プロトコルに対応でき、ソフトウェアの更新だけで機能を拡張できる柔軟性が最大の利点です。
本記事では、SDRの基本原理からアーキテクチャ、Pythonでの信号処理の実装例までを解説します。
本記事の内容
- SDRの基本概念と従来型無線機との違い
- SDRのアーキテクチャ
- IQ信号の仕組み
- Pythonでの信号処理実装
前提知識
この記事を読む前に、以下の概念を理解しておくと読みやすくなります。
- 基本的な三角関数と周波数の概念
- フーリエ変換の基礎
SDRとは
従来の無線機(ハードウェア無線機)では、変調・復調・フィルタリングなどの信号処理が専用の回路で実装されています。異なる変調方式に対応するには、ハードウェア自体を変更する必要がありました。
SDRでは、アンテナで受信した高周波信号をADC(アナログ-デジタル変換器)でデジタル化し、その後の処理を全てソフトウェア(CPU/GPU上のプログラム)で行います。
| 項目 | 従来型無線機 | SDR |
|---|---|---|
| 変復調処理 | ハードウェア(ASIC/FPGA) | ソフトウェア(CPU/GPU) |
| 対応方式の変更 | ハードウェア交換が必要 | ソフトウェア更新で対応 |
| 柔軟性 | 低い | 高い |
| 処理速度 | 高速(固定回路) | ハードウェアに依存 |
| コスト | 方式ごとに専用機が必要 | 1台で多方式対応 |
SDRのアーキテクチャ
SDRの基本的なアーキテクチャは以下の構成要素で成り立っています。
受信系
- アンテナ: 電磁波を受信
- RF フロントエンド: 低雑音増幅器(LNA)、バンドパスフィルタ
- ダウンコンバータ: 高周波信号を中間周波数(IF)またはベースバンドに変換
- ADC: アナログ信号をデジタル信号に変換
- デジタル信号処理: フィルタリング、復調、デコードなど
送信系
送信系はこの逆の流れになります。
- デジタル信号処理: エンコード、変調
- DAC: デジタル信号をアナログ信号に変換
- アップコンバータ: ベースバンド信号をRF周波数に変換
- パワーアンプ: 信号を増幅
- アンテナ: 電磁波として送信
IQ信号の基礎
SDRの信号処理で中心的な役割を果たすのがIQ信号(In-phase / Quadrature)です。
高周波信号 $s(t)$ は、搬送波周波数 $f_c$ を用いて次のように表せます。
$$ \begin{equation} s(t) = I(t)\cos(2\pi f_c t) – Q(t)\sin(2\pi f_c t) \end{equation} $$
ここで、
- $I(t)$:同相成分(In-phase)
- $Q(t)$:直交成分(Quadrature)
これを複素ベースバンド信号として表現すると、
$$ \begin{equation} \tilde{s}(t) = I(t) + jQ(t) \end{equation} $$
となります。元の信号は
$$ \begin{equation} s(t) = \text{Re}\left[\tilde{s}(t) \cdot e^{j2\pi f_c t}\right] \end{equation} $$
で復元できます。
IQ信号の利点
IQ表現を使う利点は以下の通りです。
- 振幅と位相の両方を表現: $|\tilde{s}(t)| = \sqrt{I^2 + Q^2}$(振幅)、$\angle \tilde{s}(t) = \arctan(Q/I)$(位相)
- 負の周波数を扱える: 実数信号では正負対称だったスペクトルを、複素信号では非対称に表現可能
- ベースバンド処理: 搬送波周波数に依存しない低いサンプリングレートで処理可能
ナイキストの定理とサンプリング
ADCでアナログ信号をデジタル化する際、サンプリング周波数 $f_s$ は信号の最大周波数 $f_{\max}$ の2倍以上でなければなりません。
$$ \begin{equation} f_s \geq 2 f_{\max} \end{equation} $$
これをナイキストの定理と呼びます。SDRでは、IQ信号を使うことで、帯域幅 $B$ の信号を $f_s = B$ のサンプリングレートで扱えます(実数信号では $f_s = 2B$ 必要)。
代表的なSDRハードウェア
| デバイス | 周波数範囲 | 帯域幅 | 価格帯 | 特徴 |
|---|---|---|---|---|
| RTL-SDR | 24〜1766 MHz | 2.4 MHz | 約2,000円 | 受信のみ、入門用 |
| HackRF One | 1〜6000 MHz | 20 MHz | 約40,000円 | 送受信対応 |
| ADALM-PLUTO | 325〜3800 MHz | 20 MHz | 約25,000円 | 送受信対応、教育用 |
| USRP B210 | 70〜6000 MHz | 56 MHz | 約200,000円 | 研究・業務用 |
Pythonでの実装
SDRの基本的な信号処理をPythonで実装します。FM変調信号の生成と復調を行います。
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(42)
# パラメータ
fs = 240000 # サンプリング周波数 [Hz]
duration = 0.01 # 信号の長さ [s]
fc = 10000 # 搬送波周波数 [Hz]
fm = 1000 # メッセージ信号の周波数 [Hz]
freq_dev = 5000 # 周波数偏移 [Hz]
t = np.arange(0, duration, 1/fs)
n_samples = len(t)
# メッセージ信号(変調する情報信号)
message = np.sin(2 * np.pi * fm * t)
# FM変調
# 瞬時位相 = 2*pi*fc*t + 2*pi*freq_dev * integral(message)
phase = 2 * np.pi * fc * t + 2 * np.pi * freq_dev * np.cumsum(message) / fs
fm_signal = np.cos(phase)
# IQ信号への変換(搬送波を除去してベースバンドに)
# ダウンコンバート: 搬送波 e^{-j*2*pi*fc*t} を掛ける
lo_i = np.cos(2 * np.pi * fc * t)
lo_q = -np.sin(2 * np.pi * fc * t)
iq_i = fm_signal * lo_i
iq_q = fm_signal * lo_q
# ローパスフィルタ(移動平均で簡易実装)
def moving_average(x, w=50):
"""移動平均フィルタ"""
return np.convolve(x, np.ones(w)/w, mode='same')
iq_i_filtered = moving_average(iq_i)
iq_q_filtered = moving_average(iq_q)
# 複素ベースバンド信号
iq_complex = iq_i_filtered + 1j * iq_q_filtered
# FM復調(瞬時周波数の計算)
# 位相の微分 = 瞬時周波数
phase_demod = np.angle(iq_complex)
# 位相差分(微分の離散近似)
freq_demod = np.diff(np.unwrap(phase_demod)) * fs / (2 * np.pi)
# スペクトル計算
def compute_spectrum(signal, fs):
"""パワースペクトルを計算"""
N = len(signal)
freqs = np.fft.fftfreq(N, 1/fs)
spectrum = np.abs(np.fft.fft(signal)) / N
# 正の周波数のみ
pos_mask = freqs >= 0
return freqs[pos_mask], 2 * spectrum[pos_mask]
# 可視化
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# 左上: 元の信号とFM変調信号
axes[0, 0].plot(t[:500] * 1000, message[:500], 'b-', linewidth=1.5, label='Message signal')
axes[0, 0].plot(t[:500] * 1000, fm_signal[:500], 'r-', alpha=0.5, linewidth=0.5, label='FM signal')
axes[0, 0].set_xlabel('Time [ms]')
axes[0, 0].set_ylabel('Amplitude')
axes[0, 0].set_title('Message Signal and FM Modulated Signal')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)
# 右上: IQ信号
axes[0, 1].plot(t[:500] * 1000, iq_i_filtered[:500], 'b-', linewidth=1.5, label='I (In-phase)')
axes[0, 1].plot(t[:500] * 1000, iq_q_filtered[:500], 'r-', linewidth=1.5, label='Q (Quadrature)')
axes[0, 1].set_xlabel('Time [ms]')
axes[0, 1].set_ylabel('Amplitude')
axes[0, 1].set_title('IQ Baseband Signal')
axes[0, 1].legend()
axes[0, 1].grid(True, alpha=0.3)
# 左下: IQコンスタレーション
axes[1, 0].plot(iq_i_filtered, iq_q_filtered, 'g.', markersize=1, alpha=0.3)
axes[1, 0].set_xlabel('I (In-phase)')
axes[1, 0].set_ylabel('Q (Quadrature)')
axes[1, 0].set_title('IQ Constellation')
axes[1, 0].set_aspect('equal')
axes[1, 0].grid(True, alpha=0.3)
# 右下: 復調結果
t_demod = t[:-1]
axes[1, 1].plot(t_demod[:500] * 1000, freq_demod[:500] / freq_dev, 'purple',
linewidth=1.5, label='Demodulated')
axes[1, 1].plot(t[:500] * 1000, message[:500], 'b--', alpha=0.5,
linewidth=1.5, label='Original message')
axes[1, 1].set_xlabel('Time [ms]')
axes[1, 1].set_ylabel('Normalized Amplitude')
axes[1, 1].set_title('FM Demodulation Result')
axes[1, 1].legend()
axes[1, 1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
左上のグラフでは、元のメッセージ信号(青)とFM変調された信号(赤)を比較しています。FM変調では振幅は一定で、周波数がメッセージ信号に応じて変化します。右上ではIQ信号(ベースバンド信号)、左下ではIQコンスタレーション(FM信号は円を描く)、右下ではFM復調の結果を示しています。
まとめ
本記事では、ソフトウェア無線(SDR)について解説しました。
- SDRは無線信号の処理をソフトウェアで行う技術で、1台のハードウェアで多様な通信方式に対応できる
- IQ信号(複素ベースバンド信号)がSDRの信号処理の基盤である
- IQ表現により振幅と位相を同時に扱え、低いサンプリングレートで効率的に処理できる
- RTL-SDRなどの安価なハードウェアにより、個人でもSDRを体験できる
- PythonでFM変調・復調の信号処理を実装し、基本的な動作を確認した
次のステップとして、以下の記事も参考にしてください。