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

Channel analyzer NG: use settings

This commit is contained in:
f4exb 2018-05-20 01:10:08 +02:00
parent d6f5de1ad7
commit 524c7fbe7c
6 changed files with 326 additions and 559 deletions

View File

@ -48,13 +48,15 @@ ChannelAnalyzerNG::ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI) :
m_useInterpolator = false;
m_interpolatorDistance = 1.0f;
m_interpolatorDistanceRemain = 0.0f;
SSBFilter = new fftfilt(m_config.m_LowCutoff / m_config.m_inputSampleRate, m_config.m_Bandwidth / m_config.m_inputSampleRate, ssbFftLen);
DSBFilter = new fftfilt(m_config.m_Bandwidth / m_config.m_inputSampleRate, 2*ssbFftLen);
m_inputSampleRate = 48000;
m_inputFrequencyOffset = 0;
SSBFilter = new fftfilt(m_settings.m_lowCutoff / m_inputSampleRate, m_settings.m_bandwidth / m_inputSampleRate, ssbFftLen);
DSBFilter = new fftfilt(m_settings.m_bandwidth / m_inputSampleRate, 2*ssbFftLen);
//m_pll.computeCoefficients(0.05f, 0.707f, 1000.0f); // bandwidth, damping factor, loop gain
m_pll.computeCoefficients(0.002f, 0.5f, 10.0f); // bandwidth, damping factor, loop gain
m_fll.setSampleRate(48000);
apply(true);
applyChannelSettings(m_inputSampleRate, m_inputFrequencyOffset, true);
applySettings(m_settings, true);
m_channelizer = new DownChannelizer(this);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
@ -114,7 +116,7 @@ void ChannelAnalyzerNG::feed(const SampleVector::const_iterator& begin, const Sa
if(m_sampleSink != 0)
{
m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), m_running.m_ssb); // m_ssb = positive only
m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), m_settings.m_ssb); // m_ssb = positive only
}
m_sampleBuffer.clear();
@ -122,8 +124,81 @@ void ChannelAnalyzerNG::feed(const SampleVector::const_iterator& begin, const Sa
m_settingsMutex.unlock();
}
void ChannelAnalyzerNG::processOneSample(Complex& c, fftfilt::cmplx *sideband)
{
int n_out;
int decim = 1<<m_settings.m_spanLog2;
if (m_settings.m_ssb) {
n_out = SSBFilter->runSSB(c, &sideband, m_usb);
} else {
n_out = DSBFilter->runDSB(c, &sideband);
}
for (int i = 0; i < n_out; i++)
{
// Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display
// smart decimation with bit gain using float arithmetic (23 bits significand)
m_sum += sideband[i];
if (!(m_undersampleCount++ & (decim - 1))) // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1)
{
m_sum /= decim;
Real re = m_sum.real() / SDR_RX_SCALED;
Real im = m_sum.imag() / SDR_RX_SCALED;
m_magsq = re*re + im*im;
Real mixI = 1.0f;
Real mixQ = 0.0f;
if (m_settings.m_pll)
{
if (m_settings.m_fll)
{
m_fll.feed(re, im);
// Use -fPLL to mix (exchange PLL real and image in the complex multiplication)
mixI = m_sum.real() * m_fll.getImag() - m_sum.imag() * m_fll.getReal();
mixQ = m_sum.real() * m_fll.getReal() + m_sum.imag() * m_fll.getImag();
// mixI = m_fll.getReal() * SDR_RX_SCALED;
// mixQ = m_fll.getImag() * SDR_RX_SCALED;
}
else
{
m_pll.feed(re, im);
// Use -fPLL to mix (exchange PLL real and image in the complex multiplication)
mixI = m_sum.real() * m_pll.getImag() - m_sum.imag() * m_pll.getReal();
mixQ = m_sum.real() * m_pll.getReal() + m_sum.imag() * m_pll.getImag();
}
if (m_settings.m_ssb & !m_usb)
{ // invert spectrum for LSB
m_sampleBuffer.push_back(Sample(mixQ, mixI));
}
else
{
m_sampleBuffer.push_back(Sample(mixI, mixQ));
}
}
else
{
if (m_settings.m_ssb & !m_usb)
{ // invert spectrum for LSB
m_sampleBuffer.push_back(Sample(m_sum.imag(), m_sum.real()));
}
else
{
m_sampleBuffer.push_back(Sample(m_sum.real(), m_sum.imag()));
}
}
m_sum = 0;
}
}
}
void ChannelAnalyzerNG::start()
{
applyChannelSettings(m_inputSampleRate, m_inputFrequencyOffset, true);
}
void ChannelAnalyzerNG::stop()
@ -132,20 +207,14 @@ void ChannelAnalyzerNG::stop()
bool ChannelAnalyzerNG::handleMessage(const Message& cmd)
{
qDebug() << "ChannelAnalyzerNG::handleMessage: " << cmd.getIdentifier();
if (DownChannelizer::MsgChannelizerNotification::match(cmd))
{
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
qDebug() << "ChannelAnalyzerNG::handleMessage: DownChannelizer::MsgChannelizerNotification:"
<< " sampleRate: " << notif.getSampleRate()
<< " frequencyOffset: " << notif.getFrequencyOffset();
m_config.m_inputSampleRate = notif.getSampleRate();
m_config.m_frequency = notif.getFrequencyOffset();
qDebug() << "ChannelAnalyzerNG::handleMessage: MsgChannelizerNotification:"
<< " m_sampleRate: " << m_config.m_inputSampleRate
<< " frequencyOffset: " << m_config.m_frequency;
apply();
applyChannelSettings(notif.getSampleRate(), notif.getFrequencyOffset());
if (getMessageQueueToGUI())
{
@ -158,37 +227,25 @@ bool ChannelAnalyzerNG::handleMessage(const Message& cmd)
else if (MsgConfigureChannelizer::match(cmd))
{
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
qDebug() << "ChannelAnalyzerNG::handleMessage: MsgConfigureChannelizer:"
<< " sampleRate: " << cfg.getSampleRate()
<< " centerFrequency: " << cfg.getCenterFrequency();
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
cfg.getSampleRate(),
cfg.getCenterFrequency());
cfg.getSampleRate(),
cfg.getCenterFrequency());
return true;
}
else if (MsgConfigureChannelAnalyzerOld::match(cmd))
{
MsgConfigureChannelAnalyzerOld& cfg = (MsgConfigureChannelAnalyzerOld&) cmd;
else if (MsgConfigureChannelAnalyzer::match(cmd))
{
qDebug("ChannelAnalyzerNG::handleMessage: MsgConfigureChannelAnalyzer");
MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd;
m_config.m_channelSampleRate = cfg.getChannelSampleRate();
m_config.m_Bandwidth = cfg.getBandwidth();
m_config.m_LowCutoff = cfg.getLoCutoff();
m_config.m_spanLog2 = cfg.getSpanLog2();
m_config.m_ssb = cfg.getSSB();
m_config.m_pll = cfg.getPLL();
m_config.m_fll = cfg.getFLL();
m_config.m_pllPskOrder = cfg.getPLLPSKOrder();
applySettings(cfg.getSettings(), cfg.getForce());
qDebug() << "ChannelAnalyzerNG::handleMessage: MsgConfigureChannelAnalyzer:"
<< " m_channelSampleRate: " << m_config.m_channelSampleRate
<< " m_Bandwidth: " << m_config.m_Bandwidth
<< " m_LowCutoff: " << m_config.m_LowCutoff
<< " m_spanLog2: " << m_config.m_spanLog2
<< " m_ssb: " << m_config.m_ssb
<< " m_pll: " << m_config.m_pll
<< " m_fll: " << m_config.m_fll
<< " m_pllPskOrder: " << m_config.m_pllPskOrder;
apply();
return true;
}
return true;
}
else
{
if (m_sampleSink != 0)
@ -202,106 +259,6 @@ bool ChannelAnalyzerNG::handleMessage(const Message& cmd)
}
}
void ChannelAnalyzerNG::apply(bool force)
{
if ((m_running.m_frequency != m_config.m_frequency) ||
(m_running.m_inputSampleRate != m_config.m_inputSampleRate) ||
force)
{
m_nco.setFreq(-m_config.m_frequency, m_config.m_inputSampleRate);
}
if ((m_running.m_inputSampleRate != m_config.m_inputSampleRate) ||
(m_running.m_channelSampleRate != m_config.m_channelSampleRate) ||
force)
{
m_settingsMutex.lock();
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_inputSampleRate / 2.2);
m_interpolatorDistanceRemain = 0.0f;
m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_channelSampleRate;
m_useInterpolator = (m_config.m_inputSampleRate != m_config.m_channelSampleRate); // optim
m_settingsMutex.unlock();
}
if ((m_running.m_channelSampleRate != m_config.m_channelSampleRate) ||
(m_running.m_Bandwidth != m_config.m_Bandwidth) ||
(m_running.m_LowCutoff != m_config.m_LowCutoff) ||
force)
{
float bandwidth = m_config.m_Bandwidth;
float lowCutoff = m_config.m_LowCutoff;
if (bandwidth < 0)
{
bandwidth = -bandwidth;
lowCutoff = -lowCutoff;
m_usb = false;
}
else
{
m_usb = true;
}
if (bandwidth < 100.0f)
{
bandwidth = 100.0f;
lowCutoff = 0;
}
m_settingsMutex.lock();
SSBFilter->create_filter(lowCutoff / m_config.m_channelSampleRate, bandwidth / m_config.m_channelSampleRate);
DSBFilter->create_dsb_filter(bandwidth / m_config.m_channelSampleRate);
m_settingsMutex.unlock();
}
if ((m_running.m_channelSampleRate != m_config.m_channelSampleRate) ||
(m_running.m_spanLog2 != m_config.m_spanLog2) || force)
{
int sampleRate = m_running.m_channelSampleRate / (1<<m_running.m_spanLog2);
m_pll.setSampleRate(sampleRate);
m_fll.setSampleRate(sampleRate);
}
if (m_running.m_pll != m_config.m_pll || force)
{
if (m_config.m_pll)
{
m_pll.reset();
m_fll.reset();
}
}
if (m_running.m_fll != m_config.m_fll || force)
{
if (m_config.m_fll) {
m_fll.reset();
}
}
if (m_running.m_pllPskOrder != m_config.m_pllPskOrder || force)
{
if (m_config.m_pllPskOrder < 5) {
m_pll.setPskOrder(m_config.m_pllPskOrder);
}
}
m_running.m_frequency = m_config.m_frequency;
m_running.m_channelSampleRate = m_config.m_channelSampleRate;
m_running.m_inputSampleRate = m_config.m_inputSampleRate;
m_running.m_Bandwidth = m_config.m_Bandwidth;
m_running.m_LowCutoff = m_config.m_LowCutoff;
//m_settingsMutex.lock();
m_running.m_spanLog2 = m_config.m_spanLog2;
m_running.m_ssb = m_config.m_ssb;
m_running.m_pll = m_config.m_pll;
m_running.m_fll = m_config.m_fll;
m_running.m_pllPskOrder = m_config.m_pllPskOrder;
//m_settingsMutex.unlock();
}
void ChannelAnalyzerNG::applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force)
{
qDebug() << "ChannelAnalyzerNG::applyChannelSettings:"
@ -338,6 +295,9 @@ void ChannelAnalyzerNG::applyChannelSettings(int inputSampleRate, int inputFrequ
void ChannelAnalyzerNG::setFilters(int sampleRate, float bandwidth, float lowCutoff)
{
qDebug("ChannelAnalyzerNG::setFilters: sampleRate: %d bandwidth: %f lowCutoff: %f",
sampleRate, bandwidth, lowCutoff);
if (bandwidth < 0)
{
bandwidth = -bandwidth;
@ -361,6 +321,17 @@ void ChannelAnalyzerNG::setFilters(int sampleRate, float bandwidth, float lowCut
void ChannelAnalyzerNG::applySettings(const ChannelAnalyzerNGSettings& settings, bool force)
{
qDebug() << "ChannelAnalyzerNG::applySettings:"
<< " m_downSample: " << settings.m_downSample
<< " m_downSampleRate: " << settings.m_downSampleRate
<< " m_bandwidth: " << settings.m_bandwidth
<< " m_lowCutoff: " << settings.m_lowCutoff
<< " m_spanLog2: " << settings.m_spanLog2
<< " m_ssb: " << settings.m_ssb
<< " m_pll: " << settings.m_pll
<< " m_fll: " << settings.m_fll
<< " m_pllPskOrder: " << settings.m_pllPskOrder;
if ((settings.m_downSampleRate != m_settings.m_downSampleRate) || force)
{
m_settingsMutex.lock();
@ -392,7 +363,7 @@ void ChannelAnalyzerNG::applySettings(const ChannelAnalyzerNGSettings& settings,
if ((settings.m_spanLog2 != m_settings.m_spanLog2) || force)
{
int sampleRate = (settings.m_downSample ? settings.m_downSampleRate : m_inputSampleRate) / (1<<m_running.m_spanLog2);
int sampleRate = (settings.m_downSample ? settings.m_downSampleRate : m_inputSampleRate) / (1<<m_settings.m_spanLog2);
m_pll.setSampleRate(sampleRate);
m_fll.setSampleRate(sampleRate);
}

View File

@ -184,10 +184,10 @@ public:
unsigned int pllPskOrder);
DownChannelizer *getChannelizer() { return m_channelizer; }
int getInputSampleRate() const { return m_running.m_inputSampleRate; }
int getChannelSampleRate() const { return m_running.m_channelSampleRate; }
int getInputSampleRate() const { return m_inputSampleRate; }
int getChannelSampleRate() const { return m_settings.m_downSample ? m_settings.m_downSampleRate : m_inputSampleRate; }
double getMagSq() const { return m_magsq; }
bool isPllLocked() const { return m_running.m_pll && m_pll.locked(); }
bool isPllLocked() const { return m_settings.m_pll && m_pll.locked(); }
Real getPllFrequency() const { return m_pll.getFreq(); }
Real getPllDeltaPhase() const { return m_pll.getDeltaPhi(); }
Real getPllPhase() const { return m_pll.getPhiHat(); }
@ -199,7 +199,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = objectName(); }
virtual qint64 getCenterFrequency() const { return m_running.m_frequency; }
virtual qint64 getCenterFrequency() const { return m_settings.m_frequency; }
virtual QByteArray serialize() const { return QByteArray(); }
virtual bool deserialize(const QByteArray& data __attribute__((unused))) { return false; }
@ -208,37 +208,6 @@ public:
static const QString m_channelId;
private:
struct Config
{
int m_frequency;
int m_inputSampleRate;
int m_channelSampleRate;
Real m_Bandwidth;
Real m_LowCutoff;
int m_spanLog2;
bool m_ssb;
bool m_pll;
bool m_fll;
unsigned int m_pllPskOrder;
Config() :
m_frequency(0),
m_inputSampleRate(96000),
m_channelSampleRate(96000),
m_Bandwidth(5000),
m_LowCutoff(300),
m_spanLog2(3),
m_ssb(false),
m_pll(false),
m_fll(false),
m_pllPskOrder(1)
{}
};
Config m_config;
Config m_running;
DeviceSourceAPI *m_deviceAPI;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
@ -266,85 +235,11 @@ private:
SampleVector m_sampleBuffer;
QMutex m_settingsMutex;
void apply(bool force = false);
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force);
// void apply(bool force = false);
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force = false);
void applySettings(const ChannelAnalyzerNGSettings& settings, bool force = false);
void setFilters(int sampleRate, float bandwidth, float lowCutoff);
void processOneSample(Complex& c, fftfilt::cmplx *sideband)
{
int n_out;
int decim = 1<<m_running.m_spanLog2;
if (m_running.m_ssb)
{
n_out = SSBFilter->runSSB(c, &sideband, m_usb);
}
else
{
n_out = DSBFilter->runDSB(c, &sideband);
}
for (int i = 0; i < n_out; i++)
{
// Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display
// smart decimation with bit gain using float arithmetic (23 bits significand)
m_sum += sideband[i];
if (!(m_undersampleCount++ & (decim - 1))) // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1)
{
m_sum /= decim;
Real re = m_sum.real() / SDR_RX_SCALED;
Real im = m_sum.imag() / SDR_RX_SCALED;
m_magsq = re*re + im*im;
Real mixI = 1.0f;
Real mixQ = 0.0f;
if (m_running.m_pll)
{
if (m_running.m_fll)
{
m_fll.feed(re, im);
// Use -fPLL to mix (exchange PLL real and image in the complex multiplication)
mixI = m_sum.real() * m_fll.getImag() - m_sum.imag() * m_fll.getReal();
mixQ = m_sum.real() * m_fll.getReal() + m_sum.imag() * m_fll.getImag();
// mixI = m_fll.getReal() * SDR_RX_SCALED;
// mixQ = m_fll.getImag() * SDR_RX_SCALED;
}
else
{
m_pll.feed(re, im);
// Use -fPLL to mix (exchange PLL real and image in the complex multiplication)
mixI = m_sum.real() * m_pll.getImag() - m_sum.imag() * m_pll.getReal();
mixQ = m_sum.real() * m_pll.getReal() + m_sum.imag() * m_pll.getImag();
}
if (m_running.m_ssb & !m_usb)
{ // invert spectrum for LSB
m_sampleBuffer.push_back(Sample(mixQ, mixI));
}
else
{
m_sampleBuffer.push_back(Sample(mixI, mixQ));
}
}
else
{
if (m_running.m_ssb & !m_usb)
{ // invert spectrum for LSB
m_sampleBuffer.push_back(Sample(m_sum.imag(), m_sum.real()));
}
else
{
m_sampleBuffer.push_back(Sample(m_sum.real(), m_sum.imag()));
}
}
m_sum = 0;
}
}
}
void processOneSample(Complex& c, fftfilt::cmplx *sideband);
};
#endif // INCLUDE_CHANALYZERNG_H

View File

@ -29,6 +29,7 @@
#include "dsp/scopevis.h"
#include "gui/glspectrum.h"
#include "gui/glscopeng.h"
#include "gui/basicchannelsettingsdialog.h"
#include "plugin/pluginapi.h"
#include "util/simpleserializer.h"
#include "util/db.h"
@ -66,133 +67,103 @@ qint64 ChannelAnalyzerNGGUI::getCenterFrequency() const
void ChannelAnalyzerNGGUI::setCenterFrequency(qint64 centerFrequency)
{
m_channelMarker.setCenterFrequency(centerFrequency);
m_settings.m_frequency = m_channelMarker.getCenterFrequency();
applySettings();
}
void ChannelAnalyzerNGGUI::resetToDefaults()
{
blockApplySettings(true);
m_settings.resetToDefaults();
}
ui->useRationalDownsampler->setChecked(false);
ui->BW->setValue(30);
ui->deltaFrequency->setValue(0);
ui->spanLog2->setCurrentIndex(3);
void ChannelAnalyzerNGGUI::displaySettings()
{
m_channelMarker.blockSignals(true);
m_channelMarker.setCenterFrequency(m_settings.m_frequency);
m_channelMarker.setBandwidth(m_settings.m_bandwidth * 2);
m_channelMarker.setTitle(m_settings.m_title);
m_channelMarker.setLowCutoff(m_settings.m_lowCutoff);
blockApplySettings(false);
applySettings();
if (m_settings.m_ssb)
{
if (m_settings.m_bandwidth < 0) {
m_channelMarker.setSidebands(ChannelMarker::lsb);
} else {
m_channelMarker.setSidebands(ChannelMarker::usb);
}
}
else
{
m_channelMarker.setSidebands(ChannelMarker::dsb);
}
m_channelMarker.blockSignals(false);
m_channelMarker.setColor(m_settings.m_rgbColor); // activate signal on the last setting only
setTitleColor(m_settings.m_rgbColor);
setWindowTitle(m_channelMarker.getTitle());
blockApplySettings(true);
ui->useRationalDownsampler->setChecked(m_settings.m_downSample);
ui->BW->setValue(m_settings.m_bandwidth/100);
ui->lowCut->setValue(m_settings.m_lowCutoff/100);
ui->deltaFrequency->setValue(m_settings.m_frequency);
ui->spanLog2->setCurrentIndex(m_settings.m_spanLog2);
blockApplySettings(false);
setNewFinalRate();
}
void ChannelAnalyzerNGGUI::setSpectrumDisplay()
{
qDebug("ChannelAnalyzerNGGUI::setSpectrumDisplay: m_rate: %d", m_rate);
if (m_settings.m_ssb)
{
ui->glSpectrum->setCenterFrequency(m_rate/4);
ui->glSpectrum->setSampleRate(m_rate/2);
ui->glSpectrum->setSsbSpectrum(true);
ui->glSpectrum->setLsbDisplay(ui->BW->value() < 0);
}
else
{
ui->glSpectrum->setCenterFrequency(0);
ui->glSpectrum->setSampleRate(m_rate);
ui->glSpectrum->setSsbSpectrum(false);
ui->glSpectrum->setLsbDisplay(false);
}
}
QByteArray ChannelAnalyzerNGGUI::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_channelMarker.getCenterFrequency());
s.writeS32(2, ui->BW->value());
s.writeBlob(3, ui->spectrumGUI->serialize());
s.writeU32(4, m_channelMarker.getColor().rgb());
s.writeS32(5, ui->lowCut->value());
s.writeS32(6, ui->spanLog2->currentIndex());
s.writeBool(7, ui->ssb->isChecked());
s.writeBlob(8, ui->scopeGUI->serialize());
s.writeU64(9, ui->channelSampleRate->getValueNew());
return s.final();
return m_settings.serialize();
}
bool ChannelAnalyzerNGGUI::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid())
if(m_settings.deserialize(data))
{
resetToDefaults();
return false;
}
if(d.getVersion() == 1)
{
QByteArray bytetmp;
quint32 u32tmp;
quint64 u64tmp;
qint32 tmp, spanLog2, bw, lowCut;
bool tmpBool;
blockApplySettings(true);
m_channelMarker.blockSignals(true);
d.readS32(1, &tmp, 0);
m_channelMarker.setCenterFrequency(tmp);
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
d.readS32(2, &bw, 30);
d.readBlob(3, &bytetmp);
ui->spectrumGUI->deserialize(bytetmp);
if(d.readU32(4, &u32tmp))
{
m_channelMarker.setColor(u32tmp);
}
d.readS32(5, &lowCut, 3);
d.readS32(6, &spanLog2, 3);
d.readBool(7, &tmpBool, false);
ui->ssb->setChecked(tmpBool);
d.readBlob(8, &bytetmp);
ui->scopeGUI->deserialize(bytetmp);
d.readU64(9, &u64tmp, 2000U);
ui->channelSampleRate->setValue(u64tmp);
blockApplySettings(false);
m_channelMarker.blockSignals(false);
m_channelMarker.emitChangedByAPI();
ui->spanLog2->setCurrentIndex(spanLog2);
setNewFinalRate(spanLog2);
ui->BW->setValue(bw);
ui->lowCut->setValue(lowCut); // does applySettings();
return true;
}
displaySettings();
applySettings(true); // will have true
return true;
}
else
{
resetToDefaults();
return false;
}
m_settings.resetToDefaults();
displaySettings();
applySettings(true); // will have true
return false;
}
}
bool ChannelAnalyzerNGGUI::handleMessage(const Message& message)
{
if (ChannelAnalyzerNG::MsgReportChannelSampleRateChanged::match(message))
{
int newRate = getRequestedChannelSampleRate() / (1<<m_spanLog2);
qDebug() << "ChannelAnalyzerNGGUI::handleMessage: MsgReportChannelSampleRateChanged:"
<< "m_rate: " << m_rate
<< " newRate: " << newRate;
m_rate = newRate;
blockApplySettings(true);
setFiltersUIBoundaries();
blockApplySettings(false);
if (ui->ssb->isChecked())
{
QString s = QString::number(ui->BW->value()/10.0, 'f', 1);
ui->BWText->setText(tr("%1k").arg(s));
}
else
{
QString s = QString::number(ui->BW->value()/5.0, 'f', 1); // BW = value * 2
ui->BWText->setText(tr("%1k").arg(s));
}
QString s = QString::number(ui->lowCut->value()/10.0, 'f', 1);
ui->lowCutText->setText(tr("%1k").arg(s));
s = QString::number(m_rate/1000.0, 'f', 1);
ui->spanText->setText(tr("%1 kS/s").arg(s));
ui->glScope->setSampleRate(m_rate);
displayBandwidth(); // sets ui->glSpectrum sample rate
qDebug() << "ChannelAnalyzerNGGUI::handleMessage: MsgReportChannelSampleRateChanged";
ui->channelSampleRate->setValueRange(7, 2000U, m_channelAnalyzer->getInputSampleRate());
setNewFinalRate();
return true;
}
@ -247,14 +218,9 @@ void ChannelAnalyzerNGGUI::tick()
void ChannelAnalyzerNGGUI::on_channelSampleRate_changed(quint64 value)
{
ui->channelSampleRate->setValueRange(7, 2000U, m_channelAnalyzer->getInputSampleRate());
if (ui->useRationalDownsampler->isChecked())
{
qDebug("ChannelAnalyzerNGGUI::on_channelSampleRate_changed: %llu", value);
setNewFinalRate(m_spanLog2);
applySettings();
}
m_settings.m_downSampleRate = value;
setNewFinalRate();
applySettings();
}
void ChannelAnalyzerNGGUI::on_pll_toggled(bool checked)
@ -266,14 +232,19 @@ void ChannelAnalyzerNGGUI::on_pll_toggled(bool checked)
applySettings();
}
void ChannelAnalyzerNGGUI::on_pllPskOrder_currentIndexChanged(int index __attribute__((unused)))
void ChannelAnalyzerNGGUI::on_pllPskOrder_currentIndexChanged(int index)
{
applySettings();
if (index < 5)
{
m_settings.m_pllPskOrder = (1<<index);
applySettings();
}
}
void ChannelAnalyzerNGGUI::on_useRationalDownsampler_toggled(bool checked __attribute__((unused)))
void ChannelAnalyzerNGGUI::on_useRationalDownsampler_toggled(bool checked)
{
setNewFinalRate(m_spanLog2);
m_settings.m_downSample = checked;
setNewFinalRate();
applySettings();
}
@ -289,115 +260,62 @@ int ChannelAnalyzerNGGUI::getRequestedChannelSampleRate()
void ChannelAnalyzerNGGUI::on_deltaFrequency_changed(qint64 value)
{
m_channelMarker.setCenterFrequency(value);
m_settings.m_frequency = m_channelMarker.getCenterFrequency();
applySettings();
}
void ChannelAnalyzerNGGUI::on_BW_valueChanged(int value)
void ChannelAnalyzerNGGUI::on_BW_valueChanged(int value __attribute__((unused)))
{
// m_channelMarker.setBandwidth(value * 100 * 2);
if (ui->ssb->isChecked())
{
QString s = QString::number(value/10.0, 'f', 1);
ui->BWText->setText(tr("%1k").arg(s));
}
else
{
QString s = QString::number(value/5.0, 'f', 1); // BW = value * 2
ui->BWText->setText(tr("%1k").arg(s));
}
displayBandwidth();
on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100); // does apply settings
setFiltersUIBoundaries();
m_settings.m_bandwidth = ui->BW->value() * 100;
m_settings.m_lowCutoff = ui->lowCut->value() * 100;
applySettings();
}
int ChannelAnalyzerNGGUI::getEffectiveLowCutoff(int lowCutoff)
void ChannelAnalyzerNGGUI::on_lowCut_valueChanged(int value __attribute__((unused)))
{
int ssbBW = m_channelMarker.getBandwidth() / 2;
int effectiveLowCutoff = lowCutoff;
const int guard = 100;
if (ssbBW < 0) {
if (effectiveLowCutoff < ssbBW + guard) {
effectiveLowCutoff = ssbBW + guard;
}
if (effectiveLowCutoff > 0) {
effectiveLowCutoff = 0;
}
} else {
if (effectiveLowCutoff > ssbBW - guard) {
effectiveLowCutoff = ssbBW - guard;
}
if (effectiveLowCutoff < 0) {
effectiveLowCutoff = 0;
}
}
return effectiveLowCutoff;
}
void ChannelAnalyzerNGGUI::on_lowCut_valueChanged(int value)
{
blockApplySettings(true);
int lowCutoff = getEffectiveLowCutoff(value * 100);
m_channelMarker.setLowCutoff(lowCutoff);
QString s = QString::number(lowCutoff/1000.0, 'f', 1);
ui->lowCutText->setText(tr("%1k").arg(s));
ui->lowCut->setValue(lowCutoff/100);
blockApplySettings(false);
setFiltersUIBoundaries();
m_settings.m_bandwidth = ui->BW->value() * 100;
m_settings.m_lowCutoff = ui->lowCut->value() * 100;
applySettings();
}
void ChannelAnalyzerNGGUI::on_spanLog2_currentIndexChanged(int index)
{
if (setNewFinalRate(index)) {
applySettings();
}
if ((index < 0) || (index > 6)) {
return;
}
m_settings.m_spanLog2 = index;
setNewFinalRate();
applySettings();
}
void ChannelAnalyzerNGGUI::on_ssb_toggled(bool checked)
{
//int bw = m_channelMarker.getBandwidth();
if (checked)
{
setFiltersUIBoundaries();
ui->BWLabel->setText("LP");
QString s = QString::number(ui->BW->value()/10.0, 'f', 1); // bw/2
ui->BWText->setText(tr("%1k").arg(s));
on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100);
}
else
{
if (ui->BW->value() < 0) {
ui->BW->setValue(-ui->BW->value());
}
setFiltersUIBoundaries();
//m_channelMarker.setBandwidth(ui->BW->value() * 200.0);
ui->BWLabel->setText("BP");
QString s = QString::number(ui->BW->value()/5.0, 'f', 1); // bw
ui->BWText->setText(tr("%1k").arg(s));
ui->lowCut->setEnabled(false);
ui->lowCut->setValue(0);
ui->lowCutText->setText("0.0k");
}
m_settings.m_ssb = checked;
setFiltersUIBoundaries();
applySettings();
displayBandwidth();
}
void ChannelAnalyzerNGGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool rollDown __attribute__((unused)))
{
/*
if((widget == ui->spectrumContainer) && (m_ssbDemod != NULL))
m_ssbDemod->setSpectrum(m_threadedSampleSink->getMessageQueue(), rollDown);
*/
}
void ChannelAnalyzerNGGUI::onMenuDialogCalled(const QPoint& p)
{
BasicChannelSettingsDialog dialog(&m_channelMarker, this);
dialog.move(p);
dialog.exec();
m_settings.m_frequency = m_channelMarker.getCenterFrequency();
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
m_settings.m_title = m_channelMarker.getTitle();
setWindowTitle(m_settings.m_title);
setTitleColor(m_settings.m_rgbColor);
applySettings();
}
ChannelAnalyzerNGGUI::ChannelAnalyzerNGGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent) :
@ -407,12 +325,12 @@ ChannelAnalyzerNGGUI::ChannelAnalyzerNGGUI(PluginAPI* pluginAPI, DeviceUISet *de
m_deviceUISet(deviceUISet),
m_channelMarker(this),
m_doApplySettings(true),
m_rate(6000),
m_spanLog2(0)
m_rate(48000)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose, true);
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
m_spectrumVis = new SpectrumVis(SDR_RX_SCALEF, ui->glSpectrum);
m_scopeVis = new ScopeVisNG(ui->glScope);
@ -456,12 +374,16 @@ ChannelAnalyzerNGGUI::ChannelAnalyzerNGGUI(PluginAPI* pluginAPI, DeviceUISet *de
ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope);
m_settings.setChannelMarker(&m_channelMarker);
m_settings.setSpectrumGUI(ui->spectrumGUI);
m_settings.setScopeGUI(ui->scopeGUI);
connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor()));
connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor()));
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
applySettings();
setNewFinalRate(m_spanLog2);
displaySettings();
applySettings(true);
}
ChannelAnalyzerNGGUI::~ChannelAnalyzerNGGUI()
@ -474,101 +396,79 @@ ChannelAnalyzerNGGUI::~ChannelAnalyzerNGGUI()
delete ui;
}
bool ChannelAnalyzerNGGUI::setNewFinalRate(int spanLog2)
void ChannelAnalyzerNGGUI::setNewFinalRate()
{
qDebug("ChannelAnalyzerNGGUI::setNewRate");
if ((spanLog2 < 0) || (spanLog2 > 6)) {
return false;
}
m_spanLog2 = spanLog2;
m_rate = getRequestedChannelSampleRate() / (1<<spanLog2);
m_rate = getRequestedChannelSampleRate() / (1<<m_settings.m_spanLog2);
if (m_rate == 0) {
m_rate = 6000;
m_rate = 48000;
}
qDebug("ChannelAnalyzerNGGUI::setNewFinalRate: %d m_spanLog2: %d", m_rate, m_settings.m_spanLog2);
setFiltersUIBoundaries();
QString s = QString::number(m_rate/1000.0, 'f', 1);
ui->spanText->setText(tr("%1 kS/s").arg(s));
displayBandwidth();
ui->glScope->setSampleRate(m_rate);
ui->glSpectrum->setSampleRate(m_rate);
m_scopeVis->setSampleRate(m_rate);
return true;
}
void ChannelAnalyzerNGGUI::displayBandwidth()
{
blockApplySettings(true);
m_channelMarker.setBandwidth(ui->BW->value() * 100 * 2);
if (ui->ssb->isChecked())
{
if (ui->BW->value() < 0)
{
m_channelMarker.setSidebands(ChannelMarker::lsb);
ui->glSpectrum->setLsbDisplay(true);
}
else
{
m_channelMarker.setSidebands(ChannelMarker::usb);
ui->glSpectrum->setLsbDisplay(false);
}
m_channelMarker.setLowCutoff(ui->lowCut->value()*100);
ui->glSpectrum->setSampleRate(m_rate/2);
ui->glSpectrum->setCenterFrequency(m_rate/4);
ui->glSpectrum->setSsbSpectrum(true);
}
else
{
m_channelMarker.setSidebands(ChannelMarker::dsb);
ui->glSpectrum->setCenterFrequency(0);
ui->glSpectrum->setSampleRate(m_rate);
ui->glSpectrum->setLsbDisplay(false);
ui->glSpectrum->setSsbSpectrum(false);
}
blockApplySettings(false);
}
void ChannelAnalyzerNGGUI::setFiltersUIBoundaries()
{
if (ui->BW->value() < -m_rate/200) {
ui->BW->setValue(-m_rate/200);
m_channelMarker.setBandwidth(-m_rate*2);
} else if (ui->BW->value() > m_rate/200) {
ui->BW->setValue(m_rate/200);
m_channelMarker.setBandwidth(m_rate*2);
}
bool dsb = !ui->ssb->isChecked();
int bw = ui->BW->value();
int lw = ui->lowCut->value();
int bwMax = m_rate / 200;
if (ui->lowCut->value() < -m_rate/200) {
ui->lowCut->setValue(-m_rate/200);
m_channelMarker.setLowCutoff(-m_rate);
} else if (ui->lowCut->value() > m_rate/200) {
ui->lowCut->setValue(m_rate/200);
m_channelMarker.setLowCutoff(m_rate);
}
bw = bw < -bwMax ? -bwMax : bw > bwMax ? bwMax : bw;
if (ui->ssb->isChecked()) {
ui->BW->setMinimum(-m_rate/200);
ui->lowCut->setMinimum(-m_rate/200);
if (bw < 0) {
lw = lw < bw+1 ? bw+1 : lw < 0 ? lw : 0;
} else if (bw > 0) {
lw = lw > bw-1 ? bw-1 : lw < 0 ? 0 : lw;
} else {
ui->BW->setMinimum(0);
ui->lowCut->setMinimum(-m_rate/200);
ui->lowCut->setValue(0);
lw = 0;
}
ui->BW->setMaximum(m_rate/200);
ui->lowCut->setMaximum(m_rate/200);
if (dsb)
{
bw = bw < 0 ? -bw : bw;
lw = 0;
}
QString bwStr = QString::number(bw/10.0, 'f', 1);
QString lwStr = QString::number(lw/10.0, 'f', 1);
if (dsb) {
ui->BWText->setText(tr("%1%2k").arg(QChar(0xB1, 0x00)).arg(bwStr));
} else {
ui->BWText->setText(tr("%1k").arg(bwStr));
}
ui->lowCutText->setText(tr("%1k").arg(lwStr));
ui->BW->blockSignals(true);
ui->lowCut->blockSignals(true);
ui->BW->setMaximum(bwMax);
ui->BW->setMinimum(dsb ? 0 : -bwMax);
ui->BW->setValue(bw);
ui->lowCut->setMaximum(dsb ? 0 : bw);
ui->lowCut->setMinimum(dsb ? 0 : -bw);
ui->lowCut->setValue(lw);
ui->lowCut->blockSignals(false);
ui->BW->blockSignals(false);
setSpectrumDisplay();
m_channelMarker.setBandwidth(bw * 200);
m_channelMarker.setSidebands(dsb ? ChannelMarker::dsb : bw < 0 ? ChannelMarker::lsb : ChannelMarker::usb);
if (!dsb) {
m_channelMarker.setLowCutoff(lw * 100);
}
}
void ChannelAnalyzerNGGUI::blockApplySettings(bool block)
@ -578,30 +478,23 @@ void ChannelAnalyzerNGGUI::blockApplySettings(bool block)
m_doApplySettings = !block;
}
void ChannelAnalyzerNGGUI::applySettings()
void ChannelAnalyzerNGGUI::applySettings(bool force)
{
if (m_doApplySettings)
{
int sampleRate = getRequestedChannelSampleRate();
ChannelAnalyzerNG::MsgConfigureChannelizer *msgChannelizer = ChannelAnalyzerNG::MsgConfigureChannelizer::create(sampleRate, m_channelMarker.getCenterFrequency());
ChannelAnalyzerNG::MsgConfigureChannelizer *msgChannelizer =
ChannelAnalyzerNG::MsgConfigureChannelizer::create(sampleRate, m_channelMarker.getCenterFrequency());
m_channelAnalyzer->getInputMessageQueue()->push(msgChannelizer);
ChannelAnalyzerNG::MsgConfigureChannelizer *msg =
ChannelAnalyzerNG::MsgConfigureChannelizer::create(
sampleRate,
m_channelMarker.getCenterFrequency());
ChannelAnalyzerNG::MsgConfigureChannelizer::create(sampleRate, m_channelMarker.getCenterFrequency());
m_channelAnalyzer->getInputMessageQueue()->push(msg);
m_channelAnalyzer->configure(m_channelAnalyzer->getInputMessageQueue(),
sampleRate,
ui->BW->value() * 100.0,
ui->lowCut->value() * 100.0,
m_spanLog2,
ui->ssb->isChecked(),
ui->pll->isChecked(),
ui->pllPskOrder->currentIndex() == 5,
1<<ui->pllPskOrder->currentIndex());
ChannelAnalyzerNG::MsgConfigureChannelAnalyzer* message =
ChannelAnalyzerNG::MsgConfigureChannelAnalyzer::create( m_settings, force);
m_channelAnalyzer->getInputMessageQueue()->push(message);
}
}

