CW signal to Morse Symbol decoding block

The CW symbol decoder block takes as input the power of the processed
signal and tries to identify the dot and dash symbols. It produces
asynchronous messages containing the decoded symbols. The output
messages can be directly used by the Morse code decoder block, in order
to retrieve the clear text message.

There are some few thing that need to be done for the block to be fully
operational.
This commit is contained in:
Manolis Surligas 2016-01-27 22:54:42 +02:00
parent 5d4884cf0d
commit f8b847077e
11 changed files with 1503 additions and 8 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<?grc format='1' created='3.7.8'?>
<?grc format='1' created='3.7.10'?>
<flow_graph>
<timestamp>Sun Jan 17 23:03:00 2016</timestamp>
<block>
@ -40,6 +40,10 @@
<key>generate_options</key>
<value>qt_gui</value>
</param>
<param>
<key>hier_block_src_path</key>
<value>.:</value>
</param>
<param>
<key>id</key>
<value>test_matched_filter</value>
@ -48,10 +52,18 @@
<key>max_nouts</key>
<value>0</value>
</param>
<param>
<key>qt_qss_theme</key>
<value></value>
</param>
<param>
<key>realtime_scheduling</key>
<value></value>
</param>
<param>
<key>run_command</key>
<value>{python} -u {filename}</value>
</param>
<param>
<key>run_options</key>
<value>prompt</value>

View File

@ -128,7 +128,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(944, 184)</value>
<value>(960, 168)</value>
</param>
<param>
<key>_rotation</key>
@ -159,11 +159,11 @@
</param>
<param>
<key>p</key>
<value>0.1</value>
<value>0.01</value>
</param>
<param>
<key>_coordinate</key>
<value>(240, 196)</value>
<value>(200, 150)</value>
</param>
<param>
<key>_rotation</key>
@ -210,7 +210,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(672, 180)</value>
<value>(632, 164)</value>
</param>
<param>
<key>_rotation</key>

View File

@ -20,5 +20,6 @@ install(FILES
satnogs_cw_matched_filter_ff.xml
satnogs_morse_decoder.xml
satnogs_morse_debug_source.xml
satnogs_clear_text_msg_sink.xml DESTINATION share/gnuradio/grc/blocks
satnogs_clear_text_msg_sink.xml
satnogs_cw_to_symbol.xml DESTINATION share/gnuradio/grc/blocks
)

View File

@ -0,0 +1,38 @@
<?xml version="1.0"?>
<block>
<name>CW to Symbols</name>
<key>satnogs_cw_to_symbol</key>
<category>satnogs</category>
<import>import satnogs</import>
<make>satnogs.cw_to_symbol($sampling_rate, $threshold, $wpm)</make>
<param>
<name>Sampling Rate</name>
<key>sampling_rate</key>
<value>samp_rate</value>
<type>real</type>
</param>
<param>
<name>Activation Threshold</name>
<key>threshold</key>
<type>real</type>
</param>
<param>
<name>Words per Minute</name>
<key>wpm</key>
<value>20</value>
<type>int</type>
</param>
<sink>
<name>in</name>
<type>float</type>
</sink>
<source>
<name>out</name>
<type>message</type>
</source>
</block>

View File

@ -29,5 +29,6 @@ install(FILES
morse.h
morse_decoder.h
morse_debug_source.h
clear_text_msg_sink.h DESTINATION include/satnogs
clear_text_msg_sink.h
cw_to_symbol.h DESTINATION include/satnogs
)

View File

@ -0,0 +1,63 @@
/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2016, Libre Space Foundation <http://librespacefoundation.org/>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_SATNOGS_CW_TO_SYMBOL_H
#define INCLUDED_SATNOGS_CW_TO_SYMBOL_H
#include <satnogs/api.h>
#include <gnuradio/sync_block.h>
namespace gr {
namespace satnogs {
/*!
* \brief The CW to Symbol block tries to translate the received signal
* power time-series into Morse symbols.
* \ingroup satnogs
*/
class SATNOGS_API cw_to_symbol : virtual public gr::sync_block
{
public:
typedef boost::shared_ptr<cw_to_symbol> sptr;
/*!
* The CW to Symbol block tries to translate the received signal
* power time-series into Morse symbols.
*
* The input stream is the energy of the signal in the time domain.
* For best results, a proper moving average filter should be applied
* before.
*
* Upon a successful recovery of a symbol it produces an appropriate
* asynchronous message that can directly be used by the Morse decoder
* block.
*
* @param sampling_rate the sampling rate of the signal
* @param threshold the activation threshold
* @param wpm Morse code Words per Minute
*/
static sptr make(double sampling_rate, float threshold, size_t wpm = 20);
};
} // namespace satnogs
} // namespace gr
#endif /* INCLUDED_SATNOGS_CW_TO_SYMBOL_H */

View File

@ -29,7 +29,8 @@ list(APPEND satnogs_sources
morse_tree.cc
morse_decoder_impl.cc
morse_debug_source_impl.cc
clear_text_msg_sink_impl.cc )
clear_text_msg_sink_impl.cc
cw_to_symbol_impl.cc )
set(satnogs_sources "${satnogs_sources}" PARENT_SCOPE)
if(NOT satnogs_sources)

