In [3]:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation, rc

rc('animation', html='html5')
from matplotlib.colors import LogNorm
In [ ]:
 
In [4]:
T1 = (0, 0)
T2 = (0.07, 0)
T3 = (1, .5) 
In [228]:
Fc = 2_450_000_000. # Downscale to 2.45GHz
c = 299792458. # m/s
t_off = 0.2 / Fc
scale = 0.025 # size in cm covered by single pixel
resolution = 200 # number of on plot
# we have central point at size/scale
# one point on grid represents scale*d_scale meters
In [229]:
def m_to_point(T):
    return resolution+T[1]/scale, resolution+T[0]/scale
In [230]:
m_to_point(T2)
Out[230]:
(200.0, 202.8)
In [231]:
len(np.arange(0, grid[0].shape[0], scale/9))
Out[231]:
144000
In [232]:
# grid has positions in meters
grid = np.mgrid[-resolution*scale:resolution*scale:scale,-resolution*scale:resolution*scale:scale]
In [264]:
dT_f = lambda T1: np.clip(np.sqrt( (grid[0]-T1[0])**2 + (grid[1]-T1[1])**2), 0.07, 1000)
dT1 = dT_f(T1)
dT2 = dT_f(T2)
dT3 = dT_f(T3)
In [265]:
def label_plot(*nodes):
    plt.xticks(np.linspace(0, grid[0].shape[0]-1, 9), np.linspace(-resolution*scale, resolution*scale, 9))
    plt.yticks(np.linspace(0, grid[0].shape[0]-1, 9), np.linspace(-resolution*scale, resolution*scale, 9))
    for T in nodes:
        plt.plot(*m_to_point(T), 'ro', markersize=1)
    plt.colorbar()
In [320]:
plt.imshow(1/dT1**2, vmax=5, vmin=0)
label_plot(T1)
plt.title('1/distance to node')
plt.show()
In [322]:
phase_f = lambda dT, t_off: np.sin(2*np.pi*Fc*(-dT/c+t_off))
phase = phase_f(dT1, t_off)
plt.imshow(phase)
label_plot(T1)
plt.title('Phase at a given point in time')
Out[322]:
Text(0.5, 1.0, 'Phase at a given point in time')
In [323]:
fig = plt.figure(figsize=(6, 6))

ampl_f = lambda dT1, t_off: phase_f(dT1, t_off)/(dT1**2)
ampl = ampl_f(dT1, t_off)
plt.imshow(ampl, vmax=5, vmin=0)
label_plot(T1)
plt.title('Amplitude of waveform at a given point in time')
Out[323]:
Text(0.5, 1.0, 'Amplitude of waveform at a given point in time')
In [324]:
fig = plt.figure(figsize=(6, 6))
phase = phase_f(dT1, t_off)
im = plt.imshow(phase)
label_plot(T1)
plt.title("Wave propagation animation")
def animate(i):
    im.set_data(phase_f(dT1, 0.01*i/Fc))
    return (im,)

anim = animation.FuncAnimation(fig, animate,
                               frames=100, interval=20, blit=True)
anim
Out[324]:
Your browser does not support the video tag.
In [326]:
fig = plt.figure(figsize=(10, 10))
ampl = np.abs(ampl_f(dT1, t_off))
im = plt.imshow(ampl, vmax=5, vmin=0)
label_plot(T1)
plt.title('Waveform amplitude propagation')
def animate(i):
    im.set_data(np.abs(ampl_f(dT1, 0.01*i/Fc)))
    return (im,)

anim = animation.FuncAnimation(fig, animate,
                               frames=100, interval=20, blit=True)
anim
Out[326]:
Your browser does not support the video tag.
In [ ]:

In [329]:
fig = plt.figure(figsize=(6, 6))

plt.imshow(phase_f(dT1, t_off) + phase_f(dT2, 0))
label_plot(T1, T2)
plt.title('Interference between two nodes half-wavelenght\n apart withot power attenuation (20%phi offset)')
Out[329]:
Text(0.5, 1.0, 'Interference between two nodes half-wavelenght\n apart withot power attenuation (20%phi offset)')
In [330]:
fig = plt.figure(figsize=(6, 6))
ampl = np.abs(ampl_f(dT1, t_off) + ampl_f(dT2, 0))
im = plt.imshow(ampl, vmax=5, vmin=0)
label_plot(T1, T2)
plt.title('Interference between two nodes half-wavelenght\n  (20%phi offset)')
Out[330]:
Text(0.5, 1.0, 'Interference between two nodes half-wavelenght\n  (20%phi offset)')
In [226]:
def animate(i):
    dt = 0.01*i/Fc
    im.set_data(np.abs(ampl_f(dT1, t_off+dt) + ampl_f(dT2, dt)))
    return (im,)

anim = animation.FuncAnimation(fig, animate,
                               frames=100, interval=20, blit=True)
