1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-15 12:51:49 -05:00

Channel Analyzer: fixed rational downsampler

This commit is contained in:
f4exb 2020-07-21 02:08:58 +02:00
parent cb3be14515
commit bb35db0703
6 changed files with 77 additions and 50 deletions

View File

@ -137,7 +137,7 @@ bool ChannelAnalyzerBaseband::handleMessage(const Message& cmd)
qDebug() << "ChannelAnalyzerBaseband::handleMessage: DSPSignalNotification: basebandSampleRate: " << notif.getSampleRate(); qDebug() << "ChannelAnalyzerBaseband::handleMessage: DSPSignalNotification: basebandSampleRate: " << notif.getSampleRate();
m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(notif.getSampleRate())); m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(notif.getSampleRate()));
m_channelizer->setBasebandSampleRate(notif.getSampleRate()); m_channelizer->setBasebandSampleRate(notif.getSampleRate());
int desiredSampleRate = getSinkSampleRate(m_settings); int desiredSampleRate = m_channelizer->getBasebandSampleRate() / (1<<m_settings.m_log2Decim);
m_channelizer->setChannelization(desiredSampleRate, m_settings.m_inputFrequencyOffset); m_channelizer->setChannelization(desiredSampleRate, m_settings.m_inputFrequencyOffset);
m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), desiredSampleRate, m_channelizer->getChannelFrequencyOffset()); m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), desiredSampleRate, m_channelizer->getChannelFrequencyOffset());
@ -156,7 +156,7 @@ void ChannelAnalyzerBaseband::applySettings(const ChannelAnalyzerSettings& setti
|| (settings.m_rationalDownSamplerRate != m_settings.m_rationalDownSamplerRate) || (settings.m_rationalDownSamplerRate != m_settings.m_rationalDownSamplerRate)
|| (settings.m_rationalDownSample != m_settings.m_rationalDownSample) || force) || (settings.m_rationalDownSample != m_settings.m_rationalDownSample) || force)
{ {
int desiredSampleRate = getSinkSampleRate(settings); int desiredSampleRate = m_channelizer->getBasebandSampleRate() / (1<<settings.m_log2Decim);
m_channelizer->setChannelization(desiredSampleRate, settings.m_inputFrequencyOffset); m_channelizer->setChannelization(desiredSampleRate, settings.m_inputFrequencyOffset);
m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), desiredSampleRate, m_channelizer->getChannelFrequencyOffset()); m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), desiredSampleRate, m_channelizer->getChannelFrequencyOffset());
} }
@ -165,12 +165,6 @@ void ChannelAnalyzerBaseband::applySettings(const ChannelAnalyzerSettings& setti
m_settings = settings; m_settings = settings;
} }
int ChannelAnalyzerBaseband::getSinkSampleRate(ChannelAnalyzerSettings settings)
{
int normalSinkSampleRate = m_channelizer->getBasebandSampleRate() / (1<<settings.m_log2Decim);
return settings.m_rationalDownSample ? settings.m_rationalDownSamplerRate : normalSinkSampleRate;
}
int ChannelAnalyzerBaseband::getChannelSampleRate() const int ChannelAnalyzerBaseband::getChannelSampleRate() const
{ {
return m_channelizer->getChannelSampleRate(); return m_channelizer->getChannelSampleRate();

View File

@ -84,7 +84,6 @@ private:
bool handleMessage(const Message& cmd); bool handleMessage(const Message& cmd);
void applySettings(const ChannelAnalyzerSettings& settings, bool force = false); void applySettings(const ChannelAnalyzerSettings& settings, bool force = false);
int getSinkSampleRate(ChannelAnalyzerSettings settngs);
private slots: private slots:
void handleInputMessages(); void handleInputMessages();

View File

@ -274,13 +274,6 @@ void ChannelAnalyzerGUI::on_useRationalDownsampler_toggled(bool checked)
applySettings(); applySettings();
} }
int ChannelAnalyzerGUI::getSinkSampleRate()
{
return m_settings.m_rationalDownSample ?
m_settings.m_rationalDownSamplerRate
: m_basebandSampleRate / (1<<m_settings.m_log2Decim);
}
void ChannelAnalyzerGUI::on_signalSelect_currentIndexChanged(int index) void ChannelAnalyzerGUI::on_signalSelect_currentIndexChanged(int index)
{ {
m_settings.m_inputType = (ChannelAnalyzerSettings::InputType) index; m_settings.m_inputType = (ChannelAnalyzerSettings::InputType) index;
@ -461,6 +454,13 @@ ChannelAnalyzerGUI::~ChannelAnalyzerGUI()
delete ui; delete ui;
} }
int ChannelAnalyzerGUI::getSinkSampleRate()
{
return m_settings.m_rationalDownSample ?
m_settings.m_rationalDownSamplerRate
: m_basebandSampleRate / (1<<m_settings.m_log2Decim);
}
void ChannelAnalyzerGUI::setSinkSampleRate() void ChannelAnalyzerGUI::setSinkSampleRate()
{ {
unsigned int nominalSinkSampleRate = m_basebandSampleRate / (1<<m_settings.m_log2Decim); unsigned int nominalSinkSampleRate = m_basebandSampleRate / (1<<m_settings.m_log2Decim);

View File

@ -80,7 +80,7 @@ private:
explicit ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = nullptr); explicit ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = nullptr);
virtual ~ChannelAnalyzerGUI(); virtual ~ChannelAnalyzerGUI();
int getSinkSampleRate(); //!< get actual sink sample rate from GUI settings int getSinkSampleRate(); //!< get actual sink sample rate from GUI settings
void setSinkSampleRate(); //!< set sample rate after full decimation chain void setSinkSampleRate(); //!< set sample rate after full decimation chain
void setFiltersUIBoundaries(); void setFiltersUIBoundaries();

