From 3a11b246d0ef304ef30dd6ec494ad2f9b01bf784 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 22 Sep 2022 12:07:52 +0100 Subject: [PATCH] Spectrum: Add peak power and frequency in info bar --- sdrgui/gui/glspectrum.cpp | 146 +++++++++++++++++++++++++++++++++++++- sdrgui/gui/glspectrum.h | 10 +++ 2 files changed, 155 insertions(+), 1 deletion(-) diff --git a/sdrgui/gui/glspectrum.cpp b/sdrgui/gui/glspectrum.cpp index 772137315..2d0936194 100644 --- a/sdrgui/gui/glspectrum.cpp +++ b/sdrgui/gui/glspectrum.cpp @@ -593,7 +593,6 @@ void GLSpectrum::newSpectrum(const Real *spectrum, int nbBins, int fftSize) QMutexLocker mutexLocker(&m_mutex); m_displayChanged = true; - if (m_changesPending) { m_fftSize = fftSize; @@ -1651,6 +1650,17 @@ void GLSpectrum::paintGL() m_glShaderInfo.drawSurface(m_glInfoBoxMatrix, tex1, vtx1, 4); } + // Find and display peak in info line + { + if (m_currentSpectrum) + { + float power, frequency; + + findPeak(power, frequency); + drawPeakText(power, (int64_t)frequency); + } + } + m_mutex.unlock(); } @@ -2632,6 +2642,18 @@ void GLSpectrum::applyChanges() m_glShaderInfo.initTexture(m_infoPixmap.toImage()); + // Peak details in top info line + QString minFrequencyStr = displayFull(m_centerFrequency - m_sampleRate/2); // This can be wider if negative, while max is positive + QString maxFrequencyStr = displayFull(m_centerFrequency + m_sampleRate/2); + QString widestFrequencyStr = minFrequencyStr.size() > maxFrequencyStr.size() ? minFrequencyStr : maxFrequencyStr; + widestFrequencyStr = widestFrequencyStr.append("Hz"); + m_peakLabelStr = "Peak:"; + m_peakSpaceWidth = fm.width(" "); + m_peakSpaceMidWidth = ((widestFrequencyStr.size() > 10) ? 3 : 1) * m_peakSpaceWidth; // Extra space when lots of digits + m_peakLabelWidth = fm.width(m_peakLabelStr); + m_peakPowerMaxWidth = m_linear ? fm.width("8.000e-10") : fm.width("-100.0dB"); + m_peakFrequencyMaxWidth = fm.width(widestFrequencyStr); + bool fftSizeChanged = true; if (m_waterfallBuffer) { @@ -3792,6 +3814,46 @@ void GLSpectrum::cleanup() //doneCurrent(); } +// Display number with full precision, group separators and eng. unit suffixes +// E.g: +// -1.505,123,304G +// 456.034,123M +// 300.345k +// 789 +QString GLSpectrum::displayFull(int64_t value) +{ + if (value == 0) { + return "0"; + } + int64_t absValue = std::abs(value); + + QString digits = QString::number(absValue); + int cnt = digits.size(); + + QString point = QLocale::system().decimalPoint(); + QString group = QLocale::system().groupSeparator(); + int i; + for (i = cnt - 3; i >= 4; i -= 3) + { + digits = digits.insert(i, group); + } + if (absValue >= 1000) { + digits = digits.insert(i, point); + } + if (cnt > 9) { + digits = digits.append("G"); + } else if (cnt > 6) { + digits = digits.append("M"); + } else if (cnt > 3) { + digits = digits.append("k"); + } + if (value < 0) { + digits = digits.insert(0, "-"); + } + + return digits; +} + QString GLSpectrum::displayScaled(int64_t value, char type, int precision, bool showMult) { int64_t posValue = (value < 0) ? -value : value; @@ -3867,6 +3929,88 @@ int GLSpectrum::getPrecision(int value) } } +// Find power and frequency of max peak in current spectrum +void GLSpectrum::findPeak(float &power, float &frequency) const +{ + int bin; + + bin = 0; + power = m_currentSpectrum[0]; + for (int i = 1; i < m_nbBins; i++) + { + if (m_currentSpectrum[i] > power) + { + power = m_currentSpectrum[i]; + bin = i; + } + } + + power = m_linear ? + power * (m_useCalibration ? m_calibrationGain : 1.0f): + power + (m_useCalibration ? m_calibrationShiftdB : 0.0f); + + float hzPerBin = (float) m_sampleRate / m_fftSize; + frequency = m_centerFrequency + (bin - (m_fftSize/2)) * hzPerBin; +} + +// Draws peak power and frequency right justified in top info bar +void GLSpectrum::drawPeakText(float power, int64_t frequency, bool units) +{ + QFontMetrics fm(font()); + + m_infoPixmap.fill(Qt::transparent); + + QPainter painter(&m_infoPixmap); + painter.setPen(Qt::NoPen); + painter.setBrush(Qt::black); + painter.setBrush(Qt::transparent); + painter.drawRect(m_leftMargin, 0, width() - m_leftMargin, m_infoHeight); + painter.setPen(QColor(0xf0, 0xf0, 0xff)); + painter.setFont(font()); + + QString powerStr = displayPower( + power, + m_linear ? 'e' : 'f', + m_linear ? 3 : 1 + ); + QString frequencyStr = displayFull(frequency); + if (units) + { + if (!m_linear) { + powerStr = powerStr.append("dB"); + } + frequencyStr = frequencyStr.append("Hz"); + } + + int powerWidth = fm.width(powerStr); + int frequencyWidth = fm.width(frequencyStr); + + int x = width() - m_rightMargin; + int y = fm.height() + fm.ascent() / 2 - 2; + painter.drawText(QPointF(x - frequencyWidth, y), frequencyStr); + x -= m_peakFrequencyMaxWidth + m_peakSpaceMidWidth; + painter.drawText(QPointF(x - powerWidth, y), powerStr); + x -= m_peakPowerMaxWidth + m_peakSpaceWidth; + painter.drawText(QPointF(x - m_peakLabelWidth, y), m_peakLabelStr); + + m_glShaderTextOverlay.initTexture(m_infoPixmap.toImage()); + + GLfloat vtx1[] = { + 0, 1, + 1, 1, + 1, 0, + 0, 0 + }; + GLfloat tex1[] = { + 0, 1, + 1, 1, + 1, 0, + 0, 0 + }; + + m_glShaderTextOverlay.drawSurface(m_glInfoBoxMatrix, tex1, vtx1, 4); +} + void GLSpectrum::drawTextOverlay( const QString &text, const QColor &color, diff --git a/sdrgui/gui/glspectrum.h b/sdrgui/gui/glspectrum.h index 249266dfb..de68c9e45 100644 --- a/sdrgui/gui/glspectrum.h +++ b/sdrgui/gui/glspectrum.h @@ -294,6 +294,13 @@ private: QMatrix4x4 m_glLeftScaleBoxMatrix; QMatrix4x4 m_glInfoBoxMatrix; + QString m_peakLabelStr; + int m_peakLabelWidth; + int m_peakSpaceWidth; + int m_peakSpaceMidWidth; + int m_peakPowerMaxWidth; + int m_peakFrequencyMaxWidth; + QRgb m_waterfallPalette[240]; QImage* m_waterfallBuffer; int m_waterfallBufferPos; @@ -402,10 +409,13 @@ private: void enterEvent(QEvent* event); void leaveEvent(QEvent* event); + static QString displayFull(int64_t value); static QString displayScaled(int64_t value, char type, int precision, bool showMult); static QString displayScaledF(float value, char type, int precision, bool showMult); static QString displayPower(float value, char type, int precision); int getPrecision(int value); + void findPeak(float &power, float &frequency) const; + void drawPeakText(float power, int64_t frequency, bool units=true); void drawTextOverlay( //!< Draws a text overlay const QString& text, const QColor& color,