Spectrum: implemented linear scale mode

This commit is contained in:
f4exb 2018-07-06 01:34:05 +02:00
parent d5f153ff75
commit f6c596d55a
7 changed files with 95 additions and 37 deletions

View File

@ -20,18 +20,20 @@ SpectrumVis::SpectrumVis(Real scalef, GLSpectrum* glSpectrum) :
BasebandSampleSink(), BasebandSampleSink(),
m_fft(FFTEngine::create()), m_fft(FFTEngine::create()),
m_fftBuffer(MAX_FFT_SIZE), m_fftBuffer(MAX_FFT_SIZE),
m_logPowerSpectrum(MAX_FFT_SIZE), m_powerSpectrum(MAX_FFT_SIZE),
m_fftBufferFill(0), m_fftBufferFill(0),
m_needMoreSamples(false), m_needMoreSamples(false),
m_scalef(scalef), m_scalef(scalef),
m_glSpectrum(glSpectrum), m_glSpectrum(glSpectrum),
m_averageNb(0), m_averageNb(0),
m_averagingMode(AvgModeNone), m_averagingMode(AvgModeNone),
m_linear(false),
m_ofs(0), m_ofs(0),
m_powFFTDiv(1.0),
m_mutex(QMutex::Recursive) m_mutex(QMutex::Recursive)
{ {
setObjectName("SpectrumVis"); setObjectName("SpectrumVis");
handleConfigure(1024, 0, 0, AvgModeNone, FFTWindow::BlackmanHarris); handleConfigure(1024, 0, 0, AvgModeNone, FFTWindow::BlackmanHarris, false);
} }
SpectrumVis::~SpectrumVis() SpectrumVis::~SpectrumVis()
@ -120,9 +122,9 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
{ {
c = fftOut[i]; c = fftOut[i];
v = c.real() * c.real() + c.imag() * c.imag(); v = c.real() * c.real() + c.imag() * c.imag();
v = m_mult * log2f(v) + m_ofs; v = m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
m_logPowerSpectrum[i * 2] = v; m_powerSpectrum[i * 2] = v;
m_logPowerSpectrum[i * 2 + 1] = v; m_powerSpectrum[i * 2 + 1] = v;
} }
} }
else else
@ -131,18 +133,18 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
{ {
c = fftOut[i + halfSize]; c = fftOut[i + halfSize];
v = c.real() * c.real() + c.imag() * c.imag(); v = c.real() * c.real() + c.imag() * c.imag();
v = m_mult * log2f(v) + m_ofs; v = m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
m_logPowerSpectrum[i] = v; m_powerSpectrum[i] = v;
c = fftOut[i]; c = fftOut[i];
v = c.real() * c.real() + c.imag() * c.imag(); v = c.real() * c.real() + c.imag() * c.imag();
v = m_mult * log2f(v) + m_ofs; v = m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
m_logPowerSpectrum[i + halfSize] = v; m_powerSpectrum[i + halfSize] = v;
} }
} }
// send new data to visualisation // send new data to visualisation
m_glSpectrum->newSpectrum(m_logPowerSpectrum, m_fftSize); m_glSpectrum->newSpectrum(m_powerSpectrum, m_fftSize);
} }
else if (m_averagingMode == AvgModeMoving) else if (m_averagingMode == AvgModeMoving)
{ {
@ -153,9 +155,9 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
c = fftOut[i]; c = fftOut[i];
v = c.real() * c.real() + c.imag() * c.imag(); v = c.real() * c.real() + c.imag() * c.imag();
v = m_movingAverage.storeAndGetAvg(v, i); v = m_movingAverage.storeAndGetAvg(v, i);
v = m_mult * log2f(v) + m_ofs; v = m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
m_logPowerSpectrum[i * 2] = v; m_powerSpectrum[i * 2] = v;
m_logPowerSpectrum[i * 2 + 1] = v; m_powerSpectrum[i * 2 + 1] = v;
} }
} }
else else
@ -165,19 +167,19 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
c = fftOut[i + halfSize]; c = fftOut[i + halfSize];
v = c.real() * c.real() + c.imag() * c.imag(); v = c.real() * c.real() + c.imag() * c.imag();
v = m_movingAverage.storeAndGetAvg(v, i+halfSize); v = m_movingAverage.storeAndGetAvg(v, i+halfSize);
v = m_mult * log2f(v) + m_ofs; v = m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
m_logPowerSpectrum[i] = v; m_powerSpectrum[i] = v;
c = fftOut[i]; c = fftOut[i];
v = c.real() * c.real() + c.imag() * c.imag(); v = c.real() * c.real() + c.imag() * c.imag();
v = m_movingAverage.storeAndGetAvg(v, i); v = m_movingAverage.storeAndGetAvg(v, i);
v = m_mult * log2f(v) + m_ofs; v = m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
m_logPowerSpectrum[i + halfSize] = v; m_powerSpectrum[i + halfSize] = v;
} }
} }
// send new data to visualisation // send new data to visualisation
m_glSpectrum->newSpectrum(m_logPowerSpectrum, m_fftSize); m_glSpectrum->newSpectrum(m_powerSpectrum, m_fftSize);
m_movingAverage.nextAverage(); m_movingAverage.nextAverage();
} }
else if (m_averagingMode == AvgModeFixed) else if (m_averagingMode == AvgModeFixed)
@ -193,9 +195,9 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
if (m_fixedAverage.storeAndGetAvg(avg, v, i)) if (m_fixedAverage.storeAndGetAvg(avg, v, i))
{ {
avg = m_mult * log2f(avg) + m_ofs; avg = m_linear ? v/m_powFFTDiv : m_mult * log2f(avg) + m_ofs;
m_logPowerSpectrum[i * 2] = avg; m_powerSpectrum[i * 2] = avg;
m_logPowerSpectrum[i * 2 + 1] = avg; m_powerSpectrum[i * 2 + 1] = avg;
} }
} }
} }
@ -208,8 +210,8 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
if (m_fixedAverage.storeAndGetAvg(avg, v, i+halfSize)) if (m_fixedAverage.storeAndGetAvg(avg, v, i+halfSize))
{ // result available { // result available
avg = m_mult * log2f(avg) + m_ofs; avg = m_linear ? v/m_powFFTDiv : m_mult * log2f(avg) + m_ofs;
m_logPowerSpectrum[i] = avg; m_powerSpectrum[i] = avg;
} }
c = fftOut[i]; c = fftOut[i];
@ -217,8 +219,8 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
if (m_fixedAverage.storeAndGetAvg(avg, v, i)) if (m_fixedAverage.storeAndGetAvg(avg, v, i))
{ // result available { // result available
avg = m_mult * log2f(avg) + m_ofs; avg = m_linear ? v/m_powFFTDiv : m_mult * log2f(avg) + m_ofs;
m_logPowerSpectrum[i + halfSize] = avg; m_powerSpectrum[i + halfSize] = avg;
} }
} }
} }
@ -226,7 +228,7 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
if (m_fixedAverage.nextAverage()) if (m_fixedAverage.nextAverage())
{ // result available { // result available
// send new data to visualisation // send new data to visualisation
m_glSpectrum->newSpectrum(m_logPowerSpectrum, m_fftSize); m_glSpectrum->newSpectrum(m_powerSpectrum, m_fftSize);
} }
} }
@ -268,7 +270,8 @@ bool SpectrumVis::handleMessage(const Message& message)
conf.getOverlapPercent(), conf.getOverlapPercent(),
conf.getAverageNb(), conf.getAverageNb(),
conf.getAveragingMode(), conf.getAveragingMode(),
conf.getWindow()); conf.getWindow(),
conf.getLinear());
return true; return true;
} }
else else
@ -281,7 +284,8 @@ void SpectrumVis::handleConfigure(int fftSize,
int overlapPercent, int overlapPercent,
unsigned int averageNb, unsigned int averageNb,
AveragingMode averagingMode, AveragingMode averagingMode,
FFTWindow::Function window) FFTWindow::Function window,
bool linear)
{ {
QMutexLocker mutexLocker(&m_mutex); QMutexLocker mutexLocker(&m_mutex);
@ -317,5 +321,7 @@ void SpectrumVis::handleConfigure(int fftSize,
m_fixedAverage.resize(fftSize, averageNb); m_fixedAverage.resize(fftSize, averageNb);
m_averageNb = averageNb; m_averageNb = averageNb;
m_averagingMode = averagingMode; m_averagingMode = averagingMode;
m_linear = linear;
m_ofs = 20.0f * log10f(1.0f / m_fftSize); m_ofs = 20.0f * log10f(1.0f / m_fftSize);
m_powFFTDiv = m_fftSize*m_fftSize;
} }

View File

@ -82,7 +82,7 @@ private:
FFTWindow m_window; FFTWindow m_window;
std::vector<Complex> m_fftBuffer; std::vector<Complex> m_fftBuffer;
std::vector<Real> m_logPowerSpectrum; std::vector<Real> m_powerSpectrum;
std::size_t m_fftSize; std::size_t m_fftSize;
std::size_t m_overlapPercent; std::size_t m_overlapPercent;
@ -97,8 +97,10 @@ private:
FixedAverage2D<double> m_fixedAverage; FixedAverage2D<double> m_fixedAverage;
unsigned int m_averageNb; unsigned int m_averageNb;
AveragingMode m_averagingMode; AveragingMode m_averagingMode;
bool m_linear;
Real m_ofs; Real m_ofs;
Real m_powFFTDiv;
static const Real m_mult; static const Real m_mult;
QMutex m_mutex; QMutex m_mutex;
@ -107,7 +109,8 @@ private:
int overlapPercent, int overlapPercent,
unsigned int averageNb, unsigned int averageNb,
AveragingMode averagingMode, AveragingMode averagingMode,
FFTWindow::Function window); FFTWindow::Function window,
bool linear);
}; };
#endif // INCLUDE_SPECTRUMVIS_H #endif // INCLUDE_SPECTRUMVIS_H

