1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-22 08:04:49 -05:00

Print scale on scope part #1

This commit is contained in:
f4exb 2015-07-06 09:17:51 +02:00
parent 78c944ce69
commit 5a8c3d8e5b
10 changed files with 377 additions and 10 deletions

View File

@ -24,6 +24,7 @@
#include <QMutex>
#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);

View File

@ -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);

View File

@ -28,7 +28,8 @@ namespace Unit {
DecibelMilliWatt,
DecibelMicroVolt,
AngleDegrees,
Time
Time,
Volt
};
};

View File

@ -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<<spanLog2);
m_rate = m_channelAnalyzer->getSampleRate() / (1<<spanLog2);
std::cerr << "ChannelAnalyzerGUI::setNewRate: " << m_rate << std::endl;
if (ui->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;

View File

@ -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) {

View File

@ -3,6 +3,8 @@
#include "dsp/dspcommands.h"
#include "util/messagequeue.h"
#include <cstdio>
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)) {

View File

@ -3,6 +3,8 @@
#include "gui/glscope.h"
#include "dsp/dspengine.h"
#include <iostream>
#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<Complex>::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(),

View File

@ -6,6 +6,7 @@
#include "ui_glscopegui.h"
#include <iostream>
#include <cstdio>
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;
}
*/
}

View File

@ -48,6 +48,11 @@
</property>
<item>
<widget class="QLabel" name="dataLabel">
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string>Data</string>
</property>
@ -61,6 +66,11 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="toolTip">
<string>Grid intensity</string>
</property>
@ -166,6 +176,11 @@
</item>
<item>
<widget class="QLabel" name="timeLabel">
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string>Time</string>
</property>
@ -207,6 +222,11 @@
<height>0</height>
</size>
</property>
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string>0.1000
/div</string>
@ -224,6 +244,9 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Time offset</string>
</property>
<property name="minimum">
<number>0</number>
</property>
@ -240,12 +263,17 @@
<enum>QSlider::NoTicks</enum>
</property>
<property name="tickInterval">
<number>50</number>
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="timeOfsLabel">
<widget class="QLabel" name="timeOfsText">
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string>0</string>
</property>
@ -260,6 +288,11 @@
</item>
<item>
<widget class="QLabel" name="ampLabel">
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string>Amp</string>
</property>
@ -304,6 +337,11 @@
<height>0</height>
</size>
</property>
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string>0.2000
/div</string>
@ -313,6 +351,43 @@
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="ampOfs">
<property name="toolTip">
<string>Y offset</string>
</property>
<property name="minimum">
<number>-100</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="ampOfsText">
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="ampLine">
<property name="orientation">

View File

@ -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;
}
}