Add CW decoder
* Filtering and decimation stages tested for USRP * TODO: Test filtering for the rest of the SDR devices
This commit is contained in:
parent
ca1b8b1242
commit
ea5a5632f5
|
@ -28,6 +28,7 @@ GR_PYTHON_INSTALL(
|
|||
flowgraphs/satnogs_cw_demod.py
|
||||
flowgraphs/satnogs_generic_iq_receiver.py
|
||||
flowgraphs/satnogs_bpsk_demod.py
|
||||
flowgraphs/satnogs_cw_decoder.py
|
||||
flowgraphs/satnogs_apt_demod.py
|
||||
flowgraphs/satnogs_fsk9600_ax25.py
|
||||
flowgraphs/satnogs_fsk9600_g3ruh_ax25.py
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
#!/usr/bin/env python2
|
||||
# -*- coding: utf-8 -*-
|
||||
##################################################
|
||||
# GNU Radio Python Flow Graph
|
||||
# Title: CW Decoder
|
||||
# Author: Manolis Surligas (surligas@gmail.com)
|
||||
# Description: A CW (Morse) Decoder
|
||||
# Generated: Sat Apr 8 22:15:03 2017
|
||||
##################################################
|
||||
|
||||
from gnuradio import analog
|
||||
from gnuradio import blocks
|
||||
from gnuradio import eng_notation
|
||||
from gnuradio import filter
|
||||
from gnuradio import gr
|
||||
from gnuradio.eng_option import eng_option
|
||||
from gnuradio.filter import firdes
|
||||
from optparse import OptionParser
|
||||
import osmosdr
|
||||
import satnogs
|
||||
import time
|
||||
|
||||
|
||||
class satnogs_cw_decoder(gr.top_block):
|
||||
|
||||
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):
|
||||
gr.top_block.__init__(self, "CW Decoder")
|
||||
|
||||
##################################################
|
||||
# Parameters
|
||||
##################################################
|
||||
self.doppler_correction_per_sec = doppler_correction_per_sec
|
||||
self.file_path = file_path
|
||||
self.lo_offset = lo_offset
|
||||
self.ppm = ppm
|
||||
self.rigctl_port = rigctl_port
|
||||
self.rx_freq = rx_freq
|
||||
self.rx_sdr_device = rx_sdr_device
|
||||
self.waterfall_file_path = waterfall_file_path
|
||||
self.wpm = wpm
|
||||
|
||||
##################################################
|
||||
# Variables
|
||||
##################################################
|
||||
self.samp_rate_rx = samp_rate_rx = satnogs.hw_rx_settings[rx_sdr_device]['samp_rate']
|
||||
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.ndelay = ndelay = 100
|
||||
self.filter_rate = filter_rate = 100000
|
||||
|
||||
##################################################
|
||||
# Blocks
|
||||
##################################################
|
||||
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_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_coarse_doppler_correction_cc_0 = satnogs.coarse_doppler_correction_cc(rx_freq, samp_rate_rx)
|
||||
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_center_freq(rx_freq - lo_offset, 0)
|
||||
self.osmosdr_source_0.set_freq_corr(ppm, 0)
|
||||
self.osmosdr_source_0.set_dc_offset_mode(2, 0)
|
||||
self.osmosdr_source_0.set_iq_balance_mode(0, 0)
|
||||
self.osmosdr_source_0.set_gain_mode(False, 0)
|
||||
self.osmosdr_source_0.set_gain(satnogs.hw_rx_settings[rx_sdr_device]['rf_gain'], 0)
|
||||
self.osmosdr_source_0.set_if_gain(satnogs.hw_rx_settings[rx_sdr_device]['if_gain'], 0)
|
||||
self.osmosdr_source_0.set_bb_gain(satnogs.hw_rx_settings[rx_sdr_device]['bb_gain'], 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.low_pass_filter_0 = filter.fir_filter_ccf(5, firdes.low_pass(
|
||||
1, int(samp_rate_rx/filter_rate), 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.fir_filter_xxx_0 = filter.fir_filter_ccc(1, ([1,] * ndelay))
|
||||
self.fir_filter_xxx_0.declare_sample_delay(0)
|
||||
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_delay_0 = blocks.delay(gr.sizeof_gr_complex*1, ndelay)
|
||||
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.set_max_gain(65536)
|
||||
|
||||
##################################################
|
||||
# Connections
|
||||
##################################################
|
||||
self.msg_connect((self.satnogs_cw_to_symbol_0, 'out'), (self.satnogs_morse_decoder_0, 'in'))
|
||||
self.msg_connect((self.satnogs_morse_decoder_0, 'out'), (self.satnogs_multi_format_msg_sink_0, 'in'))
|
||||
self.msg_connect((self.satnogs_tcp_rigctl_msg_source_0, 'freq'), (self.satnogs_coarse_doppler_correction_cc_0, 'freq'))
|
||||
self.connect((self.analog_agc2_xx_0, 0), (self.blocks_delay_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_delay_0, 0), (self.blocks_multiply_conjugate_cc_0, 1))
|
||||
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.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.low_pass_filter_0, 0), (self.analog_agc2_xx_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))
|
||||
|
||||
def get_doppler_correction_per_sec(self):
|
||||
return self.doppler_correction_per_sec
|
||||
|
||||
def set_doppler_correction_per_sec(self, doppler_correction_per_sec):
|
||||
self.doppler_correction_per_sec = doppler_correction_per_sec
|
||||
|
||||
def get_file_path(self):
|
||||
return self.file_path
|
||||
|
||||
def set_file_path(self, file_path):
|
||||
self.file_path = file_path
|
||||
|
||||
def get_lo_offset(self):
|
||||
return self.lo_offset
|
||||
|
||||
def set_lo_offset(self, lo_offset):
|
||||
self.lo_offset = lo_offset
|
||||
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)
|
||||
|
||||
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_rigctl_port(self):
|
||||
return self.rigctl_port
|
||||
|
||||
def set_rigctl_port(self, rigctl_port):
|
||||
self.rigctl_port = rigctl_port
|
||||
|
||||
def get_rx_freq(self):
|
||||
return self.rx_freq
|
||||
|
||||
def set_rx_freq(self, rx_freq):
|
||||
self.rx_freq = rx_freq
|
||||
self.satnogs_coarse_doppler_correction_cc_0.set_new_freq_locked(self.rx_freq)
|
||||
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.set_samp_rate_rx(satnogs.hw_rx_settings[self.rx_sdr_device]['samp_rate'])
|
||||
self.osmosdr_source_0.set_gain(satnogs.hw_rx_settings[self.rx_sdr_device]['rf_gain'], 0)
|
||||
self.osmosdr_source_0.set_if_gain(satnogs.hw_rx_settings[self.rx_sdr_device]['if_gain'], 0)
|
||||
self.osmosdr_source_0.set_bb_gain(satnogs.hw_rx_settings[self.rx_sdr_device]['bb_gain'], 0)
|
||||
self.osmosdr_source_0.set_antenna(satnogs.hw_rx_settings[self.rx_sdr_device]['antenna'], 0)
|
||||
|
||||
def get_waterfall_file_path(self):
|
||||
return self.waterfall_file_path
|
||||
|
||||
def set_waterfall_file_path(self, waterfall_file_path):
|
||||
self.waterfall_file_path = waterfall_file_path
|
||||
|
||||
def get_wpm(self):
|
||||
return self.wpm
|
||||
|
||||
def set_wpm(self, wpm):
|
||||
self.wpm = wpm
|
||||
|
||||
def get_samp_rate_rx(self):
|
||||
return self.samp_rate_rx
|
||||
|
||||
def set_samp_rate_rx(self, 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.osmosdr_source_0.set_sample_rate(self.samp_rate_rx)
|
||||
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))
|
||||
|
||||
def get_xlate_filter_taps(self):
|
||||
return self.xlate_filter_taps
|
||||
|
||||
def set_xlate_filter_taps(self, xlate_filter_taps):
|
||||
self.xlate_filter_taps = xlate_filter_taps
|
||||
self.freq_xlating_fir_filter_xxx_0.set_taps((self.xlate_filter_taps))
|
||||
|
||||
def get_taps(self):
|
||||
return self.taps
|
||||
|
||||
def set_taps(self, taps):
|
||||
self.taps = taps
|
||||
|
||||
def get_ndelay(self):
|
||||
return self.ndelay
|
||||
|
||||
def set_ndelay(self, ndelay):
|
||||
self.ndelay = ndelay
|
||||
self.fir_filter_xxx_0.set_taps(([1,] * self.ndelay))
|
||||
self.blocks_moving_average_xx_0.set_length_and_scale(self.ndelay, 1)
|
||||
self.blocks_delay_0.set_dly(self.ndelay)
|
||||
|
||||
def get_filter_rate(self):
|
||||
return self.filter_rate
|
||||
|
||||
def set_filter_rate(self, filter_rate):
|
||||
self.filter_rate = filter_rate
|
||||
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))
|
||||
|
||||
|
||||
def argument_parser():
|
||||
description = 'A CW (Morse) Decoder'
|
||||
parser = OptionParser(usage="%prog: [options]", option_class=eng_option, description=description)
|
||||
parser.add_option(
|
||||
"", "--doppler-correction-per-sec", dest="doppler_correction_per_sec", type="intx", default=1000,
|
||||
help="Set doppler_correction_per_sec [default=%default]")
|
||||
parser.add_option(
|
||||
"", "--file-path", dest="file_path", type="string", default='test.txt',
|
||||
help="Set file_path [default=%default]")
|
||||
parser.add_option(
|
||||
"", "--lo-offset", dest="lo_offset", type="eng_float", default=eng_notation.num_to_str(100e3),
|
||||
help="Set lo_offset [default=%default]")
|
||||
parser.add_option(
|
||||
"", "--ppm", dest="ppm", type="intx", default=0,
|
||||
help="Set ppm [default=%default]")
|
||||
parser.add_option(
|
||||
"", "--rigctl-port", dest="rigctl_port", type="intx", default=4532,
|
||||
help="Set rigctl_port [default=%default]")
|
||||
parser.add_option(
|
||||
"", "--rx-freq", dest="rx_freq", type="eng_float", default=eng_notation.num_to_str(100e6),
|
||||
help="Set rx_freq [default=%default]")
|
||||
parser.add_option(
|
||||
"", "--rx-sdr-device", dest="rx_sdr_device", type="string", default='usrpb200',
|
||||
help="Set rx_sdr_device [default=%default]")
|
||||
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=22,
|
||||
help="Set wpm [default=%default]")
|
||||
return parser
|
||||
|
||||
|
||||
def main(top_block_cls=satnogs_cw_decoder, options=None):
|
||||
if options is None:
|
||||
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)
|
||||
tb.start()
|
||||
tb.wait()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -34,62 +34,63 @@ namespace gr
|
|||
{
|
||||
|
||||
cw_to_symbol::sptr
|
||||
cw_to_symbol::make (double sampling_rate, float threshold,
|
||||
float conf_level, size_t wpm, bool auto_config)
|
||||
cw_to_symbol::make (double sampling_rate, float threshold, float conf_level,
|
||||
size_t wpm, bool auto_config)
|
||||
{
|
||||
return gnuradio::get_initial_sptr (
|
||||
new cw_to_symbol_impl (sampling_rate, threshold, conf_level,
|
||||
wpm, auto_config));
|
||||
new cw_to_symbol_impl (sampling_rate, threshold, conf_level, wpm,
|
||||
auto_config));
|
||||
}
|
||||
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
cw_to_symbol_impl::cw_to_symbol_impl (double sampling_rate, float threshold,
|
||||
float conf_level, size_t wpm,
|
||||
bool auto_config) :
|
||||
gr::sync_block ("cw_to_symbol",
|
||||
gr::io_signature::make (1, 1, sizeof(float)),
|
||||
gr::io_signature::make (0, 0, 0)),
|
||||
d_sampling_rate(sampling_rate),
|
||||
d_act_thrshld(threshold),
|
||||
d_confidence_level(conf_level),
|
||||
d_sync_limit(15),
|
||||
d_auto_sync(auto_config),
|
||||
d_dot_samples((1.2/wpm) / (1.0 / sampling_rate)),
|
||||
d_dash_samples(3 * d_dot_samples),
|
||||
d_short_pause_samples(3 * d_dot_samples),
|
||||
d_long_pause_samples(7 * d_dot_samples),
|
||||
d_state(IDLE),
|
||||
d_state_cnt(0),
|
||||
d_pause_cnt(0),
|
||||
d_est_cnt(0),
|
||||
d_mean_cnt(0),
|
||||
d_have_sync(!auto_config),
|
||||
d_seq_started(false),
|
||||
d_sync_state(SYNC_TRIGGER_OFF)
|
||||
float conf_level, size_t wpm,
|
||||
bool auto_config) :
|
||||
gr::sync_block ("cw_to_symbol",
|
||||
gr::io_signature::make (1, 1, sizeof(float)),
|
||||
gr::io_signature::make (0, 0, 0)),
|
||||
d_sampling_rate (sampling_rate),
|
||||
d_act_thrshld (threshold),
|
||||
d_confidence_level (conf_level),
|
||||
d_sync_limit (15),
|
||||
d_auto_sync (auto_config),
|
||||
d_dot_samples ((1.2 / wpm) / (1.0 / sampling_rate)),
|
||||
d_dash_samples (3 * d_dot_samples),
|
||||
d_short_pause_samples (3 * d_dot_samples),
|
||||
d_long_pause_samples (7 * d_dot_samples),
|
||||
d_state (IDLE),
|
||||
d_state_cnt (0),
|
||||
d_pause_cnt (0),
|
||||
d_est_cnt (0),
|
||||
d_mean_cnt (0),
|
||||
d_have_sync (!auto_config),
|
||||
d_seq_started (false),
|
||||
d_sync_state (SYNC_TRIGGER_OFF)
|
||||
{
|
||||
message_port_register_in(pmt::mp("act_threshold"));
|
||||
message_port_register_in(pmt::mp("sync"));
|
||||
message_port_register_out(pmt::mp("out"));
|
||||
message_port_register_in (pmt::mp ("act_threshold"));
|
||||
message_port_register_in (pmt::mp ("sync"));
|
||||
message_port_register_out (pmt::mp ("out"));
|
||||
|
||||
/* Register the message handlers */
|
||||
set_msg_handler(pmt::mp("act_threshold"),
|
||||
boost::bind(&cw_to_symbol_impl::set_act_threshold_msg_handler,
|
||||
this, _1));
|
||||
set_msg_handler(pmt::mp("sync"),
|
||||
boost::bind(&cw_to_symbol_impl::sync_msg_handler,
|
||||
this, _1));
|
||||
set_msg_handler (
|
||||
pmt::mp ("act_threshold"),
|
||||
boost::bind (&cw_to_symbol_impl::set_act_threshold_msg_handler, this,
|
||||
_1));
|
||||
set_msg_handler (
|
||||
pmt::mp ("sync"),
|
||||
boost::bind (&cw_to_symbol_impl::sync_msg_handler, this, _1));
|
||||
|
||||
if( auto_config ){
|
||||
d_dot_samples = (1.2/MIN_WPM) / (1.0 / d_sampling_rate);
|
||||
if (auto_config) {
|
||||
d_dot_samples = (1.2 / MIN_WPM) / (1.0 / d_sampling_rate);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
cw_to_symbol_impl::send_symbol_msg (morse_symbol_t s)
|
||||
{
|
||||
message_port_pub(pmt::mp("out"), pmt::from_long(s));
|
||||
message_port_pub (pmt::mp ("out"), pmt::from_long (s));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -138,177 +139,179 @@ namespace gr
|
|||
void
|
||||
cw_to_symbol_impl::set_act_threshold_msg_handler (pmt::pmt_t msg)
|
||||
{
|
||||
if(pmt::is_pair(msg)){
|
||||
set_act_threshold(pmt::to_double(pmt::cdr(msg)));
|
||||
if (pmt::is_pair (msg)) {
|
||||
set_act_threshold (pmt::to_double (pmt::cdr (msg)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cw_to_symbol_impl::sync_msg_handler (pmt::pmt_t msg)
|
||||
{
|
||||
if(pmt::is_pair(msg)){
|
||||
if(pmt::to_bool(pmt::cdr(msg))){
|
||||
start_timing_recovery();
|
||||
}
|
||||
if (pmt::is_pair (msg)) {
|
||||
if (pmt::to_bool (pmt::cdr (msg))) {
|
||||
start_timing_recovery ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
cw_to_symbol_impl::work (int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
{
|
||||
int i;
|
||||
float conf_lvl;
|
||||
const float *in = (const float *) input_items[0];
|
||||
|
||||
/* The estimation for the WPM has not yet been computed */
|
||||
if(!d_have_sync){
|
||||
for(i = 0; i < noutput_items; i++) {
|
||||
switch (d_sync_state) {
|
||||
case SYNC_TRIGGER_OFF:
|
||||
if(in[i] > d_act_thrshld) {
|
||||
d_sync_state = SYNC_TRIGGER_ON;
|
||||
}
|
||||
break;
|
||||
case SYNC_TRIGGER_ON:
|
||||
if(in[i] > d_act_thrshld) {
|
||||
d_state_cnt++;
|
||||
}
|
||||
else {
|
||||
/* Trigger is OFF. Extract the best timing information available */
|
||||
d_sync_state = SYNC_TRIGGER_OFF;
|
||||
estimate_dot_duration(d_state_cnt);
|
||||
d_state_cnt = 0;
|
||||
if (!d_have_sync) {
|
||||
for (i = 0; i < noutput_items; i++) {
|
||||
switch (d_sync_state)
|
||||
{
|
||||
case SYNC_TRIGGER_OFF:
|
||||
if (in[i] > d_act_thrshld) {
|
||||
d_sync_state = SYNC_TRIGGER_ON;
|
||||
}
|
||||
break;
|
||||
case SYNC_TRIGGER_ON:
|
||||
if (in[i] > d_act_thrshld) {
|
||||
d_state_cnt++;
|
||||
}
|
||||
else {
|
||||
/* Trigger is OFF. Extract the best timing information available */
|
||||
d_sync_state = SYNC_TRIGGER_OFF;
|
||||
estimate_dot_duration (d_state_cnt);
|
||||
d_state_cnt = 0;
|
||||
|
||||
/*
|
||||
* If the sync process was over set the state to idle and
|
||||
* return for proper decoding
|
||||
*/
|
||||
if(d_have_sync) {
|
||||
set_idle();
|
||||
return i+1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If the sync process was over set the state to idle and
|
||||
* return for proper decoding
|
||||
*/
|
||||
if (d_have_sync) {
|
||||
set_idle ();
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return noutput_items;
|
||||
return noutput_items;
|
||||
}
|
||||
|
||||
for(i = 0; i < noutput_items; i++) {
|
||||
switch(d_state){
|
||||
case IDLE:
|
||||
if(in[i] > d_act_thrshld) {
|
||||
set_short_on();
|
||||
}
|
||||
break;
|
||||
for (i = 0; i < noutput_items; i++) {
|
||||
switch (d_state)
|
||||
{
|
||||
case IDLE:
|
||||
if (in[i] > d_act_thrshld) {
|
||||
set_short_on ();
|
||||
}
|
||||
break;
|
||||
|
||||
case SHORT_ON_PERIOD:
|
||||
if( in[i] > d_act_thrshld ) {
|
||||
d_state_cnt++;
|
||||
case SHORT_ON_PERIOD:
|
||||
if (in[i] > d_act_thrshld) {
|
||||
d_state_cnt++;
|
||||
|
||||
if(d_state_cnt > d_dot_samples){
|
||||
set_long_on();
|
||||
}
|
||||
}
|
||||
else{
|
||||
/*
|
||||
* Before going to short pause, check the confidence level.
|
||||
* Perhaps a short symbol should be produced.
|
||||
*
|
||||
* Otherwise, it was a false alarm.
|
||||
*/
|
||||
conf_lvl = ((float) d_state_cnt) / d_dot_samples;
|
||||
if(conf_lvl > d_confidence_level){
|
||||
LOG_DEBUG("DOT");
|
||||
send_symbol_msg(MORSE_DOT);
|
||||
}
|
||||
if (d_state_cnt > d_dot_samples) {
|
||||
set_long_on ();
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* Before going to short pause, check the confidence level.
|
||||
* Perhaps a short symbol should be produced.
|
||||
*
|
||||
* Otherwise, it was a false alarm.
|
||||
*/
|
||||
conf_lvl = ((float) d_state_cnt) / d_dot_samples;
|
||||
if (conf_lvl > d_confidence_level) {
|
||||
LOG_DEBUG("DOT");
|
||||
send_symbol_msg (MORSE_DOT);
|
||||
}
|
||||
|
||||
/* Go find a possible short pause symbol */
|
||||
set_short_off();
|
||||
}
|
||||
break;
|
||||
/* Go find a possible short pause symbol */
|
||||
set_short_off ();
|
||||
}
|
||||
break;
|
||||
|
||||
case LONG_ON_PERIOD:
|
||||
if( in[i] > d_act_thrshld ) {
|
||||
d_state_cnt++;
|
||||
}
|
||||
else {
|
||||
conf_lvl = ((float) d_state_cnt) / d_dash_samples;
|
||||
if(conf_lvl > d_confidence_level) {
|
||||
LOG_DEBUG("DASH");
|
||||
send_symbol_msg(MORSE_DASH);
|
||||
set_short_off();
|
||||
break;
|
||||
}
|
||||
case LONG_ON_PERIOD:
|
||||
if (in[i] > d_act_thrshld) {
|
||||
d_state_cnt++;
|
||||
}
|
||||
else {
|
||||
conf_lvl = ((float) d_state_cnt) / d_dash_samples;
|
||||
if (conf_lvl > d_confidence_level) {
|
||||
LOG_DEBUG("DASH");
|
||||
send_symbol_msg (MORSE_DASH);
|
||||
set_short_off ();
|
||||
break;
|
||||
}
|
||||
|
||||
/* Perhaps this was a short on symbol */
|
||||
conf_lvl = ((float) d_state_cnt) / d_dot_samples;
|
||||
if(conf_lvl > d_confidence_level) {
|
||||
LOG_DEBUG("DOT");
|
||||
send_symbol_msg(MORSE_DOT);
|
||||
set_short_off();
|
||||
}
|
||||
/* Perhaps this was a short on symbol */
|
||||
conf_lvl = ((float) d_state_cnt) / d_dot_samples;
|
||||
if (conf_lvl > d_confidence_level) {
|
||||
LOG_DEBUG("DOT");
|
||||
send_symbol_msg (MORSE_DOT);
|
||||
set_short_off ();
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SHORT_OFF_PERIOD:
|
||||
if(in[i] > d_act_thrshld) {
|
||||
/*
|
||||
* Before going to ON state, again check if a short pause symbol
|
||||
* should be produced
|
||||
*/
|
||||
conf_lvl = ((float) d_pause_cnt) / d_short_pause_samples;
|
||||
if(conf_lvl > d_confidence_level) {
|
||||
LOG_DEBUG("Short space");
|
||||
send_symbol_msg(MORSE_S_SPACE);
|
||||
}
|
||||
set_short_on();
|
||||
}
|
||||
else {
|
||||
d_pause_cnt++;
|
||||
if(d_pause_cnt > d_short_pause_samples) {
|
||||
set_long_off();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SHORT_OFF_PERIOD:
|
||||
if (in[i] > d_act_thrshld) {
|
||||
/*
|
||||
* Before going to ON state, again check if a short pause symbol
|
||||
* should be produced
|
||||
*/
|
||||
conf_lvl = ((float) d_pause_cnt) / d_short_pause_samples;
|
||||
if (conf_lvl > d_confidence_level) {
|
||||
LOG_DEBUG("Short space");
|
||||
send_symbol_msg (MORSE_S_SPACE);
|
||||
}
|
||||
set_short_on ();
|
||||
}
|
||||
else {
|
||||
d_pause_cnt++;
|
||||
if (d_pause_cnt > d_short_pause_samples) {
|
||||
set_long_off ();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LONG_OFF_PERIOD:
|
||||
if(in[i] > d_act_thrshld) {
|
||||
conf_lvl = ((float) d_pause_cnt) / d_long_pause_samples;
|
||||
if (conf_lvl > d_confidence_level) {
|
||||
LOG_DEBUG("Long space");
|
||||
send_symbol_msg (MORSE_L_SPACE);
|
||||
set_idle();
|
||||
break;
|
||||
}
|
||||
else {
|
||||
LOG_DEBUG("Short space");
|
||||
send_symbol_msg (MORSE_S_SPACE);
|
||||
}
|
||||
set_short_on();
|
||||
}
|
||||
else {
|
||||
d_pause_cnt++;
|
||||
/*
|
||||
* If the pause duration is greater than the long pause symbol,
|
||||
* definitely a long pause symbol should be produced
|
||||
*/
|
||||
if(d_pause_cnt > d_long_pause_samples) {
|
||||
LOG_DEBUG("Long space");
|
||||
send_symbol_msg(MORSE_L_SPACE);
|
||||
d_seq_started = false;
|
||||
set_idle();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Invalid State.");
|
||||
d_state = IDLE;
|
||||
}
|
||||
case LONG_OFF_PERIOD:
|
||||
if (in[i] > d_act_thrshld) {
|
||||
conf_lvl = ((float) d_pause_cnt) / d_long_pause_samples;
|
||||
if (conf_lvl > d_confidence_level) {
|
||||
LOG_DEBUG("Long space");
|
||||
send_symbol_msg (MORSE_L_SPACE);
|
||||
set_idle ();
|
||||
break;
|
||||
}
|
||||
else {
|
||||
LOG_DEBUG("Short space");
|
||||
send_symbol_msg (MORSE_S_SPACE);
|
||||
}
|
||||
set_short_on ();
|
||||
}
|
||||
else {
|
||||
d_pause_cnt++;
|
||||
/*
|
||||
* If the pause duration is greater than the long pause symbol,
|
||||
* definitely a long pause symbol should be produced
|
||||
*/
|
||||
if (d_pause_cnt > d_long_pause_samples) {
|
||||
LOG_DEBUG("Long space");
|
||||
send_symbol_msg (MORSE_L_SPACE);
|
||||
d_seq_started = false;
|
||||
set_idle ();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Invalid State.");
|
||||
d_state = IDLE;
|
||||
}
|
||||
}
|
||||
return noutput_items;
|
||||
}
|
||||
|
@ -320,9 +323,9 @@ namespace gr
|
|||
* The estimations should be in a logical range of
|
||||
* [MIN_WPM - MAX_WPM] WPM. Otherwise it is considered a false alarm.
|
||||
*/
|
||||
if( estimate < (1.2/MAX_WPM) / (1.0 / d_sampling_rate)
|
||||
|| estimate >= (1.2/MIN_WPM) / (1.0 / d_sampling_rate)) {
|
||||
return;
|
||||
if (estimate < (1.2 / MAX_WPM) / (1.0 / d_sampling_rate)
|
||||
|| estimate >= (1.2 / MIN_WPM) / (1.0 / d_sampling_rate)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -330,34 +333,34 @@ namespace gr
|
|||
* At the end the resulting dot duration will be a mean value of
|
||||
* possible dot durations
|
||||
*/
|
||||
if(estimate < d_dot_samples) {
|
||||
d_dot_samples = estimate;
|
||||
d_mean_cnt += estimate;
|
||||
d_est_cnt++;
|
||||
if (estimate < d_dot_samples) {
|
||||
d_dot_samples = estimate;
|
||||
d_mean_cnt += estimate;
|
||||
d_est_cnt++;
|
||||
}
|
||||
else if(mape(d_dot_samples, estimate) < 1 - d_confidence_level) {
|
||||
d_mean_cnt += estimate;
|
||||
d_est_cnt++;
|
||||
else if (mape (d_dot_samples, estimate) < 1 - d_confidence_level) {
|
||||
d_mean_cnt += estimate;
|
||||
d_est_cnt++;
|
||||
}
|
||||
/*
|
||||
* Perhaps the synchronization process was triggered by a dash.
|
||||
* Check this possibility and use MAPE and confidence level to
|
||||
* decide or not to take into consideration the new estimation
|
||||
*/
|
||||
else if ( mape(d_dot_samples, estimate / 3.0) < 1 - d_confidence_level ) {
|
||||
d_mean_cnt += estimate / 3.0;
|
||||
d_est_cnt++;
|
||||
else if (mape (d_dot_samples, estimate / 3.0) < 1 - d_confidence_level) {
|
||||
d_mean_cnt += estimate / 3.0;
|
||||
d_est_cnt++;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the synchronization process is over update the dot duration
|
||||
* with an average estimation
|
||||
*/
|
||||
if(d_est_cnt == d_sync_limit) {
|
||||
d_have_sync = true;
|
||||
d_dot_samples = d_mean_cnt / d_sync_limit;
|
||||
set_symbols_duration();
|
||||
std::cout << "Have sync" << d_dot_samples << std::endl;
|
||||
if (d_est_cnt == d_sync_limit) {
|
||||
d_have_sync = true;
|
||||
d_dot_samples = d_mean_cnt / d_sync_limit;
|
||||
set_symbols_duration ();
|
||||
std::cout << "Have sync" << d_dot_samples << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -397,11 +400,11 @@ namespace gr
|
|||
cw_to_symbol_impl::set_act_threshold (float thrhld)
|
||||
{
|
||||
d_act_thrshld = thrhld;
|
||||
/* When a new activation threshold is set,
|
||||
* if the automatic synchronization is set it should be again performed
|
||||
/* When a new activation threshold is set and automatic synchronization
|
||||
* is set, the automatic timing recovery should be again performed
|
||||
*/
|
||||
if(d_auto_sync) {
|
||||
reset_sync();
|
||||
if (d_auto_sync) {
|
||||
reset_sync ();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -412,7 +415,7 @@ namespace gr
|
|||
void
|
||||
cw_to_symbol_impl::start_timing_recovery ()
|
||||
{
|
||||
reset_sync();
|
||||
reset_sync ();
|
||||
}
|
||||
|
||||
} /* namespace satnogs */
|
||||
|
|
Loading…
Reference in New Issue