Commit d07fd192 authored by Manolis Surligas's avatar Manolis Surligas

Fix CW decoder issue

The CW decoder was wrongly producing a Short Pause symbol instead of a
dot symbol. With this fix the decoder can now reconstruct the initial
text sequence sent.

Also the CW matched filter now can directly produce the power of the
filtered samples. This is very handy in order to get rid off an
additional multiply block, saving vital resources especially for
embedded platforms.

For testing and demonstration purposes the morse_decoding_flowgraph can
be used. The word sequence is the `HELLO WORLD`.
parent 43bf2774
......@@ -10,4 +10,10 @@ Words per Minute (WPM) is about 20.
## Flowgraphs
* `test_matched_filter.grc`: Demonstrates the performance of the implemented
matched filter for CW decoding.
\ No newline at end of file
matched filter for CW decoding.
* `morse_decoding_flowgraph.grc`: This flowgraph decodes a CW signal and
prints the corresponding message at the `stdout`. To demonstrate the
capabilities of the decoder, signal and noise power GUI sliders are provided
for easy testing and experimenting.
\ No newline at end of file
This diff is collapsed.
No preview for this file type
......@@ -4,7 +4,7 @@
<key>satnogs_cw_matched_filter_ff</key>
<category>satnogs</category>
<import>import satnogs</import>
<make>satnogs.cw_matched_filter_ff($sampling_rate, $carrier_freq, $wpm)
<make>satnogs.cw_matched_filter_ff($sampling_rate, $carrier_freq, $wpm, $energy)
</make>
<param>
......@@ -25,6 +25,20 @@
<value>20</value>
<type>int</type>
</param>
<param>
<name>Compute Energy</name>
<key>energy</key>
<type>enum</type>
<option>
<name>No</name>
<key>False</key>
</option>
<option>
<name>Yes</name>
<key>True</key>
</option>
</param>
<sink>
<name>in</name>
......
......@@ -21,6 +21,11 @@
#ifndef INCLUDE_SATNOGS_CONFIG_H_
#define INCLUDE_SATNOGS_CONFIG_H_
/*!
* Enable debug messages for the module
*/
#define ENABLE_DEBUG_MSG 0
/*!
* Enable debug messages for the CW decoding mechanism
*/
......
......@@ -45,9 +45,14 @@ namespace gr {
* @param sampling_rate the sampling rate of the signal
* @param carrier_freq the audio frequency of the CW signal
* @param wpm Morse code Words per Minute
* @param energy_out if true, the filter produces the energy of the
* resulting filtered samples, otherwise the raw filter samples are
* produced. This is handy, in order to save the flowgraph from
* am additional signal energy block.
*/
static sptr make(double sampling_rate, double carrier_freq = 500,
size_t wpm = 20);
size_t wpm = 20,
bool energy_out = false);
};
} // namespace satnogs
......
......@@ -29,7 +29,7 @@
#include <sys/syscall.h>
#if CW_DEBUG
#if ENABLE_DEBUG_MSG
#define LOG_INFO(M, ...) \
fprintf(stderr, "[INFO]: " M " \n", ##__VA_ARGS__)
......@@ -43,7 +43,7 @@
#define LOG_WARN(M, ...) \
fprintf(stderr, "[WARNING] %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#if CW_DEBUG
#if ENABLE_DEBUG_MSG
#define LOG_DEBUG(M, ...) \
fprintf(stderr, "[DEBUG]: " M "\n", ##__VA_ARGS__)
#else
......
......@@ -39,7 +39,7 @@ namespace gr {
clear_text_msg_sink_impl::msg_handler (pmt::pmt_t msg)
{
std::string s((const char *)pmt::blob_data(msg), pmt::blob_length(msg));
std::cout << s << " " << std::endl;
std::cout << "Received text sequence:" << s << " " << std::endl;
}
/*
......
......@@ -32,10 +32,12 @@ namespace gr {
namespace satnogs {
cw_matched_filter_ff::sptr
cw_matched_filter_ff::make(double sampling_rate, double carrier_freq, size_t wpm)
cw_matched_filter_ff::make(double sampling_rate, double carrier_freq,
size_t wpm, bool energy_out)
{
return gnuradio::get_initial_sptr
(new cw_matched_filter_ff_impl(sampling_rate, carrier_freq, wpm));
(new cw_matched_filter_ff_impl(sampling_rate, carrier_freq,
wpm, energy_out));
}
/*
......@@ -43,11 +45,13 @@ namespace gr {
*/
cw_matched_filter_ff_impl::cw_matched_filter_ff_impl (double sampling_rate,
double carrier_freq,
size_t wpm) :
size_t wpm,
bool energy_out) :
gr::sync_block ("cw_matched_filter_ff",
gr::io_signature::make (1, 1, sizeof(float)),
gr::io_signature::make (1, 1, sizeof(float))),
d_dot_duration(1.2/wpm),
d_produce_enrg(energy_out),
d_dot_samples(d_dot_duration / (1.0 / sampling_rate))
{
const int alignment_multiple = volk_get_alignment() / sizeof(float);
......@@ -85,6 +89,9 @@ namespace gr {
volk_32f_x2_dot_prod_32f(out + i, in + i, d_sin_wave,
d_dot_samples);
}
if(d_produce_enrg){
volk_32f_s32f_power_32f(out, out, 2, noutput_items);
}
return noutput_items;
}
......
......@@ -34,6 +34,11 @@ namespace gr {
* The duration of the dot in seconds
*/
const double d_dot_duration;
/**
* If set to true, this block produces the energy of the filtered
* samples, rather the samples themselves
*/
const bool d_produce_enrg;
/**
* The duration of the dot in number of samples
*/
......@@ -43,7 +48,7 @@ namespace gr {
public:
cw_matched_filter_ff_impl(double sampling_rate, double carrier_freq,
size_t wpm);
size_t wpm, bool energy_out);
~cw_matched_filter_ff_impl();
// Where all the action really happens
......
......@@ -78,7 +78,6 @@ 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;
......@@ -87,7 +86,6 @@ 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;
......@@ -96,14 +94,12 @@ namespace gr
inline void
cw_to_symbol_impl::set_long_on ()
{
LOG_WARN("Enter LONG ON");
d_state = LONG_ON_PERIOD;
}
inline void
cw_to_symbol_impl::set_short_off ()
{
LOG_WARN("Enter SHORT OFF");
d_state = SHORT_OFF_PERIOD;
d_state_cnt = 0;
d_pause_cnt = 1;
......@@ -112,7 +108,6 @@ namespace gr
inline void
cw_to_symbol_impl::set_long_off ()
{
LOG_WARN("Enter LONG OFF");
d_state = LONG_OFF_PERIOD;
}
......@@ -150,8 +145,8 @@ namespace gr
*/
conf_lvl = ((float) d_state_cnt) / d_dot_samples;
if(conf_lvl > d_confidence_level){
LOG_DEBUG("Short space");
send_symbol_msg(MORSE_S_SPACE);
LOG_DEBUG("DOT");
send_symbol_msg(MORSE_DOT);
}
/* Go find a possible short pause symbol */
......
......@@ -56,6 +56,11 @@ namespace gr
* word
*/
case MORSE_L_SPACE:
/*
* Inject a character separator, for the morse decoder to commit
* the outstanding character
*/
res = d_morse_tree.received_symbol(MORSE_S_SPACE);
/* Just ignore the word separator if no word is yet decoded */
if (d_morse_tree.get_word_len() == 0) {
res = true;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment