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:
parent
3e9db6af09
commit
6c60189fdc
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user