In [227]:
anim
Out[227]:
Your browser does not support the video tag.
In [ ]:
 
In [331]:
fig = plt.figure(figsize=(6, 6))
ampl = np.abs(ampl_f(dT1, 0) + ampl_f(dT2, 0))
im = plt.imshow(ampl, vmax=5, vmin=0)
label_plot(T1, T2)
plt.title("Beamforming with 0 offset")
Out[331]:
Text(0.5, 1.0, 'Beamforming with 0 offset')
In [171]:
def animate(i):
    dt = 0.01*(i%100)/Fc
    t_off = 0.1*(i//100)/Fc
    im.set_data(np.abs(ampl_f(dT1, t_off+dt) + ampl_f(dT2, dt)))
    return (im,)

anim = animation.FuncAnimation(fig, animate,
                               frames=10_00, interval=20, blit=True)
In [172]:
anim
Out[172]:
Your browser does not support the video tag.
In [ ]:
 
In [ ]:
 
In [268]:
t = np.linspace(0., 1., 200)/Fc
In [269]:
ampls = np.array([ampl_f(dT1, ti) for ti in t])
In [270]:
ampl_agg_baseline = np.mean(np.abs(ampls), axis=0)
In [332]:
fig = plt.figure(figsize=(6, 6))
im = plt.imshow(ampl_agg_baseline, vmax=5, vmin=0)
label_plot(T1)
plt.title('Single node signal amplitude')
Out[332]:
Text(0.5, 1.0, 'Single node signal amplitude')
In [272]:
import pandas as pd
pd.Series(ampl_agg.ravel()).describe()
Out[272]:
count    160000.000000
mean          0.348738
std          23.813855
min           0.000408
25%           0.011352
50%           0.028389
75%           0.070958
max        6247.967411
dtype: float64
In [333]:
%%time
ampls2 = np.array([ampl_f(dT2, ti+0) for ti in t])
ampl_agg_baseline2 = np.mean(np.abs(ampls2), axis=0)
Wall time: 1.34 s
In [334]:
ampl_agg = np.mean(np.abs(ampls+ampls2), axis=0)+1e-9
In [335]:
fig = plt.figure(figsize=(6, 6))
im = plt.imshow(ampl_agg, vmax=5, vmin=0)
label_plot(T1, T2)
plt.title('Two node signal amplitude')
Out[335]:
Text(0.5, 1.0, 'Two node signal amplitude')
In [336]:
import tqdm
In [337]:
import tqdm.notebook as tqdm

frames = 100
pbar = tqdm.tqdm(total=frames)

def animate(i):
    t_off = i / frames/Fc
    ampls2 = np.array([ampl_f(dT2, ti+t_off) for ti in t])
    ampl_agg = np.mean(np.abs(ampls+ampls2), axis=0)
    im.set_data(ampl_agg)
    
    pbar.update(1)
    return (im,)

anim = animation.FuncAnimation(fig, animate,
                               frames=frames, interval=100, blit=True)
anim
Out[337]:
Your browser does not support the video tag.
In [ ]:
 
In [318]:
def gain_max(ampl_agg, *baselines):
    return ampl_agg/np.max(np.dstack([*baselines]), axis=-1)
gain_kwargs = dict( vmax=2, vmin=0, cmap='coolwarm')
In [319]:
fig = plt.figure(figsize=(6, 6))
plt.title("Standard MIMO gain – 2 antennas separated by\nhalf wavelenght with 0 phase offset")
im = plt.imshow(gain_max(ampl_agg, ampl_agg_baseline, ampl_agg_baseline2), **gain_kwargs)
label_plot(T1, T2)
In [ ]:
 
In [338]:
# Why? Let's take a point (0.5, 0.5) and see
x, y = 100, 100
plt.plot(ampls[:,x, y], label='from T1')
plt.plot(ampls2[:,x, y], label='from T2')
plt.plot(ampls[:,x, y]+ampls2[:,x, y], label='sum')
plt.legend()
plt.title('Why? Offset in phase due to wavelenght propagation time')
Out[338]:
Text(0.5, 1.0, 'Why? Offset in phase due to wavelenght propagation time')
In [ ]:
 
In [341]:
ampls3 = np.array([ampl_f(dT3, ti+0) for ti in t])
ampl_agg_baseline3 = np.mean(np.abs(ampls3), axis=0)
In [342]:
ampl_agg = np.mean(np.abs(ampls+ampls3), axis=0)
In [343]:
fig = plt.figure(figsize=(6, 6))

im = plt.imshow(ampl_agg, vmax=5, vmin=0)
label_plot(T1, T3)
plt.title('Two nodes with perfectly synchronized nodes (sig power)')
Out[343]:
Text(0.5, 1.0, 'Two nodes with perfectly synchronized nodes (sig power)')
In [345]:
fig = plt.figure(figsize=(6, 6))

im = plt.imshow(gain_max(ampl_agg, ampl_agg_baseline, ampl_agg_baseline3), **gain_kwargs)
label_plot(T1, T3)
plt.title('Two nodes with perfectly synchronized clocks\nGain over best of 2 signals')
Out[345]:
Text(0.5, 1.0, 'Two nodes with perfectly synchronized clocks\nGain over best of 2 signals')
In [346]:
import tqdm.notebook as tqdm

frames = 100
pbar = tqdm.tqdm(total=frames)
fig = plt.figure(figsize=(6, 6))

im = plt.imshow(ampl_agg, vmax=5, vmin=0)
plt.title('Two nodes with drifting clocks\n(sig power, time not to scale)')
def animate(i):
    t_off = i / frames/Fc
    ampls2 = np.array([ampl_f(dT3, ti+t_off) for ti in t])
    ampl_agg = np.mean(np.abs(ampls+ampls2), axis=0)
    im.set_data(ampl_agg)
    
    pbar.update(1)
    return (im,)

anim = animation.FuncAnimation(fig, animate,
                               frames=frames, interval=100, blit=True)
anim
Out[346]:
Your browser does not support the video tag.
In [ ]:
 
In [352]:
T4 = (-3, 1.5)
dT4 = dT_f(T4)
In [353]:
ampls4 = np.array([ampl_f(dT4, ti+0.45/Fc) for ti in t])
ampl_agg_baseline4 = np.mean(np.abs(ampls4), axis=0)
In [354]:
ampl_agg = np.mean(np.abs(ampls+ampls4), axis=0)
In [355]:
fig = plt.figure(figsize=(6, 6))

im = plt.imshow(ampl_agg, vmax=5, vmin=0)
label_plot(T1, T4)
plt.title('Two distant nodes with perfectly synchronized cloks\n with 45%ph offset (sig power)')
Out[355]:
Text(0.5, 1.0, 'Two distant nodes with perfectly synchronized cloks\n with 45%ph offset (sig power)')
In [356]:
fig = plt.figure(figsize=(6, 6))

im = plt.imshow(gain_max(ampl_agg, ampl_agg_baseline, ampl_agg_baseline4), **gain_kwargs)
label_plot(T1, T4)
plt.title('Two distant nodes with perfectly synchronized clocks\nwith 45%ph offset Gain over best of 2 signals')
Out[356]:
Text(0.5, 1.0, 'Two distant nodes with perfectly synchronized clocks\nwith 45%ph offset Gain over best of 2 signals')
In [ ]:

In [357]:
ampl_agg = np.mean(np.abs(ampls+ampls4+ampls3), axis=0)
In [358]:
fig = plt.figure(figsize=(6, 6))

im = plt.imshow(ampl_agg, vmax=5, vmin=0)
label_plot(T1, T3, T4)
plt.title('Three nodes with perfectly synchronized clocks up to phase.')
Out[358]:
Text(0.5, 1.0, 'Three nodes with perfectly synchronized clocks up to phase.')
In [361]:
fig = plt.figure(figsize=(6, 6))
gain = gain_max(ampl_agg, ampl_agg_baseline,ampl_agg_baseline4,ampl_agg_baseline3)
im = plt.imshow(gain, **gain_kwargs)
label_plot(T1, T3, T4)
plt.title('Gain of using 3 nodes over the best of 3 signals.\nPerfect clocks.')
Out[361]:
Text(0.5, 1.0, 'Gain of using 3 nodes over the best of 3 signals.\nPerfect clocks.')
In [314]:
import tqdm.notebook as tqdm

frames = 50
pbar = tqdm.tqdm(total=frames)
fig = plt.figure(figsize=(10, 10))

gain = gain_max(ampl_agg, ampl_agg_baseline,ampl_agg_baseline4,ampl_agg_baseline3)
im = plt.imshow(gain, **gain_kwargs)
label_plot(T1, T3, T4)
plt.xlabel('Meters')
plt.ylabel('Meters')
plt.title('Gain of using 3 nodes over the best signal sequentially')
plt.suptitle('Nodes have some clock drift (imagine 5sec is .5us)')

def animate(i):
    perc = i / frames
    
    t3_off = 0.4/Fc + perc*(1.2/Fc) 
    t4_off = 0.1/Fc + perc*(3/Fc) 
    
    ampls3 = np.array([ampl_f(dT3, ti+t3_off) for ti in t])
    ampls4 = np.array([ampl_f(dT4, ti+t4_off) for ti in t])

    ampl_agg = np.mean(np.abs(ampls+ampls3+ampls4), axis=0)
    gain = gain_max(ampl_agg, ampl_agg_baseline,ampl_agg_baseline4,ampl_agg_baseline3)

    im.set_data(gain)
    
    pbar.update(1)
    return (im,)

anim = animation.FuncAnimation(fig, animate,
                               frames=frames, interval=200, blit=True)
anim
Out[314]:
Your browser does not support the video tag.
In [ ]: