Rayleigh Fading in GNU Radio
This IPython notebook generates channel coefficients with GNU Radio’s flat fader block and plots their autocorrelation at different points in time. The goal is to show how autocorrelation properties change, highlighting a potential bug in the model. See also the corresponding thread on the GNU Radio mailing list.
In [1]:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('bmh')
plt.rcParams['figure.figsize'] = (10, 10.0*2/3)
plt.rcParams['font.size'] = 14
plt.rcParams['lines.linewidth'] = '3'
N = 12 # N sinusoids
v = 400 / 3.6 # speed (km/h to m/s)
f = 6e9 # freq
c = 3e8 # speed of light
f_d = f * v / c # max. Doppler
samp_rate = 1e6 # 10 MHz
N_samp = int(1000 * samp_rate) # samples to generate
fDTs = f * v / c / samp_rate
seed = np.random.randint(10000)
Generate Channel Coefficients¶
In [2]:
from gnuradio import gr, blocks, channels, analog
sig = analog.sig_source_c(0, analog.GR_CONST_WAVE, 0, 0, 1)
head = blocks.head(gr.sizeof_gr_complex*1, N_samp)
chan = channels.fading_model(N, fDTs, False, 4.0, seed)
snk = blocks.file_sink(gr.sizeof_gr_complex*1, "/home/basti/channel.bin", False)
snk.set_unbuffered(True)
## do simulations
tb = gr.top_block()
tb.connect(sig, head)
tb.connect(head, chan)
tb.connect(chan, snk)
tb.run()
Autocorrelation over Time¶
In [3]:
import os
n_w = 4
w = int(n_w * c / f / v * samp_rate)
def autocorr(x, t=1):
return np.corrcoef(np.array([x[0:len(x)-t], x[t:len(x)]]))
# resolution of autocorrelation
gaps = np.round(np.linspace(0, w, num=80))
gaps = gaps.astype(int)
## analytical
import scipy.special
bessel = map(lambda x: scipy.special.jv(0, 2 * np.pi * f_d / samp_rate * x), gaps)
N_items = 1000000
i = 0
while i < (N_samp - N_items):
file = open("/home/basti/channel.bin", "rb")
file.seek(i * 8, os.SEEK_SET)
chan = np.fromfile(file, dtype=np.complex64, count=N_items)
file.close()
acorr = map(lambda x: np.abs(autocorr(chan, x)[0, 1]), gaps)
fig, ax = plt.subplots()
ax.plot(gaps/c*f*v/samp_rate, acorr, label='Simulations')
ax.plot(gaps/c*f*v/samp_rate, np.abs(bessel), linestyle=':', label='Analytical')
ax.axvline(0.4, linewidth=1, color='gray');
ax.legend(loc=1)
plt.show()
i += 100000000
Values over time¶
To get a better understanding we plot the variables over time.
In [1]:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('bmh')
plt.rcParams['figure.figsize'] = (18, 15)
plt.rcParams['font.size'] = 14
plt.rcParams['lines.linewidth'] = '3'
d_step = .1
fDTs = 1
N_samp = 1600
n = 0
d_theta = 0
d_N = 8
thetas = []
alphas = []
dopplers = []
coeffs = []
diffs = []
def update_theta():
global d_theta
global d_step
d_theta += np.random.random() * d_step
if (d_theta > np.pi):
d_theta = np.pi
d_step = -d_step
elif (d_theta < -np.pi):
d_theta = -np.pi
d_step = -d_step
tmp = 0
for d_m in range(N_samp):
alpha_n = (2*np.pi*n - np.pi + d_theta)/(4*d_N)
doppler = 2*np.pi*fDTs*d_m*np.cos(alpha_n)
coeff = np.cos(2*np.pi*fDTs*d_m*np.cos(alpha_n))
diffs.append(doppler - tmp)
tmp = doppler
thetas.append(d_theta)
alphas.append(alpha_n)
dopplers.append(doppler)
coeffs.append(coeff)
update_theta()
fig, ax = plt.subplots(4, sharex=True)
fig.set_size_inches(18.5, 15.5)
ax[0].plot(thetas)
ax[0].set_title("d_theta")
ax[1].plot(alphas)
ax[1].set_title("alpha_n")
ax[2].plot(diffs)
ax[2].set_title("phase diff")
ax[3].plot(coeffs)
ax[3].set_title("coeff")
ax[3].set_xlabel("d_m (time)");