1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-26 17:58:43 -05:00

New scope: mag (dB) power overlay on XY polar trace - basic

This commit is contained in:
f4exb 2017-02-26 04:46:02 +01:00
parent 3e9db6af09
commit 6c60189fdc
5 changed files with 128 additions and 10 deletions

View File

@ -49,6 +49,7 @@ ScopeVisNG::ScopeVisNG(GLScopeNG* glScope) :
m_traceStart(true), m_traceStart(true),
m_traceFill(0), m_traceFill(0),
m_zTraceIndex(-1), m_zTraceIndex(-1),
m_timeBase(1),
m_timeOfsProMill(0), m_timeOfsProMill(0),
m_sampleRate(0), m_sampleRate(0),
m_traceDiscreteMemory(m_nbTraceMemories), m_traceDiscreteMemory(m_nbTraceMemories),
@ -424,20 +425,53 @@ int ScopeVisNG::processTraces(const SampleVector::const_iterator& cbegin, const
continue; continue;
} }
ProjectionType projectionType = itData->m_projectionType;
if (itCtl->m_traceCount[m_traces.currentBufferIndex()] < m_traceSize) if (itCtl->m_traceCount[m_traces.currentBufferIndex()] < m_traceSize)
{ {
ProjectionType projectionType = itData->m_projectionType;
float v; float v;
if (projectionType == ProjectionMagLin) { if (projectionType == ProjectionMagLin)
{
v = (itCtl->m_projector.run(*begin) - itData->m_ofs)*itData->m_amp - 1.0f; 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 // 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; // 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; // 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; 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; 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 (*itTrace)[2*(itCtl->m_traceCount[m_traces.currentBufferIndex()]) + 1] = v; // display y
itCtl->m_traceCount[m_traces.currentBufferIndex()]++; itCtl->m_traceCount[m_traces.currentBufferIndex()]++;
} }
else
{
// if (projectionType == ProjectionMagDB) // create power display overlay
// {
// }
}
} }
++begin; ++begin;

View File

@ -64,6 +64,8 @@ public:
float m_traceColorR; //!< Trace display color - red shortcut float m_traceColorR; //!< Trace display color - red shortcut
float m_traceColorG; //!< Trace display color - green shortcut float m_traceColorG; //!< Trace display color - green shortcut
float m_traceColorB; //!< Trace display color - blue 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() : TraceData() :
m_projectionType(ProjectionReal), m_projectionType(ProjectionReal),
@ -77,7 +79,8 @@ public:
m_traceDelayCoarse(0), m_traceDelayCoarse(0),
m_traceDelayFine(0), m_traceDelayFine(0),
m_triggerDisplayLevel(2.0), // OVer scale by default (2.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); setColor(m_traceColor);
} }
@ -705,6 +708,9 @@ private:
{ {
Projector m_projector; //!< Projector transform from complex trace to real (displayable) trace Projector m_projector; //!< Projector transform from complex trace to real (displayable) trace
int m_traceCount[2]; //!< Count of samples processed (double buffered) 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) TraceControl() : m_projector(ProjectionReal)
{ {
@ -728,6 +734,9 @@ private:
{ {
m_traceCount[0] = 0; m_traceCount[0] = 0;
m_traceCount[1] = 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_focusedTraceIndex; //!< Index of the trace that has focus
int m_traceSize; //!< Size of traces in number of samples 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_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 int m_timeOfsProMill; //!< Start trace shift in 1/1000 trace size
bool m_traceStart; //!< Trace is at start point bool m_traceStart; //!< Trace is at start point
int m_traceFill; //!< Count of samples accumulated into trace int m_traceFill; //!< Count of samples accumulated into trace

View File

@ -56,8 +56,8 @@ GLScopeNG::GLScopeNG(QWidget* parent) :
m_x2Scale.setFont(font()); m_x2Scale.setFont(font());
m_x2Scale.setOrientation(Qt::Horizontal); m_x2Scale.setOrientation(Qt::Horizontal);
m_powerOverlayFont.setBold(true); m_channelOverlayFont.setBold(true);
m_powerOverlayFont.setPointSize(font().pointSize()+1); m_channelOverlayFont.setPointSize(font().pointSize()+1);
//m_traceCounter = 0; //m_traceCounter = 0;
} }
@ -715,6 +715,12 @@ void GLScopeNG::paintGL()
mat.scale(2.0f * rectW, -2.0f * rectH); mat.scale(2.0f * rectW, -2.0f * rectH);
m_glShaderSimple.drawSegments(mat, color, q3, 2); 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 } // all traces display
} // trace length > 0 } // 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() void GLScopeNG::tick()
{ {
if(m_dataChanged) { if(m_dataChanged) {

View File

@ -111,7 +111,8 @@ private:
QPixmap m_left2ScalePixmap; QPixmap m_left2ScalePixmap;
QPixmap m_bot1ScalePixmap; QPixmap m_bot1ScalePixmap;
QPixmap m_bot2ScalePixmap; QPixmap m_bot2ScalePixmap;
QPixmap m_powerOverlayPixmap1; QPixmap m_channelOverlayPixmap1;
QPixmap m_channelOverlayPixmap2;
int m_displayGridIntensity; int m_displayGridIntensity;
int m_displayTraceIntensity; int m_displayTraceIntensity;
@ -121,7 +122,7 @@ private:
ScaleEngine m_y1Scale; //!< Display #1 Y scale. Always connected to trace #0 (X trace) 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) ScaleEngine m_y2Scale; //!< Display #2 Y scale. Connected to highlighted Y trace (#1..n)
QFont m_powerOverlayFont; QFont m_channelOverlayFont;
GLShaderSimple m_glShaderSimple; GLShaderSimple m_glShaderSimple;
GLShaderTextured m_glShaderLeft1Scale; GLShaderTextured m_glShaderLeft1Scale;
@ -146,6 +147,11 @@ private:
void setHorizontalDisplays(); //!< Arrange displays when X and Y are stacked horizontally 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 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: protected slots:
void cleanup(); void cleanup();
void tick(); void tick();

View File

@ -309,6 +309,7 @@ bool GLScopeNGGUI::deserialize(const QByteArray& data)
ui->trace->setMaximum(nbTracesSaved-1); ui->trace->setMaximum(nbTracesSaved-1);
ui->trace->setValue(nbTracesSaved-1); ui->trace->setValue(nbTracesSaved-1);
m_glScope->setFocusedTraceIndex(nbTracesSaved-1);
int r,g,b,a; int r,g,b,a;
m_focusedTraceColor.getRgb(&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); m_scopeVis->addTrigger(triggerData);
} }
if (iTrigger == nbTriggersSaved-1)
{
m_glScope->setFocusedTriggerData(triggerData);
}
} }
ui->trig->setMaximum(nbTriggersSaved-1); ui->trig->setMaximum(nbTriggersSaved-1);
@ -1107,6 +1113,8 @@ void GLScopeNGGUI::disableLiveMode(bool disable)
void GLScopeNGGUI::fillTraceData(ScopeVisNG::TraceData& traceData) void GLScopeNGGUI::fillTraceData(ScopeVisNG::TraceData& traceData)
{ {
traceData.m_projectionType = (ScopeVisNG::ProjectionType) ui->traceMode->currentIndex(); 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_inputIndex = 0;
traceData.m_amp = 0.2 / amps[ui->amp->value()]; traceData.m_amp = 0.2 / amps[ui->amp->value()];
traceData.m_ampIndex = ui->amp->value(); traceData.m_ampIndex = ui->amp->value();