diff options
author | japm48 <japm48@users.noreply.github.com> | 2020-10-20 07:54:59 +0200 |
---|---|---|
committer | mormj <34754695+mormj@users.noreply.github.com> | 2020-10-28 14:15:25 -0400 |
commit | 1458b71d90310444e556f515ee86dde7c287ed79 (patch) | |
tree | 69ac890ede9ed5b5c9ebdf1e571d3d13ff5a0263 /gr-digital | |
parent | 15efb1ed8d089b3e5ef2aac7f55f483e36d4866d (diff) |
digital: ofdm_equalizer_simpledfe: add enable_soft_output option
Enable outputting equalized symbols that are not exactly constellation
symbols. This is useful for OFDM soft decoding/demodulation (e.g.
optimal turbo or LDPC decoding).
For compatibility, this new behaviour has to be enabled by setting the
new option "enable_soft_output" to true (false by default).
Diffstat (limited to 'gr-digital')
-rw-r--r-- | gr-digital/include/gnuradio/digital/ofdm_equalizer_simpledfe.h | 18 | ||||
-rw-r--r-- | gr-digital/lib/ofdm_equalizer_simpledfe.cc | 30 | ||||
-rw-r--r-- | gr-digital/python/digital/bindings/ofdm_equalizer_simpledfe_python.cc | 3 | ||||
-rwxr-xr-x[-rw-r--r--] | gr-digital/python/digital/qa_ofdm_frame_equalizer_vcvc.py | 37 |
4 files changed, 68 insertions, 20 deletions
diff --git a/gr-digital/include/gnuradio/digital/ofdm_equalizer_simpledfe.h b/gr-digital/include/gnuradio/digital/ofdm_equalizer_simpledfe.h index 54c9c43fea..725ef7c6c8 100644 --- a/gr-digital/include/gnuradio/digital/ofdm_equalizer_simpledfe.h +++ b/gr-digital/include/gnuradio/digital/ofdm_equalizer_simpledfe.h @@ -44,9 +44,12 @@ namespace digital { * channel state is estimated incorrectly during equalization; after that, * all subsequent symbols will be completely wrong. * - * Note that the equalized symbols are *exact points* on the constellation. - * This means soft information of the modulation symbols is lost after the + * Note that, by default, the equalized symbols are *exact points* on the + * constellation. + * This means that soft information of the modulation symbols is lost after the * equalization, which is suboptimal for channel codes that use soft decision. + * If this behaviour is not desired, set the `enable_soft_output` parameter to + * true. * */ class DIGITAL_API ofdm_equalizer_simpledfe : public ofdm_equalizer_1d_pilots @@ -64,7 +67,8 @@ public: std::vector<std::vector<gr_complex>>(), int symbols_skipped = 0, float alpha = 0.1, - bool input_is_shifted = true); + bool input_is_shifted = true, + bool enable_soft_output = false); ~ofdm_equalizer_simpledfe(); @@ -97,6 +101,9 @@ public: * the first input items is on the DC carrier. * Note that a lot of the OFDM receiver blocks operate on * shifted signals! + * \param enable_soft_output Output noisy equalized symbols instead of exact + * constellation symbols. + * This is useful for soft demodulation and decoding. */ static sptr make(int fft_len, const gr::digital::constellation_sptr& constellation, @@ -108,12 +115,15 @@ public: std::vector<std::vector<gr_complex>>(), int symbols_skipped = 0, float alpha = 0.1, - bool input_is_shifted = true); + bool input_is_shifted = true, + bool enable_soft_output = false); private: gr::digital::constellation_sptr d_constellation; //! Averaging coefficient float d_alpha; + //! Do not output exact constellation symbols + bool d_enable_soft_output; }; } /* namespace digital */ diff --git a/gr-digital/lib/ofdm_equalizer_simpledfe.cc b/gr-digital/lib/ofdm_equalizer_simpledfe.cc index 6ba0ca1b6e..0bca3bdbf6 100644 --- a/gr-digital/lib/ofdm_equalizer_simpledfe.cc +++ b/gr-digital/lib/ofdm_equalizer_simpledfe.cc @@ -24,16 +24,19 @@ ofdm_equalizer_simpledfe::make(int fft_len, const std::vector<std::vector<gr_complex>>& pilot_symbols, int symbols_skipped, float alpha, - bool input_is_shifted) + bool input_is_shifted, + bool enable_soft_output) { - return ofdm_equalizer_simpledfe::sptr(new ofdm_equalizer_simpledfe(fft_len, - constellation, - occupied_carriers, - pilot_carriers, - pilot_symbols, - symbols_skipped, - alpha, - input_is_shifted)); + return ofdm_equalizer_simpledfe::sptr( + new ofdm_equalizer_simpledfe(fft_len, + constellation, + occupied_carriers, + pilot_carriers, + pilot_symbols, + symbols_skipped, + alpha, + input_is_shifted, + enable_soft_output)); } ofdm_equalizer_simpledfe::ofdm_equalizer_simpledfe( @@ -44,7 +47,8 @@ ofdm_equalizer_simpledfe::ofdm_equalizer_simpledfe( const std::vector<std::vector<gr_complex>>& pilot_symbols, int symbols_skipped, float alpha, - bool input_is_shifted) + bool input_is_shifted, + bool enable_soft_output) : ofdm_equalizer_1d_pilots(fft_len, occupied_carriers, pilot_carriers, @@ -52,7 +56,8 @@ ofdm_equalizer_simpledfe::ofdm_equalizer_simpledfe( symbols_skipped, input_is_shifted), d_constellation(constellation), - d_alpha(alpha) + d_alpha(alpha), + d_enable_soft_output(enable_soft_output) { } @@ -69,6 +74,7 @@ void ofdm_equalizer_simpledfe::equalize(gr_complex* frame, d_channel_state = initial_taps; } gr_complex sym_eq, sym_est; + bool enable_soft_output = d_enable_soft_output; for (int i = 0; i < n_sym; i++) { for (int k = 0; k < d_fft_len; k++) { @@ -92,7 +98,7 @@ void ofdm_equalizer_simpledfe::equalize(gr_complex* frame, &sym_est); d_channel_state[k] = d_alpha * d_channel_state[k] + (1 - d_alpha) * frame[i * d_fft_len + k] / sym_est; - frame[i * d_fft_len + k] = sym_est; + frame[i * d_fft_len + k] = enable_soft_output ? sym_eq : sym_est; } } if (!d_pilot_carriers.empty()) { diff --git a/gr-digital/python/digital/bindings/ofdm_equalizer_simpledfe_python.cc b/gr-digital/python/digital/bindings/ofdm_equalizer_simpledfe_python.cc index 44bb7e5b42..fcd939057f 100644 --- a/gr-digital/python/digital/bindings/ofdm_equalizer_simpledfe_python.cc +++ b/gr-digital/python/digital/bindings/ofdm_equalizer_simpledfe_python.cc @@ -14,7 +14,7 @@ /* BINDTOOL_GEN_AUTOMATIC(0) */ /* BINDTOOL_USE_PYGCCXML(0) */ /* BINDTOOL_HEADER_FILE(ofdm_equalizer_simpledfe.h) */ -/* BINDTOOL_HEADER_FILE_HASH(8091e37dbba4afc0b7a2fd9441996144) */ +/* BINDTOOL_HEADER_FILE_HASH(e484906ff9740a46f83b999ec69f511e) */ /***********************************************************************************/ #include <pybind11/complex.h> @@ -47,6 +47,7 @@ void bind_ofdm_equalizer_simpledfe(py::module& m) py::arg("symbols_skipped") = 0, py::arg("alpha") = 0.10000000000000001, py::arg("input_is_shifted") = true, + py::arg("enable_soft_output") = false, D(ofdm_equalizer_simpledfe, make)) diff --git a/gr-digital/python/digital/qa_ofdm_frame_equalizer_vcvc.py b/gr-digital/python/digital/qa_ofdm_frame_equalizer_vcvc.py index 6af2817685..a1b2a2e070 100644..100755 --- a/gr-digital/python/digital/qa_ofdm_frame_equalizer_vcvc.py +++ b/gr-digital/python/digital/qa_ofdm_frame_equalizer_vcvc.py @@ -167,6 +167,7 @@ class qa_ofdm_frame_equalizer_vcvc (gr_unittest.TestCase): # Check data self.assertComplexTuplesAlmostEqual(rx_expected, sink.data()[0], places=4) + def test_002_static (self): """ - Add a simple channel @@ -229,6 +230,9 @@ class qa_ofdm_frame_equalizer_vcvc (gr_unittest.TestCase): expected_dict = { 'ofdm_sync_chan_taps': channel[-fft_len:] } + # Won't be exactly the same when compiled with -fcx-limited-range + self.assertTrue(numpy.allclose(tag_dict['ofdm_sync_chan_taps'], expected_dict['ofdm_sync_chan_taps'])) + expected_dict['ofdm_sync_chan_taps'] = tag_dict['ofdm_sync_chan_taps'] self.assertEqual(tag_dict, expected_dict) def test_002_static_wo_tags (self): @@ -330,6 +334,9 @@ class qa_ofdm_frame_equalizer_vcvc (gr_unittest.TestCase): equalizer = digital.ofdm_equalizer_simpledfe( fft_len, cnst.base(), occupied_carriers, pilot_carriers, pilot_symbols, 0, 0.01 ) + equalizer_soft = digital.ofdm_equalizer_simpledfe( + fft_len, cnst.base(), occupied_carriers, pilot_carriers, pilot_symbols, 0, 0.01, enable_soft_output=True + ) channel = [ 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, # These coefficients will be rotated slightly... @@ -346,16 +353,40 @@ class qa_ofdm_frame_equalizer_vcvc (gr_unittest.TestCase): chan_tag.value = pmt.init_c32vector(fft_len, channel[:fft_len]) src = blocks.vector_source_c(numpy.multiply(tx_signal, channel), False, fft_len, (chan_tag,)) eq = digital.ofdm_frame_equalizer_vcvc(equalizer.base(), 0, self.tsb_key, True) + eq_soft = digital.ofdm_frame_equalizer_vcvc(equalizer_soft.base(), 0, self.tsb_key, True) sink = blocks.tsb_vector_sink_c(fft_len, tsb_key=self.tsb_key) + sink_soft = blocks.tsb_vector_sink_c(fft_len, tsb_key=self.tsb_key) + stream_to_tagged = blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, fft_len, len(tx_data) // fft_len, self.tsb_key) self.tb.connect( src, - blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, fft_len, len(tx_data) // fft_len, self.tsb_key), + stream_to_tagged, eq, sink ) + self.tb.connect( + stream_to_tagged, + eq_soft, + sink_soft + ) self.tb.run () - rx_data = [cnst.decision_maker_v((x,)) if x != 0 else -1 for x in sink.data()[0]] + + out_syms = numpy.array(sink.data()[0]) + out_syms_soft = numpy.array(sink_soft.data()[0]) + demod = lambda syms: [cnst.decision_maker_v((x,)) if x != 0 else -1 for x in syms] + rx_data = demod(out_syms) + rx_data_soft = demod(out_syms_soft) + + ## Uncomment to plot symbols + #import matplotlib.pyplot as plt + #def plot_syms(d): plt.figure(); plt.plot(d.real, d.imag, 'b.') + # + #plot_syms(out_syms) + #plot_syms(out_syms_soft) + #plt.show() + self.assertEqual(tx_data, rx_data) + self.assertEqual(rx_data, rx_data_soft) + self.assertFalse(numpy.allclose(out_syms, out_syms_soft)) self.assertEqual(len(sink.tags()), 1) tag = sink.tags()[0] self.assertEqual(pmt.symbol_to_string(tag.key), "ofdm_sync_chan_taps") @@ -363,5 +394,5 @@ class qa_ofdm_frame_equalizer_vcvc (gr_unittest.TestCase): if __name__ == '__main__': - gr_unittest.run(qa_ofdm_frame_equalizer_vcvc, "qa_ofdm_frame_equalizer_vcvc.xml") + gr_unittest.run(qa_ofdm_frame_equalizer_vcvc) |