diff options
author | Max <ikj1234i@yahoo.com> | 2017-05-10 09:45:34 -0400 |
---|---|---|
committer | Max <ikj1234i@yahoo.com> | 2017-05-10 09:45:34 -0400 |
commit | 8f7932224451db4e8aeee5291e78c2ffb69cb353 (patch) | |
tree | f7e8a9a79d99262b0d86ec2b99f6ba59a3b88b02 /op25 | |
parent | 8c98a8be5215db0a6e4c7e23059ef76aff8d55ba (diff) |
add fft and catch exceptions
Diffstat (limited to 'op25')
-rw-r--r-- | op25/gr-op25_repeater/apps/gr_gnuplot.py | 50 | ||||
-rw-r--r-- | op25/gr-op25_repeater/apps/p25_demodulator.py | 3 | ||||
-rwxr-xr-x | op25/gr-op25_repeater/apps/rx.py | 27 | ||||
-rw-r--r-- | op25/gr-op25_repeater/apps/terminal.py | 28 |
4 files changed, 87 insertions, 21 deletions
diff --git a/op25/gr-op25_repeater/apps/gr_gnuplot.py b/op25/gr-op25_repeater/apps/gr_gnuplot.py index 168941e..f4e4942 100644 --- a/op25/gr-op25_repeater/apps/gr_gnuplot.py +++ b/op25/gr-op25_repeater/apps/gr_gnuplot.py @@ -36,9 +36,11 @@ GNUPLOT = '/usr/bin/gnuplot' class wrap_gp(object): def __init__(self, sps=_def_sps): self.sps = sps + self.center_freq = None + self.width = None + self.buf = [] self.attach_gp() - self.buf = [] def attach_gp(self): args = (GNUPLOT, '-noraise') @@ -80,29 +82,51 @@ class wrap_gp(object): self.buf = [] plots.append('"-" with dots') elif mode == 'fft': - ffbuf = np.fft.fft(self.buf) - for b in ffbuf: - s += '%f\n' % (b.real**2 + b.imag**2) + ffbuf = np.fft.fft(self.buf * np.blackman(BUFSZ)) / (0.42 * BUFSZ) + ffbuf = np.fft.fftshift(ffbuf) + for i in xrange(len(ffbuf)): + if self.center_freq and self.width: + f = (self.center_freq - self.width / 2.0) / 1e6 + w = self.width / 1e6 + s += '%f\t%f\n' % (f + i*(w/BUFSZ), 20 * np.log10(np.abs(ffbuf[i]))) + else: + s += '%f\n' % (20 * np.log10(np.abs(ffbuf[i]))) s += 'e\n' self.buf = [] plots.append('"-" with lines') self.buf = [] h= 'set terminal x11 noraise\n' - h+= 'set size square\n' - h += 'set object 1 rectangle from screen 0,0 to screen 1,1 fillcolor rgb"black"\n' + background = 'set object 1 circle from screen 0,0 to screen 1,1 fillcolor rgb"black"\n' h+= 'set key off\n' if mode == 'constellation': + h += background + h+= 'set size square\n' h+= 'set xrange [-1:1]\n' h+= 'set yrange [-1:1]\n' elif mode == 'eye': + h += background h+= 'set yrange [-4:4]\n' elif mode == 'symbol': + h += background h+= 'set yrange [-4:4]\n' + elif mode == 'fft': + h+= 'set yrange [-100:0]\n' + h+= 'set grid\n' + if self.center_freq: + h += 'set title "%f"\n' % (self.center_freq / 1e6) dat = '%splot %s\n%s' % (h, ','.join(plots), s) self.gp.stdin.write(dat) return consumed + def set_center_freq(self, f): + sys.stderr.write('set_center_freq: %s\n' % f) + self.center_freq = f + + def set_width(self, w): + sys.stderr.write('set_width: %f\n' % w) + self.width = w + class eye_sink_f(gr.sync_block): """ """ @@ -152,15 +176,25 @@ class fft_sink_c(gr.sync_block): out_sig=None) self.debug = debug self.gnuplot = wrap_gp() + self.skip = 0 def work(self, input_items, output_items): - in0 = input_items[0] - self.gnuplot.plot(in0, 512, mode='fft') + self.skip += 1 + if self.skip == 50: + self.skip = 0 + in0 = input_items[0] + self.gnuplot.plot(in0, 512, mode='fft') return len(input_items[0]) def kill(self): self.gnuplot.kill() + def set_center_freq(self, f): + self.gnuplot.set_center_freq(f) + + def set_width(self, w): + self.gnuplot.set_width(w) + class symbol_sink_f(gr.sync_block): """ """ diff --git a/op25/gr-op25_repeater/apps/p25_demodulator.py b/op25/gr-op25_repeater/apps/p25_demodulator.py index cca35ab..646d621 100644 --- a/op25/gr-op25_repeater/apps/p25_demodulator.py +++ b/op25/gr-op25_repeater/apps/p25_demodulator.py @@ -296,3 +296,6 @@ class p25_demod_cb(p25_demod_base): elif src == 'mixer': self.connect(self.mixer, sink) self.complex_sink = [self.mixer, sink] + elif src == 'src': + self.connect(self, sink) + self.complex_sink = [self, sink] diff --git a/op25/gr-op25_repeater/apps/rx.py b/op25/gr-op25_repeater/apps/rx.py index 6cf6aaf..fa97a2c 100755 --- a/op25/gr-op25_repeater/apps/rx.py +++ b/op25/gr-op25_repeater/apps/rx.py @@ -33,6 +33,7 @@ import numpy import time import re import json +import traceback try: import Hamlib except: @@ -95,7 +96,7 @@ class p25_rx_block (gr.top_block): parser.add_option("-c", "--calibration", type="eng_float", default=0.0, help="USRP offset or audio IF frequency", metavar="Hz") parser.add_option("-C", "--costas-alpha", type="eng_float", default=0.04, help="value of alpha for Costas loop", metavar="Hz") parser.add_option("-D", "--demod-type", type="choice", default="cqpsk", choices=('cqpsk', 'fsk4'), help="cqpsk | fsk4") - parser.add_option("-P", "--plot-mode", type="choice", default=None, choices=(None, 'constellation', 'symbol', 'datascope'), help="constellation | symbol | datascope") + parser.add_option("-P", "--plot-mode", type="choice", default=None, choices=(None, 'constellation', 'fft', 'symbol', 'datascope'), help="constellation | fft | symbol | datascope") parser.add_option("-f", "--frequency", type="eng_float", default=0.0, help="USRP center frequency", metavar="Hz") parser.add_option("-F", "--ifile", type="string", default=None, help="read input from complex capture file") parser.add_option("-H", "--hamlib-model", type="int", default=None, help="specify model for hamlib") @@ -128,6 +129,7 @@ class p25_rx_block (gr.top_block): self.baseband_input = False self.rtl_found = False self.channel_rate = options.sample_rate + self.fft_sink = None self.src = None if not options.input: @@ -202,10 +204,8 @@ class p25_rx_block (gr.top_block): print 'Ready for GDB to attach (pid = %d)' % (os.getpid(),) raw_input("Press 'Enter' to continue...") - # attach terminal thread self.input_q = gr.msg_queue(10) self.output_q = gr.msg_queue(10) - self.terminal = curses_terminal(self.input_q, self.output_q) # configure specified data source if options.input: @@ -221,6 +221,9 @@ class p25_rx_block (gr.top_block): else: pass + # attach terminal thread + self.terminal = curses_terminal(self.input_q, self.output_q) + # setup common flow graph elements # def __build_graph(self, source, capture_rate): @@ -285,6 +288,12 @@ class p25_rx_block (gr.top_block): self.symbol_sink = symbol_sink_f() self.demod.connect_float(self.symbol_sink) self.kill_sink = self.symbol_sink + elif self.options.plot_mode == 'fft': + self.fft_sink = fft_sink_c() + self.spectrum_decim = filter.rational_resampler_ccf(1, self.options.decim_amt) + self.connect(self.spectrum_decim, self.fft_sink) + self.demod.connect_complex('src', self.spectrum_decim) + self.kill_sink = self.fft_sink elif self.options.plot_mode == 'datascope': assert self.options.demod_type == 'fsk4' ## datascope requires fsk4 demod-type self.eye_sink = eye_sink_f(sps=10) @@ -441,7 +450,11 @@ class p25_rx_block (gr.top_block): return False tune_freq = target_freq + self.options.calibration + self.options.offset r = self.src.set_center_freq(tune_freq) - + + if self.fft_sink: + self.fft_sink.set_center_freq(tune_freq) + self.fft_sink.set_width(self.options.sample_rate) + if r: #self.myform['freq'].set_value(target_freq) # update displayed va #if self.show_debug_info: @@ -628,8 +641,10 @@ if __name__ == "__main__": msg = tb.output_q.delete_head() if tb.process_qmsg(msg): break - except KeyboardInterrupt: - print 'keyboard interrupt' + except: + sys.stderr.write('main: exception occurred\n') + sys.stderr.write('main: exception:\n%s\n' % traceback.format_exc()) + tb.terminal.end_curses() tb.stop() if tb.kill_sink: tb.kill_sink.kill() diff --git a/op25/gr-op25_repeater/apps/terminal.py b/op25/gr-op25_repeater/apps/terminal.py index a32dbe1..46efa1a 100644 --- a/op25/gr-op25_repeater/apps/terminal.py +++ b/op25/gr-op25_repeater/apps/terminal.py @@ -27,6 +27,7 @@ import curses.textpad import time import json import threading +import traceback from gnuradio import gr @@ -39,7 +40,6 @@ class curses_terminal(threading.Thread): self.keep_running = True self.last_update = 0 self.auto_update = True - self.setup_curses() self.current_nac = None self.start() @@ -58,6 +58,12 @@ class curses_terminal(threading.Thread): self.textpad = curses.textpad.Textbox(self.text_win) + def end_curses(self): + try: + curses.endwin() + except: + pass + def do_auto_update(self): UPDATE_INTERVAL = 1 # sec. if not self.auto_update: @@ -104,6 +110,8 @@ class curses_terminal(threading.Thread): if freq: msg = gr.message().make_from_string('set_freq', -2, freq, 0) self.output_q.insert_tail(msg) + elif c == ord('x'): + assert 1 == 0 return False def process_json(self, js): @@ -163,11 +171,17 @@ class curses_terminal(threading.Thread): return False def run(self): - while(self.keep_running): - if self.process_terminal_events(): - break - if self.process_q_events(): - break - curses.endwin() + try: + self.setup_curses() + while(self.keep_running): + if self.process_terminal_events(): + break + if self.process_q_events(): + break + except: + sys.stderr.write('terminal: exception occurred\n') + sys.stderr.write('terminal: exception:\n%s\n' % traceback.format_exc()) + finally: + self.end_curses() msg = gr.message().make_from_string('quit', -2, 0, 0) self.output_q.insert_tail(msg) |