From 5a8c3d8e5bfd5566a80fae5119fa21fb917e7c61 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 6 Jul 2015 09:17:51 +0200 Subject: [PATCH] Print scale on scope part #1 --- include-gpl/gui/glscope.h | 21 +++ include-gpl/gui/glscopegui.h | 2 + include-gpl/gui/physicalunit.h | 3 +- plugins/channel/chanalyzer/chanalyzergui.cpp | 5 + .../samplesource/bladerf/bladerfthread.cpp | 77 +++++++++ sdrbase/dsp/scopevis.cpp | 3 + sdrbase/gui/glscope.cpp | 156 +++++++++++++++++- sdrbase/gui/glscopegui.cpp | 22 ++- sdrbase/gui/glscopegui.ui | 79 ++++++++- sdrbase/gui/scaleengine.cpp | 19 +++ 10 files changed, 377 insertions(+), 10 deletions(-) diff --git a/include-gpl/gui/glscope.h b/include-gpl/gui/glscope.h index 36d9cdd59..e9aea6232 100644 --- a/include-gpl/gui/glscope.h +++ b/include-gpl/gui/glscope.h @@ -24,6 +24,7 @@ #include #include "dsp/dsptypes.h" #include "dsp/scopevis.h" +#include "gui/scaleengine.h" #include "util/export.h" class DSPEngine; @@ -46,6 +47,7 @@ public: void setDSPEngine(DSPEngine* dspEngine); void setAmp(Real amp); + void setAmpOfs(Real ampOfs); void setTimeBase(int timeBase); void setTimeOfsProMill(int timeOfsProMill); void setMode(Mode mode); @@ -56,6 +58,14 @@ public: int getTraceSize() const { return m_rawTrace.size(); } + void setSampleRate(int sampleRate) { + m_sampleRate = sampleRate; + } + + int getSampleRate() const { + return m_sampleRate; + } + signals: void traceSizeChanged(int); @@ -85,6 +95,7 @@ private: // config Real m_amp; + Real m_ofs; int m_timeBase; int m_timeOfsProMill; ScopeVis::TriggerChannel m_triggerChannel; @@ -95,6 +106,16 @@ private: QRectF m_glScopeRect1; QRectF m_glScopeRect2; int m_displayGridIntensity; + QRectF m_glLeft1ScaleRect; + QRectF m_glLeft2ScaleRect; + QRectF m_glBot1ScaleRect; + QRectF m_glBot2ScaleRect; + QPixmap m_left1ScalePixmap; + bool m_left1ScaleTextureAllocated; + GLuint m_leftScaleTexture; + ScaleEngine m_timeScale; + ScaleEngine m_powerScale; + ScaleEngine m_amplitudeScale; void initializeGL(); void resizeGL(int width, int height); diff --git a/include-gpl/gui/glscopegui.h b/include-gpl/gui/glscopegui.h index aad967894..587a37e5e 100644 --- a/include-gpl/gui/glscopegui.h +++ b/include-gpl/gui/glscopegui.h @@ -44,12 +44,14 @@ private: qint32 m_timeBase; qint32 m_timeOffset; qint32 m_amplification; + qint32 m_ampOffset; int m_displayGridIntensity; void applySettings(); private slots: void on_amp_valueChanged(int value); + void on_ampOfs_valueChanged(int value); void on_scope_traceSizeChanged(int value); void on_time_valueChanged(int value); void on_timeOfs_valueChanged(int value); diff --git a/include-gpl/gui/physicalunit.h b/include-gpl/gui/physicalunit.h index e8eda2b9f..778637845 100644 --- a/include-gpl/gui/physicalunit.h +++ b/include-gpl/gui/physicalunit.h @@ -28,7 +28,8 @@ namespace Unit { DecibelMilliWatt, DecibelMicroVolt, AngleDegrees, - Time + Time, + Volt }; }; diff --git a/plugins/channel/chanalyzer/chanalyzergui.cpp b/plugins/channel/chanalyzer/chanalyzergui.cpp index ea5eab582..3c0dd9c5d 100644 --- a/plugins/channel/chanalyzer/chanalyzergui.cpp +++ b/plugins/channel/chanalyzer/chanalyzergui.cpp @@ -276,6 +276,7 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, QWidget* parent) : ui->spectrumGUI->setBuddies(m_threadedSampleSink->getMessageQueue(), m_spectrumVis, ui->glSpectrum); ui->scopeGUI->setBuddies(m_threadedSampleSink->getMessageQueue(), m_scopeVis, ui->glScope); + std::cerr << "ui->glScope: " << ui->glScope->getSampleRate() << std::endl; applySettings(); } @@ -304,6 +305,8 @@ bool ChannelAnalyzerGUI::setNewRate(int spanLog2) //m_rate = 48000 / (1<getSampleRate() / (1<BW->value() < -m_rate/100) { ui->BW->setValue(-m_rate/100); m_channelMarker->setBandwidth(-m_rate*2); @@ -339,12 +342,14 @@ bool ChannelAnalyzerGUI::setNewRate(int spanLog2) ui->glSpectrum->setCenterFrequency(m_rate/2); ui->glSpectrum->setSampleRate(m_rate); ui->glSpectrum->setSsbSpectrum(true); + ui->glScope->setSampleRate(m_rate); } else { m_channelMarker->setSidebands(ChannelMarker::dsb); ui->glSpectrum->setCenterFrequency(0); ui->glSpectrum->setSampleRate(2*m_rate); ui->glSpectrum->setSsbSpectrum(false); + ui->glScope->setSampleRate(2*m_rate); } return true; diff --git a/plugins/samplesource/bladerf/bladerfthread.cpp b/plugins/samplesource/bladerf/bladerfthread.cpp index c55e4a64a..9186011d0 100644 --- a/plugins/samplesource/bladerf/bladerfthread.cpp +++ b/plugins/samplesource/bladerf/bladerfthread.cpp @@ -151,6 +151,83 @@ void BladerfThread::decimate2_sup(SampleVector::iterator* it, const qint16* buf, } } +/* +void BladerfThread::decimate2_cen(SampleVector::iterator* it, const qint16* buf, qint32 len) +{ + for (int pos = 0; pos < len - 1; pos += 2) { + Sample s(buf[pos+0] << 3, buf[pos+1] << 3); + if (m_decimator2.workDecimateCenter(&s)) { + **it = s; + (*it)++; + } + } +} + +void BladerfThread::decimate4_cen(SampleVector::iterator* it, const qint16* buf, qint32 len) +{ + for (int pos = 0; pos < len - 1; pos += 2) { + Sample s(buf[pos+0] << 4, buf[pos+1] << 4); + if (m_decimator2.workDecimateCenter(&s)) { + if (m_decimator4.workDecimateCenter(&s)) { + **it = s; + (*it)++; + } + } + } +} + +void BladerfThread::decimate8_cen(SampleVector::iterator* it, const qint16* buf, qint32 len) +{ + for (int pos = 0; pos < len - 1; pos += 2) { + Sample s(buf[pos+0] << 4, buf[pos+1] << 4); + if (m_decimator2.workDecimateCenter(&s)) { + if (m_decimator4.workDecimateCenter(&s)) { + if (m_decimator8.workDecimateCenter(&s)) { + **it = s; + (*it)++; + } + } + } + } +} + +void BladerfThread::decimate16_cen(SampleVector::iterator* it, const qint16* buf, qint32 len) +{ + for (int pos = 0; pos < len - 11; pos += 2) { + Sample s(buf[pos+0] << 4, buf[pos+1] << 4); + if (m_decimator2.workDecimateCenter(&s)) { + if (m_decimator4.workDecimateCenter(&s)) { + if (m_decimator8.workDecimateCenter(&s)) { + if (m_decimator16.workDecimateCenter(&s)) { + **it = s; + (*it)++; + } + } + } + } + } +} + +void BladerfThread::decimate32_cen(SampleVector::iterator* it, const qint16* buf, qint32 len) +{ + for (int pos = 0; pos < len - 11; pos += 2) { + Sample s(buf[pos+0] << 4, buf[pos+1] << 4); + if (m_decimator2.workDecimateCenter(&s)) { + if (m_decimator4.workDecimateCenter(&s)) { + if (m_decimator8.workDecimateCenter(&s)) { + if (m_decimator16.workDecimateCenter(&s)) { + if (m_decimator32.workDecimateCenter(&s)) { + **it = s; + (*it)++; + } + } + } + } + } + } +} +*/ + void BladerfThread::decimate2_cen(SampleVector::iterator* it, const qint16* buf, qint32 len) { for (int pos = 0; pos < len - 3; pos += 4) { diff --git a/sdrbase/dsp/scopevis.cpp b/sdrbase/dsp/scopevis.cpp index bdfa77879..b261cd96a 100644 --- a/sdrbase/dsp/scopevis.cpp +++ b/sdrbase/dsp/scopevis.cpp @@ -3,6 +3,8 @@ #include "dsp/dspcommands.h" #include "util/messagequeue.h" +#include + ScopeVis::ScopeVis(GLScope* glScope) : m_glScope(glScope), m_trace(100000), @@ -124,6 +126,7 @@ bool ScopeVis::handleMessageKeep(Message* message) { if(DSPSignalNotification::match(message)) { DSPSignalNotification* signal = (DSPSignalNotification*)message; + //fprintf(stderr, "ScopeVis::handleMessage @%x : %d samples/sec, %lld Hz offset\n", this, signal->getSampleRate(), signal->getFrequencyOffset()); m_sampleRate = signal->getSampleRate(); return true; } else if(DSPConfigureScopeVis::match(message)) { diff --git a/sdrbase/gui/glscope.cpp b/sdrbase/gui/glscope.cpp index 1be4d9e15..73ef8f17d 100644 --- a/sdrbase/gui/glscope.cpp +++ b/sdrbase/gui/glscope.cpp @@ -3,6 +3,8 @@ #include "gui/glscope.h" #include "dsp/dspengine.h" +#include + #ifdef _WIN32 static double log2f(double n) { @@ -22,6 +24,7 @@ GLScope::GLScope(QWidget* parent) : m_dspEngine(NULL), m_scopeVis(NULL), m_amp(1.0), + m_ofs(0.0), m_timeBase(1), m_timeOfsProMill(0), m_triggerChannel(ScopeVis::TriggerFreeRun), @@ -30,6 +33,8 @@ GLScope::GLScope(QWidget* parent) : setAttribute(Qt::WA_OpaquePaintEvent); connect(&m_timer, SIGNAL(timeout()), this, SLOT(tick())); m_timer.start(50); + m_powerScale.setFont(font()); + m_powerScale.setOrientation(Qt::Vertical); } GLScope::~GLScope() @@ -52,6 +57,14 @@ void GLScope::setDSPEngine(DSPEngine* dspEngine) void GLScope::setAmp(Real amp) { m_amp = amp; + m_configChanged = true; + update(); +} + +void GLScope::setAmpOfs(Real ampOfs) +{ + m_ofs = ampOfs; + m_configChanged = true; update(); } @@ -157,6 +170,7 @@ void GLScope::paintGL() glVertex2f(1, 0); glEnd(); glDisable(GL_BLEND); + // paint grid glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -176,6 +190,31 @@ void GLScope::paintGL() } glPopMatrix(); + // paint left scale + glBindTexture(GL_TEXTURE_2D, m_leftScaleTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + glPushMatrix(); + glTranslatef(m_glLeft1ScaleRect.x(), m_glLeft1ScaleRect.y(), 0); + glScalef(m_glLeft1ScaleRect.width(), m_glLeft1ScaleRect.height(), 1); + + glEnable(GL_TEXTURE_2D); + glBegin(GL_QUADS); + glTexCoord2f(0, 1); + glVertex2f(0, 1); + glTexCoord2f(1, 1); + glVertex2f(1, 1); + glTexCoord2f(1, 0); + glVertex2f(1, 0); + glTexCoord2f(0, 0); + glVertex2f(0, 0); + glEnd(); + glDisable(GL_TEXTURE_2D); + glPopMatrix(); + if(m_triggerChannel == ScopeVis::TriggerChannelI) { glPushMatrix(); glTranslatef(m_glScopeRect1.x(), m_glScopeRect1.y() + m_glScopeRect1.height() / 2.0, 0); @@ -401,7 +440,7 @@ void GLScope::handleMode() Real mult = (10.0f / log2f(10.0f)); for(std::vector::const_iterator src = m_rawTrace.begin(); src != m_rawTrace.end(); ++src) { Real v = src->real() * src->real() + src->imag() * src->imag(); - v = (96.0 + (mult * log2f(v))) / 96.0; + v = (100.0 - m_ofs*100.0 + (mult * log2f(v))) / 100.0; // TODO: first term is the offset *dst++ = Complex(v, arg(*src) / M_PI); } m_displayTrace = &m_mathTrace; @@ -452,33 +491,140 @@ void GLScope::applyConfig() { m_configChanged = false; + QFontMetrics fm(font()); + int M = fm.width("-"); + int topMargin = 5; int botMargin = 20; - int leftMargin = 20; + int leftMargin = 35; int rightMargin = 5; // QRectF(x, y, w, h); (x, y) = top left corner if(m_orientation == Qt::Vertical) { + int scopeHeight = (height() - botMargin - botMargin - topMargin) / 2; m_glScopeRect1 = QRectF( (float)leftMargin / (float)width(), (float)topMargin / (float)height(), (float)(width() - leftMargin - rightMargin) / (float)width(), - (float)((height() - botMargin - botMargin - topMargin) / 2) / (float)height() + (float) scopeHeight / (float) height() ); + m_glLeft1ScaleRect = QRectF( + 0, + (float)topMargin / (float)height(), + (float)(leftMargin-1) / (float)width(), + (float) scopeHeight / (float) height() + ); + { // Scales + float pow_floor = -100.0 + m_ofs * 100.0; + float pow_range = 100.0 / m_amp; + float amp_range = 2.0 / m_amp; + + m_powerScale.setSize(scopeHeight); + m_powerScale.setRange(Unit::Decibel, pow_floor, pow_floor + pow_range); + + std::cerr << "Vertical: " << width() << "x" << scopeHeight << " amp:" << m_amp << std::endl; + + m_left1ScalePixmap = QPixmap( + leftMargin - 1, + scopeHeight + ); + + m_left1ScalePixmap.fill(Qt::black); + QPainter painter(&m_left1ScalePixmap); + painter.setPen(QColor(0xf0, 0xf0, 0xff)); + const ScaleEngine::TickList* tickList; + const ScaleEngine::Tick* tick; + tickList = &m_powerScale.getTickList(); + + for(int i = 0; i < tickList->count(); i++) { + tick = &(*tickList)[i]; + if(tick->major) { + if(tick->textSize > 0) { + std::cerr << (tick->text).toStdString() << " @ " << tick->textPos << std::endl; + painter.drawText(QPointF(leftMargin - M - tick->textSize, topMargin + scopeHeight - tick->textPos - fm.ascent()/2), tick->text); + } + } + } + + //painter.drawText(QPointF(2, 2), "0"); + + if (m_left1ScaleTextureAllocated) + deleteTexture(m_left1ScaleTextureAllocated); + m_leftScaleTexture = bindTexture(m_left1ScalePixmap, + GL_TEXTURE_2D, + GL_RGBA, + QGLContext::LinearFilteringBindOption | + QGLContext::MipmapBindOption); + m_left1ScaleTextureAllocated = true; + } + m_glScopeRect2 = QRectF( (float)leftMargin / (float)width(), (float)(botMargin + topMargin + (height() - botMargin - botMargin - topMargin) / 2) / (float)height(), (float)(width() - leftMargin - rightMargin) / (float)width(), (float)((height() - botMargin - botMargin - topMargin) / 2) / (float)height() ); - } else { + } + else // Horizontal + { + int scopeHeight = height() - topMargin - botMargin; m_glScopeRect1 = QRectF( (float)leftMargin / (float)width(), (float)topMargin / (float)height(), (float)((width() - leftMargin - leftMargin - rightMargin) / 2) / (float)width(), - (float)(height() - topMargin - botMargin) / (float)height() + (float) scopeHeight / (float) height() ); + m_glLeft1ScaleRect = QRectF( + 0, + (float)topMargin / (float)height(), + (float)(leftMargin-1) / (float)width(), + (float) scopeHeight / (float) height() + ); + { // Scales + std::cerr << "Horizontal: " << width() << "x" << scopeHeight << " amp:" << m_amp << std::endl; + + float pow_floor = -100.0 + m_ofs * 100.0; + float pow_range = 100.0 / m_amp; + float amp_range = 2.0 / m_amp; + + m_powerScale.setSize(scopeHeight); + m_powerScale.setRange(Unit::Decibel, pow_floor, pow_floor + pow_range); + + m_left1ScalePixmap = QPixmap( + leftMargin - 1, + scopeHeight + ); + + m_left1ScalePixmap.fill(Qt::black); + QPainter painter(&m_left1ScalePixmap); + painter.setPen(QColor(0xf0, 0xf0, 0xff)); + const ScaleEngine::TickList* tickList; + const ScaleEngine::Tick* tick; + tickList = &m_powerScale.getTickList(); + + for(int i = 0; i < tickList->count(); i++) { + tick = &(*tickList)[i]; + if(tick->major) { + if(tick->textSize > 0) { + std::cerr << (tick->text).toStdString() << " @ " << tick->textPos << std::endl; + painter.drawText(QPointF(leftMargin - M - tick->textSize, topMargin + scopeHeight - tick->textPos - fm.ascent()/2), tick->text); + } + } + } + + //painter.drawText(QPointF(2, 2), "0"); + + if (m_left1ScaleTextureAllocated) + deleteTexture(m_left1ScaleTextureAllocated); + m_leftScaleTexture = bindTexture(m_left1ScalePixmap, + GL_TEXTURE_2D, + GL_RGBA, + QGLContext::LinearFilteringBindOption | + QGLContext::MipmapBindOption); + m_left1ScaleTextureAllocated = true; + } + m_glScopeRect2 = QRectF( (float)(leftMargin + leftMargin + ((width() - leftMargin - leftMargin - rightMargin) / 2)) / (float)width(), (float)topMargin / (float)height(), diff --git a/sdrbase/gui/glscopegui.cpp b/sdrbase/gui/glscopegui.cpp index 43842089c..a67a91e29 100644 --- a/sdrbase/gui/glscopegui.cpp +++ b/sdrbase/gui/glscopegui.cpp @@ -6,6 +6,7 @@ #include "ui_glscopegui.h" #include +#include GLScopeGUI::GLScopeGUI(QWidget* parent) : QWidget(parent), @@ -13,12 +14,13 @@ GLScopeGUI::GLScopeGUI(QWidget* parent) : m_messageQueue(NULL), m_scopeVis(NULL), m_glScope(NULL), - m_sampleRate(0), + m_sampleRate(1), m_displayData(GLScope::ModeIQ), m_displayOrientation(Qt::Horizontal), m_timeBase(1), m_timeOffset(0), m_amplification(0), + m_ampOffset(0), m_displayGridIntensity(1) { ui->setupUi(this); @@ -31,6 +33,7 @@ GLScopeGUI::~GLScopeGUI() void GLScopeGUI::setBuddies(MessageQueue* messageQueue, ScopeVis* scopeVis, GLScope* glScope) { + std::cerr << "GLScopeGUI::setBuddies: scopeVis @" << scopeVis << std::endl; m_messageQueue = messageQueue; m_scopeVis = scopeVis; m_glScope = glScope; @@ -64,6 +67,7 @@ QByteArray GLScopeGUI::serialize() const s.writeS32(4, m_timeOffset); s.writeS32(5, m_amplification); s.writeS32(6, m_displayGridIntensity); + s.writeS32(7, m_ampOffset); return s.final(); } @@ -86,6 +90,7 @@ bool GLScopeGUI::deserialize(const QByteArray& data) d.readS32(6, &m_displayGridIntensity, 5); if(m_timeBase < 0) m_timeBase = 1; + d.readS32(7, &m_ampOffset, 0); applySettings(); return true; } else { @@ -120,8 +125,17 @@ void GLScopeGUI::on_amp_valueChanged(int value) m_amplification = value; } +void GLScopeGUI::on_ampOfs_valueChanged(int value) +{ + m_ampOffset = value; + ui->ampOfsText->setText(tr("%1").arg(value/100.0, 0, 'f', 2)); + m_glScope->setAmpOfs(value/100.0); // scale to [-1.0,1.0] +} + void GLScopeGUI::on_scope_traceSizeChanged(int) { + std::cerr << "GLScopeGUI::on_scope_traceSizeChanged: sample rate: " << m_glScope->getSampleRate() << std::endl; + m_sampleRate = m_glScope->getSampleRate(); qreal t = (m_glScope->getTraceSize() * 0.1 / m_sampleRate) / (qreal)m_timeBase; if(t < 0.000001) ui->timeText->setText(tr("%1\nns/div").arg(t * 1000000000.0)); @@ -142,6 +156,7 @@ void GLScopeGUI::on_time_valueChanged(int value) void GLScopeGUI::on_timeOfs_valueChanged(int value) { m_timeOffset = value; + ui->timeOfsText->setText(tr("%1").arg(value/1000.0, 0, 'f', 3)); m_glScope->setTimeOfsProMill(value); } @@ -202,10 +217,12 @@ void GLScopeGUI::on_gridIntensity_valueChanged(int index) bool GLScopeGUI::handleMessage(Message* cmd) { + return false; + /* if(DSPSignalNotification::match(cmd)) { DSPSignalNotification* signal = (DSPSignalNotification*)cmd; - //fprintf(stderr, "%d samples/sec, %lld Hz offset", signal->getSampleRate(), signal->getFrequencyOffset()); + //fprintf(stderr, "GLScopeGUI::handleMessage: %d samples/sec, %lld Hz offset", signal->getSampleRate(), signal->getFrequencyOffset()); m_sampleRate = signal->getSampleRate(); cmd->completed(); return true; @@ -214,4 +231,5 @@ bool GLScopeGUI::handleMessage(Message* cmd) { return false; } + */ } diff --git a/sdrbase/gui/glscopegui.ui b/sdrbase/gui/glscopegui.ui index e0a83fd48..6bf0454a3 100644 --- a/sdrbase/gui/glscopegui.ui +++ b/sdrbase/gui/glscopegui.ui @@ -48,6 +48,11 @@ + + + 8 + + Data @@ -61,6 +66,11 @@ 0 + + + 8 + + Grid intensity @@ -166,6 +176,11 @@ + + + 8 + + Time @@ -207,6 +222,11 @@ 0 + + + 8 + + 0.1000 /div @@ -224,6 +244,9 @@ 0 + + Time offset + 0 @@ -240,12 +263,17 @@ QSlider::NoTicks - 50 + 1 - + + + + 8 + + 0 @@ -260,6 +288,11 @@ + + + 8 + + Amp @@ -304,6 +337,11 @@ 0 + + + 8 + + 0.2000 /div @@ -313,6 +351,43 @@ + + + + Y offset + + + -100 + + + 100 + + + 1 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 1 + + + + + + + + 8 + + + + 0 + + + diff --git a/sdrbase/gui/scaleengine.cpp b/sdrbase/gui/scaleengine.cpp index da173e3a6..696464aad 100644 --- a/sdrbase/gui/scaleengine.cpp +++ b/sdrbase/gui/scaleengine.cpp @@ -158,6 +158,7 @@ void ScaleEngine::calcScaleFactor() case Unit::AngleDegrees: m_unitStr = QString("°"); + break; case Unit::Time: if(median < 0.001) { @@ -170,6 +171,24 @@ void ScaleEngine::calcScaleFactor() m_unitStr = QString("s"); } break; + + case Unit::Volt: + if (median < 1e-9) { + m_unitStr = QString("pV"); + m_scale = 1e-12; + } else if (median < 1e-6) { + m_unitStr = QString("nV"); + m_scale = 1e-9; + } else if (median < 1e-3) { + m_unitStr = QString("µV"); + m_scale = 1e-6; + } else if (median < 1.0) { + m_unitStr = QString("mV"); + m_scale = 1e-3; + } else { + m_unitStr = QString("V"); + } + break; } }