From 94eef1463cfcab16bd9d4eda7e29688ea4977316 Mon Sep 17 00:00:00 2001 From: Manolis Surligas Date: Sun, 6 Aug 2017 23:48:34 +0300 Subject: [PATCH] Improve CW decoding performance and complexity --- lib/cw_to_symbol_impl.cc | 109 ++++++++++++++++++++++++++++++--------- lib/cw_to_symbol_impl.h | 25 ++------- 2 files changed, 89 insertions(+), 45 deletions(-) diff --git a/lib/cw_to_symbol_impl.cc b/lib/cw_to_symbol_impl.cc index 8ea7e9c..7eebb0e 100644 --- a/lib/cw_to_symbol_impl.cc +++ b/lib/cw_to_symbol_impl.cc @@ -59,17 +59,22 @@ namespace gr d_window_size(0), d_window_cnt(0), d_dot_windows_num(0), - d_state (IDLE), d_dec_state (NO_SYNC), - d_prev_space_symbol (true), - d_sync_state (SYNC_TRIGGER_OFF) + d_prev_space_symbol (true) { - if(wpm < MIN_WPM){ - throw std::invalid_argument("Decoder can not handle such low WPM setting"); + if (wpm < MIN_WPM) { + throw std::invalid_argument ( + "Decoder can not handle such low WPM setting"); } - if(wpm > MAX_WPM) { - throw std::invalid_argument("Decoder can not handle such high WPM setting"); + if (wpm > MAX_WPM) { + throw std::invalid_argument ( + "Decoder can not handle such high WPM setting"); + } + + if (conf_level > 1.0 || conf_level < 0.5) { + throw std::invalid_argument ( + "Confidence level should be in the range [0.5, 1.0]"); } message_port_register_in (pmt::mp ("act_threshold")); @@ -137,6 +142,12 @@ namespace gr message_port_pub (pmt::mp ("out"), pmt::from_long (s)); } + inline bool + cw_to_symbol_impl::check_conf_level(size_t cnt, size_t target) + { + return ((float)cnt > target * d_confidence_level); + } + /* * Our virtual destructor. */ @@ -150,14 +161,13 @@ namespace gr inline void cw_to_symbol_impl::set_idle () { - d_state = IDLE; + d_dec_state = NO_SYNC; d_window_cnt = 0; } inline void cw_to_symbol_impl::set_short_on () { - d_state = TRIGGED; d_dec_state = SEARCH_DOT; d_window_cnt = 1; } @@ -169,18 +179,12 @@ namespace gr } inline void - cw_to_symbol_impl::set_short_off () + cw_to_symbol_impl::set_search_space () { - d_dec_state = SEARCH_SHORT_OFF; + d_dec_state = SEARCH_SPACE; d_window_cnt = 1; } - inline void - cw_to_symbol_impl::set_long_off () - { - d_dec_state = SEARCH_LONG_OFF; - } - void cw_to_symbol_impl::set_act_threshold_msg_handler (pmt::pmt_t msg) { @@ -194,15 +198,13 @@ namespace gr gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { - int32_t cnt; bool triggered; int i; const float *in_old = (const float *) input_items[0]; const float *in = in_old + history() - 1; - float conf; /* During idle state search for a possible trigger */ - if(d_state == IDLE) { + if(d_dec_state == NO_SYNC) { for(i = 0; i < noutput_items; i++) { /* * Clamp the input so the window mean is not affected by strong spikes @@ -210,19 +212,76 @@ namespace gr */ triggered = is_triggered(in_old + i, d_window_size); if(triggered) { + LOG_DEBUG("Triggered!"); set_short_on(); return i+1; } } return noutput_items; } - else{ - /* From now one, we handle the input in multiples of a window */ - for (i = 0; i < noutput_items / d_window_size; i++) { - triggered = is_triggered(in + i * d_window_size, d_window_size); + + /* From now one, we handle the input in multiples of a window */ + for (i = 0; i < noutput_items / d_window_size; i++) { + triggered = is_triggered(in + i * d_window_size, d_window_size); + switch(d_dec_state) { + case SEARCH_DOT: + if(triggered) { + d_window_cnt++; + if(d_window_cnt > d_dot_windows_num) { + set_long_on(); + } + } + else { + if(check_conf_level(d_window_cnt, d_dot_windows_num)) { + LOG_DEBUG("DOT"); + send_symbol_msg(MORSE_DOT); + } + set_search_space (); + } + break; + case SEARCH_DASH: + if(triggered) { + d_window_cnt++; + } + else{ + if(check_conf_level(d_window_cnt, d_dash_windows_num)) { + LOG_DEBUG("DASH"); + send_symbol_msg(MORSE_DASH); + } + else{ + LOG_DEBUG("DOT"); + send_symbol_msg(MORSE_DOT); + } + set_search_space (); + } + break; + case SEARCH_SPACE: + if (triggered) { + if(check_conf_level(d_window_cnt, d_long_pause_windows_num)) { + LOG_DEBUG("LONG SPACE"); + send_symbol_msg(MORSE_L_SPACE); + } + else if(check_conf_level(d_window_cnt, d_short_pause_windows_num)){ + LOG_DEBUG("SHORT SPACE"); + send_symbol_msg(MORSE_S_SPACE); + } + set_short_on(); + } + else{ + d_window_cnt++; + if(d_window_cnt > d_long_pause_windows_num) { + LOG_DEBUG("LONG SPACE"); + send_symbol_msg(MORSE_L_SPACE); + set_idle(); + return (i + 1) * d_window_size; + } + } + break; + default: + LOG_ERROR("Invalid decoder state"); } } - return noutput_items; + return i * d_window_size; } /** diff --git a/lib/cw_to_symbol_impl.h b/lib/cw_to_symbol_impl.h index 345bdf8..ec3d31d 100644 --- a/lib/cw_to_symbol_impl.h +++ b/lib/cw_to_symbol_impl.h @@ -32,25 +32,12 @@ namespace gr class cw_to_symbol_impl : public cw_to_symbol { - typedef enum - { - IDLE, TRIGGED - } cw_state_t; typedef enum { - NO_SYNC, SEARCH_DOT, SEARCH_DASH, SEARCH_SHORT_OFF, SEARCH_LONG_OFF, + NO_SYNC, SEARCH_DOT, SEARCH_DASH, SEARCH_SPACE } cw_dec_state_t; - /** - * Different states during the WPM auto synchronization - */ - typedef enum - { - SYNC_TRIGGER_OFF, //!< SYNC_TRIGGER_OFF Signal is below threshold - SYNC_TRIGGER_ON //!< SYNC_TRIGGER_ON Signal is above threshold - } sync_state_t; - private: const double d_sampling_rate; float d_act_thrshld; @@ -62,10 +49,8 @@ namespace gr size_t d_dash_windows_num; size_t d_short_pause_windows_num; size_t d_long_pause_windows_num; - cw_state_t d_state; cw_dec_state_t d_dec_state; bool d_prev_space_symbol; - sync_state_t d_sync_state; float *d_const_val; float *d_tmp; int32_t *d_out; @@ -80,10 +65,7 @@ namespace gr set_long_on (); inline void - set_short_off (); - - inline void - set_long_off (); + set_search_space (); inline int32_t hadd (const int32_t *in, size_t len); @@ -97,6 +79,9 @@ namespace gr inline void send_symbol_msg (morse_symbol_t s); + inline bool + check_conf_level(size_t cnt, size_t target); + void set_act_threshold_msg_handler (pmt::pmt_t msg);