Improve CW flowgraph

This commit is contained in:
Manolis Surligas 2017-04-25 21:28:55 +03:00
parent 2e095e9976
commit 800d0710f9
2 changed files with 1167 additions and 56 deletions

File diff suppressed because it is too large Load Diff

View File

@ -5,30 +5,67 @@
# Title: CW Decoder # Title: CW Decoder
# Author: Manolis Surligas (surligas@gmail.com) # Author: Manolis Surligas (surligas@gmail.com)
# Description: A CW (Morse) Decoder # Description: A CW (Morse) Decoder
# Generated: Sat Apr 8 22:15:03 2017 # Generated: Tue Apr 25 21:28:22 2017
################################################## ##################################################
if __name__ == '__main__':
import ctypes
import sys
if sys.platform.startswith('linux'):
try:
x11 = ctypes.cdll.LoadLibrary('libX11.so')
x11.XInitThreads()
except:
print "Warning: failed to XInitThreads()"
from PyQt4 import Qt
from gnuradio import analog from gnuradio import analog
from gnuradio import blocks from gnuradio import blocks
from gnuradio import eng_notation from gnuradio import eng_notation
from gnuradio import filter from gnuradio import filter
from gnuradio import gr from gnuradio import gr
from gnuradio import qtgui
from gnuradio.eng_option import eng_option from gnuradio.eng_option import eng_option
from gnuradio.filter import firdes from gnuradio.filter import firdes
from optparse import OptionParser from optparse import OptionParser
import osmosdr import osmosdr
import satnogs import satnogs
import sip
import sys
import time import time
from gnuradio import qtgui
class satnogs_cw_decoder(gr.top_block): class satnogs_cw_decoder(gr.top_block, Qt.QWidget):
def __init__(self, doppler_correction_per_sec=1000, file_path='test.txt', lo_offset=100e3, ppm=0, rigctl_port=4532, rx_freq=100e6, rx_sdr_device='usrpb200', waterfall_file_path='/tmp/waterfall.dat', wpm=22): def __init__(self, cw_offset=700, doppler_correction_per_sec=1000, file_path='test.txt', lo_offset=100e3, ppm=0, rigctl_port=4532, rx_freq=100e6, rx_sdr_device='usrpb200', waterfall_file_path='/tmp/waterfall.dat', wpm=20):
gr.top_block.__init__(self, "CW Decoder") gr.top_block.__init__(self, "CW Decoder")
Qt.QWidget.__init__(self)
self.setWindowTitle("CW Decoder")
qtgui.util.check_set_qss()
try:
self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc'))
except:
pass
self.top_scroll_layout = Qt.QVBoxLayout()
self.setLayout(self.top_scroll_layout)
self.top_scroll = Qt.QScrollArea()
self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame)
self.top_scroll_layout.addWidget(self.top_scroll)
self.top_scroll.setWidgetResizable(True)
self.top_widget = Qt.QWidget()
self.top_scroll.setWidget(self.top_widget)
self.top_layout = Qt.QVBoxLayout(self.top_widget)
self.top_grid_layout = Qt.QGridLayout()
self.top_layout.addLayout(self.top_grid_layout)
self.settings = Qt.QSettings("GNU Radio", "satnogs_cw_decoder")
self.restoreGeometry(self.settings.value("geometry").toByteArray())
################################################## ##################################################
# Parameters # Parameters
################################################## ##################################################
self.cw_offset = cw_offset
self.doppler_correction_per_sec = doppler_correction_per_sec self.doppler_correction_per_sec = doppler_correction_per_sec
self.file_path = file_path self.file_path = file_path
self.lo_offset = lo_offset self.lo_offset = lo_offset
@ -43,21 +80,112 @@ class satnogs_cw_decoder(gr.top_block):
# Variables # Variables
################################################## ##################################################
self.samp_rate_rx = samp_rate_rx = satnogs.hw_rx_settings[rx_sdr_device]['samp_rate'] self.samp_rate_rx = samp_rate_rx = satnogs.hw_rx_settings[rx_sdr_device]['samp_rate']
self.xlating_decimation = xlating_decimation = 5
self.xlate_filter_taps = xlate_filter_taps = firdes.low_pass(1, samp_rate_rx, 125000, 25000, firdes.WIN_HAMMING, 6.76) self.xlate_filter_taps = xlate_filter_taps = firdes.low_pass(1, samp_rate_rx, 125000, 25000, firdes.WIN_HAMMING, 6.76)
self.taps = taps = firdes.low_pass(12.0, samp_rate_rx, 100e3, 60000, firdes.WIN_HAMMING, 6.76) self.taps = taps = firdes.low_pass(12.0, samp_rate_rx, 100e3, 60000, firdes.WIN_HAMMING, 6.76)
self.ndelay = ndelay = 100 self.ndelay = ndelay = 250
self.filter_rate = filter_rate = 100000 self.lpf_decimation = lpf_decimation = 5
################################################## ##################################################
# Blocks # Blocks
################################################## ##################################################
self.satnogs_tcp_rigctl_msg_source_0 = satnogs.tcp_rigctl_msg_source("127.0.0.1", rigctl_port, False, 1000, 1500) self.satnogs_tcp_rigctl_msg_source_0 = satnogs.tcp_rigctl_msg_source("127.0.0.1", rigctl_port, False, 1000, 1500)
self.satnogs_multi_format_msg_sink_0 = satnogs.multi_format_msg_sink(0, True, False, 'test.txt') self.satnogs_multi_format_msg_sink_0 = satnogs.multi_format_msg_sink(0, True, True, 'test.txt')
self.satnogs_morse_decoder_0 = satnogs.morse_decoder(ord('#')) self.satnogs_morse_decoder_0 = satnogs.morse_decoder(ord('#'))
self.satnogs_cw_to_symbol_0 = satnogs.cw_to_symbol(int(samp_rate_rx/filter_rate) / 5, 2e6, 0.9, wpm, False) self.satnogs_cw_to_symbol_0 = satnogs.cw_to_symbol(int((samp_rate_rx/xlating_decimation)/lpf_decimation), 300000, 0.9, wpm, False)
self.satnogs_coarse_doppler_correction_cc_0 = satnogs.coarse_doppler_correction_cc(rx_freq, samp_rate_rx) self.satnogs_coarse_doppler_correction_cc_0 = satnogs.coarse_doppler_correction_cc(rx_freq, samp_rate_rx)
self.qtgui_time_sink_x_0 = qtgui.time_sink_f(
1024, #size
int((samp_rate_rx/xlating_decimation)/lpf_decimation), #samp_rate
"", #name
1 #number of inputs
)
self.qtgui_time_sink_x_0.set_update_time(0.10)
self.qtgui_time_sink_x_0.set_y_axis(-1, 1)
self.qtgui_time_sink_x_0.set_y_label('Amplitude', "")
self.qtgui_time_sink_x_0.enable_tags(-1, True)
self.qtgui_time_sink_x_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, 0, "")
self.qtgui_time_sink_x_0.enable_autoscale(False)
self.qtgui_time_sink_x_0.enable_grid(False)
self.qtgui_time_sink_x_0.enable_axis_labels(True)
self.qtgui_time_sink_x_0.enable_control_panel(False)
if not True:
self.qtgui_time_sink_x_0.disable_legend()
labels = ['', '', '', '', '',
'', '', '', '', '']
widths = [1, 1, 1, 1, 1,
1, 1, 1, 1, 1]
colors = ["blue", "red", "green", "black", "cyan",
"magenta", "yellow", "dark red", "dark green", "blue"]
styles = [1, 1, 1, 1, 1,
1, 1, 1, 1, 1]
markers = [-1, -1, -1, -1, -1,
-1, -1, -1, -1, -1]
alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
1.0, 1.0, 1.0, 1.0, 1.0]
for i in xrange(1):
if len(labels[i]) == 0:
self.qtgui_time_sink_x_0.set_line_label(i, "Data {0}".format(i))
else:
self.qtgui_time_sink_x_0.set_line_label(i, labels[i])
self.qtgui_time_sink_x_0.set_line_width(i, widths[i])
self.qtgui_time_sink_x_0.set_line_color(i, colors[i])
self.qtgui_time_sink_x_0.set_line_style(i, styles[i])
self.qtgui_time_sink_x_0.set_line_marker(i, markers[i])
self.qtgui_time_sink_x_0.set_line_alpha(i, alphas[i])
self._qtgui_time_sink_x_0_win = sip.wrapinstance(self.qtgui_time_sink_x_0.pyqwidget(), Qt.QWidget)
self.top_layout.addWidget(self._qtgui_time_sink_x_0_win)
self.qtgui_freq_sink_x_0 = qtgui.freq_sink_c(
1024, #size
firdes.WIN_BLACKMAN_hARRIS, #wintype
0, #fc
samp_rate_rx/xlating_decimation, #bw
"", #name
1 #number of inputs
)
self.qtgui_freq_sink_x_0.set_update_time(0.10)
self.qtgui_freq_sink_x_0.set_y_axis(-140, 10)
self.qtgui_freq_sink_x_0.set_y_label('Relative Gain', 'dB')
self.qtgui_freq_sink_x_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, 0.0, 0, "")
self.qtgui_freq_sink_x_0.enable_autoscale(False)
self.qtgui_freq_sink_x_0.enable_grid(False)
self.qtgui_freq_sink_x_0.set_fft_average(1.0)
self.qtgui_freq_sink_x_0.enable_axis_labels(True)
self.qtgui_freq_sink_x_0.enable_control_panel(False)
if not True:
self.qtgui_freq_sink_x_0.disable_legend()
if "complex" == "float" or "complex" == "msg_float":
self.qtgui_freq_sink_x_0.set_plot_pos_half(not True)
labels = ['', '', '', '', '',
'', '', '', '', '']
widths = [1, 1, 1, 1, 1,
1, 1, 1, 1, 1]
colors = ["blue", "red", "green", "black", "cyan",
"magenta", "yellow", "dark red", "dark green", "dark blue"]
alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
1.0, 1.0, 1.0, 1.0, 1.0]
for i in xrange(1):
if len(labels[i]) == 0:
self.qtgui_freq_sink_x_0.set_line_label(i, "Data {0}".format(i))
else:
self.qtgui_freq_sink_x_0.set_line_label(i, labels[i])
self.qtgui_freq_sink_x_0.set_line_width(i, widths[i])
self.qtgui_freq_sink_x_0.set_line_color(i, colors[i])
self.qtgui_freq_sink_x_0.set_line_alpha(i, alphas[i])
self._qtgui_freq_sink_x_0_win = sip.wrapinstance(self.qtgui_freq_sink_x_0.pyqwidget(), Qt.QWidget)
self.top_layout.addWidget(self._qtgui_freq_sink_x_0_win)
self.osmosdr_source_0 = osmosdr.source( args="numchan=" + str(1) + " " + satnogs.hw_rx_settings[rx_sdr_device]['dev_arg'] ) self.osmosdr_source_0 = osmosdr.source( args="numchan=" + str(1) + " " + satnogs.hw_rx_settings[rx_sdr_device]['dev_arg'] )
self.osmosdr_source_0.set_sample_rate(samp_rate_rx) self.osmosdr_source_0.set_sample_rate(samp_rate_rx)
self.osmosdr_source_0.set_center_freq(rx_freq - lo_offset, 0) self.osmosdr_source_0.set_center_freq(rx_freq - lo_offset, 0)
@ -71,17 +199,17 @@ class satnogs_cw_decoder(gr.top_block):
self.osmosdr_source_0.set_antenna(satnogs.hw_rx_settings[rx_sdr_device]['antenna'], 0) self.osmosdr_source_0.set_antenna(satnogs.hw_rx_settings[rx_sdr_device]['antenna'], 0)
self.osmosdr_source_0.set_bandwidth(samp_rate_rx, 0) self.osmosdr_source_0.set_bandwidth(samp_rate_rx, 0)
self.low_pass_filter_0 = filter.fir_filter_ccf(5, firdes.low_pass( self.low_pass_filter_0 = filter.fir_filter_ccf(lpf_decimation, firdes.low_pass(
1, int(samp_rate_rx/filter_rate), 2e3, 500, firdes.WIN_HAMMING, 6.76)) 1, samp_rate_rx/xlating_decimation, 2e3, 500, firdes.WIN_HAMMING, 6.76))
self.freq_xlating_fir_filter_xxx_0 = filter.freq_xlating_fir_filter_ccc(int(samp_rate_rx/filter_rate), (xlate_filter_taps), lo_offset, samp_rate_rx) self.freq_xlating_fir_filter_xxx_0 = filter.freq_xlating_fir_filter_ccc(xlating_decimation, (xlate_filter_taps), lo_offset - cw_offset, samp_rate_rx)
self.fir_filter_xxx_0 = filter.fir_filter_ccc(1, ([1,] * ndelay)) self.fir_filter_xxx_0 = filter.fir_filter_ccc(1, ([1,] * ndelay))
self.fir_filter_xxx_0.declare_sample_delay(0) self.fir_filter_xxx_0.declare_sample_delay(0)
self.blocks_multiply_conjugate_cc_0 = blocks.multiply_conjugate_cc(1) self.blocks_multiply_conjugate_cc_0 = blocks.multiply_conjugate_cc(1)
self.blocks_moving_average_xx_0 = blocks.moving_average_ff(ndelay, 1, 4000) self.blocks_moving_average_xx_0 = blocks.moving_average_ff(ndelay, 1, 4000)
self.blocks_delay_0 = blocks.delay(gr.sizeof_gr_complex*1, ndelay) self.blocks_delay_0 = blocks.delay(gr.sizeof_gr_complex*1, ndelay)
self.blocks_complex_to_mag_squared_0 = blocks.complex_to_mag_squared(1) self.blocks_complex_to_mag_squared_0 = blocks.complex_to_mag_squared(1)
self.analog_agc2_xx_0 = analog.agc2_cc(0.01, 0.001, 1.0, 1.0) self.analog_agc2_xx_0 = analog.agc2_cc(0.1, 0.8, 0.6, 0.0)
self.analog_agc2_xx_0.set_max_gain(65536) self.analog_agc2_xx_0.set_max_gain(1e3)
################################################## ##################################################
# Connections # Connections
@ -93,14 +221,28 @@ class satnogs_cw_decoder(gr.top_block):
self.connect((self.analog_agc2_xx_0, 0), (self.blocks_multiply_conjugate_cc_0, 0)) self.connect((self.analog_agc2_xx_0, 0), (self.blocks_multiply_conjugate_cc_0, 0))
self.connect((self.blocks_complex_to_mag_squared_0, 0), (self.blocks_moving_average_xx_0, 0)) self.connect((self.blocks_complex_to_mag_squared_0, 0), (self.blocks_moving_average_xx_0, 0))
self.connect((self.blocks_delay_0, 0), (self.blocks_multiply_conjugate_cc_0, 1)) self.connect((self.blocks_delay_0, 0), (self.blocks_multiply_conjugate_cc_0, 1))
self.connect((self.blocks_moving_average_xx_0, 0), (self.qtgui_time_sink_x_0, 0))
self.connect((self.blocks_moving_average_xx_0, 0), (self.satnogs_cw_to_symbol_0, 0)) self.connect((self.blocks_moving_average_xx_0, 0), (self.satnogs_cw_to_symbol_0, 0))
self.connect((self.blocks_multiply_conjugate_cc_0, 0), (self.fir_filter_xxx_0, 0)) self.connect((self.blocks_multiply_conjugate_cc_0, 0), (self.fir_filter_xxx_0, 0))
self.connect((self.fir_filter_xxx_0, 0), (self.blocks_complex_to_mag_squared_0, 0)) self.connect((self.fir_filter_xxx_0, 0), (self.blocks_complex_to_mag_squared_0, 0))
self.connect((self.freq_xlating_fir_filter_xxx_0, 0), (self.low_pass_filter_0, 0)) self.connect((self.freq_xlating_fir_filter_xxx_0, 0), (self.low_pass_filter_0, 0))
self.connect((self.low_pass_filter_0, 0), (self.analog_agc2_xx_0, 0)) self.connect((self.low_pass_filter_0, 0), (self.analog_agc2_xx_0, 0))
self.connect((self.low_pass_filter_0, 0), (self.qtgui_freq_sink_x_0, 0))
self.connect((self.osmosdr_source_0, 0), (self.satnogs_coarse_doppler_correction_cc_0, 0)) self.connect((self.osmosdr_source_0, 0), (self.satnogs_coarse_doppler_correction_cc_0, 0))
self.connect((self.satnogs_coarse_doppler_correction_cc_0, 0), (self.freq_xlating_fir_filter_xxx_0, 0)) self.connect((self.satnogs_coarse_doppler_correction_cc_0, 0), (self.freq_xlating_fir_filter_xxx_0, 0))
def closeEvent(self, event):
self.settings = Qt.QSettings("GNU Radio", "satnogs_cw_decoder")
self.settings.setValue("geometry", self.saveGeometry())
event.accept()
def get_cw_offset(self):
return self.cw_offset
def set_cw_offset(self, cw_offset):
self.cw_offset = cw_offset
self.freq_xlating_fir_filter_xxx_0.set_center_freq(self.lo_offset - self.cw_offset)
def get_doppler_correction_per_sec(self): def get_doppler_correction_per_sec(self):
return self.doppler_correction_per_sec return self.doppler_correction_per_sec
@ -119,7 +261,7 @@ class satnogs_cw_decoder(gr.top_block):
def set_lo_offset(self, lo_offset): def set_lo_offset(self, lo_offset):
self.lo_offset = lo_offset self.lo_offset = lo_offset
self.osmosdr_source_0.set_center_freq(self.rx_freq - self.lo_offset, 0) self.osmosdr_source_0.set_center_freq(self.rx_freq - self.lo_offset, 0)
self.freq_xlating_fir_filter_xxx_0.set_center_freq(self.lo_offset) self.freq_xlating_fir_filter_xxx_0.set_center_freq(self.lo_offset - self.cw_offset)
def get_ppm(self): def get_ppm(self):
return self.ppm return self.ppm
@ -171,9 +313,20 @@ class satnogs_cw_decoder(gr.top_block):
def set_samp_rate_rx(self, samp_rate_rx): def set_samp_rate_rx(self, samp_rate_rx):
self.samp_rate_rx = samp_rate_rx self.samp_rate_rx = samp_rate_rx
self.set_xlate_filter_taps(firdes.low_pass(1, self.samp_rate_rx, 125000, 25000, firdes.WIN_HAMMING, 6.76)) self.set_xlate_filter_taps(firdes.low_pass(1, self.samp_rate_rx, 125000, 25000, firdes.WIN_HAMMING, 6.76))
self.qtgui_time_sink_x_0.set_samp_rate(int((self.samp_rate_rx/self.xlating_decimation)/self.lpf_decimation))
self.qtgui_freq_sink_x_0.set_frequency_range(0, self.samp_rate_rx/self.xlating_decimation)
self.osmosdr_source_0.set_sample_rate(self.samp_rate_rx) self.osmosdr_source_0.set_sample_rate(self.samp_rate_rx)
self.osmosdr_source_0.set_bandwidth(self.samp_rate_rx, 0) self.osmosdr_source_0.set_bandwidth(self.samp_rate_rx, 0)
self.low_pass_filter_0.set_taps(firdes.low_pass(1, int(self.samp_rate_rx/self.filter_rate), 2e3, 500, firdes.WIN_HAMMING, 6.76)) self.low_pass_filter_0.set_taps(firdes.low_pass(1, self.samp_rate_rx/self.xlating_decimation, 2e3, 500, firdes.WIN_HAMMING, 6.76))
def get_xlating_decimation(self):
return self.xlating_decimation
def set_xlating_decimation(self, xlating_decimation):
self.xlating_decimation = xlating_decimation
self.qtgui_time_sink_x_0.set_samp_rate(int((self.samp_rate_rx/self.xlating_decimation)/self.lpf_decimation))
self.qtgui_freq_sink_x_0.set_frequency_range(0, self.samp_rate_rx/self.xlating_decimation)
self.low_pass_filter_0.set_taps(firdes.low_pass(1, self.samp_rate_rx/self.xlating_decimation, 2e3, 500, firdes.WIN_HAMMING, 6.76))
def get_xlate_filter_taps(self): def get_xlate_filter_taps(self):
return self.xlate_filter_taps return self.xlate_filter_taps
@ -197,17 +350,20 @@ class satnogs_cw_decoder(gr.top_block):
self.blocks_moving_average_xx_0.set_length_and_scale(self.ndelay, 1) self.blocks_moving_average_xx_0.set_length_and_scale(self.ndelay, 1)
self.blocks_delay_0.set_dly(self.ndelay) self.blocks_delay_0.set_dly(self.ndelay)
def get_filter_rate(self): def get_lpf_decimation(self):
return self.filter_rate return self.lpf_decimation
def set_filter_rate(self, filter_rate): def set_lpf_decimation(self, lpf_decimation):
self.filter_rate = filter_rate self.lpf_decimation = lpf_decimation
self.low_pass_filter_0.set_taps(firdes.low_pass(1, int(self.samp_rate_rx/self.filter_rate), 2e3, 500, firdes.WIN_HAMMING, 6.76)) self.qtgui_time_sink_x_0.set_samp_rate(int((self.samp_rate_rx/self.xlating_decimation)/self.lpf_decimation))
def argument_parser(): def argument_parser():
description = 'A CW (Morse) Decoder' description = 'A CW (Morse) Decoder'
parser = OptionParser(usage="%prog: [options]", option_class=eng_option, description=description) parser = OptionParser(usage="%prog: [options]", option_class=eng_option, description=description)
parser.add_option(
"", "--cw-offset", dest="cw_offset", type="eng_float", default=eng_notation.num_to_str(700),
help="Set cw_offset [default=%default]")
parser.add_option( parser.add_option(
"", "--doppler-correction-per-sec", dest="doppler_correction_per_sec", type="intx", default=1000, "", "--doppler-correction-per-sec", dest="doppler_correction_per_sec", type="intx", default=1000,
help="Set doppler_correction_per_sec [default=%default]") help="Set doppler_correction_per_sec [default=%default]")
@ -233,7 +389,7 @@ def argument_parser():
"", "--waterfall-file-path", dest="waterfall_file_path", type="string", default='/tmp/waterfall.dat', "", "--waterfall-file-path", dest="waterfall_file_path", type="string", default='/tmp/waterfall.dat',
help="Set waterfall_file_path [default=%default]") help="Set waterfall_file_path [default=%default]")
parser.add_option( parser.add_option(
"", "--wpm", dest="wpm", type="intx", default=22, "", "--wpm", dest="wpm", type="intx", default=20,
help="Set wpm [default=%default]") help="Set wpm [default=%default]")
return parser return parser
@ -242,9 +398,21 @@ def main(top_block_cls=satnogs_cw_decoder, options=None):
if options is None: if options is None:
options, _ = argument_parser().parse_args() options, _ = argument_parser().parse_args()
tb = top_block_cls(doppler_correction_per_sec=options.doppler_correction_per_sec, file_path=options.file_path, lo_offset=options.lo_offset, ppm=options.ppm, rigctl_port=options.rigctl_port, rx_freq=options.rx_freq, rx_sdr_device=options.rx_sdr_device, waterfall_file_path=options.waterfall_file_path, wpm=options.wpm) from distutils.version import StrictVersion
if StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0"):
style = gr.prefs().get_string('qtgui', 'style', 'raster')
Qt.QApplication.setGraphicsSystem(style)
qapp = Qt.QApplication(sys.argv)
tb = top_block_cls(cw_offset=options.cw_offset, doppler_correction_per_sec=options.doppler_correction_per_sec, file_path=options.file_path, lo_offset=options.lo_offset, ppm=options.ppm, rigctl_port=options.rigctl_port, rx_freq=options.rx_freq, rx_sdr_device=options.rx_sdr_device, waterfall_file_path=options.waterfall_file_path, wpm=options.wpm)
tb.start() tb.start()
tb.wait() tb.show()
def quitting():
tb.stop()
tb.wait()
qapp.connect(qapp, Qt.SIGNAL("aboutToQuit()"), quitting)
qapp.exec_()
if __name__ == '__main__': if __name__ == '__main__':