View File

@ -17,13 +17,15 @@
#ifndef INCLUDE_CHANNELANALYZERNGGUI_H
#define INCLUDE_CHANNELANALYZERNGGUI_H
#include <plugin/plugininstancegui.h>
#include "plugin/plugininstancegui.h"
#include "gui/rollupwidget.h"
#include "dsp/channelmarker.h"
#include "dsp/dsptypes.h"
#include "util/movingaverage.h"
#include "util/messagequeue.h"
#include "chanalyzerngsettings.h"
class PluginAPI;
class DeviceUISet;
class BasebandSampleSink;
@ -63,9 +65,9 @@ private:
PluginAPI* m_pluginAPI;
DeviceUISet* m_deviceUISet;
ChannelMarker m_channelMarker;
ChannelAnalyzerNGSettings m_settings;
bool m_doApplySettings;
int m_rate; //!< sample rate after final in-channel decimation (spanlog2)
int m_spanLog2;
MovingAverageUtil<Real, double, 40> m_channelPowerDbAvg;
ChannelAnalyzerNG* m_channelAnalyzer;
@ -78,13 +80,13 @@ private:
virtual ~ChannelAnalyzerNGGUI();
int getRequestedChannelSampleRate();
int getEffectiveLowCutoff(int lowCutoff);
bool setNewFinalRate(int spanLog2); //!< set sample rate after final in-channel decimation
void setNewFinalRate(); //!< set sample rate after final in-channel decimation
void setFiltersUIBoundaries();
void blockApplySettings(bool block);
void applySettings();
void displayBandwidth();
void applySettings(bool force = false);
void displaySettings();
void setSpectrumDisplay();
void leaveEvent(QEvent*);
void enterEvent(QEvent*);
@ -100,6 +102,7 @@ private slots:
void on_spanLog2_currentIndexChanged(int index);
void on_ssb_toggled(bool checked);
void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p);
void handleInputMessages();
void tick();
};

