diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt index 22ff453..122b647 100644 --- a/grc/CMakeLists.txt +++ b/grc/CMakeLists.txt @@ -52,5 +52,5 @@ if(${INCLUDE_DEBUG_BLOCKS}) endif() install(FILES ${enabled_blocks} - DESTINATION share/gnuradio/grc/blocks + satnogs_quad_demod_filter_ff.xml DESTINATION share/gnuradio/grc/blocks ) diff --git a/grc/satnogs_block_tree.xml b/grc/satnogs_block_tree.xml index c052cee..17f5742 100644 --- a/grc/satnogs_block_tree.xml +++ b/grc/satnogs_block_tree.xml @@ -29,4 +29,5 @@ satnogs_ax25_encoder_mb satnogs_ax25_decoder_bm satnogs_waterfall_sink + satnogs_quad_demod_filter_ff \ No newline at end of file diff --git a/grc/satnogs_quad_demod_filter_ff.xml b/grc/satnogs_quad_demod_filter_ff.xml new file mode 100644 index 0000000..f1be4c8 --- /dev/null +++ b/grc/satnogs_quad_demod_filter_ff.xml @@ -0,0 +1,34 @@ + + + Quadrature Demod Filter + satnogs_quad_demod_filter_ff + import satnogs + satnogs.quad_demod_filter_ff($thresh) + + + Threshold + thresh + math.pi + real + + + + + in + float + + + + + out + float + + diff --git a/include/satnogs/CMakeLists.txt b/include/satnogs/CMakeLists.txt index 2e38fed..ea2a968 100644 --- a/include/satnogs/CMakeLists.txt +++ b/include/satnogs/CMakeLists.txt @@ -67,5 +67,5 @@ endif() install(FILES ${HEADER_FILES} - DESTINATION include/satnogs + quad_demod_filter_ff.h DESTINATION include/satnogs ) \ No newline at end of file diff --git a/include/satnogs/quad_demod_filter_ff.h b/include/satnogs/quad_demod_filter_ff.h new file mode 100644 index 0000000..d34d42d --- /dev/null +++ b/include/satnogs/quad_demod_filter_ff.h @@ -0,0 +1,82 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2018, Libre Space Foundation + * + * 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 . + */ + + +#ifndef INCLUDED_SATNOGS_QUAD_DEMOD_FILTER_FF_H +#define INCLUDED_SATNOGS_QUAD_DEMOD_FILTER_FF_H + +#include +#include + +namespace gr { + namespace satnogs { + + /*! + * \brief The goal of this block is to act as a valve for a signal + * commonly originating from a clock recovered quadrature demodulated stream. + * + * A very common problem in such cases, is that after the quadrature + * demodulation the signal is on the phase domain and the detection + * of signal presence or absence cannot be performed with energy detection. + * Why do we need to identify signal presence? Most of the amateur satellites + * uses quite poor and short training sequences, especially in the AX.25 + * AFSK1200 mode. Thus, the decoders have too many false alarms and due to + * this, they miss frames. + * + * Some may argue that you can perform energy detection before the quadrature + * demodulation, but this implies a 'magic' threshold should be set. + * In the SatNOGS case, this is not possible. Every ground station is unique + * in terms of performance and RF characteristics. On the other hand the + * phase domain has the nice property that the signal level is known. This + * level can be +-pi. This block tries to find an SNR-like metric based + * on the variance and the mean of the signal. + * \ingroup satnogs + * + */ + class SATNOGS_API quad_demod_filter_ff : virtual public gr::block + { + public: + typedef boost::shared_ptr sptr; + + + /** + * Creates a Quadrature Demodulate filter. The block will output samples + * only in signal presence acting as a valve to reduce false alarms of + * the FSK decoders. + * + * @param gain this MUST be the gain set on the quadrature demodulate + * gain or an appropriate value if the amplitude of the quadrature + * demodulated signal somehow is scaled. By default if the signal is + * on the +-pi region, the gain should be one. If it is on the +-2pi, the + * gain should be set to 2.0 etc. + * + * @param window the window size to calculate the moving average and + * variance. + * + * @return shared pointer of the block + */ + static sptr make(float gain, int window = 80); + }; + + } // namespace satnogs +} // namespace gr + +#endif /* INCLUDED_SATNOGS_QUAD_DEMOD_FILTER_FF_H */ + diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 40f44e2..5fd37e5 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -64,7 +64,8 @@ list(APPEND satnogs_sources ogg_source_impl.cc noaa_apt_sink_impl.cc frame_file_sink_impl.cc - iq_sink_impl.cc) + iq_sink_impl.cc + quad_demod_filter_ff_impl.cc) if(${INCLUDE_DEBUG_BLOCKS}) list(APPEND satnogs_sources ${satnogs_debug_sources}) diff --git a/lib/quad_demod_filter_ff_impl.cc b/lib/quad_demod_filter_ff_impl.cc new file mode 100644 index 0000000..f039123 --- /dev/null +++ b/lib/quad_demod_filter_ff_impl.cc @@ -0,0 +1,140 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2018, Libre Space Foundation + * + * 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 . + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "quad_demod_filter_ff_impl.h" + +namespace gr { + namespace satnogs { + + quad_demod_filter_ff::sptr + quad_demod_filter_ff::make(float gain, int window) + { + return gnuradio::get_initial_sptr + (new quad_demod_filter_ff_impl(gain, window)); + } + + /* + * The private constructor + */ + quad_demod_filter_ff_impl::quad_demod_filter_ff_impl (float gain, + int window) : + gr::block ("quad_demod_filter_ff", + gr::io_signature::make (1, 1, sizeof(float)), + gr::io_signature::make (1, 1, sizeof(float))), + d_gain (gain), + d_norm (1.0f / window), + d_win (window), + d_sum (0.0f), + d_sum_sq (0.0f), + d_remaining (0) + { + if(window < 1) { + throw std::invalid_argument ("Window must be a positive"); + } + set_history (2 * window); + } + + /* + * Our virtual destructor. + */ + quad_demod_filter_ff_impl::~quad_demod_filter_ff_impl() + { + } + + /** + * Fast approximation of the inverse of the square root. + * Thank you OpenArena! + * @param number the number to be computed + * @return the inverse of the square root of the number + */ + static inline float + inv_sqrt (float number) + { + long i; + float x2, y; + const float threehalfs = 1.5f; + + x2 = number * 0.5f; + y = number; + i = *(long *) &y; + i = 0x5f3759df - (i >> 1); /* what the fuck? */ + y = *(float *) &i; + y = y * (threehalfs - (x2 * y * y)); + return y; + } + + int + quad_demod_filter_ff_impl::general_work ( + int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const float *in = (const float *) input_items[0]; + float *out = (float *) output_items[0]; + int available = std::min(ninput_items[0], noutput_items); + int produced = 0; + float m; + float m_sq; + float snr; + float in_old; + float in_new; + + float diff; + for(int i = 0; i < available; i++) { + in_old = std::abs(in[i + d_win]); + in_new = std::abs(in[i + 2*d_win - 1]); + d_sum -= in_old; + d_sum += in_new; + d_sum_sq -= (in_old * in_old); + d_sum_sq += (in_new * in_new); + + m = (d_sum * d_norm); + m_sq = (d_sum_sq * d_norm); + snr = m * inv_sqrt(m_sq - m*m); + + /* + * If the SNR is high enough start passing the data to the output. + * In order not to loose any samples due to the settling period, start + * from the buffered and let a window of samples to pass after the + * trigger is off + */ + if(snr > d_gain * 1.8) { + d_remaining = 2*d_win; + } + + if(d_remaining) { + out[produced++] = in[i]; + d_remaining--; + } + } + + // Tell runtime system how many output items we produced. + consume_each(available); + return produced; + } + + } /* namespace satnogs */ +} /* namespace gr */ + diff --git a/lib/quad_demod_filter_ff_impl.h b/lib/quad_demod_filter_ff_impl.h new file mode 100644 index 0000000..06fa2a7 --- /dev/null +++ b/lib/quad_demod_filter_ff_impl.h @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2018, Libre Space Foundation + * + * 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 . + */ + +#ifndef INCLUDED_SATNOGS_QUAD_DEMOD_FILTER_FF_IMPL_H +#define INCLUDED_SATNOGS_QUAD_DEMOD_FILTER_FF_IMPL_H + +#include + +namespace gr { + namespace satnogs { + + class quad_demod_filter_ff_impl : public quad_demod_filter_ff + { + private: + const float d_gain; + const float d_norm; + const int d_win; + float d_sum; + float d_sum_sq; + int d_remaining; + + public: + quad_demod_filter_ff_impl(float gain, int window); + ~quad_demod_filter_ff_impl(); + + // Where all the action really happens + int + general_work (int noutput_items, gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace satnogs +} // namespace gr + +#endif /* INCLUDED_SATNOGS_QUAD_DEMOD_FILTER_FF_IMPL_H */ + diff --git a/swig/satnogs_swig0.i b/swig/satnogs_swig0.i index 6f4c040..e73340a 100644 --- a/swig/satnogs_swig0.i +++ b/swig/satnogs_swig0.i @@ -31,6 +31,7 @@ #include "satnogs/noaa_apt_sink.h" #include "satnogs/frame_file_sink.h" #include "satnogs/iq_sink.h" +#include "satnogs/quad_demod_filter_ff.h" %} @@ -97,3 +98,5 @@ GR_SWIG_BLOCK_MAGIC2(satnogs, frame_file_sink); %include "satnogs/iq_sink.h" GR_SWIG_BLOCK_MAGIC2(satnogs, iq_sink); +%include "satnogs/quad_demod_filter_ff.h" +GR_SWIG_BLOCK_MAGIC2(satnogs, quad_demod_filter_ff);