From c13b993a9cbf2dd8c60da19b11f63febe7bc39a8 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Tue, 26 Nov 2024 10:00:28 +0100 Subject: Restore ofdmwindowing for fixed point --- src/GuardIntervalInserter.cpp | 250 ++++++++++++++++++++++++------------------ src/GuardIntervalInserter.h | 7 +- 2 files changed, 148 insertions(+), 109 deletions(-) diff --git a/src/GuardIntervalInserter.cpp b/src/GuardIntervalInserter.cpp index 26d4fd1..3ff8fd5 100644 --- a/src/GuardIntervalInserter.cpp +++ b/src/GuardIntervalInserter.cpp @@ -2,7 +2,7 @@ Copyright (C) 2005, 2206, 2007, 2008, 2009, 2010, 2011 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2023 + Copyright (C) 2024 Matthias P. Braendli, matthias.braendli@mpb.li http://opendigitalradio.org @@ -100,9 +100,15 @@ void GuardIntervalInserter::update_window(size_t new_window_overlap) m_params.windowOverlap = new_window_overlap; // m_params.window only contains the rising window edge. - m_params.window.resize(2*m_params.windowOverlap); + m_params.windowFloat.resize(2*m_params.windowOverlap); + m_params.windowFix.resize(2*m_params.windowOverlap); + m_params.windowFixWide.resize(2*m_params.windowOverlap); for (size_t i = 0; i < 2*m_params.windowOverlap; i++) { - m_params.window[i] = (float)(0.5 * (1.0 - cos(M_PI * i / (2*m_params.windowOverlap - 1)))); + const float value = (float)(0.5 * (1.0 - cos(M_PI * i / (2*m_params.windowOverlap - 1)))); + + m_params.windowFloat[i] = value; + m_params.windowFix[i] = complexfix::value_type((double)value); + m_params.windowFixWide[i] = complexfix_wide::value_type((double)value); } } @@ -141,120 +147,155 @@ int do_process(const GuardIntervalInserter::Params& p, Buffer* const dataIn, Buf std::lock_guard lock(p.windowMutex); if (p.windowOverlap) { - if constexpr (std::is_same_v) { - { - // Handle Null symbol separately because it is longer - const size_t prefixlength = p.nullSize - p.spacing; - - // end = spacing - memcpy(out, &in[p.spacing - prefixlength], - prefixlength * sizeof(T)); - - memcpy(&out[prefixlength], in, (p.spacing - p.windowOverlap) * sizeof(T)); - - // The remaining part of the symbol must have half of the window applied, - // sloping down from 1 to 0.5 - for (size_t i = 0; i < p.windowOverlap; i++) { - const size_t out_ix = prefixlength + p.spacing - p.windowOverlap + i; - const size_t in_ix = p.spacing - p.windowOverlap + i; - out[out_ix] = in[in_ix] * p.window[2*p.windowOverlap - (i+1)]; + { + // Handle Null symbol separately because it is longer + const size_t prefixlength = p.nullSize - p.spacing; + + // end = spacing + memcpy(out, &in[p.spacing - prefixlength], + prefixlength * sizeof(T)); + + memcpy(&out[prefixlength], in, (p.spacing - p.windowOverlap) * sizeof(T)); + + // The remaining part of the symbol must have half of the window applied, + // sloping down from 1 to 0.5 + for (size_t i = 0; i < p.windowOverlap; i++) { + const size_t out_ix = prefixlength + p.spacing - p.windowOverlap + i; + const size_t in_ix = p.spacing - p.windowOverlap + i; + if constexpr (std::is_same_v) { + out[out_ix] = in[in_ix] * p.windowFloat[2*p.windowOverlap - (i+1)]; } - - // Suffix is taken from the beginning of the symbol, and sees the other - // half of the window applied. - for (size_t i = 0; i < p.windowOverlap; i++) { - const size_t out_ix = prefixlength + p.spacing + i; - out[out_ix] = in[i] * p.window[p.windowOverlap - (i+1)]; + if constexpr (std::is_same_v) { + out[out_ix] = in[in_ix] * p.windowFix[2*p.windowOverlap - (i+1)]; + } + if constexpr (std::is_same_v) { + out[out_ix] = in[in_ix] * p.windowFixWide[2*p.windowOverlap - (i+1)]; } - - in += p.spacing; - out += p.nullSize; - // out is now pointing to the proper end of symbol. There are - // windowOverlap samples ahead that were already written. } - // Data symbols - for (size_t sym_ix = 0; sym_ix < p.nbSymbols; sym_ix++) { - /* _ix variables are indices into in[], _ox variables are - * indices for out[] */ - const ssize_t start_rise_ox = -p.windowOverlap; - const size_t start_rise_ix = 2 * p.spacing - p.symSize - p.windowOverlap; - /* - const size_t start_real_symbol_ox = 0; - const size_t start_real_symbol_ix = 2 * p.spacing - p.symSize; - */ - const ssize_t end_rise_ox = p.windowOverlap; - const size_t end_rise_ix = 2 * p.spacing - p.symSize + p.windowOverlap; - const ssize_t end_cyclic_prefix_ox = p.symSize - p.spacing; - /* end_cyclic_prefix_ix = end of symbol - const size_t begin_fall_ox = p.symSize - p.windowOverlap; - const size_t begin_fall_ix = p.spacing - p.windowOverlap; - const size_t end_real_symbol_ox = p.symSize; - end_real_symbol_ix = end of symbol - const size_t end_fall_ox = p.symSize + p.windowOverlap; - const size_t end_fall_ix = p.spacing + p.windowOverlap; - */ - - ssize_t ox = start_rise_ox; - size_t ix = start_rise_ix; - - for (size_t i = 0; ix < end_rise_ix; i++) { - out[ox] += in[ix] * p.window.at(i); - ix++; - ox++; + // Suffix is taken from the beginning of the symbol, and sees the other + // half of the window applied. + for (size_t i = 0; i < p.windowOverlap; i++) { + const size_t out_ix = prefixlength + p.spacing + i; + if constexpr (std::is_same_v) { + out[out_ix] = in[i] * p.windowFloat[p.windowOverlap - (i+1)]; + } + if constexpr (std::is_same_v) { + out[out_ix] = in[i] * p.windowFix[p.windowOverlap - (i+1)]; + } + if constexpr (std::is_same_v) { + out[out_ix] = in[i] * p.windowFixWide[p.windowOverlap - (i+1)]; } - assert(ox == end_rise_ox); + } - const size_t remaining_prefix_length = end_cyclic_prefix_ox - end_rise_ox; - memcpy( &out[ox], &in[ix], - remaining_prefix_length * sizeof(T)); - ox += remaining_prefix_length; - assert(ox == end_cyclic_prefix_ox); - ix = 0; + in += p.spacing; + out += p.nullSize; + // out is now pointing to the proper end of symbol. There are + // windowOverlap samples ahead that were already written. + } - const bool last_symbol = (sym_ix + 1 >= p.nbSymbols); - if (last_symbol) { - // No windowing at all at end - memcpy(&out[ox], &in[ix], p.spacing * sizeof(T)); - ox += p.spacing; + // Data symbols + for (size_t sym_ix = 0; sym_ix < p.nbSymbols; sym_ix++) { + /* _ix variables are indices into in[], _ox variables are + * indices for out[] */ + const ssize_t start_rise_ox = -p.windowOverlap; + const size_t start_rise_ix = 2 * p.spacing - p.symSize - p.windowOverlap; + /* + const size_t start_real_symbol_ox = 0; + const size_t start_real_symbol_ix = 2 * p.spacing - p.symSize; + */ + const ssize_t end_rise_ox = p.windowOverlap; + const size_t end_rise_ix = 2 * p.spacing - p.symSize + p.windowOverlap; + const ssize_t end_cyclic_prefix_ox = p.symSize - p.spacing; + /* end_cyclic_prefix_ix = end of symbol + const size_t begin_fall_ox = p.symSize - p.windowOverlap; + const size_t begin_fall_ix = p.spacing - p.windowOverlap; + const size_t end_real_symbol_ox = p.symSize; + end_real_symbol_ix = end of symbol + const size_t end_fall_ox = p.symSize + p.windowOverlap; + const size_t end_fall_ix = p.spacing + p.windowOverlap; + */ + + ssize_t ox = start_rise_ox; + size_t ix = start_rise_ix; + + for (size_t i = 0; ix < end_rise_ix; i++) { + if constexpr (std::is_same_v) { + out[ox] += in[ix] * p.windowFloat.at(i); + } + if constexpr (std::is_same_v) { + out[ox] += in[ix] * p.windowFix.at(i); } - else { - // Copy the middle part of the symbol, p.windowOverlap samples - // short of the end. - memcpy( &out[ox], - &in[ix], - (p.spacing - p.windowOverlap) * sizeof(T)); - ox += p.spacing - p.windowOverlap; - ix += p.spacing - p.windowOverlap; - assert(ox == (ssize_t)(p.symSize - p.windowOverlap)); - - // Apply window from 1 to 0.5 for the end of the symbol - for (size_t i = 0; ox < (ssize_t)p.symSize; i++) { - out[ox] = in[ix] * p.window[2*p.windowOverlap - (i+1)]; - ox++; - ix++; + if constexpr (std::is_same_v) { + out[ox] += in[ix] * p.windowFixWide.at(i); + } + ix++; + ox++; + } + assert(ox == end_rise_ox); + + const size_t remaining_prefix_length = end_cyclic_prefix_ox - end_rise_ox; + memcpy( &out[ox], &in[ix], + remaining_prefix_length * sizeof(T)); + ox += remaining_prefix_length; + assert(ox == end_cyclic_prefix_ox); + ix = 0; + + const bool last_symbol = (sym_ix + 1 >= p.nbSymbols); + if (last_symbol) { + // No windowing at all at end + memcpy(&out[ox], &in[ix], p.spacing * sizeof(T)); + ox += p.spacing; + } + else { + // Copy the middle part of the symbol, p.windowOverlap samples + // short of the end. + memcpy( &out[ox], + &in[ix], + (p.spacing - p.windowOverlap) * sizeof(T)); + ox += p.spacing - p.windowOverlap; + ix += p.spacing - p.windowOverlap; + assert(ox == (ssize_t)(p.symSize - p.windowOverlap)); + + // Apply window from 1 to 0.5 for the end of the symbol + for (size_t i = 0; ox < (ssize_t)p.symSize; i++) { + if constexpr (std::is_same_v) { + out[ox] = in[ix] * p.windowFloat[2*p.windowOverlap - (i+1)]; + } + if constexpr (std::is_same_v) { + out[ox] = in[ix] * p.windowFix[2*p.windowOverlap - (i+1)]; } - assert(ix == p.spacing); - - ix = 0; - // Cyclic suffix, with window from 0.5 to 0 - for (size_t i = 0; ox < (ssize_t)(p.symSize + p.windowOverlap); i++) { - out[ox] = in[ix] * p.window[p.windowOverlap - (i+1)]; - ox++; - ix++; + if constexpr (std::is_same_v) { + out[ox] = in[ix] * p.windowFixWide[2*p.windowOverlap - (i+1)]; } + ox++; + ix++; + } + assert(ix == p.spacing); - assert(ix == p.windowOverlap); + ix = 0; + // Cyclic suffix, with window from 0.5 to 0 + for (size_t i = 0; ox < (ssize_t)(p.symSize + p.windowOverlap); i++) { + if constexpr (std::is_same_v) { + out[ox] = in[ix] * p.windowFloat[p.windowOverlap - (i+1)]; + } + if constexpr (std::is_same_v) { + out[ox] = in[ix] * p.windowFix[p.windowOverlap - (i+1)]; + } + if constexpr (std::is_same_v) { + out[ox] = in[ix] * p.windowFixWide[p.windowOverlap - (i+1)]; + } + ox++; + ix++; } - out += p.symSize; - in += p.spacing; - // out is now pointing to the proper end of symbol. There are - // windowOverlap samples ahead that were already written. + assert(ix == p.windowOverlap); } - } - else { - throw std::runtime_error("fixed-point doesn't support window overlap"); + + out += p.symSize; + in += p.spacing; + // out is now pointing to the proper end of symbol. There are + // windowOverlap samples ahead that were already written. } } else { @@ -287,9 +328,6 @@ int GuardIntervalInserter::process(Buffer* const dataIn, Buffer* dataOut) case FFTEngine::FFTW: return do_process(m_params, dataIn, dataOut); case FFTEngine::KISS: - if (m_params.windowOverlap) { - throw std::runtime_error("fixed point and ofdm windowing not supported"); - } return do_process(m_params, dataIn, dataOut); case FFTEngine::DEXTER: return do_process(m_params, dataIn, dataOut); diff --git a/src/GuardIntervalInserter.h b/src/GuardIntervalInserter.h index 8d329ff..738d5b3 100644 --- a/src/GuardIntervalInserter.h +++ b/src/GuardIntervalInserter.h @@ -2,7 +2,7 @@ Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2023 + Copyright (C) 2024 Matthias P. Braendli, matthias.braendli@mpb.li http://opendigitalradio.org @@ -33,7 +33,6 @@ #include "ConfigParser.h" #include "ModPlugin.h" #include "RemoteControl.h" -#include #include /* The GuardIntervalInserter prepends the cyclic prefix to all @@ -79,7 +78,9 @@ class GuardIntervalInserter : public ModCodec, public RemoteControllable size_t& windowOverlap; mutable std::mutex windowMutex; - std::vector window; + std::vector windowFloat; + std::vector windowFix; + std::vector windowFixWide; }; protected: -- cgit v1.2.3