View File

@ -22,7 +22,9 @@
#include "chanalyzerngsettings.h"
ChannelAnalyzerNGSettings::ChannelAnalyzerNGSettings() :
m_channelMarker(0)
m_channelMarker(0),
m_spectrumGUI(0),
m_scopeGUI(0)
{
resetToDefaults();
}
@ -34,11 +36,12 @@ void ChannelAnalyzerNGSettings::resetToDefaults()
m_downSampleRate = 0;
m_bandwidth = 5000;
m_lowCutoff = 300;
m_spanLog2 = 3;
m_spanLog2 = 0;
m_ssb = false;
m_pll = false;
m_fll = false;
m_pllPskOrder = 1;
m_rgbColor = QColor(128, 128, 128).rgb();
}
QByteArray ChannelAnalyzerNGSettings::serialize() const
@ -86,7 +89,7 @@ bool ChannelAnalyzerNGSettings::deserialize(const QByteArray& data)
d.readU32(4, &m_rgbColor);
d.readS32(5, &m_lowCutoff, 3);
d.readS32(6, &m_spanLog2, 3);
d.readS32(6, &m_spanLog2, 0);
d.readBool(7, &m_ssb, false);
if (m_scopeGUI) {

View File

@ -42,6 +42,8 @@ struct ChannelAnalyzerNGSettings
ChannelAnalyzerNGSettings();
void resetToDefaults();
void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; }
void setSpectrumGUI(Serializable *spectrumGUI) { m_spectrumGUI = spectrumGUI; }
void setScopeGUI(Serializable *scopeGUI) { m_scopeGUI = scopeGUI; }
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};