From 9abd62f40e8b890b5bec7d888c493a6ffe256168 Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 17 Oct 2023 02:52:45 +0200 Subject: [PATCH] Change down and up channelizers filter chain strategy. Fixes #1846 --- sdrbase/dsp/downchannelizer.cpp | 63 ++++++++++++++----------- sdrbase/dsp/downchannelizer.h | 2 +- sdrbase/dsp/upchannelizer.cpp | 81 ++++++++++++++++++--------------- sdrbase/dsp/upchannelizer.h | 2 +- 4 files changed, 82 insertions(+), 66 deletions(-) diff --git a/sdrbase/dsp/downchannelizer.cpp b/sdrbase/dsp/downchannelizer.cpp index 06b9b49cd..fc98bac1a 100644 --- a/sdrbase/dsp/downchannelizer.cpp +++ b/sdrbase/dsp/downchannelizer.cpp @@ -218,46 +218,55 @@ DownChannelizer::FilterStage::~FilterStage() delete m_filter; } -bool DownChannelizer::signalContainsChannel(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) const +Real DownChannelizer::channelMinSpace(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) { - //qDebug(" testing signal [%f, %f], channel [%f, %f]", sigStart, sigEnd, chanStart, chanEnd); - if(sigEnd <= sigStart) - return false; - if(chanEnd <= chanStart) - return false; - return (sigStart <= chanStart) && (sigEnd >= chanEnd); + Real leftSpace = chanStart - sigStart; + Real rightSpace = sigEnd - chanEnd; + return std::min(leftSpace, rightSpace); } Real DownChannelizer::createFilterChain(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) { Real sigBw = sigEnd - sigStart; + Real chanBw = chanEnd - chanStart; Real rot = sigBw / 4; qDebug("DownChannelizer::createFilterChain: Signal [%.1f, %.1f] (BW %.1f), Channel [%.1f, %.1f], Rot %.1f", sigStart, sigEnd, sigBw, chanStart, chanEnd, rot); - // check if it fits into the center - if(signalContainsChannel(sigStart + rot, sigEnd - rot, chanStart, chanEnd)) - { - qDebug("DownChannelizer::createFilterChain: -> take center half (decimate by 2)"); - m_filterStages.push_back(new FilterStage(FilterStage::ModeCenter)); - return createFilterChain(sigStart + rot, sigEnd - rot, chanStart, chanEnd); - } + std::array filterMinSpaces; // Array of left, center and right filter min spaces respectively + filterMinSpaces[0] = channelMinSpace(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd); + filterMinSpaces[1] = channelMinSpace(sigStart + rot, sigEnd - rot, chanStart, chanEnd); + filterMinSpaces[2] = channelMinSpace(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd); + auto maxIt = std::max_element(filterMinSpaces.begin(), filterMinSpaces.end()); + int maxIndex = maxIt - filterMinSpaces.begin(); + Real maxValue = *maxIt; - // check if it fits into the left half - if(signalContainsChannel(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd)) - { - qDebug("DownChannelizer::createFilterChain: -> take left half (rotate by +1/4 and decimate by 2)"); - m_filterStages.push_back(new FilterStage(FilterStage::ModeLowerHalf)); - return createFilterChain(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd); - } + qDebug("DownChannelizer::createFilterChain: best index: %d best value: %.1f sigBW: %.1f chanBW: %.1f", + maxIndex, maxValue, sigBw, chanBw); - // check if it fits into the right half - if(signalContainsChannel(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd)) + if ((sigStart < sigEnd) && (chanStart < chanEnd) && (maxValue >= chanBw/10.0)) { - qDebug("DownChannelizer::createFilterChain: -> take right half (rotate by -1/4 and decimate by 2)"); - m_filterStages.push_back(new FilterStage(FilterStage::ModeUpperHalf)); - return createFilterChain(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd); - } + if (maxIndex == 0) + { + qDebug("DownChannelizer::createFilterChain: -> take left half (rotate by +1/4 and decimate by 2)"); + m_filterStages.push_back(new FilterStage(FilterStage::ModeLowerHalf)); + return createFilterChain(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd); + } + + if (maxIndex == 1) + { + qDebug("DownChannelizer::createFilterChain: -> take center half (decimate by 2)"); + m_filterStages.push_back(new FilterStage(FilterStage::ModeCenter)); + return createFilterChain(sigStart + rot, sigEnd - rot, chanStart, chanEnd); + } + + if (maxIndex == 2) + { + qDebug("DownChannelizer::createFilterChain: -> take right half (rotate by -1/4 and decimate by 2)"); + m_filterStages.push_back(new FilterStage(FilterStage::ModeUpperHalf)); + return createFilterChain(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd); + } + } Real ofs = ((chanEnd - chanStart) / 2.0 + chanStart) - ((sigEnd - sigStart) / 2.0 + sigStart); qDebug("DownChannelizer::createFilterChain: -> complete (final BW %.1f, frequency offset %.1f)", sigBw, ofs); diff --git a/sdrbase/dsp/downchannelizer.h b/sdrbase/dsp/downchannelizer.h index f04e0c0cc..b84afcc00 100644 --- a/sdrbase/dsp/downchannelizer.h +++ b/sdrbase/dsp/downchannelizer.h @@ -87,7 +87,7 @@ protected: void applyChannelization(); void applyDecimation(); - bool signalContainsChannel(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) const; + static Real channelMinSpace(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd); Real createFilterChain(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd); double setFilterChain(const std::vector& stageIndexes); void freeFilterChain(); diff --git a/sdrbase/dsp/upchannelizer.cpp b/sdrbase/dsp/upchannelizer.cpp index 52484672a..dcb5c1972 100644 --- a/sdrbase/dsp/upchannelizer.cpp +++ b/sdrbase/dsp/upchannelizer.cpp @@ -237,19 +237,17 @@ UpChannelizer::FilterStage::~FilterStage() delete m_filter; } -bool UpChannelizer::signalContainsChannel(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) const +Real UpChannelizer::channelMinSpace(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) { - //qDebug(" testing signal [%f, %f], channel [%f, %f]", sigStart, sigEnd, chanStart, chanEnd); - if(sigEnd <= sigStart) - return false; - if(chanEnd <= chanStart) - return false; - return (sigStart <= chanStart) && (sigEnd >= chanEnd); + Real leftSpace = chanStart - sigStart; + Real rightSpace = sigEnd - chanEnd; + return std::min(leftSpace, rightSpace); } Real UpChannelizer::createFilterChain(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) { Real sigBw = sigEnd - sigStart; + Real chanBw = chanEnd - chanStart; Real rot = sigBw / 4; Sample s; @@ -259,39 +257,48 @@ Real UpChannelizer::createFilterChain(Real sigStart, Real sigEnd, Real chanStart << " chan: [" << chanStart << ":" << chanEnd << "]" << " rot: " << rot; - // check if it fits into the center - // Was: if(signalContainsChannel(sigStart + rot + safetyMargin, sigStart + rot + sigBw / 2.0f - safetyMargin, chanStart, chanEnd)) { - if(signalContainsChannel(sigStart + rot, sigEnd - rot, chanStart, chanEnd)) - { - qDebug() << "UpChannelizer::createFilterChain: take center half (decimate by 2):" - << " [" << m_filterStages.size() << "]" - << " sig: [" << sigStart + rot << ":" << sigEnd - rot << "]"; - m_filterStages.push_back(new FilterStage(FilterStage::ModeCenter)); - m_stageSamples.push_back(s); - // Was: return createFilterChain(sigStart + rot, sigStart + sigBw / 2.0f + rot, chanStart, chanEnd); - return createFilterChain(sigStart + rot, sigEnd - rot, chanStart, chanEnd); - } + std::array filterMinSpaces; // Array of left, center and right filter min spaces respectively + filterMinSpaces[0] = channelMinSpace(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd); + filterMinSpaces[1] = channelMinSpace(sigStart + rot, sigEnd - rot, chanStart, chanEnd); + filterMinSpaces[2] = channelMinSpace(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd); + auto maxIt = std::max_element(filterMinSpaces.begin(), filterMinSpaces.end()); + int maxIndex = maxIt - filterMinSpaces.begin(); + Real maxValue = *maxIt; - // check if it fits into the left half - if(signalContainsChannel(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd)) - { - qDebug() << "UpChannelizer::createFilterChain: take left half (rotate by +1/4 and decimate by 2):" - << " [" << m_filterStages.size() << "]" - << " sig: [" << sigStart << ":" << sigStart + sigBw / 2.0 << "]"; - m_filterStages.push_back(new FilterStage(FilterStage::ModeLowerHalf)); - m_stageSamples.push_back(s); - return createFilterChain(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd); - } + qDebug("UpChannelizer::createFilterChain: best index: %d best value: %.1f sigBW: %.1f chanBW: %.1f", + maxIndex, maxValue, sigBw, chanBw); - // check if it fits into the right half - if(signalContainsChannel(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd)) + if ((sigStart < sigEnd) && (chanStart < chanEnd) && (maxValue >= chanBw/10.0)) { - qDebug() << "UpChannelizer::createFilterChain: take right half (rotate by -1/4 and decimate by 2):" - << " [" << m_filterStages.size() << "]" - << " sig: [" << sigEnd - sigBw / 2.0f << ":" << sigEnd << "]"; - m_filterStages.push_back(new FilterStage(FilterStage::ModeUpperHalf)); - m_stageSamples.push_back(s); - return createFilterChain(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd); + if (maxIndex == 0) + { + qDebug() << "UpChannelizer::createFilterChain: take left half (rotate by +1/4 and decimate by 2):" + << " [" << m_filterStages.size() << "]" + << " sig: [" << sigStart << ":" << sigStart + sigBw / 2.0 << "]"; + m_filterStages.push_back(new FilterStage(FilterStage::ModeLowerHalf)); + m_stageSamples.push_back(s); + return createFilterChain(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd); + } + + if (maxIndex == 1) + { + qDebug() << "UpChannelizer::createFilterChain: take center half (decimate by 2):" + << " [" << m_filterStages.size() << "]" + << " sig: [" << sigStart + rot << ":" << sigEnd - rot << "]"; + m_filterStages.push_back(new FilterStage(FilterStage::ModeCenter)); + m_stageSamples.push_back(s); + return createFilterChain(sigStart + rot, sigEnd - rot, chanStart, chanEnd); + } + + if (maxIndex == 2) + { + qDebug() << "UpChannelizer::createFilterChain: take right half (rotate by -1/4 and decimate by 2):" + << " [" << m_filterStages.size() << "]" + << " sig: [" << sigEnd - sigBw / 2.0f << ":" << sigEnd << "]"; + m_filterStages.push_back(new FilterStage(FilterStage::ModeUpperHalf)); + m_stageSamples.push_back(s); + return createFilterChain(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd); + } } Real ofs = ((chanEnd - chanStart) / 2.0 + chanStart) - ((sigEnd - sigStart) / 2.0 + sigStart); diff --git a/sdrbase/dsp/upchannelizer.h b/sdrbase/dsp/upchannelizer.h index ce464276b..5e989bf3a 100644 --- a/sdrbase/dsp/upchannelizer.h +++ b/sdrbase/dsp/upchannelizer.h @@ -92,7 +92,7 @@ protected: void applyChannelization(); void applyInterpolation(); - bool signalContainsChannel(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) const; + static Real channelMinSpace(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd); Real createFilterChain(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd); double setFilterChain(const std::vector& stageIndexes); //!< returns offset in ratio of sample rate void freeFilterChain();