View File

@ -39,6 +39,7 @@ GLSpectrum::GLSpectrum(QWidget* parent) :
m_centerFrequency(100000000), m_centerFrequency(100000000),
m_referenceLevel(0), m_referenceLevel(0),
m_powerRange(100), m_powerRange(100),
m_linear(false),
m_decay(0), m_decay(0),
m_sampleRate(500000), m_sampleRate(500000),
m_timingRate(1), m_timingRate(1),
@ -291,6 +292,13 @@ void GLSpectrum::setDisplayTraceIntensity(int intensity)
update(); update();
} }
void GLSpectrum::setLinear(bool linear)
{
m_linear = linear;
m_changesPending = true;
update();
}
void GLSpectrum::addChannelMarker(ChannelMarker* channelMarker) void GLSpectrum::addChannelMarker(ChannelMarker* channelMarker)
{ {
QMutexLocker mutexLocker(&m_mutex); QMutexLocker mutexLocker(&m_mutex);
@ -1075,7 +1083,13 @@ void GLSpectrum::applyChanges()
} }
m_powerScale.setSize(histogramHeight); m_powerScale.setSize(histogramHeight);
if (m_linear) {
m_powerScale.setRange(Unit::Scientific, m_referenceLevel - m_powerRange, m_referenceLevel);
} else {
m_powerScale.setRange(Unit::Decibel, m_referenceLevel - m_powerRange, m_referenceLevel); m_powerScale.setRange(Unit::Decibel, m_referenceLevel - m_powerRange, m_referenceLevel);
}
leftMargin = m_timeScale.getScaleWidth(); leftMargin = m_timeScale.getScaleWidth();
if(m_powerScale.getScaleWidth() > leftMargin) if(m_powerScale.getScaleWidth() > leftMargin)

