From 6c60189fdcfe8950d870b64ad41db4c4128ef81f Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 26 Feb 2017 04:46:02 +0100 Subject: [PATCH] New scope: mag (dB) power overlay on XY polar trace - basic --- sdrbase/dsp/scopevisng.cpp | 50 +++++++++++++++++++++++++++---- sdrbase/dsp/scopevisng.h | 12 +++++++- sdrbase/gui/glscopeng.cpp | 58 ++++++++++++++++++++++++++++++++++-- sdrbase/gui/glscopeng.h | 10 +++++-- sdrbase/gui/glscopenggui.cpp | 8 +++++ 5 files changed, 128 insertions(+), 10 deletions(-) diff --git a/sdrbase/dsp/scopevisng.cpp b/sdrbase/dsp/scopevisng.cpp index 41a75d3db..4455ea546 100644 --- a/sdrbase/dsp/scopevisng.cpp +++ b/sdrbase/dsp/scopevisng.cpp @@ -49,6 +49,7 @@ ScopeVisNG::ScopeVisNG(GLScopeNG* glScope) : m_traceStart(true), m_traceFill(0), m_zTraceIndex(-1), + m_timeBase(1), m_timeOfsProMill(0), m_sampleRate(0), m_traceDiscreteMemory(m_nbTraceMemories), @@ -424,20 +425,53 @@ int ScopeVisNG::processTraces(const SampleVector::const_iterator& cbegin, const continue; } + ProjectionType projectionType = itData->m_projectionType; + if (itCtl->m_traceCount[m_traces.currentBufferIndex()] < m_traceSize) { - ProjectionType projectionType = itData->m_projectionType; float v; - if (projectionType == ProjectionMagLin) { + if (projectionType == ProjectionMagLin) + { v = (itCtl->m_projector.run(*begin) - itData->m_ofs)*itData->m_amp - 1.0f; - } else if (projectionType == ProjectionMagDB) { + } + else if (projectionType == ProjectionMagDB) + { // there is no processing advantage in direct calculation without projector // uint32_t magsq = begin->m_real*begin->m_real + begin->m_imag*begin->m_imag; // v = ((log10f(magsq/1073741824.0f)*0.2f - 2.0f*itData->m_ofs) + 2.0f)*itData->m_amp - 1.0f; - float p = itCtl->m_projector.run(*begin) - (100.0f * itData->m_ofs); + float pdB = itCtl->m_projector.run(*begin); + float p = pdB - (100.0f * itData->m_ofs); v = ((p/50.0f) + 2.0f)*itData->m_amp - 1.0f; - } else { + + if (itCtl->m_nbPow == 0) + { + itCtl->m_maxPow = -200.0f; + itCtl->m_sumPow = 0.0f; + itCtl->m_nbPow = 1; + } + + if (pdB > -200.0f) + { + if (pdB > itCtl->m_maxPow) + { + itCtl->m_maxPow = pdB; + } + + itCtl->m_sumPow += pdB; + itCtl->m_nbPow++; + } + + if ((m_nbSamples == 1) && (itCtl->m_nbPow > 0)) + { + double avgPow = itCtl->m_sumPow / itCtl->m_nbPow; + double peakToAvgPow = itCtl->m_maxPow - avgPow; + itData->m_textOverlay = QString("%1 %2 %3").arg(itCtl->m_maxPow, 0, 'f', 1).arg(avgPow, 0, 'f', 1).arg(peakToAvgPow, 0, 'f', 1); + itCtl->m_nbPow = 0; + } + } + else + { v = (itCtl->m_projector.run(*begin) - itData->m_ofs) * itData->m_amp; } @@ -452,6 +486,12 @@ int ScopeVisNG::processTraces(const SampleVector::const_iterator& cbegin, const (*itTrace)[2*(itCtl->m_traceCount[m_traces.currentBufferIndex()]) + 1] = v; // display y itCtl->m_traceCount[m_traces.currentBufferIndex()]++; } + else + { +// if (projectionType == ProjectionMagDB) // create power display overlay +// { +// } + } } ++begin; diff --git a/sdrbase/dsp/scopevisng.h b/sdrbase/dsp/scopevisng.h index 70ac1771d..ba62739a0 100644 --- a/sdrbase/dsp/scopevisng.h +++ b/sdrbase/dsp/scopevisng.h @@ -64,6 +64,8 @@ public: float m_traceColorR; //!< Trace display color - red shortcut float m_traceColorG; //!< Trace display color - green shortcut float m_traceColorB; //!< Trace display color - blue shortcut + bool m_hasTextOverlay; //!< True if a text overlay has to be displayed + QString m_textOverlay; //!< Text overlay to display TraceData() : m_projectionType(ProjectionReal), @@ -77,7 +79,8 @@ public: m_traceDelayCoarse(0), m_traceDelayFine(0), m_triggerDisplayLevel(2.0), // OVer scale by default (2.0) - m_traceColor(255,255,64) + m_traceColor(255,255,64), + m_hasTextOverlay(false) { setColor(m_traceColor); } @@ -705,6 +708,9 @@ private: { Projector m_projector; //!< Projector transform from complex trace to real (displayable) trace int m_traceCount[2]; //!< Count of samples processed (double buffered) + Real m_maxPow; //!< Maximum power over the current trace for MagDB overlay display + Real m_sumPow; //!< Cumulative power over the current trace for MagDB overlay display + int m_nbPow; //!< Number of power samples over the current trace for MagDB overlay display TraceControl() : m_projector(ProjectionReal) { @@ -728,6 +734,9 @@ private: { m_traceCount[0] = 0; m_traceCount[1] = 0; + m_maxPow = 0.0f; + m_sumPow = 0.0f; + m_nbPow = 0; } }; @@ -920,6 +929,7 @@ private: int m_focusedTraceIndex; //!< Index of the trace that has focus int m_traceSize; //!< Size of traces in number of samples int m_nbSamples; //!< Number of samples yet to process in one complex trace + int m_timeBase; //!< Trace display time divisor int m_timeOfsProMill; //!< Start trace shift in 1/1000 trace size bool m_traceStart; //!< Trace is at start point int m_traceFill; //!< Count of samples accumulated into trace diff --git a/sdrbase/gui/glscopeng.cpp b/sdrbase/gui/glscopeng.cpp index 06c8b8477..bc8522d33 100644 --- a/sdrbase/gui/glscopeng.cpp +++ b/sdrbase/gui/glscopeng.cpp @@ -56,8 +56,8 @@ GLScopeNG::GLScopeNG(QWidget* parent) : m_x2Scale.setFont(font()); m_x2Scale.setOrientation(Qt::Horizontal); - m_powerOverlayFont.setBold(true); - m_powerOverlayFont.setPointSize(font().pointSize()+1); + m_channelOverlayFont.setBold(true); + m_channelOverlayFont.setPointSize(font().pointSize()+1); //m_traceCounter = 0; } @@ -715,6 +715,12 @@ void GLScopeNG::paintGL() mat.scale(2.0f * rectW, -2.0f * rectH); m_glShaderSimple.drawSegments(mat, color, q3, 2); } + + // Paint overlay if any + if ((i == m_focusedTraceIndex) && (traceData.m_hasTextOverlay)) + { + drawChannelOverlay(traceData.m_textOverlay, m_channelOverlayPixmap1, m_glScopeRect1); + } } // all traces display } // trace length > 0 @@ -1824,6 +1830,54 @@ void GLScopeNG::setYScale(ScaleEngine& scale, uint32_t highlightedTraceIndex) } } +void GLScopeNG::drawChannelOverlay(const QString& text, QPixmap& channelOverlayPixmap, QRectF& glScopeRect) +{ + if (text.isEmpty()) { + return; + } + + QFontMetricsF metrics(m_channelOverlayFont); + QRectF rect = metrics.boundingRect(text); + channelOverlayPixmap = QPixmap(rect.width() + 4.0f, rect.height()); + channelOverlayPixmap.fill(Qt::transparent); + QPainter painter(&channelOverlayPixmap); + painter.setRenderHints(QPainter::Antialiasing|QPainter::TextAntialiasing, false); + painter.fillRect(rect, QColor(0, 0, 0, 0x80)); + painter.setPen(QColor(0xff, 0xff, 0xff, 0x80)); + painter.setFont(m_channelOverlayFont); + painter.drawText(QPointF(0, rect.height() - 2.0f), text); + painter.end(); + + m_glShaderPowerOverlay.initTexture(channelOverlayPixmap.toImage()); + + { + GLfloat vtx1[] = { + 0, 1, + 1, 1, + 1, 0, + 0, 0 + }; + GLfloat tex1[] = { + 0, 1, + 1, 1, + 1, 0, + 0, 0 + }; + + float shiftX = glScopeRect.width() - ((rect.width() + 4.0f) / width()); + float rectX = glScopeRect.x() + shiftX; + float rectY = 0; + float rectW = rect.width() / (float) width(); + float rectH = rect.height() / (float) height(); + + QMatrix4x4 mat; + mat.setToIdentity(); + mat.translate(-1.0f + 2.0f * rectX, 1.0f - 2.0f * rectY); + mat.scale(2.0f * rectW, -2.0f * rectH); + m_glShaderPowerOverlay.drawSurface(mat, tex1, vtx1, 4); + } +} + void GLScopeNG::tick() { if(m_dataChanged) { diff --git a/sdrbase/gui/glscopeng.h b/sdrbase/gui/glscopeng.h index ce6d66df4..0274a452c 100644 --- a/sdrbase/gui/glscopeng.h +++ b/sdrbase/gui/glscopeng.h @@ -111,7 +111,8 @@ private: QPixmap m_left2ScalePixmap; QPixmap m_bot1ScalePixmap; QPixmap m_bot2ScalePixmap; - QPixmap m_powerOverlayPixmap1; + QPixmap m_channelOverlayPixmap1; + QPixmap m_channelOverlayPixmap2; int m_displayGridIntensity; int m_displayTraceIntensity; @@ -121,7 +122,7 @@ private: ScaleEngine m_y1Scale; //!< Display #1 Y scale. Always connected to trace #0 (X trace) ScaleEngine m_y2Scale; //!< Display #2 Y scale. Connected to highlighted Y trace (#1..n) - QFont m_powerOverlayFont; + QFont m_channelOverlayFont; GLShaderSimple m_glShaderSimple; GLShaderTextured m_glShaderLeft1Scale; @@ -146,6 +147,11 @@ private: void setHorizontalDisplays(); //!< Arrange displays when X and Y are stacked horizontally void setPolarDisplays(); //!< Arrange displays when X and Y are stacked over on the left and polar display is on the right + void drawChannelOverlay( //!< Draws a text overlay + const QString& text, + QPixmap& channelOverlayPixmap, + QRectF& glScopeRect); + protected slots: void cleanup(); void tick(); diff --git a/sdrbase/gui/glscopenggui.cpp b/sdrbase/gui/glscopenggui.cpp index 58863a9af..93dc6482d 100644 --- a/sdrbase/gui/glscopenggui.cpp +++ b/sdrbase/gui/glscopenggui.cpp @@ -309,6 +309,7 @@ bool GLScopeNGGUI::deserialize(const QByteArray& data) ui->trace->setMaximum(nbTracesSaved-1); ui->trace->setValue(nbTracesSaved-1); + m_glScope->setFocusedTraceIndex(nbTracesSaved-1); int r,g,b,a; m_focusedTraceColor.getRgb(&r, &g, &b, &a); @@ -379,6 +380,11 @@ bool GLScopeNGGUI::deserialize(const QByteArray& data) { m_scopeVis->addTrigger(triggerData); } + + if (iTrigger == nbTriggersSaved-1) + { + m_glScope->setFocusedTriggerData(triggerData); + } } ui->trig->setMaximum(nbTriggersSaved-1); @@ -1107,6 +1113,8 @@ void GLScopeNGGUI::disableLiveMode(bool disable) void GLScopeNGGUI::fillTraceData(ScopeVisNG::TraceData& traceData) { traceData.m_projectionType = (ScopeVisNG::ProjectionType) ui->traceMode->currentIndex(); + traceData.m_hasTextOverlay = (traceData.m_projectionType == ScopeVisNG::ProjectionMagDB); + traceData.m_textOverlay.clear(); traceData.m_inputIndex = 0; traceData.m_amp = 0.2 / amps[ui->amp->value()]; traceData.m_ampIndex = ui->amp->value();