Carriers Everywhere

GNU Radio / Simulation

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 matplotlib.pyplot as plt
plt.style.use('bmh')
plt.rcParams['figure.facecolor'] = '#222222'
plt.rcParams['axes.facecolor'] = 'None'
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, "/Users/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("/Users/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 [2]:
%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('bmh')
plt.rcParams['figure.facecolor'] = '#222222'
plt.rcParams['axes.facecolor'] = 'None'
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)");