View File

@ -81,6 +81,7 @@ public:
void setDisplayGrid(bool display); void setDisplayGrid(bool display);
void setDisplayGridIntensity(int intensity); void setDisplayGridIntensity(int intensity);
void setDisplayTraceIntensity(int intensity); void setDisplayTraceIntensity(int intensity);
void setLinear(bool linear);
qint32 getSampleRate() const { return m_sampleRate; } qint32 getSampleRate() const { return m_sampleRate; }
void addChannelMarker(ChannelMarker* channelMarker); void addChannelMarker(ChannelMarker* channelMarker);
@ -130,6 +131,7 @@ private:
qint64 m_centerFrequency; qint64 m_centerFrequency;
Real m_referenceLevel; Real m_referenceLevel;
Real m_powerRange; Real m_powerRange;
bool m_linear;
int m_decay; int m_decay;
quint32 m_sampleRate; quint32 m_sampleRate;
quint32 m_timingRate; quint32 m_timingRate;

View File

@ -77,6 +77,7 @@ void GLSpectrumGUI::resetToDefaults()
m_invert = true; m_invert = true;
m_averagingMode = AvgModeNone; m_averagingMode = AvgModeNone;
m_averagingIndex = 0; m_averagingIndex = 0;
m_linear = false;
applySettings(); applySettings();
} }
@ -103,6 +104,7 @@ QByteArray GLSpectrumGUI::serialize() const
s.writeReal(18, m_glSpectrum->getWaterfallShare()); s.writeReal(18, m_glSpectrum->getWaterfallShare());
s.writeS32(19, (int) m_averagingMode); s.writeS32(19, (int) m_averagingMode);
s.writeS32(20, (qint32) getAveragingValue(m_averagingIndex)); s.writeS32(20, (qint32) getAveragingValue(m_averagingIndex));
s.writeBool(21, m_linear);
return s.final(); return s.final();
} }
@ -142,6 +144,7 @@ bool GLSpectrumGUI::deserialize(const QByteArray& data)
d.readS32(20, &tmp, 0); d.readS32(20, &tmp, 0);
m_averagingIndex = getAveragingIndex(tmp); m_averagingIndex = getAveragingIndex(tmp);
m_averagingNb = getAveragingValue(m_averagingIndex); m_averagingNb = getAveragingValue(m_averagingIndex);
d.readBool(21, &m_linear, false);
m_glSpectrum->setWaterfallShare(waterfallShare); m_glSpectrum->setWaterfallShare(waterfallShare);
applySettings(); applySettings();
@ -165,6 +168,7 @@ void GLSpectrumGUI::applySettings()
ui->levelRange->setCurrentIndex((100 - m_powerRange) / 5); ui->levelRange->setCurrentIndex((100 - m_powerRange) / 5);
ui->averaging->setCurrentIndex(m_averagingIndex); ui->averaging->setCurrentIndex(m_averagingIndex);
ui->averagingMode->setCurrentIndex((int) m_averagingMode); ui->averagingMode->setCurrentIndex((int) m_averagingMode);
ui->linscale->setChecked(m_linear);
ui->decay->setSliderPosition(m_decay); ui->decay->setSliderPosition(m_decay);
ui->holdoff->setSliderPosition(m_histogramLateHoldoff); ui->holdoff->setSliderPosition(m_histogramLateHoldoff);
ui->stroke->setSliderPosition(m_histogramStroke); ui->stroke->setSliderPosition(m_histogramStroke);
@ -193,6 +197,7 @@ void GLSpectrumGUI::applySettings()
m_glSpectrum->setInvertedWaterfall(m_invert); m_glSpectrum->setInvertedWaterfall(m_invert);
m_glSpectrum->setDisplayGrid(m_displayGrid); m_glSpectrum->setDisplayGrid(m_displayGrid);
m_glSpectrum->setDisplayGridIntensity(m_displayGridIntensity); m_glSpectrum->setDisplayGridIntensity(m_displayGridIntensity);
m_glSpectrum->setLinear(m_linear);
if (m_spectrumVis) { if (m_spectrumVis) {
m_spectrumVis->configure(m_messageQueueToVis, m_spectrumVis->configure(m_messageQueueToVis,
@ -298,21 +303,43 @@ void GLSpectrumGUI::on_linscale_toggled(bool checked)
(FFTWindow::Function)m_fftWindow, (FFTWindow::Function)m_fftWindow,
m_linear); m_linear);
} }
if(m_glSpectrum != 0)
{
Real refLevel = m_linear ? pow(10.0, m_refLevel/10.0) : m_refLevel;
Real powerRange = m_linear ? pow(10.0, m_refLevel/10.0) : m_powerRange;
qDebug("GLSpectrumGUI::on_linscale_toggled: refLevel: %e powerRange: %e", refLevel, powerRange);
m_glSpectrum->setReferenceLevel(refLevel);
m_glSpectrum->setPowerRange(powerRange);
m_glSpectrum->setLinear(m_linear);
}
} }
void GLSpectrumGUI::on_refLevel_currentIndexChanged(int index) void GLSpectrumGUI::on_refLevel_currentIndexChanged(int index)
{ {
m_refLevel = 0 - index * 5; m_refLevel = 0 - index * 5;
if(m_glSpectrum != 0) {
m_glSpectrum->setReferenceLevel(m_refLevel); if(m_glSpectrum != 0)
{
Real refLevel = m_linear ? pow(10.0, m_refLevel/10.0) : m_refLevel;
Real powerRange = m_linear ? pow(10.0, m_refLevel/10.0) : m_powerRange;
qDebug("GLSpectrumGUI::on_refLevel_currentIndexChanged: refLevel: %e ", refLevel);
m_glSpectrum->setReferenceLevel(refLevel);
m_glSpectrum->setPowerRange(powerRange);
} }
} }
void GLSpectrumGUI::on_levelRange_currentIndexChanged(int index) void GLSpectrumGUI::on_levelRange_currentIndexChanged(int index)
{ {
m_powerRange = 100 - index * 5; m_powerRange = 100 - index * 5;
if(m_glSpectrum != 0) {
m_glSpectrum->setPowerRange(m_powerRange); if(m_glSpectrum != 0)
{
Real refLevel = m_linear ? pow(10.0, m_refLevel/10.0) : m_refLevel;
Real powerRange = m_linear ? pow(10.0, m_refLevel/10.0) : m_powerRange;
qDebug("GLSpectrumGUI::on_levelRange_currentIndexChanged: powerRange: %e", powerRange);
m_glSpectrum->setReferenceLevel(refLevel);
m_glSpectrum->setPowerRange(powerRange);
} }
} }

View File

@ -30,7 +30,8 @@ namespace Unit {
AngleDegrees, AngleDegrees,
Time, Time,
TimeHMS, TimeHMS,
Volt Volt,
Scientific
}; };
}; };

View File

@ -31,8 +31,12 @@ QString ScaleEngine::formatTick(double value, int decimalPlaces)
{ {
if (m_physicalUnit != Unit::TimeHMS) if (m_physicalUnit != Unit::TimeHMS)
{ {
if (m_physicalUnit == Unit::Scientific) {
return QString("%1").arg(m_makeOpposite ? -value : value, 0, 'e', 2);
} else {
return QString("%1").arg(m_makeOpposite ? -value : value, 0, 'f', decimalPlaces); return QString("%1").arg(m_makeOpposite ? -value : value, 0, 'f', decimalPlaces);
} }
}
else else
{ {
if (m_scale < 1.0f) { // sub second prints just as is if (m_scale < 1.0f) { // sub second prints just as is
@ -106,6 +110,7 @@ void ScaleEngine::calcScaleFactor()
switch(m_physicalUnit) { switch(m_physicalUnit) {
case Unit::None: case Unit::None:
case Unit::Scientific:
m_unitStr.clear(); m_unitStr.clear();
break; break;