Spectrum frequency zoom: implementation for spectrum and waterfall only

This commit is contained in:
f4exb 2021-02-15 21:29:27 +01:00
parent ab0a7f2e60
commit 4d99533009
4 changed files with 101 additions and 48 deletions

View File

@ -26,9 +26,10 @@ class GLSpectrumInterface
public: public:
GLSpectrumInterface() {} GLSpectrumInterface() {}
virtual ~GLSpectrumInterface() {} virtual ~GLSpectrumInterface() {}
virtual void newSpectrum(const Real* spectrum, int fftSize) virtual void newSpectrum(const Real* spectrum, int nbBins, int fftSize)
{ {
(void) spectrum; (void) spectrum;
(void) nbBins;
(void) fftSize; (void) fftSize;
} }
}; };

View File

@ -127,7 +127,7 @@ void SpectrumVis::feed(const Complex *begin, unsigned int length)
int fftMin = (m_frequencyZoomFactor == 1.0f) ? int fftMin = (m_frequencyZoomFactor == 1.0f) ?
0 : (m_frequencyZoomPos - (0.5f / m_frequencyZoomFactor)) * m_settings.m_fftSize; 0 : (m_frequencyZoomPos - (0.5f / m_frequencyZoomFactor)) * m_settings.m_fftSize;
int fftMax = (m_frequencyZoomFactor == 1.0f) ? int fftMax = (m_frequencyZoomFactor == 1.0f) ?
m_settings.m_fftSize : (m_frequencyZoomPos - (0.5f / m_frequencyZoomFactor)) * m_settings.m_fftSize; m_settings.m_fftSize : (m_frequencyZoomPos + (0.5f / m_frequencyZoomFactor)) * m_settings.m_fftSize;
if (m_settings.m_averagingMode == GLSpectrumSettings::AvgModeNone) if (m_settings.m_averagingMode == GLSpectrumSettings::AvgModeNone)
{ {
@ -146,8 +146,13 @@ void SpectrumVis::feed(const Complex *begin, unsigned int length)
} }
// send new data to visualisation // send new data to visualisation
if (m_glSpectrum) { if (m_glSpectrum)
m_glSpectrum->newSpectrum(m_powerSpectrum.data(), m_settings.m_fftSize); {
m_glSpectrum->newSpectrum(
&m_powerSpectrum.data()[fftMin],
fftMax - fftMin,
m_settings.m_fftSize
);
} }
// web socket spectrum connections // web socket spectrum connections
@ -182,8 +187,13 @@ void SpectrumVis::feed(const Complex *begin, unsigned int length)
} }
// send new data to visualisation // send new data to visualisation
if (m_glSpectrum) { if (m_glSpectrum)
m_glSpectrum->newSpectrum(m_powerSpectrum.data(), m_settings.m_fftSize); {
m_glSpectrum->newSpectrum(
&m_powerSpectrum.data()[fftMin],
fftMax - fftMin,
m_settings.m_fftSize
);
} }
// web socket spectrum connections // web socket spectrum connections
@ -229,8 +239,13 @@ void SpectrumVis::feed(const Complex *begin, unsigned int length)
if (m_fixedAverage.nextAverage()) if (m_fixedAverage.nextAverage())
{ {
// send new data to visualisation // send new data to visualisation
if (m_glSpectrum) { if (m_glSpectrum)
m_glSpectrum->newSpectrum(m_powerSpectrum.data(), m_settings.m_fftSize); {
m_glSpectrum->newSpectrum(
&m_powerSpectrum.data()[fftMin],
fftMax - fftMin,
m_settings.m_fftSize
);
} }
// web socket spectrum connections // web socket spectrum connections
@ -275,8 +290,13 @@ void SpectrumVis::feed(const Complex *begin, unsigned int length)
if (m_max.nextMax()) if (m_max.nextMax())
{ {
// send new data to visualisation // send new data to visualisation
if (m_glSpectrum) { if (m_glSpectrum)
m_glSpectrum->newSpectrum(m_powerSpectrum.data(), m_settings.m_fftSize); {
m_glSpectrum->newSpectrum(
&m_powerSpectrum.data()[fftMin],
fftMax - fftMin,
m_settings.m_fftSize
);
} }
// web socket spectrum connections // web socket spectrum connections
@ -314,6 +334,10 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
} }
SampleVector::const_iterator begin(cbegin); SampleVector::const_iterator begin(cbegin);
int fftMin = (m_frequencyZoomFactor == 1.0f) ?
0 : (m_frequencyZoomPos - (0.5f / m_frequencyZoomFactor)) * m_settings.m_fftSize;
int fftMax = (m_frequencyZoomFactor == 1.0f) ?
m_settings.m_fftSize : (m_frequencyZoomPos + (0.5f / m_frequencyZoomFactor)) * m_settings.m_fftSize;
while (begin < end) while (begin < end)
{ {
@ -380,8 +404,13 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
} }
// send new data to visualisation // send new data to visualisation
if (m_glSpectrum) { if (m_glSpectrum)
m_glSpectrum->newSpectrum(m_powerSpectrum.data(), m_settings.m_fftSize); {
m_glSpectrum->newSpectrum(
&m_powerSpectrum.data()[fftMin],
fftMax - fftMin,
m_settings.m_fftSize
);
} }
// web socket spectrum connections // web socket spectrum connections
@ -439,8 +468,13 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
} }
// send new data to visualisation // send new data to visualisation
if (m_glSpectrum) { if (m_glSpectrum)
m_glSpectrum->newSpectrum(m_powerSpectrum.data(), m_settings.m_fftSize); {
m_glSpectrum->newSpectrum(
&m_powerSpectrum.data()[fftMin],
fftMax - fftMin,
m_settings.m_fftSize
);
} }
// web socket spectrum connections // web socket spectrum connections
@ -518,8 +552,13 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
m_specMax = specMax; m_specMax = specMax;
// send new data to visualisation // send new data to visualisation
if (m_glSpectrum) { if (m_glSpectrum)
m_glSpectrum->newSpectrum(m_powerSpectrum.data(), m_settings.m_fftSize); {
m_glSpectrum->newSpectrum(
&m_powerSpectrum.data()[fftMin],
fftMax - fftMin,
m_settings.m_fftSize
);
} }
// web socket spectrum connections // web socket spectrum connections
@ -596,8 +635,13 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
m_specMax = specMax; m_specMax = specMax;
// send new data to visualisation // send new data to visualisation
if (m_glSpectrum) { if (m_glSpectrum)
m_glSpectrum->newSpectrum(m_powerSpectrum.data(), m_settings.m_fftSize); {
m_glSpectrum->newSpectrum(
&m_powerSpectrum.data()[fftMin],
fftMax - fftMin,
m_settings.m_fftSize
);
} }
// web socket spectrum connections // web socket spectrum connections