211
lib/cw_to_symbol_impl.cc Normal file
View File

@ -0,0 +1,211 @@
/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2016, Libre Space Foundation <http://librespacefoundation.org/>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include <satnogs/log.h>
#include <satnogs/morse.h>
#include "cw_to_symbol_impl.h"
namespace gr
{
namespace satnogs
{
cw_to_symbol::sptr
cw_to_symbol::make (double sampling_rate, float threshold, size_t wpm)
{
return gnuradio::get_initial_sptr (
new cw_to_symbol_impl (sampling_rate, threshold, wpm));
}
/*
* The private constructor
*/
cw_to_symbol_impl::cw_to_symbol_impl (double sampling_rate, float threshold,
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_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)
{
message_port_register_out(pmt::mp("out"));
}
/*
* Our virtual destructor.
*/
cw_to_symbol_impl::~cw_to_symbol_impl ()
{
}
inline void
cw_to_symbol_impl::set_idle ()
{
d_state = IDLE;
d_state_cnt = 0;
d_pause_cnt = 0;
}
inline void
cw_to_symbol_impl::set_short_on ()
{
d_state = SHORT_ON_PERIOD;
d_state_cnt = 1;
}
inline void
cw_to_symbol_impl::set_long_on ()
{
d_state = LONG_ON_PERIOD;
d_pause_cnt = 0;
}
inline void
cw_to_symbol_impl::set_short_off (size_t borrow_cnt)
{
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;
}
}
inline void
cw_to_symbol_impl::set_long_off ()
{
d_state = LONG_OFF_PERIOD;
}
int
cw_to_symbol_impl::work (int noutput_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];
for(i = 0; i < noutput_items; i++) {
switch(d_state){
case IDLE:
if(in[i] > d_act_thrshld) {
set_short_on();
}
// TODO Avoid unnecessary pause messages
break;
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. So the time-slots counted
* so far should be assigned as pause time-slots.
*/
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);
}
}
break;
case LONG_ON_PERIOD:
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
*/
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));
}
else{
message_port_pub(pmt::mp("out"), pmt::from_long(MORSE_DOT));
}
set_short_off(0);
}
break;
case SHORT_OFF_PERIOD:
if(in[i] > d_act_thrshld) {
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) {
set_short_on();
}
else {
d_pause_cnt++;
if(d_pause_cnt > d_long_pause_samples) {
message_port_pub(pmt::mp("out"), pmt::from_long(MORSE_L_SPACE));
set_idle();
}
}
break;
default:
LOG_ERROR("Invalid State.");
d_state = IDLE;
}
}
return noutput_items;
}
} /* namespace satnogs */
} /* namespace gr */

81
lib/cw_to_symbol_impl.h Normal file
View File

@ -0,0 +1,81 @@
/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2016, Libre Space Foundation <http://librespacefoundation.org/>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_SATNOGS_CW_TO_SYMBOL_IMPL_H
#define INCLUDED_SATNOGS_CW_TO_SYMBOL_IMPL_H
#include <satnogs/cw_to_symbol.h>
namespace gr
{
namespace satnogs
{
class cw_to_symbol_impl : public cw_to_symbol
{
typedef enum {
IDLE,
SHORT_ON_PERIOD,
LONG_ON_PERIOD,
SHORT_OFF_PERIOD,
LONG_OFF_PERIOD
} cw_state_t;
private:
const double d_sampling_rate;
const float d_act_thrshld;
const float d_confidence_level;
const size_t d_dot_samples;
const size_t d_dash_samples;
const size_t d_short_pause_samples;
const size_t d_long_pause_samples;
cw_state_t d_state;
size_t d_state_cnt;
size_t d_pause_cnt;
inline void
set_idle ();
inline void
set_short_on ();
inline void
set_long_on ();
inline void
set_short_off (size_t borrow_cnt);
inline void
set_long_off ();
public:
cw_to_symbol_impl (double sampling_rate, float threshold, size_t wpm);
~cw_to_symbol_impl ();
// Where all the action really happens
int
work (int noutput_items, gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
};
} // namespace satnogs
} // namespace gr
#endif /* INCLUDED_SATNOGS_CW_TO_SYMBOL_IMPL_H */

View File

@ -13,6 +13,7 @@
#include "satnogs/morse_decoder.h"
#include "satnogs/morse_debug_source.h"
#include "satnogs/clear_text_msg_sink.h"
#include "satnogs/cw_to_symbol.h"
%}
%include "satnogs/cw_matched_filter_ff.h"
@ -24,3 +25,5 @@ GR_SWIG_BLOCK_MAGIC2(satnogs, morse_decoder);
GR_SWIG_BLOCK_MAGIC2(satnogs, morse_debug_source);
%include "satnogs/clear_text_msg_sink.h"
GR_SWIG_BLOCK_MAGIC2(satnogs, clear_text_msg_sink);
%include "satnogs/cw_to_symbol.h"
GR_SWIG_BLOCK_MAGIC2(satnogs, cw_to_symbol);