diff --git a/examples/morse_decoding_flowgraph.grc b/examples/morse_decoding_flowgraph.grc index a148221..71e9820 100644 --- a/examples/morse_decoding_flowgraph.grc +++ b/examples/morse_decoding_flowgraph.grc @@ -97,7 +97,7 @@ _coordinate - (136, 120) + (216, 25) gui_hint @@ -171,6 +171,96 @@ 8000 + + variable_qtgui_range + + comment + + + + value + 0 + + + _enabled + True + + + _coordinate + (392, 49) + + + gui_hint + + + + _rotation + 0 + + + id + switch + + + label + Switch + + + min_len + 200 + + + orient + Qt.Horizontal + + + start + 0 + + + step + 1 + + + stop + 1 + + + rangeType + float + + + widget + counter_slider + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (16, 237) + + + _rotation + 0 + + + id + taps + + + value + 12 + + analog_agc2_xx @@ -199,7 +289,7 @@ _coordinate - (672, 320) + (584, 368) _rotation @@ -211,7 +301,7 @@ id - analog_agc2_xx_0 + analog_agc2_xx_0_0 max_gain @@ -293,53 +383,6 @@ 8192 - - audio_sink - - alias - - - - comment - - - - affinity - - - - device_name - - - - _enabled - 1 - - - _coordinate - (1032, 348) - - - _rotation - 0 - - - id - audio_sink_0 - - - num_inputs - 1 - - - ok_to_block - True - - - samp_rate - samp_rate - - blocks_add_xx @@ -391,6 +434,57 @@ 1 + + blocks_file_sink + + append + False + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + file + /home/surligas/test.dat + + + _coordinate + (1104, 296) + + + _rotation + 0 + + + id + blocks_file_sink_0 + + + type + float + + + unbuffered + False + + + vlen + 1 + + blocks_moving_average_xx @@ -411,7 +505,7 @@ _coordinate - (728, 134) + (880, 158) _rotation @@ -423,7 +517,7 @@ length - 8 + taps max_iter @@ -470,7 +564,7 @@ _coordinate - (344, 276) + (216, 276) _rotation @@ -497,6 +591,108 @@ 1 + + blocks_multiply_const_vxx + + alias + + + + comment + + + + const + const + + + affinity + + + + _enabled + True + + + _coordinate + (416, 396) + + + _rotation + 0 + + + id + blocks_multiply_const_vxx_0_0 + + + type + float + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + + + blocks_multiply_const_vxx + + alias + + + + comment + + + + const + switch + + + affinity + + + + _enabled + 2 + + + _coordinate + (872, 340) + + + _rotation + 180 + + + id + blocks_multiply_const_vxx_1 + + + type + float + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + blocks_multiply_xx @@ -517,7 +713,7 @@ _coordinate - (616, 136) + (768, 256) _rotation @@ -548,6 +744,61 @@ 1 + + blocks_throttle + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (368, 276) + + + _rotation + 0 + + + id + blocks_throttle_0 + + + ignoretag + True + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samples_per_second + samp_rate + + + type + float + + + vlen + 1 + + blocks_wavfile_source @@ -572,7 +823,7 @@ _coordinate - (96, 237) + (40, 365) _rotation @@ -631,7 +882,7 @@ _coordinate - (1032, 166) + (1096, 110) gui_hint @@ -735,7 +986,7 @@ label3 - Square + marker3 @@ -899,7 +1150,7 @@ nconnections - 3 + 1 size @@ -958,6 +1209,37 @@ -1 + + satnogs_clear_text_msg_sink + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (1080, 544) + + + _rotation + 0 + + + id + satnogs_clear_text_msg_sink_0 + + satnogs_cw_matched_filter_ff @@ -982,7 +1264,7 @@ _coordinate - (480, 262) + (536, 270) _rotation @@ -1009,27 +1291,107 @@ 20 + + satnogs_cw_to_symbol + + threshold + 20e3 + + + alias + + + + comment + + + + conf_level + 0.85 + + + affinity + + + + _enabled + True + + + _coordinate + (856, 383) + + + _rotation + 0 + + + id + satnogs_cw_to_symbol_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + sampling_rate + samp_rate + + + wpm + 20 + + + + satnogs_morse_decoder + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (848, 540) + + + _rotation + 0 + + + id + satnogs_morse_decoder_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + unrecognized_char + ord('#') + + - analog_agc2_xx_0 - audio_sink_0 - 0 - 0 - - - analog_agc2_xx_0 - blocks_multiply_xx_0 - 0 - 0 - - - analog_agc2_xx_0 - blocks_multiply_xx_0 - 0 - 1 - - - analog_agc2_xx_0 - qtgui_time_sink_x_0 + analog_agc2_xx_0_0 + satnogs_cw_matched_filter_ff_0 0 0 @@ -1045,15 +1407,39 @@ 0 0 + + blocks_moving_average_xx_0 + blocks_file_sink_0 + 0 + 0 + + + blocks_moving_average_xx_0 + blocks_multiply_const_vxx_1 + 0 + 0 + blocks_moving_average_xx_0 qtgui_time_sink_x_0 0 - 2 + 0 blocks_multiply_const_vxx_0 - satnogs_cw_matched_filter_ff_0 + blocks_throttle_0 + 0 + 0 + + + blocks_multiply_const_vxx_0_0 + analog_agc2_xx_0_0 + 0 + 0 + + + blocks_multiply_const_vxx_1 + satnogs_cw_to_symbol_0 0 0 @@ -1063,6 +1449,12 @@ 0 0 + + blocks_throttle_0 + blocks_multiply_const_vxx_0_0 + 0 + 0 + blocks_wavfile_source_0 blocks_add_xx_0 @@ -1071,14 +1463,26 @@ satnogs_cw_matched_filter_ff_0 - analog_agc2_xx_0 + blocks_multiply_xx_0 0 0 satnogs_cw_matched_filter_ff_0 - qtgui_time_sink_x_0 + blocks_multiply_xx_0 0 1 + + satnogs_cw_to_symbol_0 + satnogs_morse_decoder_0 + out + in + + + satnogs_morse_decoder_0 + satnogs_clear_text_msg_sink_0 + out + in + diff --git a/examples/test_matched_filter.grc b/examples/test_matched_filter.grc index 0c03289..1691611 100644 --- a/examples/test_matched_filter.grc +++ b/examples/test_matched_filter.grc @@ -81,6 +81,69 @@ + + variable_qtgui_range + + comment + + + + value + 1 + + + _enabled + True + + + _coordinate + (152, 113) + + + gui_hint + + + + _rotation + 0 + + + id + const + + + label + Signal Amplitude + + + min_len + 200 + + + orient + Qt.Horizontal + + + start + 0 + + + step + 0.01 + + + stop + 5 + + + rangeType + float + + + widget + counter_slider + + variable @@ -108,6 +171,33 @@ 8000 + + variable + + comment + + + + _enabled + True + + + _coordinate + (8, 229) + + + _rotation + 0 + + + id + taps + + + value + 12 + + analog_agc2_xx @@ -128,7 +218,7 @@ decay_rate - 2e-6 + 6.25e-4 _enabled @@ -136,7 +226,7 @@ _coordinate - (752, 320) + (536, 384) _rotation @@ -148,7 +238,7 @@ id - analog_agc2_xx_0 + analog_agc2_xx_0_0 max_gain @@ -230,53 +320,6 @@ 8192 - - audio_sink - - alias - - - - comment - - - - affinity - - - - device_name - - - - _enabled - 1 - - - _coordinate - (1032, 348) - - - _rotation - 0 - - - id - audio_sink_0 - - - num_inputs - 1 - - - ok_to_block - True - - - samp_rate - samp_rate - - blocks_add_xx @@ -297,7 +340,7 @@ _coordinate - (416, 440) + (240, 344) _rotation @@ -328,6 +371,218 @@ 1 + + blocks_moving_average_xx + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (936, 150) + + + _rotation + 0 + + + id + blocks_moving_average_xx_0 + + + length + taps + + + max_iter + 4000 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + scale + 1 + + + type + float + + + + blocks_multiply_const_vxx + + alias + + + + comment + + + + const + const + + + affinity + + + + _enabled + True + + + _coordinate + (424, 508) + + + _rotation + 0 + + + id + blocks_multiply_const_vxx_0 + + + type + float + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + + + blocks_multiply_xx + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (768, 176) + + + _rotation + 0 + + + id + blocks_multiply_xx_0 + + + type + float + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + num_inputs + 2 + + + vlen + 1 + + + + blocks_throttle + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (344, 356) + + + _rotation + 0 + + + id + blocks_throttle_0 + + + ignoretag + True + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samples_per_second + samp_rate + + + type + float + + + vlen + 1 + + blocks_wavfile_source @@ -411,7 +666,7 @@ _coordinate - (952, 166) + (1112, 166) gui_hint @@ -679,7 +934,7 @@ nconnections - 2 + 1 size @@ -762,7 +1017,7 @@ _coordinate - (536, 222) + (488, 182) _rotation @@ -790,14 +1045,8 @@ - analog_agc2_xx_0 - audio_sink_0 - 0 - 0 - - - analog_agc2_xx_0 - qtgui_time_sink_x_0 + analog_agc2_xx_0_0 + satnogs_cw_matched_filter_ff_0 0 0 @@ -809,7 +1058,31 @@ blocks_add_xx_0 - satnogs_cw_matched_filter_ff_0 + blocks_throttle_0 + 0 + 0 + + + blocks_moving_average_xx_0 + qtgui_time_sink_x_0 + 0 + 0 + + + blocks_multiply_const_vxx_0 + analog_agc2_xx_0_0 + 0 + 0 + + + blocks_multiply_xx_0 + blocks_moving_average_xx_0 + 0 + 0 + + + blocks_throttle_0 + blocks_multiply_const_vxx_0 0 0 @@ -821,13 +1094,13 @@ satnogs_cw_matched_filter_ff_0 - analog_agc2_xx_0 + blocks_multiply_xx_0 0 0 satnogs_cw_matched_filter_ff_0 - qtgui_time_sink_x_0 + blocks_multiply_xx_0 0 1 diff --git a/grc/satnogs_cw_to_symbol.xml b/grc/satnogs_cw_to_symbol.xml index 36bd9a7..46d447f 100644 --- a/grc/satnogs_cw_to_symbol.xml +++ b/grc/satnogs_cw_to_symbol.xml @@ -4,7 +4,7 @@ satnogs_cw_to_symbol satnogs import satnogs - satnogs.cw_to_symbol($sampling_rate, $threshold, $wpm) + satnogs.cw_to_symbol($sampling_rate, $threshold, $conf_level, $wpm) Sampling Rate @@ -18,6 +18,13 @@ threshold real + + + Confidence Level + conf_level + 0.9 + real + Words per Minute diff --git a/include/satnogs/cw_to_symbol.h b/include/satnogs/cw_to_symbol.h index ac53400..32e6f02 100644 --- a/include/satnogs/cw_to_symbol.h +++ b/include/satnogs/cw_to_symbol.h @@ -51,9 +51,15 @@ namespace gr { * * @param sampling_rate the sampling rate of the signal * @param threshold the activation threshold + * @param conf_level the confidence level, for the decisions made by + * the decoder. Higher values, means that the decoder would be more + * conservative, whereas lower may help in noisy environments but may + * trigger false alarms too, especially for the case of short pauses + * symbols * @param wpm Morse code Words per Minute */ - static sptr make(double sampling_rate, float threshold, size_t wpm = 20); + static sptr make(double sampling_rate, float threshold, + float conf_level = 0.9, size_t wpm = 20); }; } // namespace satnogs diff --git a/lib/cw_to_symbol_impl.cc b/lib/cw_to_symbol_impl.cc index 3aa39f9..113d825 100644 --- a/lib/cw_to_symbol_impl.cc +++ b/lib/cw_to_symbol_impl.cc @@ -24,7 +24,6 @@ #include #include -#include #include "cw_to_symbol_impl.h" namespace gr @@ -33,34 +32,42 @@ namespace gr { cw_to_symbol::sptr - cw_to_symbol::make (double sampling_rate, float threshold, size_t wpm) + cw_to_symbol::make (double sampling_rate, float threshold, + float conf_level, size_t wpm) { return gnuradio::get_initial_sptr ( - new cw_to_symbol_impl (sampling_rate, threshold, wpm)); + new cw_to_symbol_impl (sampling_rate, threshold, conf_level, wpm)); } /* * The private constructor */ cw_to_symbol_impl::cw_to_symbol_impl (double sampling_rate, float threshold, - size_t wpm) : + float conf_level, size_t wpm) : 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(0.90), + d_confidence_level(conf_level), 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_pause_cnt(0), + d_seq_started(false) { message_port_register_out(pmt::mp("out")); } + inline void + cw_to_symbol_impl::send_symbol_msg (morse_symbol_t s) + { + message_port_pub(pmt::mp("out"), pmt::from_long(s)); + } + /* * Our virtual destructor. */ @@ -71,6 +78,7 @@ namespace gr inline void cw_to_symbol_impl::set_idle () { + LOG_WARN("Enter IDLE"); d_state = IDLE; d_state_cnt = 0; d_pause_cnt = 0; @@ -79,33 +87,32 @@ namespace gr inline void cw_to_symbol_impl::set_short_on () { + LOG_WARN("Enter SHORT ON"); d_state = SHORT_ON_PERIOD; d_state_cnt = 1; + d_pause_cnt = 0; } inline void cw_to_symbol_impl::set_long_on () { + LOG_WARN("Enter LONG ON"); d_state = LONG_ON_PERIOD; - d_pause_cnt = 0; } inline void - cw_to_symbol_impl::set_short_off (size_t borrow_cnt) + cw_to_symbol_impl::set_short_off () { + LOG_WARN("Enter SHORT OFF"); d_state = SHORT_OFF_PERIOD; d_state_cnt = 0; - d_pause_cnt += borrow_cnt; - - /* Due to time-slots borrowing we may be already at the Long pause */ - if(d_pause_cnt > d_short_pause_samples) { - d_state = LONG_OFF_PERIOD; - } + d_pause_cnt = 1; } inline void cw_to_symbol_impl::set_long_off () { + LOG_WARN("Enter LONG OFF"); d_state = LONG_OFF_PERIOD; } @@ -124,7 +131,6 @@ namespace gr if(in[i] > d_act_thrshld) { set_short_on(); } - // TODO Avoid unnecessary pause messages break; case SHORT_ON_PERIOD: @@ -140,17 +146,16 @@ namespace gr * Before going to short pause, check the confidence level. * Perhaps a short symbol should be produced. * - * Otherwise, it was a false alarm. So the time-slots counted - * so far should be assigned as pause time-slots. + * Otherwise, it was a false alarm. */ conf_lvl = ((float) d_state_cnt) / d_dot_samples; if(conf_lvl > d_confidence_level){ - message_port_pub(pmt::mp("out"), pmt::from_long(MORSE_DOT)); - set_short_off(0); - } - else{ - set_short_off(d_state_cnt); + LOG_DEBUG("Short space"); + send_symbol_msg(MORSE_S_SPACE); } + + /* Go find a possible short pause symbol */ + set_short_off(); } break; @@ -158,25 +163,37 @@ namespace gr if( in[i] > d_act_thrshld ) { d_state_cnt++; } - else{ - /* - * In this case the FSM should continue at the SHORT_OFF state. - * Before this depending the confidence for a long pulse, produce - * a short or long pulse message - */ + else { conf_lvl = ((float) d_state_cnt) / d_dash_samples; - if(conf_lvl > d_confidence_level){ - message_port_pub(pmt::mp("out"), pmt::from_long(MORSE_DASH)); + if(conf_lvl > d_confidence_level) { + LOG_DEBUG("DASH"); + send_symbol_msg(MORSE_DASH); + set_short_off(); + break; } - else{ - message_port_pub(pmt::mp("out"), pmt::from_long(MORSE_DOT)); + + /* 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(); } - set_short_off(0); + } 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 { @@ -186,14 +203,32 @@ namespace gr } } 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) { - message_port_pub(pmt::mp("out"), pmt::from_long(MORSE_L_SPACE)); + LOG_DEBUG("Long space"); + send_symbol_msg(MORSE_L_SPACE); + d_seq_started = false; set_idle(); } } diff --git a/lib/cw_to_symbol_impl.h b/lib/cw_to_symbol_impl.h index 790eac0..98812a0 100644 --- a/lib/cw_to_symbol_impl.h +++ b/lib/cw_to_symbol_impl.h @@ -21,6 +21,7 @@ #ifndef INCLUDED_SATNOGS_CW_TO_SYMBOL_IMPL_H #define INCLUDED_SATNOGS_CW_TO_SYMBOL_IMPL_H +#include #include namespace gr @@ -48,6 +49,7 @@ namespace gr cw_state_t d_state; size_t d_state_cnt; size_t d_pause_cnt; + bool d_seq_started; inline void set_idle (); @@ -59,13 +61,17 @@ namespace gr set_long_on (); inline void - set_short_off (size_t borrow_cnt); + set_short_off (); inline void set_long_off (); + inline void + send_symbol_msg (morse_symbol_t s); + public: - cw_to_symbol_impl (double sampling_rate, float threshold, size_t wpm); + cw_to_symbol_impl (double sampling_rate, float threshold, + float conf_level, size_t wpm); ~cw_to_symbol_impl (); // Where all the action really happens diff --git a/lib/morse_decoder_impl.cc b/lib/morse_decoder_impl.cc index f1a90b6..4d91e36 100644 --- a/lib/morse_decoder_impl.cc +++ b/lib/morse_decoder_impl.cc @@ -56,6 +56,11 @@ namespace gr * word */ case MORSE_L_SPACE: + /* Just ignore the word separator if no word is yet decoded */ + if (d_morse_tree.get_word_len() == 0) { + res = true; + break; + } str = d_morse_tree.get_word(); d_morse_tree.reset(); message_port_pub(pmt::mp("out"), pmt::make_blob(str.c_str(), diff --git a/lib/morse_tree.cc b/lib/morse_tree.cc index 9d65eaa..b4bf901 100644 --- a/lib/morse_tree.cc +++ b/lib/morse_tree.cc @@ -217,6 +217,13 @@ namespace gr } break; case MORSE_S_SPACE: + /* + * A short space received, but the decoder is still at the root. + * This is not in general an error so we return true + */ + if(d_current == d_root){ + return true; + } c = d_current->get_char (); d_current = d_root; /*