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`.
This commit is contained in:
parent
43bf277442
commit
d07fd19285
|
@ -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.
|
||||
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.
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue