diff options
| author | Yuval Adam <_@yuv.al> | 2018-03-26 19:47:08 +0200 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2018-03-26 19:47:08 +0200 |
| commit | a340c14bdf9e877b6496d0c0df034b1b64e50713 (patch) | |
| tree | 4267e664beeafb3baa4ef4e80553b298b06663eb /numpy_fm_demod.py | |
| parent | 73d1989f569ebfa5908ac1fce4bb1d0c67703b98 (diff) | |
Finalize demod
Diffstat (limited to 'numpy_fm_demod.py')
| -rw-r--r-- | numpy_fm_demod.py | 46 |
1 files changed, 42 insertions, 4 deletions
diff --git a/numpy_fm_demod.py b/numpy_fm_demod.py index fb2c46b..44d232d 100644 --- a/numpy_fm_demod.py +++ b/numpy_fm_demod.py @@ -10,7 +10,7 @@ class NumpyFmDemod(): Based on the great tutorial by Fraida Fund https://witestlab.poly.edu/blog/capture-and-decode-fm-radio/ ''' - def __init__(frequency, sample_rate=1140000, sample_count=8192000, dc_offset=250000): + def __init__(self, frequency, sample_rate=1140000, sample_count=8192000, dc_offset=250000): self.freq = int(frequency) self.sample_rate = sample_rate self.sample_count = sample_count @@ -21,12 +21,50 @@ class NumpyFmDemod(): sdr.sample_rate = self.sample_rate sdr.center_freq = self.freq - self.dc_offset sdr.gain = 'auto' - - samples = sdr.read_samples(self.sample_count) + self.samples = sdr.read_samples(self.sample_count) sdr.close() - self.raw_samples = np.array(samples).astype('complex64') + def demod(self): + # Convert samples to a numpy array + x1 = np.array(self.samples).astype('complex64') + + # Mix the samples back down to avoid DC offset + fc1 = np.exp(-1.0j * 2.0 * np.pi * self.dc_offset / self.sample_rate * np.arange(len(x1))) + x2 = x1 * fc1 + + # Downsample the signal to catch only the target frequency + BANDWIDTH = 200000 # wideband FM signal is always 200kHz + TAPS = 64 + + # Use Remez algorithm to design filter coefficients + lpf = signal.remez(TAPS, [0, BANDWIDTH, BANDWIDTH + (self.sample_rate / 2 - BANDWIDTH) / 4, self.sample_rate / 2], [1,0], Hz=self.sample_rate) + x3 = signal.lfilter(lpf, 1.0, x2) + + decimation_rate = int(self.sample_rate / BANDWIDTH) + x4 = x3[0::decimation_rate] + decimated_rate = self.sample_rate / decimation_rate + + y5 = x4[1:] * np.conj(x4[:-1]) + x5 = np.angle(y5) + + d = decimated_rate * 75e-6 # Calculate the # of samples to hit the -3dB point + x = np.exp(-1/d) # Calculate the decay between each sample + b = [1-x] # Create the filter coefficients + a = [1,-x] + x6 = signal.lfilter(b,a,x5) + + audio_freq = 44100.0 + dec_audio = int(decimated_rate / audio_freq) + Fs_audio = decimated_rate / dec_audio + + x7 = signal.decimate(x6, dec_audio) + + x7 *= 10000 / np.max(np.abs(x7)) + x7.astype('int16').tofile('wbfm-mono.raw') + def run(self): + self.capture_samples() + self.demod() if __name__ == '__main__': nfd = NumpyFmDemod(frequency=96.3e6) |
