1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-26 09:48:45 -05:00

Down channelizer: implemented direct setting of filter chain

This commit is contained in:
f4exb 2019-04-25 09:14:17 +02:00
parent 8d799a5a6b
commit 3a5bc0ac3a
2 changed files with 96 additions and 17 deletions

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 F4EXB // // Copyright (C) 2016-2019 F4EXB //
// written by Edouard Griffiths // // written by Edouard Griffiths //
// // // //
// This program is free software; you can redistribute it and/or modify // // This program is free software; you can redistribute it and/or modify //
@ -24,6 +24,7 @@
#include <QDebug> #include <QDebug>
MESSAGE_CLASS_DEFINITION(DownChannelizer::MsgChannelizerNotification, Message) MESSAGE_CLASS_DEFINITION(DownChannelizer::MsgChannelizerNotification, Message)
MESSAGE_CLASS_DEFINITION(DownChannelizer::MsgSetChannelizer, Message)
DownChannelizer::DownChannelizer(BasebandSampleSink* sampleSink) : DownChannelizer::DownChannelizer(BasebandSampleSink* sampleSink) :
m_sampleSink(sampleSink), m_sampleSink(sampleSink),
@ -143,6 +144,14 @@ bool DownChannelizer::handleMessage(const Message& cmd)
return true; return true;
} }
else if (MsgSetChannelizer::match(cmd))
{
MsgSetChannelizer& chan = (MsgSetChannelizer&) cmd;
qDebug() << "DownChannelizer::handleMessage: MsgSetChannelizer";
applySetting(chan.getStageIndexes());
return true;
}
else if (BasebandSampleSink::MsgThreadedSink::match(cmd)) else if (BasebandSampleSink::MsgThreadedSink::match(cmd))
{ {
qDebug() << "DownChannelizer::handleMessage: MsgThreadedSink: forwarded to demod"; qDebug() << "DownChannelizer::handleMessage: MsgThreadedSink: forwarded to demod";
@ -189,6 +198,30 @@ void DownChannelizer::applyConfiguration()
} }
} }
void DownChannelizer::applySetting(const std::vector<unsigned int>& stageIndexes)
{
m_mutex.lock();
freeFilterChain();
m_currentCenterFrequency = m_inputSampleRate * setFilterChain(stageIndexes);
m_mutex.unlock();
m_currentOutputSampleRate = m_inputSampleRate / (1 << m_filterStages.size());
m_requestedOutputSampleRate = m_currentOutputSampleRate;
qDebug() << "DownChannelizer::applySetting in=" << m_inputSampleRate
<< ", out=" << m_currentOutputSampleRate
<< ", fc=" << m_currentCenterFrequency;
if (m_sampleSink != 0)
{
MsgChannelizerNotification *notif = MsgChannelizerNotification::create(m_currentOutputSampleRate, m_currentCenterFrequency);
m_sampleSink->getInputMessageQueue()->push(notif);
}
}
#ifdef SDR_RX_SAMPLE_24BIT #ifdef SDR_RX_SAMPLE_24BIT
DownChannelizer::FilterStage::FilterStage(Mode mode) : DownChannelizer::FilterStage::FilterStage(Mode mode) :
m_filter(new IntHalfbandFilterEO<qint64, qint64, DOWNCHANNELIZER_HB_FILTER_ORDER>), m_filter(new IntHalfbandFilterEO<qint64, qint64, DOWNCHANNELIZER_HB_FILTER_ORDER>),
@ -251,42 +284,71 @@ bool DownChannelizer::signalContainsChannel(Real sigStart, Real sigEnd, Real cha
Real DownChannelizer::createFilterChain(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) Real DownChannelizer::createFilterChain(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd)
{ {
Real sigBw = sigEnd - sigStart; Real sigBw = sigEnd - sigStart;
Real safetyMargin = sigBw / 20;
Real rot = sigBw / 4; Real rot = sigBw / 4;
safetyMargin = 0; qDebug("DownChannelizer::createFilterChain: Signal [%.1f, %.1f] (BW %.1f), Channel [%.1f, %.1f], Rot %.1f", sigStart, sigEnd, sigBw, chanStart, chanEnd, rot);
//fprintf(stderr, "Channelizer::createFilterChain: ");
//fprintf(stderr, "Signal [%.1f, %.1f] (BW %.1f), Channel [%.1f, %.1f], Rot %.1f, Safety %.1f\n", sigStart, sigEnd, sigBw, chanStart, chanEnd, rot, safetyMargin);
#if 1
// check if it fits into the left half // check if it fits into the left half
if(signalContainsChannel(sigStart + safetyMargin, sigStart + sigBw / 2.0 - safetyMargin, chanStart, chanEnd)) { if(signalContainsChannel(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd))
//fprintf(stderr, "-> take left half (rotate by +1/4 and decimate by 2)\n"); {
qDebug("DownChannelizer::createFilterChain: -> take left half (rotate by +1/4 and decimate by 2)");
m_filterStages.push_back(new FilterStage(FilterStage::ModeLowerHalf)); m_filterStages.push_back(new FilterStage(FilterStage::ModeLowerHalf));
return createFilterChain(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd); return createFilterChain(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd);
} }
// check if it fits into the right half // check if it fits into the right half
if(signalContainsChannel(sigEnd - sigBw / 2.0f + safetyMargin, sigEnd - safetyMargin, chanStart, chanEnd)) { if(signalContainsChannel(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd))
//fprintf(stderr, "-> take right half (rotate by -1/4 and decimate by 2)\n"); {
qDebug("DownChannelizer::createFilterChain: -> take right half (rotate by -1/4 and decimate by 2)");
m_filterStages.push_back(new FilterStage(FilterStage::ModeUpperHalf)); m_filterStages.push_back(new FilterStage(FilterStage::ModeUpperHalf));
return createFilterChain(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd); return createFilterChain(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd);
} }
// check if it fits into the center // 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))
if(signalContainsChannel(sigStart + rot + safetyMargin, sigEnd - rot - safetyMargin, chanStart, chanEnd)) { {
//fprintf(stderr, "-> take center half (decimate by 2)\n"); qDebug("DownChannelizer::createFilterChain: -> take center half (decimate by 2)");
m_filterStages.push_back(new FilterStage(FilterStage::ModeCenter)); m_filterStages.push_back(new FilterStage(FilterStage::ModeCenter));
// Was: return createFilterChain(sigStart + rot, sigStart + sigBw / 2.0f + rot, chanStart, chanEnd);
return createFilterChain(sigStart + rot, sigEnd - rot, chanStart, chanEnd); return createFilterChain(sigStart + rot, sigEnd - rot, chanStart, chanEnd);
} }
#endif
Real ofs = ((chanEnd - chanStart) / 2.0 + chanStart) - ((sigEnd - sigStart) / 2.0 + sigStart); Real ofs = ((chanEnd - chanStart) / 2.0 + chanStart) - ((sigEnd - sigStart) / 2.0 + sigStart);
//fprintf(stderr, "-> complete (final BW %.1f, frequency offset %.1f)\n", sigBw, ofs); qDebug("DownChannelizer::createFilterChain: -> complete (final BW %.1f, frequency offset %.1f)", sigBw, ofs);
return ofs; return ofs;
} }
double DownChannelizer::setFilterChain(const std::vector<unsigned int>& stageIndexes)
{
// filters are described from lower to upper level but the chain is constructed the other way round
std::vector<unsigned int>::const_reverse_iterator rit = stageIndexes.rbegin();
double ofs = 0.0, ofs_stage = 0.25;
// Each index is a base 3 number with 0 = low, 1 = center, 2 = high
// Functions at upper level will convert a number to base 3 to describe the filter chain. Common converting
// algorithms will go from LSD to MSD. This explains the reverse order.
for (; rit != stageIndexes.rend(); ++rit)
{
if (*rit == 0)
{
m_filterStages.push_back(new FilterStage(FilterStage::ModeLowerHalf));
ofs -= ofs_stage;
}
else if (*rit == 1)
{
m_filterStages.push_back(new FilterStage(FilterStage::ModeCenter));
}
else if (*rit == 2)
{
m_filterStages.push_back(new FilterStage(FilterStage::ModeUpperHalf));
ofs += ofs_stage;
}
ofs_stage /= 2;
}
return ofs;
}
void DownChannelizer::freeFilterChain() void DownChannelizer::freeFilterChain()
{ {
for(FilterStages::iterator it = m_filterStages.begin(); it != m_filterStages.end(); ++it) for(FilterStages::iterator it = m_filterStages.begin(); it != m_filterStages.end(); ++it)

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 F4EXB // // Copyright (C) 2016-2019 F4EXB //
// written by Edouard Griffiths // // written by Edouard Griffiths //
// // // //
// This program is free software; you can redistribute it and/or modify // // This program is free software; you can redistribute it and/or modify //
@ -21,6 +21,7 @@
#include <dsp/basebandsamplesink.h> #include <dsp/basebandsamplesink.h>
#include <list> #include <list>
#include <vector>
#include <QMutex> #include <QMutex>
#include "export.h" #include "export.h"
#include "util/message.h" #include "util/message.h"
@ -56,6 +57,20 @@ public:
qint64 m_frequencyOffset; qint64 m_frequencyOffset;
}; };
class SDRBASE_API MsgSetChannelizer : public Message {
MESSAGE_CLASS_DECLARATION
public:
MsgSetChannelizer() :
Message()
{ }
std::vector<unsigned int>& getStageIndexes() { return m_stageIndexes; }
private:
std::vector<unsigned int> m_stageIndexes;
};
DownChannelizer(BasebandSampleSink* sampleSink); DownChannelizer(BasebandSampleSink* sampleSink);
virtual ~DownChannelizer(); virtual ~DownChannelizer();
@ -108,8 +123,10 @@ protected:
QMutex m_mutex; QMutex m_mutex;
void applyConfiguration(); void applyConfiguration();
void applySetting(const std::vector<unsigned int>& stageIndexes);
bool signalContainsChannel(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) const; bool signalContainsChannel(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) const;
Real createFilterChain(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(); void freeFilterChain();
void debugFilterChain(); void debugFilterChain();