はじめに
今回は、ノイズに埋もれて見えない信号を取り出す技術を紹介します。
ルールに従って処理をする事によって見ない信号を取り出す事ができます。その手法の一つである、M系列を使った処理を紹介したいと思います。
M系列について
疑似ランダム数列と呼ばれているもので、Maximum Length系列の略称です。
1,0が疑似的にランダムに並んだ系列となっています。
ノイズに埋もれた信号を取り出す他にも、相関の特徴から通信の多重化、ランダム性から制御や音響などでインパル応答を求めるときにも使われているようです。
特徴
-
決まった長さで1,0の同じパターン繰り返す
-
決まった長さ内では、ランダムにみえる
-
M系列の0を-1に変換し1,-1のデータにして、自己相関(Autocorrelation)をとると先頭で長さと同じ値になり、その他は-1となる
-
系列の組み合わせが良い組み合わせの場合、相互相関(Crosscorrelation)の値が小さい値をとる組み合わせもあります(今回は、使わない特性)
算出方法
- 全て0以外の1,0の組み合わせの初期値(長さN)を用意する
- 指定の場所の値で、XORを取得し、それを次の値とする
- 一番古い値を抜き、新しい値を入れ、また指定の場所で、XORを取得する
- 2^N - 1 の長さまでそれを繰り返す
M系列となる指定の場所は決まっており、繰り返すまでの長さが最大となる為、Maximum lengthつまりM系列と呼ばれる。
面白いのは、初期値を変えるとズレて出てくるだけになる事。つまり初期値の組み合わせ全てのパターンが系列に含まれているという事になります。
複数のXORについて
XORをとる配列の、1の数が偶数の時に0、奇数の時に1、になる。
実際の応用
BPSK変調
実際に波で信号を送るときは、1,-1を信号の位相に当てはめて変調して送信します。
図のように波を反転させて送ります。
ノイズがない場合の相関
信号に対して、自己相関を取得する事によって利得が得られます。
M系列の長さだけ、利得が得られてパルス圧縮なんて呼ばれたりします。
ノイズを乗せた場合の相関
ノイズまみれで見えない所からも信号が取り出せる(ピークが出ている)事がわかります。
最後に
ノイズが多い所から波の信号を取り出す技術は、チャープ波を使ったものもありますが、今回はM系列を使ったものを紹介しました。
現代社会(レーダ、測距、CDMA、システム同定)で使われている技術の基本的な所の紹介でした。
Pythonコード
import numpy as np
import matplotlib.pyplot as plt
# =============================
# M系列生成(正統なLFSR)
# x^5 + x^2 + 1
# =============================
import numpy as np
def generate_m_sequence_from_polynomial(degrees):
"""
degrees : 多項式の次数リスト(m を含める)
例: x^5 + x^2 + 1 → [5, 2, 0]
"""
m = max(degrees)
N = 2**m - 1
reg = np.ones(m, dtype=int)
seq = np.zeros(N, dtype=int)
# タップ index(x^m と x^0 は除外)
tap_indices = [m - d for d in degrees if d not in (m, 0)]
for i in range(N):
output = reg[0]
seq[i] = output
feedback = output
for idx in tap_indices:
feedback ^= reg[idx]
reg[:-1] = reg[1:]
reg[-1] = feedback
return seq
def periodic_autocorrelation(data,x):
N = len(data)
r = np.zeros(N)
for tau in range(N):
r[tau] = np.sum(x * np.roll(data, -tau))
return r
# =============================
# パラメータ
# =============================
fc = 5 # 搬送波周波数
fs = 100 # サンプリング周波数
samples_per_chip = 20
snr_db = -10
# =============================
# 1. M系列(±1)自己相関
# =============================
mseq = generate_m_sequence_from_polynomial([5,2,0])
mseq_pm = 2 * mseq - 1
print(len(mseq))
send_data = np.concatenate([mseq_pm,mseq_pm])
corr1 = np.correlate(send_data, mseq_pm, mode="vaild")
#corr1 = periodic_autocorrelation(mseq_pm,mseq_pm)
plt.figure()
plt.subplot(2,1,1)
plt.title('M-sequence (±1)')
plt.stem(mseq_pm)
plt.subplot(2,1,2)
plt.stem(corr1)
plt.title("M-sequence Autocorrelation (±1)")
plt.xlabel("Lag")
plt.ylabel("Correlation")
plt.grid(True)
plt.tight_layout()
plt.show()
# =============================
# 2. BPSK変調(搬送波あり)
# =============================
# チップ展開
baseband = np.repeat(mseq_pm, samples_per_chip)
t = np.arange(len(baseband)) / fs
t_plot = np.arange(len(baseband)*3) / fs
carrier = np.sin(2 * np.pi * fc * t)
bpsk_signal = baseband * carrier
plt.figure()
plt.plot(t[:len(mseq_pm)*samples_per_chip], bpsk_signal[:len(mseq_pm)*samples_per_chip])
plt.title("BPSK Modulated Signal (Time Domain)")
plt.xlabel("Time [s]")
plt.ylabel("Amplitude")
plt.grid(True)
plt.show()
# 相関用参照信号
ref_signal = bpsk_signal.copy()
send_data2 = np.concatenate([bpsk_signal,bpsk_signal,bpsk_signal])
corr2 = np.correlate(send_data2, ref_signal, mode="valid")
plt.figure()
plt.subplot(2,1,1)
plt.title('send signal')
plt.plot(t_plot[:-len(bpsk_signal)],send_data2[:-len(bpsk_signal)])
plt.xlabel('time')
plt.subplot(2,1,2)
plt.plot(t_plot[:-len(bpsk_signal)+1],corr2)
plt.title("Correlation of BPSK Signal (No Noise)")
plt.xlabel("Lag")
plt.ylabel("Correlation")
plt.grid(True)
plt.tight_layout()
plt.show()
# =============================
# 3. BPSK + AWGN
# =============================
signal_power = np.mean(bpsk_signal**2)
noise_power = signal_power / (10**(snr_db / 10))
noise = np.sqrt(noise_power) * np.random.randn(len(bpsk_signal))
rx_signal = bpsk_signal + noise
send_data3 = np.concatenate([rx_signal,rx_signal,rx_signal])
corr3 = np.correlate(send_data3, ref_signal, mode="vaild")
plt.figure()
plt.subplot(2,1,1)
plt.title('send signal')
plt.plot(t_plot[:-len(bpsk_signal)],send_data3[:-len(bpsk_signal)])
plt.xlabel('time')
plt.subplot(2,1,2)
plt.plot(t_plot[:-len(bpsk_signal)+1],corr3)
plt.title(f"Correlation of BPSK Signal with Noise (SNR={snr_db} dB)")
plt.xlabel("Lag")
plt.ylabel("Correlation")
plt.grid(True)
plt.tight_layout()
plt.show()



