summaryrefslogtreecommitdiff
path: root/gr-digital
diff options
context:
space:
mode:
authorjapm48 <japm48@users.noreply.github.com>2020-10-20 07:54:59 +0200
committermormj <34754695+mormj@users.noreply.github.com>2020-10-28 14:15:25 -0400
commit1458b71d90310444e556f515ee86dde7c287ed79 (patch)
tree69ac890ede9ed5b5c9ebdf1e571d3d13ff5a0263 /gr-digital
parent15efb1ed8d089b3e5ef2aac7f55f483e36d4866d (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.h18
-rw-r--r--gr-digital/lib/ofdm_equalizer_simpledfe.cc30
-rw-r--r--gr-digital/python/digital/bindings/ofdm_equalizer_simpledfe_python.cc3
-rwxr-xr-x[-rw-r--r--]gr-digital/python/digital/qa_ofdm_frame_equalizer_vcvc.py37
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)