Spectrum GUI autoscaling. Implements #771

pull/788/head
f4exb 2021-02-10 08:34:42 +01:00
rodzic 7827800d13
commit 6641355fbd
5 zmienionych plików z 94 dodań i 31 usunięć

Wyświetl plik

@ -33,7 +33,7 @@
#define MAX_FFT_SIZE 4096
#ifndef LINUX
inline double log2f(double n)
inline double log2(double n)
{
return log(n) / log(2.0);
}
@ -45,7 +45,7 @@ MESSAGE_CLASS_DEFINITION(SpectrumVis::MsgConfigureWSpectrumOpenClose, Message)
MESSAGE_CLASS_DEFINITION(SpectrumVis::MsgConfigureWSpectrum, Message)
MESSAGE_CLASS_DEFINITION(SpectrumVis::MsgStartStop, Message)
const Real SpectrumVis::m_mult = (10.0f / log2f(10.0f));
const Real SpectrumVis::m_mult = (10.0f / log2(10.0f));
SpectrumVis::SpectrumVis(Real scalef) :
BasebandSampleSink(),
@ -54,6 +54,7 @@ SpectrumVis::SpectrumVis(Real scalef) :
m_fftEngineSequence(0),
m_fftBuffer(MAX_FFT_SIZE),
m_powerSpectrum(MAX_FFT_SIZE),
m_psd(MAX_FFT_SIZE),
m_fftBufferFill(0),
m_needMoreSamples(false),
m_scalef(scalef),
@ -132,6 +133,7 @@ void SpectrumVis::feed(const Complex *begin, unsigned int length)
}
v = c.real() * c.real() + c.imag() * c.imag();
m_psd[i] = v/m_powFFTDiv;
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
m_powerSpectrum[i] = v;
}
@ -167,6 +169,7 @@ void SpectrumVis::feed(const Complex *begin, unsigned int length)
v = c.real() * c.real() + c.imag() * c.imag();
v = m_movingAverage.storeAndGetAvg(v, i);
m_psd[i] = v/m_powFFTDiv;
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
m_powerSpectrum[i] = v;
}
@ -209,6 +212,7 @@ void SpectrumVis::feed(const Complex *begin, unsigned int length)
// result available
if (m_fixedAverage.storeAndGetAvg(avg, v, i))
{
m_psd[i] = avg/m_powFFTDiv;
avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs;
m_powerSpectrum[i] = avg;
}
@ -254,6 +258,7 @@ void SpectrumVis::feed(const Complex *begin, unsigned int length)
// result available
if (m_max.storeAndGetMax(max, v, i))
{
m_psd[i] = max/m_powFFTDiv;
max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs;
m_powerSpectrum[i] = max;
}
@ -340,6 +345,7 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
{
c = fftOut[i];
v = c.real() * c.real() + c.imag() * c.imag();
m_psd[i] = v/m_powFFTDiv;
m_specMax = v > m_specMax ? v : m_specMax;
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
m_powerSpectrum[i * 2] = v;
@ -352,12 +358,14 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
{
c = fftOut[i + halfSize];
v = c.real() * c.real() + c.imag() * c.imag();
m_psd[i] = v/m_powFFTDiv;
m_specMax = v > m_specMax ? v : m_specMax;
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
m_powerSpectrum[i] = v;
c = fftOut[i];
v = c.real() * c.real() + c.imag() * c.imag();
m_psd[i + halfSize] = v/m_powFFTDiv;
m_specMax = v > m_specMax ? v : m_specMax;
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
m_powerSpectrum[i + halfSize] = v;
@ -394,6 +402,7 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
c = fftOut[i];
v = c.real() * c.real() + c.imag() * c.imag();
v = m_movingAverage.storeAndGetAvg(v, i);
m_psd[i] = v/m_powFFTDiv;
m_specMax = v > m_specMax ? v : m_specMax;
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
m_powerSpectrum[i * 2] = v;
@ -407,6 +416,7 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
c = fftOut[i + halfSize];
v = c.real() * c.real() + c.imag() * c.imag();
v = m_movingAverage.storeAndGetAvg(v, i+halfSize);
m_psd[i] = v/m_powFFTDiv;
m_specMax = v > m_specMax ? v : m_specMax;
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
m_powerSpectrum[i] = v;
@ -414,6 +424,7 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
c = fftOut[i];
v = c.real() * c.real() + c.imag() * c.imag();
v = m_movingAverage.storeAndGetAvg(v, i);
m_psd[i + halfSize] = v/m_powFFTDiv;
m_specMax = v > m_specMax ? v : m_specMax;
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
m_powerSpectrum[i + halfSize] = v;
@ -456,6 +467,7 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
// result available
if (m_fixedAverage.storeAndGetAvg(avg, v, i))
{
m_psd[i] = avg/m_powFFTDiv;
specMax = avg > specMax ? avg : specMax;
avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs;
m_powerSpectrum[i * 2] = avg;
@ -473,6 +485,7 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
// result available
if (m_fixedAverage.storeAndGetAvg(avg, v, i+halfSize))
{
m_psd[i] = avg/m_powFFTDiv;
specMax = avg > specMax ? avg : specMax;
avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs;
m_powerSpectrum[i] = avg;
@ -484,6 +497,7 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
// result available
if (m_fixedAverage.storeAndGetAvg(avg, v, i))
{
m_psd[i + halfSize] = avg/m_powFFTDiv;
specMax = avg > specMax ? avg : specMax;
avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs;
m_powerSpectrum[i + halfSize] = avg;
@ -531,6 +545,7 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
// result available
if (m_max.storeAndGetMax(max, v, i))
{
m_psd[i] = max/m_powFFTDiv;
specMax = max > specMax ? max : specMax;
max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs;
m_powerSpectrum[i * 2] = max;
@ -548,6 +563,7 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
// result available
if (m_max.storeAndGetMax(max, v, i+halfSize))
{
m_psd[i] = max/m_powFFTDiv;
specMax = max > specMax ? max : specMax;
max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs;
m_powerSpectrum[i] = max;
@ -559,6 +575,7 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
// result available
if (m_max.storeAndGetMax(max, v, i))
{
m_psd[i + halfSize] = max/m_powFFTDiv;
specMax = max > specMax ? max : specMax;
max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs;
m_powerSpectrum[i + halfSize] = max;

Wyświetl plik

@ -124,6 +124,8 @@ public:
void configureWSSpectrum(const QString& address, uint16_t port);
const GLSpectrumSettings& getSettings() const { return m_settings; }
Real getSpecMax() const { return m_specMax / m_powFFTDiv; }
void getPowerSpectrumCopy(std::vector<Real>& copy) { copy.assign(m_powerSpectrum.begin(), m_powerSpectrum.end()); }
void getPSDCopy(std::vector<Real>& copy) { copy.assign(m_psd.begin(), m_psd.begin() + m_settings.m_fftSize); }
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
virtual void feed(const Complex *begin, unsigned int length); //!< direct FFT feed
@ -187,7 +189,8 @@ private:
unsigned int m_fftEngineSequence;
std::vector<Complex> m_fftBuffer;
std::vector<Real> m_powerSpectrum;
std::vector<Real> m_powerSpectrum; //!< displayable power spectrum
std::vector<Real> m_psd; //!< real PSD
GLSpectrumSettings m_settings;
int m_overlapSize;

Wyświetl plik

@ -29,6 +29,7 @@
#include "gui/crightclickenabler.h"
#include "gui/wsspectrumsettingsdialog.h"
#include "util/simpleserializer.h"
#include "util/db.h"
#include "ui_glspectrumgui.h"
GLSpectrumGUI::GLSpectrumGUI(QWidget* parent) :
@ -48,6 +49,7 @@ GLSpectrumGUI::GLSpectrumGUI(QWidget* parent) :
);
ui->refLevel->setStyleSheet(levelStyle);
ui->levelRange->setStyleSheet(levelStyle);
ui->fftOverlap->setStyleSheet(levelStyle);
// ui->refLevel->findChild<QLineEdit*>()->setStyleSheet("color: white; background-color: rgb(79, 79, 79); border: 1px solid gray; border-radius: 4px; ");
// ui->refLevel->setStyleSheet("background-color: rgb(79, 79, 79);");
@ -143,7 +145,6 @@ void GLSpectrumGUI::displaySettings()
}
ui->fftOverlap->setValue(m_settings.m_fftOverlap);
ui->fftOverlapText->setText(tr("%1").arg(m_settings.m_fftOverlap));
setMaximumOverlap();
ui->averaging->setCurrentIndex(m_settings.m_averagingIndex);
ui->averagingMode->setCurrentIndex((int) m_settings.m_averagingMode);
@ -230,12 +231,51 @@ void GLSpectrumGUI::on_fftOverlap_valueChanged(int value)
{
qDebug("GLSpectrumGUI::on_fftOverlap_valueChanged: %d", value);
m_settings.m_fftOverlap = value;
ui->fftOverlapText->setText(tr("%1").arg(m_settings.m_fftOverlap));
setMaximumOverlap();
applySettings();
setAveragingToolitp();
}
void GLSpectrumGUI::on_autoscale_clicked(bool checked)
{
(void) checked;
if (!m_spectrumVis) {
return;
}
std::vector<Real> psd;
m_spectrumVis->getPSDCopy(psd);
int avgRange = m_settings.m_fftSize / 32;
if (psd.size() < (unsigned int) avgRange) {
return;
}
std::sort(psd.begin(), psd.end());
float maxSum = 0.0f, minSum = 0.0f;
for (int i = 0; i < avgRange; i++)
{
minSum += psd[i];
maxSum += psd[psd.size() - i-1];
}
float minAvg = minSum / avgRange;
float maxAvg = maxSum / avgRange;
int minLvl = CalcDb::dbPower(minAvg*2);
int maxLvl = CalcDb::dbPower(maxAvg*10);
m_settings.m_refLevel = maxLvl;
m_settings.m_powerRange = maxLvl - minLvl;
ui->refLevel->setValue(m_settings.m_refLevel);
ui->levelRange->setValue(m_settings.m_powerRange);
// qDebug("GLSpectrumGUI::on_autoscale_clicked: max: %d min %d max: %e min: %e",
// maxLvl, minLvl, maxAvg, minAvg);
applySettings();
}
void GLSpectrumGUI::on_averagingMode_currentIndexChanged(int index)
{
qDebug("GLSpectrumGUI::on_averagingMode_currentIndexChanged: %d", index);
@ -519,9 +559,11 @@ void GLSpectrumGUI::setFFTSize(int log2FFTSize)
void GLSpectrumGUI::setMaximumOverlap()
{
ui->fftOverlap->setMaximum((m_settings.m_fftSize/2)-1);
int halfSize = m_settings.m_fftSize/2;
ui->fftOverlap->setMaximum((halfSize)-1);
int value = ui->fftOverlap->value();
ui->fftOverlapText->setText(tr("%1").arg(value));
ui->fftOverlap->setValue(value);
ui->fftOverlap->setToolTip(tr("FFT overlap %1 %").arg((value/(float)halfSize)*100.0f));
if (m_glSpectrum) {
m_glSpectrum->setFFTOverlap(value);

Wyświetl plik

@ -86,6 +86,7 @@ private slots:
void on_fftWindow_currentIndexChanged(int index);
void on_fftSize_currentIndexChanged(int index);
void on_fftOverlap_valueChanged(int value);
void on_autoscale_clicked(bool checked);
void on_refLevel_valueChanged(int value);
void on_levelRange_valueChanged(int value);
void on_decay_valueChanged(int index);

Wyświetl plik

@ -162,41 +162,25 @@
</widget>
</item>
<item>
<widget class="QDial" name="fftOverlap">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>FFT overlap</string>
</property>
<property name="maximum">
<number>63</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="fftOverlapText">
<widget class="QSpinBox" name="fftOverlap">
<property name="minimumSize">
<size>
<width>30</width>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>FFT overlap</string>
</property>
<property name="text">
<string>0000</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>63</number>
</property>
</widget>
</item>
<item>
@ -387,6 +371,22 @@
<property name="spacing">
<number>3</number>
</property>
<item>
<widget class="QPushButton" name="autoscale">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Autoscale max level and range</string>
</property>
<property name="text">
<string>A</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="refLevel">
<property name="minimumSize">