特定の周波数帯域を利用する場合、必ず混信が発生してしまいます。混信が発生すると、信号のデータが混じってしまい、送信者が送信した内容を受信者が正しく受け取れなくなってしまいます。
携帯電話などは、キャリアに割り当てられた周波数を多数の人が同時に使うため、混信が発生しないようにする必要があります。この技術を多重化(Multiple Access)と言います。
本記事の内容
- 多重化の必要性と基本概念
- FDMA(周波数分割多重)
- TDMA(時分割多重)
- CDMA(符号分割多重)
- Pythonでのシミュレーション
多重化の基本概念
通信チャネルの容量はシャノンの定理で与えられます。
$$ C = B \log_2\left(1 + \frac{S}{N}\right) \quad [\text{bit/s}] $$
ここで $B$ は帯域幅 [Hz]、$S/N$ は信号対雑音比です。この有限の容量を複数のユーザで共有するのが多重化技術です。
FDMA(周波数分割多重アクセス)
FDMAは、利用可能な周波数帯域を複数のサブバンドに分割し、各ユーザに異なるサブバンドを割り当てる方式です。
数学的表現
全帯域幅 $B$ を $N$ ユーザに均等分割する場合、各ユーザの帯域幅は、
$$ B_{\text{user}} = \frac{B}{N} $$
各ユーザの信号は異なる搬送波周波数 $f_k$ に変調されます。
$$ s_k(t) = m_k(t) \cos(2\pi f_k t), \quad k = 1, 2, \ldots, N $$
受信側では帯域通過フィルタにより目的の信号のみを抽出します。
TDMA(時分割多重アクセス)
TDMAは、時間軸をタイムスロットに分割し、各ユーザに異なるスロットを割り当てる方式です。
数学的表現
フレーム周期 $T_f$ を $N$ 個のスロットに分割する場合、各スロットの長さは、
$$ T_{\text{slot}} = \frac{T_f}{N} $$
ユーザ $k$ は時間区間 $[(k-1)T_{\text{slot}}, kT_{\text{slot}}]$ でのみ送信します。全帯域幅 $B$ を使えるため、バースト的に高速通信が可能です。
CDMA(符号分割多重アクセス)
CDMAは、各ユーザに固有の拡散符号を割り当て、同じ周波数帯域と時間を共用する方式です。
拡散符号の直交性
各ユーザに割り当てる符号 $\bm{c}_k$ は互いに直交します。
$$ \bm{c}_i \cdot \bm{c}_j = \begin{cases} N & (i = j) \\ 0 & (i \neq j) \end{cases} $$
ここで $N$ は拡散率(チップ数)です。
Walsh-Hadamard符号
直交符号の代表例がWalsh-Hadamard符号です。次数 $N$ のWalsh行列 $\bm{H}_N$ は再帰的に生成されます。
$$ \bm{H}_1 = [1], \quad \bm{H}_{2N} = \begin{pmatrix} \bm{H}_N & \bm{H}_N \\ \bm{H}_N & -\bm{H}_N \end{pmatrix} $$
送受信の原理
送信側: ユーザ $k$ のデータビット $d_k \in \{-1, +1\}$ に拡散符号を乗じて送信します。
$$ s_k(t) = d_k \cdot \bm{c}_k $$
受信側: 受信信号 $r(t) = \sum_k s_k(t)$ に対し、目的のユーザの符号で逆拡散します。
$$ \hat{d}_k = \frac{1}{N} \bm{c}_k \cdot \bm{r} $$
直交性により、他ユーザの信号はキャンセルされます。
Pythonでのシミュレーション
import numpy as np
import matplotlib.pyplot as plt
# Walsh-Hadamard行列の生成
def walsh_hadamard(n):
"""n次のWalsh-Hadamard行列を生成(nは2の累乗)"""
H = np.array([[1]])
while H.shape[0] < n:
H = np.block([[H, H], [H, -H]])
return H
# CDMAシミュレーション
N = 8 # 拡散率(チップ数)
n_users = 4 # ユーザ数
n_bits = 10 # 各ユーザのビット数
# Walsh符号の生成
H = walsh_hadamard(N)
codes = H[:n_users] # 各ユーザの拡散符号
# データビットの生成
np.random.seed(42)
data = np.random.choice([-1, 1], size=(n_users, n_bits))
# 送信信号の生成(拡散)
tx_signals = np.zeros((n_users, n_bits * N))
for k in range(n_users):
for b in range(n_bits):
tx_signals[k, b*N:(b+1)*N] = data[k, b] * codes[k]
# チャネル(全ユーザの信号を加算)
received = np.sum(tx_signals, axis=0)
# 雑音の付加
snr_db = 10
noise_power = 10**(-snr_db / 10) * np.var(received)
noise = np.sqrt(noise_power) * np.random.randn(len(received))
received_noisy = received + noise
# 受信(逆拡散)
decoded = np.zeros((n_users, n_bits))
for k in range(n_users):
for b in range(n_bits):
chip_signal = received_noisy[b*N:(b+1)*N]
decoded[k, b] = np.dot(codes[k], chip_signal) / N
# BER計算
decoded_bits = np.sign(decoded)
ber = np.mean(decoded_bits != data)
print(f"CDMA BER (SNR={snr_db}dB): {ber:.4f}")
# 可視化
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# 拡散符号
for k in range(n_users):
axes[0, 0].plot(codes[k] + k * 2.5, label=f'User {k+1}')
axes[0, 0].set_title('Walsh-Hadamard Spreading Codes')
axes[0, 0].set_xlabel('Chip Index')
axes[0, 0].legend()
# 送信信号
t = np.arange(len(tx_signals[0]))
for k in range(min(2, n_users)):
axes[0, 1].plot(t[:3*N], tx_signals[k, :3*N] + k * 3, label=f'User {k+1}')
axes[0, 1].set_title('Transmitted Signals (first 3 bits)')
axes[0, 1].set_xlabel('Chip')
axes[0, 1].legend()
# 受信信号(重畳)
axes[1, 0].plot(t[:5*N], received[:5*N], 'b-', alpha=0.7, label='Clean')
axes[1, 0].plot(t[:5*N], received_noisy[:5*N], 'r-', alpha=0.5, label='Noisy')
axes[1, 0].set_title('Received Signal (Superimposed)')
axes[1, 0].set_xlabel('Chip')
axes[1, 0].legend()
# SNR vs BER
snr_range = np.arange(0, 20, 1)
bers = []
for snr in snr_range:
np.random.seed(0)
data_test = np.random.choice([-1, 1], size=(n_users, 100))
tx_test = np.zeros((n_users, 100 * N))
for k in range(n_users):
for b in range(100):
tx_test[k, b*N:(b+1)*N] = data_test[k, b] * codes[k]
rx = np.sum(tx_test, axis=0)
np_power = 10**(-snr / 10) * np.var(rx)
rx_noisy = rx + np.sqrt(np_power) * np.random.randn(len(rx))
dec = np.zeros((n_users, 100))
for k in range(n_users):
for b in range(100):
dec[k, b] = np.dot(codes[k], rx_noisy[b*N:(b+1)*N]) / N
ber_val = np.mean(np.sign(dec) != data_test)
bers.append(max(ber_val, 1e-5))
axes[1, 1].semilogy(snr_range, bers, 'bo-')
axes[1, 1].set_xlabel('SNR [dB]')
axes[1, 1].set_ylabel('BER')
axes[1, 1].set_title('CDMA BER vs SNR')
axes[1, 1].grid(True)
plt.tight_layout()
plt.show()
まとめ
本記事では、通信における多重化技術について解説しました。
- FDMAは周波数帯域を分割して各ユーザに割り当てる方式である
- TDMAは時間をスロットに分割して各ユーザに割り当てる方式である
- CDMAは直交する拡散符号を用いて同一周波数・時間帯を共用する方式である
- CDMAでは逆拡散により他ユーザの信号をキャンセルできる
- 各方式にはトレードオフがあり、用途に応じて使い分けられている
次のステップとして、以下の記事も参考にしてください。