Adapt CW flowgraph to gr-soapy

This commit is contained in:
Manolis Surligas 2019-12-19 20:37:46 +02:00
parent 357e7a87a6
commit 86c3c3246a
3 changed files with 1193 additions and 4275 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,54 +1,52 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
##################################################
#
# SPDX-License-Identifier: GPL-3.0
#
# GNU Radio Python Flow Graph # GNU Radio Python Flow Graph
# 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
# GNU Radio version: 3.7.13.5 # GNU Radio version: 3.8.0.0
##################################################
from gnuradio import analog from gnuradio import analog
from gnuradio import blocks from gnuradio import blocks
from gnuradio import eng_notation
from gnuradio import filter from gnuradio import filter
from gnuradio import gr
from gnuradio.eng_option import eng_option
from gnuradio.filter import firdes from gnuradio.filter import firdes
from gnuradio.filter import pfb from gnuradio import gr
from optparse import OptionParser import sys
import signal
from argparse import ArgumentParser
from gnuradio.eng_arg import eng_float, intx
from gnuradio import eng_notation
import math import math
import osmosdr
import satnogs import satnogs
import time import soapy
class satnogs_cw_decoder(gr.top_block): class satnogs_cw_decoder(gr.top_block):
def __init__(self, antenna=satnogs.not_set_antenna, bb_gain=satnogs.not_set_rx_bb_gain, bfo_freq=1e3, decoded_data_file_path='/tmp/.satnogs/data/data', dev_args=satnogs.not_set_dev_args, doppler_correction_per_sec=20, enable_iq_dump=0, file_path='test.txt', if_gain=satnogs.not_set_rx_if_gain, iq_file_path='/tmp/iq.dat', lo_offset=100e3, ppm=0, rf_gain=satnogs.not_set_rx_rf_gain, rigctl_port=4532, rx_freq=100e6, rx_sdr_device='usrpb200', samp_rate_rx=satnogs.not_set_samp_rate_rx, udp_IP='127.0.0.1', udp_port=16887, waterfall_file_path='/tmp/waterfall.dat', wpm=20): def __init__(self, antenna='', bfo_freq=1e3, bw=0.0, decoded_data_file_path='/tmp/.satnogs/data/data', dev_args='', doppler_correction_per_sec=20, enable_iq_dump=0, file_path='test.wav', gain=0.0, iq_file_path='/tmp/iq.dat', lo_offset=100e3, rigctl_port=4532, rx_freq=100e6, samp_rate_rx=0.0, soapy_rx_device='driver=invalid', udp_IP='127.0.0.1', udp_port=16887, waterfall_file_path='/tmp/waterfall.dat', wpm=20):
gr.top_block.__init__(self, "CW Decoder") gr.top_block.__init__(self, "CW Decoder")
################################################## ##################################################
# Parameters # Parameters
################################################## ##################################################
self.antenna = antenna self.antenna = antenna
self.bb_gain = bb_gain
self.bfo_freq = bfo_freq self.bfo_freq = bfo_freq
self.bw = bw
self.decoded_data_file_path = decoded_data_file_path self.decoded_data_file_path = decoded_data_file_path
self.dev_args = dev_args self.dev_args = dev_args
self.doppler_correction_per_sec = doppler_correction_per_sec self.doppler_correction_per_sec = doppler_correction_per_sec
self.enable_iq_dump = enable_iq_dump self.enable_iq_dump = enable_iq_dump
self.file_path = file_path self.file_path = file_path
self.if_gain = if_gain self.gain = gain
self.iq_file_path = iq_file_path self.iq_file_path = iq_file_path
self.lo_offset = lo_offset self.lo_offset = lo_offset
self.ppm = ppm
self.rf_gain = rf_gain
self.rigctl_port = rigctl_port self.rigctl_port = rigctl_port
self.rx_freq = rx_freq self.rx_freq = rx_freq
self.rx_sdr_device = rx_sdr_device
self.samp_rate_rx = samp_rate_rx self.samp_rate_rx = samp_rate_rx
self.soapy_rx_device = soapy_rx_device
self.udp_IP = udp_IP self.udp_IP = udp_IP
self.udp_port = udp_port self.udp_port = udp_port
self.waterfall_file_path = waterfall_file_path self.waterfall_file_path = waterfall_file_path
@ -64,49 +62,144 @@ class satnogs_cw_decoder(gr.top_block):
################################################## ##################################################
# Blocks # Blocks
################################################## ##################################################
self.satnogs_waterfall_sink_0 = satnogs.waterfall_sink(audio_samp_rate, 0.0, 10, 1024, waterfall_file_path, 1) self.soapy_source_0 = None
if "custom" == 'custom':
dev = soapy_rx_device
else:
dev = 'driver=' + "custom"
if "custom" == 'sdrplay':
f = 'if_mode=' + "Zero-IF" + ',' + 'agc_setpoint=' + str("-30") + ',' + 'biasT_ctrl=' + "True".lower() + ',' + 'rfnotch_ctrl=' + "False".lower() + ',' + 'dabnotch_ctrl=' + "False".lower() + ',' + str(dev_args)
f = f.replace('\"', '')
f = f.replace("\\'", '')
f = f.strip(',')
self.soapy_source_0 = soapy.source(1, dev, f, samp_rate_rx, "fc32")
else:
self.soapy_source_0 = soapy.source(1, dev, dev_args, samp_rate_rx, "fc32")
if 0 != 0:
self.soapy_source_0.set_master_clock_rate(0)
if len('') > 0:
self.soapy_source_0.set_clock_source('')
# Set up dc offsets
if "custom" != 'uhd':
if (self.soapy_source_0.hasDCOffset(0)):
self.soapy_source_0.set_dc_offset(0,0,False == 'True')
if (self.soapy_source_0.hasDCOffset(1)):
self.soapy_source_0.set_dc_offset(1,0,False == 'True')
# Setup IQ Balance
if "custom" != 'uhd':
if (self.soapy_source_0.hasIQBalance(0)):
self.soapy_source_0.set_iq_balance(0,0)
if (self.soapy_source_0.hasIQBalance(1)):
self.soapy_source_0.set_iq_balance(1,0)
# Setup Frequency correction
if (self.soapy_source_0.hasFrequencyCorrection(0)):
self.soapy_source_0.set_frequency_correction(0,0)
if (self.soapy_source_0.hasFrequencyCorrection(1)):
self.soapy_source_0.set_frequency_correction(1,0)
self.soapy_source_0.set_gain_mode(0,False)
self.soapy_source_0.set_gain_mode(1,False)
self.soapy_source_0.set_frequency(0, rx_freq - lo_offset)
self.soapy_source_0.set_frequency(1, 0)
# Made antenna sanity check more generic
antList = self.soapy_source_0.listAntennas(0)
if len(antList) > 1:
# If we have more than 1 possible antenna
if len(antenna) == 0 or antenna not in antList:
print("ERROR: Please define ant0 to an allowed antenna name.")
strAntList = str(antList).lstrip('(').rstrip(')').rstrip(',')
print("Allowed antennas: " + strAntList)
exit(0)
self.soapy_source_0.set_antenna(0,antenna)
if 1 > 1:
antList = self.soapy_source_0.listAntennas(1)
# If we have more than 1 possible antenna
if len(antList) > 1:
if len('RX2') == 0 or 'RX2' not in antList:
print("ERROR: Please define ant1 to an allowed antenna name.")
strAntList = str(antList).lstrip('(').rstrip(')').rstrip(',')
print("Allowed antennas: " + strAntList)
exit(0)
self.soapy_source_0.set_antenna(1,'RX2')
self.soapy_source_0.set_overall_gain(0,gain, False )
self.soapy_source_0.set_overall_gain(1,10, True )
# Prevent some weird double-gain setting issues for systems with an overall_gain setting
# noticed weird behavior with uhd
if "custom" == 'uhd' or "custom" == 'sidekiq' or "custom" == 'bladerf' or "custom" == 'lime':
self.soapy_source_0.set_gain(0,"PGA", 24, False )
self.soapy_source_0.set_gain(1,"PGA", 24, True )
else:
if "custom" == 'custom':
# If we're here and we're custom, let's still call overall gain
self.soapy_source_0.set_overall_gain(0,gain, False )
self.soapy_source_0.set_overall_gain(1,10, True )
self.soapy_source_0.set_gain(0,"LNA", 10, False )
self.soapy_source_0.set_gain(1,"LNA", 10, True )
self.soapy_source_0.set_gain(0,"TIA", 0, False )
self.soapy_source_0.set_gain(1,"TIA", 0, True )
self.soapy_source_0.set_gain(0,"MIX", 10, False )
self.soapy_source_0.set_gain(1,"MIX", 10, True )
self.soapy_source_0.set_gain(0,"VGA", 10, False )
self.soapy_source_0.set_gain(1,"VGA", 10, True )
# Only rtl-sdr uses TUNER, so just ch0
self.soapy_source_0.set_gain(0,"TUNER", 10, False )
# Only hackrf uses "AMP", so just ch0
self.soapy_source_0.set_gain(0,"AMP", 0, False )
# Only sdrplay uses IFGR so just ch0 for each
self.soapy_source_0.set_gain(0,"IFGR", 59, False )
self.soapy_source_0.set_gain(0,"RFGR", 9, False )
self.satnogs_waterfall_sink_0 = satnogs.waterfall_sink(audio_samp_rate, rx_freq, 10, 1024, waterfall_file_path, 1)
self.satnogs_udp_msg_sink_0_0 = satnogs.udp_msg_sink(udp_IP, udp_port, 1500) self.satnogs_udp_msg_sink_0_0 = satnogs.udp_msg_sink(udp_IP, udp_port, 1500)
self.satnogs_tcp_rigctl_msg_source_0 = satnogs.tcp_rigctl_msg_source("127.0.0.1", rigctl_port, False, int(1000.0/doppler_correction_per_sec) + 1, 1500) self.satnogs_tcp_rigctl_msg_source_0 = satnogs.tcp_rigctl_msg_source("127.0.0.1", rigctl_port, False, int(1000.0/doppler_correction_per_sec) + 1, 1500)
self.satnogs_ogg_encoder_0 = satnogs.ogg_encoder(file_path, audio_samp_rate, 1.0) self.satnogs_ogg_encoder_0 = satnogs.ogg_encoder(file_path, audio_samp_rate, 1.0)
self.satnogs_morse_decoder_0 = satnogs.morse_decoder(ord('#'), 3) self.satnogs_morse_decoder_0 = satnogs.morse_decoder(ord('#'), 3)
self.satnogs_iq_sink_0 = satnogs.iq_sink(16768, iq_file_path, False, enable_iq_dump) self.satnogs_iq_sink_0 = satnogs.iq_sink(16768, iq_file_path, False, 1)
self.satnogs_frame_file_sink_0_0 = satnogs.frame_file_sink(decoded_data_file_path, 0) self.satnogs_frame_file_sink_0_0 = satnogs.frame_file_sink(decoded_data_file_path, 0)
self.satnogs_cw_to_symbol_0 = satnogs.cw_to_symbol(audio_samp_rate/10.0, 2.0, 0.90, wpm, dot_samples/dec) self.satnogs_doppler_compensation_0 = satnogs.doppler_compensation(samp_rate_rx, rx_freq, lo_offset, audio_samp_rate, 1)
self.satnogs_coarse_doppler_correction_cc_0 = satnogs.coarse_doppler_correction_cc(rx_freq, satnogs.handle_samp_rate_rx(rx_sdr_device, samp_rate_rx)) self.satnogs_cw_to_symbol_1 = satnogs.cw_to_symbol(audio_samp_rate/10, 2.0, 0.9, wpm, dot_samples//dec)
self.pfb_arb_resampler_xxx_0 = pfb.arb_resampler_ccf( self.low_pass_filter_0_0 = filter.fir_filter_ccf(
audio_samp_rate/satnogs.handle_samp_rate_rx(rx_sdr_device, samp_rate_rx), 1,
taps=None, firdes.low_pass(
flt_size=32) 1,
self.pfb_arb_resampler_xxx_0.declare_sample_delay(0) audio_samp_rate,
3000,
self.osmosdr_source_0 = osmosdr.source( args="numchan=" + str(1) + " " + satnogs.handle_rx_dev_args(rx_sdr_device, dev_args) ) 1e3,
self.osmosdr_source_0.set_sample_rate(satnogs.handle_samp_rate_rx(rx_sdr_device, samp_rate_rx)) firdes.WIN_HAMMING,
self.osmosdr_source_0.set_center_freq(rx_freq - lo_offset, 0) 6.76))
self.osmosdr_source_0.set_freq_corr(ppm, 0) self.low_pass_filter_0 = filter.fir_filter_ccf(
self.osmosdr_source_0.set_dc_offset_mode(2, 0) 1,
self.osmosdr_source_0.set_iq_balance_mode(0, 0) firdes.low_pass(
self.osmosdr_source_0.set_gain_mode(False, 0) 1,
self.osmosdr_source_0.set_gain(satnogs.handle_rx_rf_gain(rx_sdr_device, rf_gain), 0) audio_samp_rate/10,
self.osmosdr_source_0.set_if_gain(satnogs.handle_rx_if_gain(rx_sdr_device, if_gain), 0) 200,
self.osmosdr_source_0.set_bb_gain(satnogs.handle_rx_bb_gain(rx_sdr_device, bb_gain), 0) 0.1e3,
self.osmosdr_source_0.set_antenna(satnogs.handle_rx_antenna(rx_sdr_device, antenna), 0) firdes.WIN_HAMMING,
self.osmosdr_source_0.set_bandwidth(satnogs.handle_samp_rate_rx(rx_sdr_device, samp_rate_rx), 0) 6.76))
self.fir_filter_xxx_0 = filter.fir_filter_ccc(1, [1.0] * int(dot_samples//dec))
self.low_pass_filter_0_0_0 = filter.fir_filter_ccf(1, firdes.low_pass(
1, audio_samp_rate, 2500, 0.8e3, firdes.WIN_HAMMING, 6.76))
self.low_pass_filter_0_0 = filter.fir_filter_ccf(10, firdes.low_pass(
1, audio_samp_rate, 2500, 0.4e3, firdes.WIN_HAMMING, 6.76))
self.low_pass_filter_0 = filter.fir_filter_ccf(1, firdes.low_pass(
1, audio_samp_rate/10, 200, 0.1e3, firdes.WIN_HAMMING, 6.76))
self.fir_filter_xxx_0 = filter.fir_filter_ccc(1, ([1.0] * (int(dot_samples)/dec)))
self.fir_filter_xxx_0.declare_sample_delay(0) self.fir_filter_xxx_0.declare_sample_delay(0)
self.blocks_rotator_cc_0 = blocks.rotator_cc(-2.0 * math.pi * (lo_offset / satnogs.handle_samp_rate_rx(rx_sdr_device, samp_rate_rx))) self.blocks_rotator_cc_0_0 = blocks.rotator_cc(2.0 * math.pi * (bfo_freq / audio_samp_rate))
self.blocks_multiply_xx_0 = blocks.multiply_vcc(1)
self.blocks_multiply_conjugate_cc_0 = blocks.multiply_conjugate_cc(1) self.blocks_multiply_conjugate_cc_0 = blocks.multiply_conjugate_cc(1)
self.blocks_delay_0 = blocks.delay(gr.sizeof_gr_complex*1, int(dot_samples)/dec) self.blocks_keep_one_in_n_0 = blocks.keep_one_in_n(gr.sizeof_gr_complex*1, 10)
self.blocks_delay_0 = blocks.delay(gr.sizeof_gr_complex*1, int(dot_samples//dec))
self.blocks_complex_to_real_0 = blocks.complex_to_real(1) self.blocks_complex_to_real_0 = blocks.complex_to_real(1)
self.blocks_complex_to_mag_0 = blocks.complex_to_mag(1) self.blocks_complex_to_mag_0 = blocks.complex_to_mag(1)
self.analog_sig_source_x_0 = analog.sig_source_c(audio_samp_rate, analog.GR_COS_WAVE, bfo_freq, 1, 0)
self.analog_pll_carriertracking_cc_0 = analog.pll_carriertracking_cc(2*math.pi/100, 2*math.pi*2500, -2*math.pi*2500) self.analog_pll_carriertracking_cc_0 = analog.pll_carriertracking_cc(2*math.pi/100, 2*math.pi*2500, -2*math.pi*2500)
self.analog_agc2_xx_0_0 = analog.agc2_cc(0.01, 0.001, 0.015, 0.0) self.analog_agc2_xx_0_0 = analog.agc2_cc(0.01, 0.001, 0.015, 0.0)
self.analog_agc2_xx_0_0.set_max_gain(65536) self.analog_agc2_xx_0_0.set_max_gain(65536)
@ -118,52 +211,49 @@ class satnogs_cw_decoder(gr.top_block):
################################################## ##################################################
# Connections # Connections
################################################## ##################################################
self.msg_connect((self.satnogs_cw_to_symbol_0, 'out'), (self.satnogs_morse_decoder_0, 'in')) self.msg_connect((self.satnogs_cw_to_symbol_1, 'out'), (self.satnogs_morse_decoder_0, 'in'))
self.msg_connect((self.satnogs_morse_decoder_0, 'out'), (self.satnogs_frame_file_sink_0_0, 'frame')) self.msg_connect((self.satnogs_morse_decoder_0, 'out'), (self.satnogs_frame_file_sink_0_0, 'frame'))
self.msg_connect((self.satnogs_morse_decoder_0, 'out'), (self.satnogs_udp_msg_sink_0_0, 'in')) self.msg_connect((self.satnogs_morse_decoder_0, 'out'), (self.satnogs_udp_msg_sink_0_0, 'in'))
self.msg_connect((self.satnogs_tcp_rigctl_msg_source_0, 'freq'), (self.satnogs_coarse_doppler_correction_cc_0, 'freq')) self.msg_connect((self.satnogs_tcp_rigctl_msg_source_0, 'freq'), (self.satnogs_doppler_compensation_0, 'doppler'))
self.connect((self.analog_agc2_xx_0, 0), (self.low_pass_filter_0_0, 0)) self.connect((self.analog_agc2_xx_0, 0), (self.low_pass_filter_0_0, 0))
self.connect((self.analog_agc2_xx_0_0, 0), (self.blocks_multiply_xx_0, 1)) self.connect((self.analog_agc2_xx_0_0, 0), (self.blocks_rotator_cc_0_0, 0))
self.connect((self.analog_pll_carriertracking_cc_0, 0), (self.low_pass_filter_0, 0)) self.connect((self.analog_pll_carriertracking_cc_0, 0), (self.low_pass_filter_0, 0))
self.connect((self.analog_sig_source_x_0, 0), (self.blocks_multiply_xx_0, 0)) self.connect((self.blocks_complex_to_mag_0, 0), (self.satnogs_cw_to_symbol_1, 0))
self.connect((self.blocks_complex_to_mag_0, 0), (self.satnogs_cw_to_symbol_0, 0))
self.connect((self.blocks_complex_to_real_0, 0), (self.satnogs_ogg_encoder_0, 0)) self.connect((self.blocks_complex_to_real_0, 0), (self.satnogs_ogg_encoder_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_keep_one_in_n_0, 0), (self.analog_pll_carriertracking_cc_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.blocks_multiply_xx_0, 0), (self.blocks_complex_to_real_0, 0)) self.connect((self.blocks_rotator_cc_0_0, 0), (self.blocks_complex_to_real_0, 0))
self.connect((self.blocks_rotator_cc_0, 0), (self.satnogs_coarse_doppler_correction_cc_0, 0))
self.connect((self.fir_filter_xxx_0, 0), (self.blocks_complex_to_mag_0, 0)) self.connect((self.fir_filter_xxx_0, 0), (self.blocks_complex_to_mag_0, 0))
self.connect((self.low_pass_filter_0, 0), (self.blocks_delay_0, 0)) self.connect((self.low_pass_filter_0, 0), (self.blocks_delay_0, 0))
self.connect((self.low_pass_filter_0, 0), (self.blocks_multiply_conjugate_cc_0, 0)) self.connect((self.low_pass_filter_0, 0), (self.blocks_multiply_conjugate_cc_0, 0))
self.connect((self.low_pass_filter_0_0, 0), (self.analog_pll_carriertracking_cc_0, 0)) self.connect((self.low_pass_filter_0_0, 0), (self.analog_agc2_xx_0_0, 0))
self.connect((self.low_pass_filter_0_0_0, 0), (self.analog_agc2_xx_0_0, 0)) self.connect((self.low_pass_filter_0_0, 0), (self.blocks_keep_one_in_n_0, 0))
self.connect((self.osmosdr_source_0, 0), (self.blocks_rotator_cc_0, 0)) self.connect((self.satnogs_doppler_compensation_0, 0), (self.analog_agc2_xx_0, 0))
self.connect((self.pfb_arb_resampler_xxx_0, 0), (self.analog_agc2_xx_0, 0)) self.connect((self.satnogs_doppler_compensation_0, 0), (self.satnogs_iq_sink_0, 0))
self.connect((self.pfb_arb_resampler_xxx_0, 0), (self.low_pass_filter_0_0_0, 0)) self.connect((self.satnogs_doppler_compensation_0, 0), (self.satnogs_waterfall_sink_0, 0))
self.connect((self.pfb_arb_resampler_xxx_0, 0), (self.satnogs_iq_sink_0, 0)) self.connect((self.soapy_source_0, 0), (self.satnogs_doppler_compensation_0, 0))
self.connect((self.pfb_arb_resampler_xxx_0, 0), (self.satnogs_waterfall_sink_0, 0))
self.connect((self.satnogs_coarse_doppler_correction_cc_0, 0), (self.pfb_arb_resampler_xxx_0, 0))
def get_antenna(self): def get_antenna(self):
return self.antenna return self.antenna
def set_antenna(self, antenna): def set_antenna(self, antenna):
self.antenna = antenna self.antenna = antenna
self.osmosdr_source_0.set_antenna(satnogs.handle_rx_antenna(self.rx_sdr_device, self.antenna), 0) self.soapy_source_0.set_antenna(0,self.antenna)
def get_bb_gain(self):
return self.bb_gain
def set_bb_gain(self, bb_gain):
self.bb_gain = bb_gain
self.osmosdr_source_0.set_bb_gain(satnogs.handle_rx_bb_gain(self.rx_sdr_device, self.bb_gain), 0)
def get_bfo_freq(self): def get_bfo_freq(self):
return self.bfo_freq return self.bfo_freq
def set_bfo_freq(self, bfo_freq): def set_bfo_freq(self, bfo_freq):
self.bfo_freq = bfo_freq self.bfo_freq = bfo_freq
self.analog_sig_source_x_0.set_frequency(self.bfo_freq) self.blocks_rotator_cc_0_0.set_phase_inc(2.0 * math.pi * (self.bfo_freq / self.audio_samp_rate))
def get_bw(self):
return self.bw
def set_bw(self, bw):
self.bw = bw
self.soapy_source_0.set_bandwidth(0,self.bw)
def get_decoded_data_file_path(self): def get_decoded_data_file_path(self):
return self.decoded_data_file_path return self.decoded_data_file_path
@ -195,40 +285,26 @@ class satnogs_cw_decoder(gr.top_block):
def set_file_path(self, file_path): def set_file_path(self, file_path):
self.file_path = file_path self.file_path = file_path
def get_if_gain(self): def get_gain(self):
return self.if_gain return self.gain
def set_if_gain(self, if_gain): def set_gain(self, gain):
self.if_gain = if_gain self.gain = gain
self.osmosdr_source_0.set_if_gain(satnogs.handle_rx_if_gain(self.rx_sdr_device, self.if_gain), 0) self.soapy_source_0.set_overall_gain(0,self.gain, False )
def get_iq_file_path(self): def get_iq_file_path(self):
return self.iq_file_path return self.iq_file_path
def set_iq_file_path(self, iq_file_path): def set_iq_file_path(self, iq_file_path):
self.iq_file_path = iq_file_path self.iq_file_path = iq_file_path
self.satnogs_iq_sink_0.open(self.iq_file_path)
def get_lo_offset(self): def get_lo_offset(self):
return self.lo_offset return self.lo_offset
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.soapy_source_0.set_frequency(0, self.rx_freq - self.lo_offset)
self.blocks_rotator_cc_0.set_phase_inc(-2.0 * math.pi * (self.lo_offset / satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx)))
def get_ppm(self):
return self.ppm
def set_ppm(self, ppm):
self.ppm = ppm
self.osmosdr_source_0.set_freq_corr(self.ppm, 0)
def get_rf_gain(self):
return self.rf_gain
def set_rf_gain(self, rf_gain):
self.rf_gain = rf_gain
self.osmosdr_source_0.set_gain(satnogs.handle_rx_rf_gain(self.rx_sdr_device, self.rf_gain), 0)
def get_rigctl_port(self): def get_rigctl_port(self):
return self.rigctl_port return self.rigctl_port
@ -241,32 +317,19 @@ class satnogs_cw_decoder(gr.top_block):
def set_rx_freq(self, rx_freq): def set_rx_freq(self, rx_freq):
self.rx_freq = rx_freq self.rx_freq = rx_freq
self.satnogs_coarse_doppler_correction_cc_0.set_new_freq_locked(self.rx_freq) self.soapy_source_0.set_frequency(0, self.rx_freq - self.lo_offset)
self.osmosdr_source_0.set_center_freq(self.rx_freq - self.lo_offset, 0)
def get_rx_sdr_device(self):
return self.rx_sdr_device
def set_rx_sdr_device(self, rx_sdr_device):
self.rx_sdr_device = rx_sdr_device
self.pfb_arb_resampler_xxx_0.set_rate(self.audio_samp_rate/satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx))
self.osmosdr_source_0.set_sample_rate(satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx))
self.osmosdr_source_0.set_gain(satnogs.handle_rx_rf_gain(self.rx_sdr_device, self.rf_gain), 0)
self.osmosdr_source_0.set_if_gain(satnogs.handle_rx_if_gain(self.rx_sdr_device, self.if_gain), 0)
self.osmosdr_source_0.set_bb_gain(satnogs.handle_rx_bb_gain(self.rx_sdr_device, self.bb_gain), 0)
self.osmosdr_source_0.set_antenna(satnogs.handle_rx_antenna(self.rx_sdr_device, self.antenna), 0)
self.osmosdr_source_0.set_bandwidth(satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx), 0)
self.blocks_rotator_cc_0.set_phase_inc(-2.0 * math.pi * (self.lo_offset / satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx)))
def get_samp_rate_rx(self): def get_samp_rate_rx(self):
return self.samp_rate_rx return self.samp_rate_rx
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.pfb_arb_resampler_xxx_0.set_rate(self.audio_samp_rate/satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx))
self.osmosdr_source_0.set_sample_rate(satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx)) def get_soapy_rx_device(self):
self.osmosdr_source_0.set_bandwidth(satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx), 0) return self.soapy_rx_device
self.blocks_rotator_cc_0.set_phase_inc(-2.0 * math.pi * (self.lo_offset / satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx)))
def set_soapy_rx_device(self, soapy_rx_device):
self.soapy_rx_device = soapy_rx_device
def get_udp_IP(self): def get_udp_IP(self):
return self.udp_IP return self.udp_IP
@ -299,103 +362,103 @@ class satnogs_cw_decoder(gr.top_block):
def set_audio_samp_rate(self, audio_samp_rate): def set_audio_samp_rate(self, audio_samp_rate):
self.audio_samp_rate = audio_samp_rate self.audio_samp_rate = audio_samp_rate
self.set_dot_samples(int((1.2 / self.wpm) / (1.0 / (self.audio_samp_rate / 10.0)))) self.set_dot_samples(int((1.2 / self.wpm) / (1.0 / (self.audio_samp_rate / 10.0))))
self.pfb_arb_resampler_xxx_0.set_rate(self.audio_samp_rate/satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx)) self.blocks_rotator_cc_0_0.set_phase_inc(2.0 * math.pi * (self.bfo_freq / self.audio_samp_rate))
self.low_pass_filter_0_0_0.set_taps(firdes.low_pass(1, self.audio_samp_rate, 2500, 0.8e3, firdes.WIN_HAMMING, 6.76))
self.low_pass_filter_0_0.set_taps(firdes.low_pass(1, self.audio_samp_rate, 2500, 0.4e3, firdes.WIN_HAMMING, 6.76))
self.low_pass_filter_0.set_taps(firdes.low_pass(1, self.audio_samp_rate/10, 200, 0.1e3, firdes.WIN_HAMMING, 6.76)) self.low_pass_filter_0.set_taps(firdes.low_pass(1, self.audio_samp_rate/10, 200, 0.1e3, firdes.WIN_HAMMING, 6.76))
self.analog_sig_source_x_0.set_sampling_freq(self.audio_samp_rate) self.low_pass_filter_0_0.set_taps(firdes.low_pass(1, self.audio_samp_rate, 3000, 1e3, firdes.WIN_HAMMING, 6.76))
def get_dot_samples(self): def get_dot_samples(self):
return self.dot_samples return self.dot_samples
def set_dot_samples(self, dot_samples): def set_dot_samples(self, dot_samples):
self.dot_samples = dot_samples self.dot_samples = dot_samples
self.fir_filter_xxx_0.set_taps(([1.0] * (int(self.dot_samples)/self.dec))) self.blocks_delay_0.set_dly(int(self.dot_samples//self.dec))
self.blocks_delay_0.set_dly(int(self.dot_samples)/self.dec) self.fir_filter_xxx_0.set_taps([1.0] * int(self.dot_samples//self.dec))
def get_dec(self): def get_dec(self):
return self.dec return self.dec
def set_dec(self, dec): def set_dec(self, dec):
self.dec = dec self.dec = dec
self.fir_filter_xxx_0.set_taps(([1.0] * (int(self.dot_samples)/self.dec))) self.blocks_delay_0.set_dly(int(self.dot_samples//self.dec))
self.blocks_delay_0.set_dly(int(self.dot_samples)/self.dec) self.fir_filter_xxx_0.set_taps([1.0] * int(self.dot_samples//self.dec))
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 = ArgumentParser(description=description)
parser.add_option( parser.add_argument(
"", "--antenna", dest="antenna", type="string", default=satnogs.not_set_antenna, "--antenna", dest="antenna", type=str, default='',
help="Set antenna [default=%default]") help="Set antenna [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--bb-gain", dest="bb_gain", type="eng_float", default=eng_notation.num_to_str(satnogs.not_set_rx_bb_gain), "--bfo-freq", dest="bfo_freq", type=eng_float, default="1.0k",
help="Set bb_gain [default=%default]") help="Set bfo_freq [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--bfo-freq", dest="bfo_freq", type="eng_float", default=eng_notation.num_to_str(1e3), "--bw", dest="bw", type=eng_float, default="0.0",
help="Set bfo_freq [default=%default]") help="Set Bandwidth [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--decoded-data-file-path", dest="decoded_data_file_path", type="string", default='/tmp/.satnogs/data/data', "--decoded-data-file-path", dest="decoded_data_file_path", type=str, default='/tmp/.satnogs/data/data',
help="Set decoded_data_file_path [default=%default]") help="Set decoded_data_file_path [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--dev-args", dest="dev_args", type="string", default=satnogs.not_set_dev_args, "--dev-args", dest="dev_args", type=str, default='',
help="Set dev_args [default=%default]") help="Set Device arguments [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--doppler-correction-per-sec", dest="doppler_correction_per_sec", type="intx", default=20, "--doppler-correction-per-sec", dest="doppler_correction_per_sec", type=intx, default=20,
help="Set doppler_correction_per_sec [default=%default]") help="Set doppler_correction_per_sec [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--enable-iq-dump", dest="enable_iq_dump", type="intx", default=0, "--enable-iq-dump", dest="enable_iq_dump", type=intx, default=0,
help="Set enable_iq_dump [default=%default]") help="Set enable_iq_dump [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--file-path", dest="file_path", type="string", default='test.txt', "--file-path", dest="file_path", type=str, default='test.wav',
help="Set file_path [default=%default]") help="Set file_path [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--if-gain", dest="if_gain", type="eng_float", default=eng_notation.num_to_str(satnogs.not_set_rx_if_gain), "--gain", dest="gain", type=eng_float, default="0.0",
help="Set if_gain [default=%default]") help="Set gain [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--iq-file-path", dest="iq_file_path", type="string", default='/tmp/iq.dat', "--iq-file-path", dest="iq_file_path", type=str, default='/tmp/iq.dat',
help="Set iq_file_path [default=%default]") help="Set iq_file_path [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--lo-offset", dest="lo_offset", type="eng_float", default=eng_notation.num_to_str(100e3), "--lo-offset", dest="lo_offset", type=eng_float, default="100.0k",
help="Set lo_offset [default=%default]") help="Set lo_offset [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--ppm", dest="ppm", type="intx", default=0, "--rigctl-port", dest="rigctl_port", type=intx, default=4532,
help="Set ppm [default=%default]") help="Set rigctl_port [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--rf-gain", dest="rf_gain", type="eng_float", default=eng_notation.num_to_str(satnogs.not_set_rx_rf_gain), "--rx-freq", dest="rx_freq", type=eng_float, default="100.0M",
help="Set rf_gain [default=%default]") help="Set rx_freq [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--rigctl-port", dest="rigctl_port", type="intx", default=4532, "--samp-rate-rx", dest="samp_rate_rx", type=eng_float, default="0.0",
help="Set rigctl_port [default=%default]") help="Set Device Sampling rate [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--rx-freq", dest="rx_freq", type="eng_float", default=eng_notation.num_to_str(100e6), "--soapy-rx-device", dest="soapy_rx_device", type=str, default='driver=invalid',
help="Set rx_freq [default=%default]") help="Set soapy_rx_device [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--rx-sdr-device", dest="rx_sdr_device", type="string", default='usrpb200', "--udp-IP", dest="udp_IP", type=str, default='127.0.0.1',
help="Set rx_sdr_device [default=%default]") help="Set udp_IP [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--samp-rate-rx", dest="samp_rate_rx", type="eng_float", default=eng_notation.num_to_str(satnogs.not_set_samp_rate_rx), "--udp-port", dest="udp_port", type=intx, default=16887,
help="Set samp_rate_rx [default=%default]") help="Set udp_port [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--udp-IP", dest="udp_IP", type="string", default='127.0.0.1', "--waterfall-file-path", dest="waterfall_file_path", type=str, default='/tmp/waterfall.dat',
help="Set udp_IP [default=%default]") help="Set waterfall_file_path [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--udp-port", dest="udp_port", type="intx", default=16887, "--wpm", dest="wpm", type=intx, default=20,
help="Set udp_port [default=%default]") help="Set wpm [default=%(default)r]")
parser.add_option(
"", "--waterfall-file-path", dest="waterfall_file_path", type="string", default='/tmp/waterfall.dat',
help="Set waterfall_file_path [default=%default]")
parser.add_option(
"", "--wpm", dest="wpm", type="intx", default=20,
help="Set wpm [default=%default]")
return parser return parser
def main(top_block_cls=satnogs_cw_decoder, options=None): 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(antenna=options.antenna, bfo_freq=options.bfo_freq, bw=options.bw, decoded_data_file_path=options.decoded_data_file_path, dev_args=options.dev_args, doppler_correction_per_sec=options.doppler_correction_per_sec, enable_iq_dump=options.enable_iq_dump, file_path=options.file_path, gain=options.gain, iq_file_path=options.iq_file_path, lo_offset=options.lo_offset, rigctl_port=options.rigctl_port, rx_freq=options.rx_freq, samp_rate_rx=options.samp_rate_rx, soapy_rx_device=options.soapy_rx_device, udp_IP=options.udp_IP, udp_port=options.udp_port, waterfall_file_path=options.waterfall_file_path, wpm=options.wpm)
def sig_handler(sig=None, frame=None):
tb.stop()
tb.wait()
sys.exit(0)
signal.signal(signal.SIGINT, sig_handler)
signal.signal(signal.SIGTERM, sig_handler)
tb = top_block_cls(antenna=options.antenna, bb_gain=options.bb_gain, bfo_freq=options.bfo_freq, decoded_data_file_path=options.decoded_data_file_path, dev_args=options.dev_args, doppler_correction_per_sec=options.doppler_correction_per_sec, enable_iq_dump=options.enable_iq_dump, file_path=options.file_path, if_gain=options.if_gain, iq_file_path=options.iq_file_path, lo_offset=options.lo_offset, ppm=options.ppm, rf_gain=options.rf_gain, rigctl_port=options.rigctl_port, rx_freq=options.rx_freq, rx_sdr_device=options.rx_sdr_device, samp_rate_rx=options.samp_rate_rx, udp_IP=options.udp_IP, udp_port=options.udp_port, waterfall_file_path=options.waterfall_file_path, wpm=options.wpm)
tb.start() tb.start()
tb.wait() tb.wait()

View File

@ -33,6 +33,7 @@ inputs:
- domain: message - domain: message
id: act_threshold id: act_threshold
optional: true
outputs: outputs:
- domain: message - domain: message
@ -40,7 +41,7 @@ outputs:
templates: templates:
imports: import satnogs imports: import satnogs
make: satnogs.cw_to_symbol(${sampling_rate}, ${threshold}, ${conf_level}, ${wpm}, ${hysteresis}) make: satnogs.cw_to_symbol(${samp_rate}, ${threshold}, ${conf_level}, ${wpm}, ${hysteresis})
callbacks: callbacks:
- set_act_threshold(${threshold}) - set_act_threshold(${threshold})