1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# This is the main program that
# - runs rtl_sdr to record files containing samples
# - runs correlate_with_ref to calculate the CIR
# - runs a webserver to present the information
#
# Copyright (C) 2016
# Matthias P. Braendli, matthias.braendli@mpb.li
# http://www.opendigitalradio.org
# Licence: The MIT License, see LICENCE file
import sys
from bottle import route, run, template, static_file, request
import subprocess
import time
import datetime
import multiprocessing as mp
import correlate_with_ref
import shlex
import argparse
# The record and correlate tasks run in alternance.
# Maybe later we want to run them simultaneously in a small
# pipeline.
class RTLSDR_CIR_Runner(mp.Process):
def __init__(self, options, iq_file, fig_file):
"""Initialise a new runner, which runs rtl_sdr
that will save to iq_file, and run the CIR analysis
that will save to fig_file.
options must contain freq, rate and samps fields"""
mp.Process.__init__(self)
self.events = mp.Queue()
self.freq = float(options.freq)
self.rate = int(options.rate)
self.samps = int(options.samps)
self.gain = float(options.gain)
self.iq_file = iq_file
self.fig_file = fig_file
def stop(self):
self.events.put("quit")
def run(self):
while True:
time.sleep(1)
try:
self.do_one_cir_run()
except Exception as e:
print("Exception occurred: {}".format(e))
try:
ev = self.events.get_nowait()
if ev == "quit":
break
except mp.queues.Empty:
pass
def do_one_cir_run(self):
# Build the rtl_sdr command line from the settings in config
rtl_sdr_cmdline = shlex.split("rtl_sdr -f {} -s {} -g {} -S -".format(self.freq, self.rate, self.gain))
dd_cmdline = shlex.split("dd of={} bs=2 count={}".format(self.iq_file, self.samps))
# To avoid calling the shell, we do the pipe between rtlsdr and dd using Popen
rtlsdr_proc = subprocess.Popen(rtl_sdr_cmdline, stdout=subprocess.PIPE)
dd_proc = subprocess.Popen(dd_cmdline, stdin=rtlsdr_proc.stdout)
# close our connection to the pipe so that rtlsdr gets the SIGPIPE
rtlsdr_proc.stdout.close()
dd_proc.communicate()
dd_proc.wait()
rtlsdr_proc.wait()
# The RTLSDR outputs u8 format
print("Starting correlation")
cir_corr = correlate_with_ref.CIR_Correlate(self.iq_file, "u8")
title = "Correlation on {}kHz done at {}".format(
int(self.freq / 1000),
datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S"))
cir_corr.plot(self.fig_file, title)
@route('/')
def index():
return template('index',
freq = cli_args.freq,
rate = cli_args.rate,
gain = cli_args.gain,
fig_file = FIG_FILE)
@route('/static/<filename:path>')
def send_static(filename):
return static_file(filename, root='./static')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='DAB Channel Impulse Measurement for RTL-SDR')
# Options for the webserver
parser.add_argument('--host', default='127.0.0.1', help='socket host (default: 127.0.0.1)',required=False)
parser.add_argument('--port', default='8000', help='socket port (default: 8000)',required=False)
# Options for RTLSDR reception
parser.add_argument('--freq', help='Receive frequency', required=True)
parser.add_argument('--samps',
default=10*196608,
help='Number of samples to analyse in one run, one transmission frame at 2048000 samples per second is 196608 samples',
required=False)
parser.add_argument('--gain', default=20, help='Gain setting for rtl_sdr', required=False)
parser.add_argument('--rate', default='2048000', help='Samplerate for RTLSDR receiver (2048000)', required=False)
cli_args = parser.parse_args()
# File to save the recorded IQ file to
IQ_FILE = "static/rtlsdr.iq"
# The figures are saved to a file
FIG_FILE = "static/rtlsdr.svg"
rtlsdr_cir = RTLSDR_CIR_Runner(cli_args, IQ_FILE, FIG_FILE)
rtlsdr_cir.start()
try:
run(host=cli_args.host, port=int(cli_args.port), debug=True, reloader=False)
finally:
rtlsdr_cir.stop()
rtlsdr_cir.join()
|