End sem 7; week 2 winter session 2025
BIN
7th-Semester-Fall-2024/ECOMMS/final-project/antenna-setup.jpg
Normal file
After Width: | Height: | Size: 102 KiB |
BIN
7th-Semester-Fall-2024/ECOMMS/final-project/antenna-setup.png
Normal file
After Width: | Height: | Size: 520 KiB |
80
7th-Semester-Fall-2024/ECOMMS/final-project/bfm_demod.py
Normal file
@ -0,0 +1,80 @@
|
||||
import numpy as np
|
||||
import scipy as sp
|
||||
import sounddevice as sd
|
||||
from threading import Thread
|
||||
import time
|
||||
import queue
|
||||
|
||||
import matplotlib.animation as anim
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from rtlsdr import RtlSdr
|
||||
import asyncio
|
||||
import dsp
|
||||
|
||||
class BfmDemod:
|
||||
def __init__(self, sdr:RtlSdr, stream:sd.OutputStream, audio_sample_rate:int=48000, num_samples:int=8192):
|
||||
self.sdr = sdr
|
||||
self.stream = stream
|
||||
self.audio_sample_rate = audio_sample_rate
|
||||
self.buffer = queue.Queue(10)
|
||||
self.num_samples = num_samples
|
||||
|
||||
self.fig, self.ax = plt.subplots()
|
||||
self.duration = self.num_samples/self.sdr.sample_rate
|
||||
#lower_extent = self.sdr.center_freq - self.sdr.sample_rate/2
|
||||
#upper_extent = self.sdr.center_freq + self.sdr.sample_rate/2
|
||||
|
||||
#self.fig, self.ax = plt.subplots()
|
||||
#self.ax.xlabel = "Frequency [Hz]"
|
||||
#self.ax.ylabel = "Amplitude [dB]"
|
||||
#self.ax.set_xlim(left=lower_extent, right=upper_extent)
|
||||
|
||||
# Plot the spectrum of the incoming samples
|
||||
def _spectrum_update(self, frame):
|
||||
self.ax.clear()
|
||||
if self.buffer is not None:
|
||||
spectrum = np.abs(sp.fft.fftshift(sp.fft.fft(self.buffer)))**2
|
||||
spectrum_db = dsp.db(spectrum)
|
||||
self.ax.plot(spectrum_db)
|
||||
return self.ax,
|
||||
|
||||
# Begin reading and demodulation
|
||||
async def start(self):
|
||||
self.stream.start()
|
||||
plt.ion()
|
||||
self.scatter = self.ax.scatter([], [])
|
||||
plt.show()
|
||||
|
||||
async for samples in self.sdr.stream(self.num_samples):
|
||||
message = dsp.quad_demod(samples)
|
||||
message = dsp.lowpass(message, 16E3, self.sdr.sample_rate)
|
||||
message /= np.max(np.abs(message))
|
||||
|
||||
time = len(message)/self.sdr.sample_rate
|
||||
num_samples = int(time*self.audio_sample_rate)
|
||||
message = sp.signal.resample(message, num_samples)
|
||||
|
||||
message = message.astype(np.float32)
|
||||
#self.stream.write(message)
|
||||
|
||||
spectrum = np.abs(sp.fft.fftshift(sp.fft.fft(samples)))**2
|
||||
spectrum_db = dsp.db(spectrum)
|
||||
self.ax.clear()
|
||||
self.ax.plot(spectrum_db)
|
||||
|
||||
self.ax.relim()
|
||||
self.ax.autoscale_view()
|
||||
|
||||
self.fig.canvas.draw()
|
||||
self.fig.canvas.flush_events()
|
||||
|
||||
await sdr.stop()
|
||||
|
||||
|
||||
def stop(self):
|
||||
self.sdr.cancel_read_async()
|
||||
self.reader.join()
|
||||
self.stream.stop()
|
||||
|
||||
|
37
7th-Semester-Fall-2024/ECOMMS/final-project/dsp.py
Normal file
@ -0,0 +1,37 @@
|
||||
import scipy as sp
|
||||
import numpy as np
|
||||
|
||||
|
||||
|
||||
def chunk_samples(samples, num_rows):
|
||||
return samples.reshape((samples.shape[0]//num_rows, num_rows))
|
||||
|
||||
|
||||
def db(x):
|
||||
return 10*np.log10(x)
|
||||
|
||||
|
||||
def quad_demod(samples):
|
||||
return 0.5*np.angle(samples[:-1] * np.conj(samples[1:]))
|
||||
|
||||
|
||||
def lowpass(data, f_cutoff, f_s):
|
||||
nyq = 0.5*f_s
|
||||
normal_cutoff = f_cutoff/nyq
|
||||
b, a = sp.signal.butter(2, normal_cutoff, btype="low", analog=False)
|
||||
y = sp.signal.lfilter(b, a, data)
|
||||
return y
|
||||
|
||||
|
||||
def sdr_bandpass(data, f_pass, f_cutoff, extent_MHz):
|
||||
|
||||
lower_extent = extent_MHz[0]*1E6
|
||||
upper_extent = extent_MHz[1]*1E6
|
||||
extent_range = upper_extent - lower_extent
|
||||
|
||||
normal_pass = (f_pass - lower_extent)/extent_range
|
||||
normal_cutoff = (f_cutoff - lower_extent)/extent_range
|
||||
|
||||
b, a = sp.signal.butter(2, (normal_pass, normal_cutoff), btype="bandpass", analog=False)
|
||||
y = sp.signal.lfilter(b, a, data)
|
||||
return y
|
BIN
7th-Semester-Fall-2024/ECOMMS/final-project/fm.wav
Normal file
58
7th-Semester-Fall-2024/ECOMMS/final-project/gfsk_demod.py
Normal file
@ -0,0 +1,58 @@
|
||||
import numpy as np
|
||||
import scipy as sp
|
||||
from threading import Thread
|
||||
import time
|
||||
import queue
|
||||
|
||||
import matplotlib.animation as animation
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from rtlsdr import RtlSdr
|
||||
|
||||
import dsp
|
||||
|
||||
|
||||
class GFSKDemod:
|
||||
def __init__(self, sdr:RtlSdr, baud_rate:int=9600, num_samples:int=512):
|
||||
self.sdr = sdr
|
||||
self.baud_rate = baud_rate
|
||||
self.num_samples = num_samples
|
||||
self.fig, self.ax = plt.subplots()
|
||||
|
||||
self.duration = self.num_samples/self.sdr.sample_rate
|
||||
|
||||
# Demodulate an update the sound buffer
|
||||
def _demod(self, samples):
|
||||
message = dsp.quad_demod(samples)
|
||||
message = dsp.lowpass(message, 16E3, self.sdr.sample_rate)
|
||||
#message /= np.max(np.abs(message))
|
||||
#message = message.astype(np.float32)
|
||||
time = len(message)*self.sdr.sample_rate
|
||||
t = np.linspace(0,time,len(message))
|
||||
return t, message
|
||||
|
||||
|
||||
# Begin reading and demodulation
|
||||
async def start(self):
|
||||
plt.ion()
|
||||
plt.show()
|
||||
|
||||
async for samples in self.sdr.stream(self.num_samples):
|
||||
self.ax.clear()
|
||||
t, message = self._demod(samples)
|
||||
|
||||
#num_samples = int(len(message)*self.resample_rate/self.sdr.sample_rate)
|
||||
#message = sp.signal.resample(message, num_samples)
|
||||
|
||||
#t = np.linspace(0,1,len(message))*t[:-1]
|
||||
#self.ax.plot(t,message)
|
||||
#spectrum = np.abs(sp.fft.fftshift(sp.fft.fft(samples)))**2
|
||||
#spectrum_db = dsp.db(spectrum)
|
||||
#self.ax.plot(spectrum_db)
|
||||
|
||||
self.fig.canvas.draw()
|
||||
self.fig.canvas.flush_events()
|
||||
|
||||
|
||||
def stop(self):
|
||||
self.sdr.cancel_read_async()
|
After Width: | Height: | Size: 1.9 MiB |
After Width: | Height: | Size: 3.2 MiB |
After Width: | Height: | Size: 1.5 MiB |
After Width: | Height: | Size: 1.5 MiB |
After Width: | Height: | Size: 1.6 MiB |
20
7th-Semester-Fall-2024/ECOMMS/final-project/sd_test.py
Normal file
@ -0,0 +1,20 @@
|
||||
import numpy as np
|
||||
import sounddevice as sd
|
||||
import scipy as sp
|
||||
from scipy.io import wavfile
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
sample_rate, wav_data = wavfile.read("fm.wav")
|
||||
time = len(wav_data)/sample_rate
|
||||
|
||||
new_sample_rate = 48E3
|
||||
num_samples = int(time*new_sample_rate)
|
||||
plt.subplot(211)
|
||||
plt.plot(wav_data)
|
||||
wav_data = sp.signal.resample(wav_data, num_samples)
|
||||
plt.subplot(212)
|
||||
plt.plot(wav_data)
|
||||
plt.show()
|
||||
|
||||
sd.play(wav_data, samplerate=new_sample_rate)
|
||||
sd.wait()
|
@ -1,13 +1,31 @@
|
||||
from rtlsdr import RtlSdr
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import scipy as sp
|
||||
#from rtlsdr.rtlsdrtcp.client import RtlSdrTcpClient
|
||||
import asyncio
|
||||
from rtlsdr import RtlSdr
|
||||
from bfm_demod import BfmDemod
|
||||
from gfsk_demod import GFSKDemod
|
||||
import sounddevice as sd
|
||||
import numpy as np
|
||||
|
||||
async def streaming():
|
||||
|
||||
def main():
|
||||
#sdr = RtlSdrTcpClient(hostname='localhost', port=12345)
|
||||
sdr = RtlSdr()
|
||||
|
||||
async for samples in sdr.stream():
|
||||
|
||||
await sdr.stop()
|
||||
sdr.set_sample_rate(2.048E6)
|
||||
sdr.set_center_freq(434.55E6)
|
||||
sdr.set_freq_correction(60)
|
||||
sdr.set_gain("auto")
|
||||
|
||||
stream = sd.OutputStream(samplerate=48E3, dtype=np.float32, channels=1)
|
||||
|
||||
sink = GFSKDemod(sdr=sdr)
|
||||
#sink = BfmDemod(sdr=sdr, stream=stream)
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(sink.start())
|
||||
|
||||
sdr.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
27
7th-Semester-Fall-2024/ECOMMS/final-project/spectrum.py
Normal file
@ -0,0 +1,27 @@
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import scipy as sp
|
||||
from rtlsdr import RtlSdr
|
||||
import asyncio
|
||||
import dsp
|
||||
|
||||
class Spectrum(Display):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def put(self, samples):
|
||||
self.buffer.put(samples)
|
||||
|
||||
def update(self):
|
||||
samples = self.buffer.get()
|
||||
spectrum = np.abs(sp.fft.fftshift(sp.fft.fft(samples)))**2
|
||||
spectrum_db = dsp.db(spectrum)
|
||||
self.ax.clear()
|
||||
self.ax.plot(spectrum_db)
|
||||
|
||||
self.ax.relim()
|
||||
self.ax.autoscale_view()
|
||||
|
||||
self.fig.canvas.draw()
|
||||
self.fig.canvas.flush_events()
|
||||
|