Skip to content

Commit

Permalink
Change down and up channelizers filter chain strategy. Fixes #1846
Browse files Browse the repository at this point in the history
  • Loading branch information
f4exb committed Oct 17, 2023
1 parent 2f2c387 commit 9abd62f
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 66 deletions.
63 changes: 36 additions & 27 deletions sdrbase/dsp/downchannelizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Real, 3> 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);
Expand Down
2 changes: 1 addition & 1 deletion sdrbase/dsp/downchannelizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class SDRBASE_API DownChannelizer : public ChannelSampleSink {

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<unsigned int>& stageIndexes);
void freeFilterChain();
Expand Down
81 changes: 44 additions & 37 deletions sdrbase/dsp/upchannelizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<Real, 3> 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);
Expand Down
2 changes: 1 addition & 1 deletion sdrbase/dsp/upchannelizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class SDRBASE_API UpChannelizer : public ChannelSampleSource {

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<unsigned int>& stageIndexes); //!< returns offset in ratio of sample rate
void freeFilterChain();
Expand Down

0 comments on commit 9abd62f

Please sign in to comment.