View File

@ -52,6 +52,7 @@ GLSpectrum::GLSpectrum(QWidget* parent) :
m_sampleRate(500000), m_sampleRate(500000),
m_timingRate(1), m_timingRate(1),
m_fftSize(512), m_fftSize(512),
m_nbBins(512),
m_displayGrid(true), m_displayGrid(true),
m_displayGridIntensity(5), m_displayGridIntensity(5),
m_displayTraceIntensity(50), m_displayTraceIntensity(50),
@ -413,7 +414,7 @@ void GLSpectrum::removeChannelMarker(ChannelMarker* channelMarker)
m_mutex.unlock(); m_mutex.unlock();
} }
void GLSpectrum::newSpectrum(const Real *spectrum, int fftSize) void GLSpectrum::newSpectrum(const Real *spectrum, int nbBins, int fftSize)
{ {
QMutexLocker mutexLocker(&m_mutex); QMutexLocker mutexLocker(&m_mutex);
@ -422,12 +423,14 @@ void GLSpectrum::newSpectrum(const Real *spectrum, int fftSize)
if (m_changesPending) if (m_changesPending)
{ {
m_fftSize = fftSize; m_fftSize = fftSize;
m_nbBins = nbBins;
return; return;
} }
if (fftSize != m_fftSize) if ((fftSize != m_fftSize) || (m_nbBins != nbBins))
{ {
m_fftSize = fftSize; m_fftSize = fftSize;
m_nbBins = nbBins;
m_changesPending = true; m_changesPending = true;
return; return;
} }
@ -446,7 +449,7 @@ void GLSpectrum::updateWaterfall(const Real *spectrum)
{ {
quint32* pix = (quint32*)m_waterfallBuffer->scanLine(m_waterfallBufferPos); quint32* pix = (quint32*)m_waterfallBuffer->scanLine(m_waterfallBufferPos);
for (int i = 0; i < m_fftSize; i++) for (int i = 0; i < m_nbBins; i++)
{ {
int v = (int)((spectrum[i] - m_referenceLevel) * 2.4 * 100.0 / m_powerRange + 240.0); int v = (int)((spectrum[i] - m_referenceLevel) * 2.4 * 100.0 / m_powerRange + 240.0);
@ -466,7 +469,7 @@ void GLSpectrum::updateWaterfall(const Real *spectrum)
void GLSpectrum::updateHistogram(const Real *spectrum) void GLSpectrum::updateHistogram(const Real *spectrum)
{ {
quint8* b = m_histogram; quint8* b = m_histogram;
int fftMulSize = 100 * m_fftSize; int fftMulSize = 100 * m_nbBins;
if ((m_displayHistogram || m_displayMaxHold) && (m_decay != 0)) if ((m_displayHistogram || m_displayMaxHold) && (m_decay != 0))
{ {
@ -557,7 +560,7 @@ void GLSpectrum::updateHistogram(const Real *spectrum)
} }
} }
#else #else
for (int i = 0; i < m_fftSize; i++) for (int i = 0; i < m_nbBins; i++)
{ {
int v = (int)((spectrum[i] - m_referenceLevel) * 100.0 / m_powerRange + 100.0); int v = (int)((spectrum[i] - m_referenceLevel) * 100.0 / m_powerRange + 100.0);
@ -626,7 +629,7 @@ void GLSpectrum::clearSpectrumHistogram()
return; return;
} }
memset(m_histogram, 0x00, 100 * m_fftSize); memset(m_histogram, 0x00, 100 * m_nbBins);
m_mutex.unlock(); m_mutex.unlock();
update(); update();
@ -644,7 +647,7 @@ void GLSpectrum::paintGL()
m_changesPending = false; m_changesPending = false;
} }
if (m_fftSize <= 0) if (m_nbBins <= 0)
{ {
m_mutex.unlock(); m_mutex.unlock();
return; return;
@ -668,15 +671,15 @@ void GLSpectrum::paintGL()
if (m_waterfallTexturePos + m_waterfallBufferPos < m_waterfallTextureHeight) if (m_waterfallTexturePos + m_waterfallBufferPos < m_waterfallTextureHeight)
{ {
m_glShaderWaterfall.subTexture(0, m_waterfallTexturePos, m_fftSize, m_waterfallBufferPos, m_waterfallBuffer->scanLine(0)); m_glShaderWaterfall.subTexture(0, m_waterfallTexturePos, m_nbBins, m_waterfallBufferPos, m_waterfallBuffer->scanLine(0));
m_waterfallTexturePos += m_waterfallBufferPos; m_waterfallTexturePos += m_waterfallBufferPos;
} }
else else
{ {
int breakLine = m_waterfallTextureHeight - m_waterfallTexturePos; int breakLine = m_waterfallTextureHeight - m_waterfallTexturePos;
int linesLeft = m_waterfallTexturePos + m_waterfallBufferPos - m_waterfallTextureHeight; int linesLeft = m_waterfallTexturePos + m_waterfallBufferPos - m_waterfallTextureHeight;
m_glShaderWaterfall.subTexture(0, m_waterfallTexturePos, m_fftSize, breakLine, m_waterfallBuffer->scanLine(0)); m_glShaderWaterfall.subTexture(0, m_waterfallTexturePos, m_nbBins, breakLine, m_waterfallBuffer->scanLine(0));
m_glShaderWaterfall.subTexture(0, 0, m_fftSize, linesLeft, m_waterfallBuffer->scanLine(breakLine)); m_glShaderWaterfall.subTexture(0, 0, m_nbBins, linesLeft, m_waterfallBuffer->scanLine(breakLine));
m_waterfallTexturePos = linesLeft; m_waterfallTexturePos = linesLeft;
} }
@ -756,7 +759,7 @@ void GLSpectrum::paintGL()
quint8* b = bs; quint8* b = bs;
pix = (quint32*)m_histogramBuffer->scanLine(99 - y); pix = (quint32*)m_histogramBuffer->scanLine(99 - y);
for (int x = 0; x < m_fftSize; x++) for (int x = 0; x < m_nbBins; x++)
{ {
*pix = m_histogramPalette[*b]; *pix = m_histogramPalette[*b];
pix++; pix++;
@ -779,7 +782,7 @@ void GLSpectrum::paintGL()
0, 1 0, 1
}; };
m_glShaderHistogram.subTexture(0, 0, m_fftSize, 100, m_histogramBuffer->scanLine(0)); m_glShaderHistogram.subTexture(0, 0, m_nbBins, 100, m_histogramBuffer->scanLine(0));
m_glShaderHistogram.drawSurface(m_glHistogramBoxMatrix, tex1, vtx1, 4); m_glShaderHistogram.drawSurface(m_glHistogramBoxMatrix, tex1, vtx1, 4);
} }
} }
@ -917,11 +920,11 @@ void GLSpectrum::paintGL()
// paint max hold lines on top of histogram // paint max hold lines on top of histogram
if (m_displayMaxHold) if (m_displayMaxHold)
{ {
if (m_maxHold.size() < (uint) m_fftSize) { if (m_maxHold.size() < (uint) m_nbBins) {
m_maxHold.resize(m_fftSize); m_maxHold.resize(m_nbBins);
} }
for (int i = 0; i < m_fftSize; i++) for (int i = 0; i < m_nbBins; i++)
{ {
int j; int j;
quint8* bs = m_histogram + i * 100; quint8* bs = m_histogram + i * 100;
@ -940,7 +943,7 @@ void GLSpectrum::paintGL()
{ {
GLfloat *q3 = m_q3FFT.m_array; GLfloat *q3 = m_q3FFT.m_array;
for (int i = 0; i < m_fftSize; i++) for (int i = 0; i < m_nbBins; i++)
{ {
Real v = m_maxHold[i] - m_referenceLevel; Real v = m_maxHold[i] - m_referenceLevel;
@ -955,7 +958,7 @@ void GLSpectrum::paintGL()
} }
QVector4D color(1.0f, 0.0f, 0.0f, (float) m_displayTraceIntensity / 100.0f); QVector4D color(1.0f, 0.0f, 0.0f, (float) m_displayTraceIntensity / 100.0f);
m_glShaderSimple.drawPolyline(m_glHistogramSpectrumMatrix, color, q3, m_fftSize); m_glShaderSimple.drawPolyline(m_glHistogramSpectrumMatrix, color, q3, m_nbBins);
} }
} }
@ -966,7 +969,7 @@ void GLSpectrum::paintGL()
Real bottom = -m_powerRange; Real bottom = -m_powerRange;
GLfloat *q3 = m_q3FFT.m_array; GLfloat *q3 = m_q3FFT.m_array;
for (int i = 0; i < m_fftSize; i++) for (int i = 0; i < m_nbBins; i++)
{ {
Real v = m_currentSpectrum[i] - m_referenceLevel; Real v = m_currentSpectrum[i] - m_referenceLevel;
@ -981,7 +984,7 @@ void GLSpectrum::paintGL()
} }
QVector4D color(1.0f, 1.0f, 0.25f, (float) m_displayTraceIntensity / 100.0f); QVector4D color(1.0f, 1.0f, 0.25f, (float) m_displayTraceIntensity / 100.0f);
m_glShaderSimple.drawPolyline(m_glHistogramSpectrumMatrix, color, q3, m_fftSize); m_glShaderSimple.drawPolyline(m_glHistogramSpectrumMatrix, color, q3, m_nbBins);
} }
} }
@ -1265,7 +1268,7 @@ void GLSpectrum::stopDrag()
void GLSpectrum::applyChanges() void GLSpectrum::applyChanges()
{ {
if (m_fftSize <= 0) { if (m_nbBins <= 0) {
return; return;
} }
@ -1371,7 +1374,7 @@ void GLSpectrum::applyChanges()
1.0f - ((float)(2*histogramTop) / (float) height()) 1.0f - ((float)(2*histogramTop) / (float) height())
); );
m_glHistogramSpectrumMatrix.scale( m_glHistogramSpectrumMatrix.scale(
((float) 2 * (width() - m_leftMargin - m_rightMargin)) / ((float) width() * (float)(m_fftSize - 1)), ((float) 2 * (width() - m_leftMargin - m_rightMargin)) / ((float) width() * (float)(m_nbBins - 1)),
((float) 2*m_histogramHeight / height()) / m_powerRange ((float) 2*m_histogramHeight / height()) / m_powerRange
); );
@ -1497,7 +1500,7 @@ void GLSpectrum::applyChanges()
1.0f - ((float)(2*histogramTop) / (float) height()) 1.0f - ((float)(2*histogramTop) / (float) height())
); );
m_glHistogramSpectrumMatrix.scale( m_glHistogramSpectrumMatrix.scale(
((float) 2 * (width() - m_leftMargin - m_rightMargin)) / ((float) width() * (float)(m_fftSize - 1)), ((float) 2 * (width() - m_leftMargin - m_rightMargin)) / ((float) width() * (float)(m_nbBins - 1)),
((float) 2*(height() - m_topMargin - m_frequencyScaleHeight)) / (height()*m_powerRange) ((float) 2*(height() - m_topMargin - m_frequencyScaleHeight)) / (height()*m_powerRange)
); );
@ -1837,7 +1840,7 @@ void GLSpectrum::applyChanges()
bool fftSizeChanged = true; bool fftSizeChanged = true;
if (m_waterfallBuffer) { if (m_waterfallBuffer) {
fftSizeChanged = m_waterfallBuffer->width() != m_fftSize; fftSizeChanged = m_waterfallBuffer->width() != m_nbBins;
} }
bool windowSizeChanged = m_waterfallTextureHeight != m_waterfallHeight; bool windowSizeChanged = m_waterfallTextureHeight != m_waterfallHeight;
@ -1848,7 +1851,7 @@ void GLSpectrum::applyChanges()
delete m_waterfallBuffer; delete m_waterfallBuffer;
} }
m_waterfallBuffer = new QImage(m_fftSize, m_waterfallHeight, QImage::Format_ARGB32); m_waterfallBuffer = new QImage(m_nbBins, m_waterfallHeight, QImage::Format_ARGB32);
m_waterfallBuffer->fill(qRgb(0x00, 0x00, 0x00)); m_waterfallBuffer->fill(qRgb(0x00, 0x00, 0x00));
m_glShaderWaterfall.initTexture(*m_waterfallBuffer); m_glShaderWaterfall.initTexture(*m_waterfallBuffer);
@ -1868,15 +1871,15 @@ void GLSpectrum::applyChanges()
m_histogram = nullptr; m_histogram = nullptr;
} }
m_histogramBuffer = new QImage(m_fftSize, 100, QImage::Format_RGB32); m_histogramBuffer = new QImage(m_nbBins, 100, QImage::Format_RGB32);
m_histogramBuffer->fill(qRgb(0x00, 0x00, 0x00)); m_histogramBuffer->fill(qRgb(0x00, 0x00, 0x00));
m_glShaderHistogram.initTexture(*m_histogramBuffer, QOpenGLTexture::ClampToEdge); m_glShaderHistogram.initTexture(*m_histogramBuffer, QOpenGLTexture::ClampToEdge);
m_histogram = new quint8[100 * m_fftSize]; m_histogram = new quint8[100 * m_nbBins];
memset(m_histogram, 0x00, 100 * m_fftSize); memset(m_histogram, 0x00, 100 * m_nbBins);
m_q3FFT.allocate(2*m_fftSize); m_q3FFT.allocate(2*m_nbBins);
} }
if (fftSizeChanged || windowSizeChanged) if (fftSizeChanged || windowSizeChanged)
@ -2217,12 +2220,16 @@ void GLSpectrum::frequencyZoom(QWheelEvent *event)
{ {
if (m_frequencyZoomFactor < m_maxFrequencyZoom) { if (m_frequencyZoomFactor < m_maxFrequencyZoom) {
m_frequencyZoomFactor += 0.5f; m_frequencyZoomFactor += 0.5f;
} else {
return;
} }
} }
else else
{ {
if (m_frequencyZoomFactor > 1.0f) { if (m_frequencyZoomFactor > 1.0f) {
m_frequencyZoomFactor -= 0.5f; m_frequencyZoomFactor -= 0.5f;
} else {
return;
} }
} }

View File

@ -104,7 +104,7 @@ public:
void removeChannelMarker(ChannelMarker* channelMarker); void removeChannelMarker(ChannelMarker* channelMarker);
void setMessageQueueToGUI(MessageQueue* messageQueue) { m_messageQueueToGUI = messageQueue; } void setMessageQueueToGUI(MessageQueue* messageQueue) { m_messageQueueToGUI = messageQueue; }
virtual void newSpectrum(const Real* spectrum, int fftSize); virtual void newSpectrum(const Real* spectrum, int nbBins, int fftSize);
void clearSpectrumHistogram(); void clearSpectrumHistogram();
Real getWaterfallShare() const { return m_waterfallShare; } Real getWaterfallShare() const { return m_waterfallShare; }
@ -253,7 +253,8 @@ private:
quint32 m_timingRate; quint32 m_timingRate;
int m_fftOverlap; int m_fftOverlap;
int m_fftSize; int m_fftSize; //!< FFT size in number of bins
int m_nbBins; //!< Number of visible FFT bins (zoom support)
bool m_displayGrid; bool m_displayGrid;
int m_displayGridIntensity; int m_displayGridIntensity;