In [1]:
%matplotlib inline
import ephem
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import blackman
from multiprocessing import Pool
import time
# Larger figure size
fig_size = [14, 8]
plt.rcParams['figure.figsize'] = fig_size
c = 299792458
line1 = "FO-29"
line2 = "1 24278U 96046B 17296.90226955 -.00000046 +00000-0 -99197-5 0 9993"
line3 = "2 24278 098.5410 162.9058 0350559 003.9820 356.3983 13.53079989046036"
sat = ephem.readtle(line1, line2, line3)
ea4gpz_qth = ephem.Observer()
ea4gpz_qth.lat, ea4gpz_qth.lon, ea4gpz_qth.elevation = '40.5962', '-3.6963', 700
start = ephem.Date('2017/10/23 20:26:00')
t_step = 1e-2
ts = np.arange(0, 990, t_step)
f_down = 435.850e6
def computeDoppler(tles, freq, delay = 0.0, qth = ea4gpz_qth):
dopplers = np.empty_like(ts)
for j in range(len(ts)):
qth.date = start + ts[j]*ephem.second - delay*ephem.second
tles.compute(qth)
dopplers[j] = -tles.range_velocity/c*freq
return dopplers
In [2]:
downlink_doppler = computeDoppler(sat, f_down)
In [3]:
wav_iq = np.memmap('/home/daniel/fo29ft8.wav', dtype=np.int16, mode='r', offset=0x28)
samp_rate = 192000
In [4]:
def oscillator(doppler, length, signal_start = 0):
phase = 0.0
x = np.empty(length, dtype=np.complex)
for j in range(length):
index = int((signal_start + j/samp_rate)/t_step)
freq = -doppler[index]
phase += 2*np.pi*freq/samp_rate
phase = np.fmod(phase + np.pi, 2*np.pi) - np.pi
x[j] = np.exp(1j*phase)
return x
In [10]:
N = 4096
#N = 1024
w = blackman(N)
def process_fft(chunk):
piece = wav_iq[chunk * N : (chunk + 2) * N]
x = piece[::2] + 1j * piece[1::2]
x = x - np.average(x) # remove DC
o = oscillator(downlink_doppler, length = N, signal_start = chunk * N//2 / samp_rate)
f = np.fft.fftshift(np.fft.fft(x * o * w))
return np.real(f * np.conj(f))
In [11]:
total_chunks = len(wav_iq) // N - 1
lines = 4096
#lines = 990
averaging = total_chunks // lines
In [12]:
def process_line(line):
chunks = range(line*averaging, (line+1)*averaging)
return 10*np.log10(np.average(np.array([process_fft(chunk) for chunk in chunks]), axis = 0))
In [13]:
t1 = time.perf_counter()
with Pool() as p:
waterfall = np.array(p.map(process_line, range(lines)))
t2 = time.perf_counter()
print(t2 - t1)
In [16]:
plt.imsave('fo29-waterfall.png', waterfall, cmap = 'viridis', vmin=52, vmax = 80)