View File

@ -34,8 +34,6 @@ ChannelAnalyzerSink::ChannelAnalyzerSink() :
{ {
m_usb = true; m_usb = true;
m_magsq = 0; m_magsq = 0;
m_interpolatorDistance = 1.0f;
m_interpolatorDistanceRemain = 0.0f;
SSBFilter = new fftfilt(m_settings.m_lowCutoff / m_channelSampleRate, m_settings.m_bandwidth / m_channelSampleRate, m_ssbFftLen); SSBFilter = new fftfilt(m_settings.m_lowCutoff / m_channelSampleRate, m_settings.m_bandwidth / m_channelSampleRate, m_ssbFftLen);
DSBFilter = new fftfilt(m_settings.m_bandwidth / m_channelSampleRate, 2*m_ssbFftLen); DSBFilter = new fftfilt(m_settings.m_bandwidth / m_channelSampleRate, 2*m_ssbFftLen);
RRCFilter = new fftfilt(m_settings.m_bandwidth / m_channelSampleRate, 2*m_ssbFftLen); RRCFilter = new fftfilt(m_settings.m_bandwidth / m_channelSampleRate, 2*m_ssbFftLen);
@ -57,34 +55,37 @@ ChannelAnalyzerSink::~ChannelAnalyzerSink()
void ChannelAnalyzerSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end) void ChannelAnalyzerSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
{ {
fftfilt::cmplx *sideband = 0; fftfilt::cmplx *sideband = 0;
Complex ci;
for (SampleVector::const_iterator it = begin; it < end; ++it) for (SampleVector::const_iterator it = begin; it < end; ++it)
{ {
Complex ci;
Complex c(it->real(), it->imag()); Complex c(it->real(), it->imag());
c *= m_nco.nextIQ(); c *= m_nco.nextIQ();
if (m_interpolatorDistance == 1) if (m_decimator.getDecim() == 1)
{ {
processOneSample(c, sideband); processOneSample(c, sideband);
} }
else else
{ {
if (m_settings.m_rationalDownSample) if (m_decimator.decimate(c, ci))
{ {
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci)) if (m_settings.m_rationalDownSample)
{
Complex cj;
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, ci, &cj))
{
processOneSample(cj, sideband);
m_interpolatorDistanceRemain += m_interpolatorDistance;
}
}
else
{ {
processOneSample(ci, sideband); processOneSample(ci, sideband);
m_interpolatorDistanceRemain += m_interpolatorDistance;
} }
} }
else }
{
if (m_decimator.decimate(c, ci)) {
processOneSample(ci, sideband);
}
}
}
} }
if (m_sampleSink) { if (m_sampleSink) {
@ -146,6 +147,7 @@ void ChannelAnalyzerSink::applyChannelSettings(int channelSampleRate, int sinkSa
<< " channelSampleRate: " << channelSampleRate << " channelSampleRate: " << channelSampleRate
<< " sinkSampleRate: " << sinkSampleRate << " sinkSampleRate: " << sinkSampleRate
<< " channelFrequencyOffset: " << channelFrequencyOffset; << " channelFrequencyOffset: " << channelFrequencyOffset;
bool doApplySampleRate = false;
if ((m_channelFrequencyOffset != channelFrequencyOffset) || if ((m_channelFrequencyOffset != channelFrequencyOffset) ||
(m_channelSampleRate != channelSampleRate) || force) (m_channelSampleRate != channelSampleRate) || force)
@ -156,13 +158,9 @@ void ChannelAnalyzerSink::applyChannelSettings(int channelSampleRate, int sinkSa
if ((m_channelSampleRate != channelSampleRate) if ((m_channelSampleRate != channelSampleRate)
|| (m_sinkSampleRate != sinkSampleRate) || force) || (m_sinkSampleRate != sinkSampleRate) || force)
{ {
m_interpolator.create(16, channelSampleRate, channelSampleRate / 2.2f); m_interpolator.create(16, sinkSampleRate, sinkSampleRate / 4.0f);
m_interpolatorDistanceRemain = 0; m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) channelSampleRate / (Real) sinkSampleRate; m_interpolatorDistance = (Real) sinkSampleRate / (Real) m_settings.m_rationalDownSamplerRate;
setFilters(sinkSampleRate, m_settings.m_bandwidth, m_settings.m_lowCutoff);
m_pll.setSampleRate(sinkSampleRate);
m_fll.setSampleRate(sinkSampleRate);
int decim = channelSampleRate / sinkSampleRate; int decim = channelSampleRate / sinkSampleRate;
m_decimator.setLog2Decim(0); m_decimator.setLog2Decim(0);
@ -178,11 +176,17 @@ void ChannelAnalyzerSink::applyChannelSettings(int channelSampleRate, int sinkSa
decim >>= 1; decim >>= 1;
} }
doApplySampleRate = true;
} }
m_channelSampleRate = channelSampleRate; m_channelSampleRate = channelSampleRate;
m_channelFrequencyOffset = channelFrequencyOffset; m_channelFrequencyOffset = channelFrequencyOffset;
m_sinkSampleRate = sinkSampleRate; m_sinkSampleRate = sinkSampleRate;
if (doApplySampleRate) {
applySampleRate();
}
} }
void ChannelAnalyzerSink::setFilters(int sampleRate, float bandwidth, float lowCutoff) void ChannelAnalyzerSink::setFilters(int sampleRate, float bandwidth, float lowCutoff)
@ -216,29 +220,25 @@ void ChannelAnalyzerSink::applySettings(const ChannelAnalyzerSettings& settings,
{ {
qDebug() << "ChannelAnalyzerSink::applySettings:" qDebug() << "ChannelAnalyzerSink::applySettings:"
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset << " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
<< " m_rationalDownSample: " << settings.m_rationalDownSample
<< " m_rationalDownSamplerRate: " << settings.m_rationalDownSamplerRate
<< " m_rcc: " << settings.m_rrc << " m_rcc: " << settings.m_rrc
<< " m_rrcRolloff: " << settings.m_rrcRolloff / 100.0 << " m_rrcRolloff: " << settings.m_rrcRolloff / 100.0
<< " m_bandwidth: " << settings.m_bandwidth << " m_bandwidth: " << settings.m_bandwidth
<< " m_lowCutoff: " << settings.m_lowCutoff << " m_lowCutoff: " << settings.m_lowCutoff
<< " m_log2Decim: " << settings.m_log2Decim << " m_log2Decim: " << settings.m_log2Decim
<< " m_rationalDownSample: " << settings.m_rationalDownSample
<< " m_rationalDownSamplerRate: " << settings.m_rationalDownSamplerRate
<< " m_ssb: " << settings.m_ssb << " m_ssb: " << settings.m_ssb
<< " m_pll: " << settings.m_pll << " m_pll: " << settings.m_pll
<< " m_fll: " << settings.m_fll << " m_fll: " << settings.m_fll
<< " m_pllPskOrder: " << settings.m_pllPskOrder << " m_pllPskOrder: " << settings.m_pllPskOrder
<< " m_inputType: " << (int) settings.m_inputType; << " m_inputType: " << (int) settings.m_inputType;
bool doApplySampleRate = false;
if ((settings.m_bandwidth != m_settings.m_bandwidth) || if ((settings.m_bandwidth != m_settings.m_bandwidth) ||
(settings.m_lowCutoff != m_settings.m_lowCutoff)|| force) (settings.m_lowCutoff != m_settings.m_lowCutoff) ||
(settings.m_rrcRolloff != m_settings.m_rrcRolloff) || force)
{ {
setFilters(m_sinkSampleRate, settings.m_bandwidth, settings.m_lowCutoff); doApplySampleRate = true;
}
if ((settings.m_rrcRolloff != m_settings.m_rrcRolloff) || force)
{
float sinkSampleRate = (float) m_sinkSampleRate;
RRCFilter->create_rrc_filter(settings.m_bandwidth / sinkSampleRate, settings.m_rrcRolloff / 100.0);
} }
if (settings.m_pll != m_settings.m_pll || force) if (settings.m_pll != m_settings.m_pll || force)
@ -264,7 +264,20 @@ void ChannelAnalyzerSink::applySettings(const ChannelAnalyzerSettings& settings,
} }
} }
if ((settings.m_rationalDownSample != m_settings.m_rationalDownSample) ||
(settings.m_rationalDownSamplerRate != m_settings.m_rationalDownSamplerRate) || force)
{
m_interpolator.create(16, m_sinkSampleRate, m_sinkSampleRate / 4.0f);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) m_sinkSampleRate / (Real) settings.m_rationalDownSamplerRate;
doApplySampleRate = true;
}
m_settings = settings; m_settings = settings;
if (doApplySampleRate) {
applySampleRate();
}
} }
Real ChannelAnalyzerSink::getPllFrequency() const Real ChannelAnalyzerSink::getPllFrequency() const
@ -277,3 +290,22 @@ Real ChannelAnalyzerSink::getPllFrequency() const
return 0.0; return 0.0;
} }
} }
int ChannelAnalyzerSink::getActualSampleRate()
{
if (m_settings.m_rationalDownSample) {
return m_settings.m_rationalDownSamplerRate;
} else {
return m_sinkSampleRate;
}
}
void ChannelAnalyzerSink::applySampleRate()
{
int sampleRate = getActualSampleRate();
qDebug("ChannelAnalyzerSink::applySampleRate: sampleRate: %d m_interpolatorDistance: %f", sampleRate, m_interpolatorDistance);
setFilters(sampleRate, m_settings.m_bandwidth, m_settings.m_lowCutoff);
m_pll.setSampleRate(sampleRate);
m_fll.setSampleRate(sampleRate);
RRCFilter->create_rrc_filter(m_settings.m_bandwidth / (float) sampleRate, m_settings.m_rrcRolloff / 100.0);
}

View File

@ -65,11 +65,11 @@ private:
double m_magsq; double m_magsq;
NCOF m_nco; NCOF m_nco;
Interpolator m_interpolator;
Real m_interpolatorDistance;
Real m_interpolatorDistanceRemain;
PhaseLockComplex m_pll; PhaseLockComplex m_pll;
FreqLockComplex m_fll; FreqLockComplex m_fll;
Interpolator m_interpolator;
Real m_interpolatorDistance;
Real m_interpolatorDistanceRemain;
DecimatorC m_decimator; DecimatorC m_decimator;
fftfilt* SSBFilter; fftfilt* SSBFilter;
@ -84,6 +84,8 @@ private:
void setFilters(int sampleRate, float bandwidth, float lowCutoff); void setFilters(int sampleRate, float bandwidth, float lowCutoff);
void processOneSample(Complex& c, fftfilt::cmplx *sideband); void processOneSample(Complex& c, fftfilt::cmplx *sideband);
int getActualSampleRate();
void applySampleRate();
inline void feedOneSample(const fftfilt::cmplx& s, const fftfilt::cmplx& pll) inline void feedOneSample(const fftfilt::cmplx& s, const fftfilt::cmplx& pll)
{ {