diff --git a/Readme.md b/Readme.md index 94d2635c4..21f8bd4ed 100644 --- a/Readme.md +++ b/Readme.md @@ -107,16 +107,22 @@ Done since the fork - As a consequence of the above added more interesting values for the available sampling rates of the BladeRF plugin - Variable span for the SSB demod down to 1.5 kHz - Filter out CTCSS tones for audio and full CTCSS support in NFMDemod - - Enhancement of the NFM squelch + - Enhancement of the NFM squelch mimicking professional analog squelch circuits (based on balance between two AF filters) - Added a channel analyzer plugin focusing on measurement (DSA/DSO functionnality). Basic functions. - Added a scope widget in the channel analyzer plugin + - Channel analyzer bandwidth up to half the available RF (IF) bandwidth (was 48k fixed) + - Enhanced scope display and controls: scale display, better X (time) and Y scales control, grid fit to scale, effectively implementing triggers, trigger on magnitude and phase, properly handling time shift, ... + - Enhanced spectrum display: Histogram: define NO_AVX, wider decay range, make stroke and late holdoff adjustable. Added option to show live spectrum (had only max hold before). + - Enhanced channel analyzer: enhanced scope and spectrum displays as mentioned above, make the spectrum display synchronous to scope (hence triggerable a la E4406A). ===== To Do ===== + - Enhance presets management (Edit, Move, Import/Export from/to human readable format like JSON) + - Variable scope memory depth + - Level calibration - Enhance WFM (stereo, RDS?) - Even more demods ... - - Triggering capability like on expensive spectrum analyzers to trap burst signals - recording capability - Tx channels for Rx/Tx boards like BladeRF diff --git a/include-gpl/gui/glspectrum.h b/include-gpl/gui/glspectrum.h index 41c00c422..900a5dc49 100644 --- a/include-gpl/gui/glspectrum.h +++ b/include-gpl/gui/glspectrum.h @@ -38,10 +38,13 @@ public: void setReferenceLevel(Real referenceLevel); void setPowerRange(Real powerRange); void setDecay(int decay); + void setHistoLateHoldoff(int lateHoldoff); + void setHistoStroke(int stroke); void setDisplayWaterfall(bool display); void setSsbSpectrum(bool ssbSpectrum); void setInvertedWaterfall(bool inv); void setDisplayMaxHold(bool display); + void setDisplayCurrent(bool display); void setDisplayHistogram(bool display); void setDisplayGrid(bool display); void setDisplayGridIntensity(int intensity); @@ -96,6 +99,8 @@ private: std::vector m_maxHold; bool m_displayMaxHold; + std::vector m_current; + bool m_displayCurrent; Real m_waterfallShare; diff --git a/include-gpl/gui/glspectrumgui.h b/include-gpl/gui/glspectrumgui.h index 24d901105..f7c9cc2e8 100644 --- a/include-gpl/gui/glspectrumgui.h +++ b/include-gpl/gui/glspectrumgui.h @@ -45,6 +45,7 @@ private: bool m_displayWaterfall; bool m_invertedWaterfall; bool m_displayMaxHold; + bool m_displayCurrent; bool m_displayHistogram; bool m_displayGrid; bool m_invert; @@ -64,6 +65,7 @@ private slots: void on_waterfall_toggled(bool checked); void on_histogram_toggled(bool checked); void on_maxHold_toggled(bool checked); + void on_current_toggled(bool checked); void on_invert_toggled(bool checked); void on_grid_toggled(bool checked); }; diff --git a/sdrbase/gui/glspectrum.cpp b/sdrbase/gui/glspectrum.cpp index 226f46c40..14d7f9ff1 100644 --- a/sdrbase/gui/glspectrum.cpp +++ b/sdrbase/gui/glspectrum.cpp @@ -36,6 +36,7 @@ GLSpectrum::GLSpectrum(QWidget* parent) : m_displayGridIntensity(5), m_invertedWaterfall(false), m_displayMaxHold(false), + m_displayCurrent(false), m_leftMarginTextureAllocated(false), m_frequencyTextureAllocated(false), m_waterfallBuffer(NULL), @@ -86,6 +87,9 @@ GLSpectrum::GLSpectrum(QWidget* parent) : ((quint8*)&m_histogramPalette[i])[2] = c.blue(); ((quint8*)&m_histogramPalette[i])[3] = c.alpha(); } + + m_current.resize(m_fftSize); + m_histogramHoldoffBase = 1; // was 4 m_histogramHoldoffCount = m_histogramHoldoffBase; m_histogramLateHoldoff = 1; // was 20 @@ -169,12 +173,30 @@ void GLSpectrum::setPowerRange(Real powerRange) void GLSpectrum::setDecay(int decay) { m_decay = decay; - if(m_decay < -2) - m_decay = -2; + if(m_decay < 0) + m_decay = 0; else if(m_decay > 10) m_decay = 10; } +void GLSpectrum::setHistoLateHoldoff(int lateHoldoff) +{ + m_histogramLateHoldoff = lateHoldoff; + if(m_histogramLateHoldoff < 0) + m_histogramLateHoldoff = 0; + else if(m_histogramLateHoldoff > 20) + m_histogramLateHoldoff = 20; +} + +void GLSpectrum::setHistoStroke(int stroke) +{ + m_histogramStroke = stroke; + if(m_histogramStroke < 4) + m_histogramStroke = 4; + else if(m_histogramStroke > 240) + m_histogramStroke = 240; +} + void GLSpectrum::setSampleRate(qint32 sampleRate) { m_sampleRate = sampleRate; @@ -212,6 +234,18 @@ void GLSpectrum::setDisplayMaxHold(bool display) update(); } +void GLSpectrum::setDisplayCurrent(bool display) +{ + if(display && (m_current.size() < (uint)m_fftSize)) { + m_current.resize(m_fftSize); + } + + m_displayCurrent = display; + m_changesPending = true; + stopDrag(); + update(); +} + void GLSpectrum::setDisplayHistogram(bool display) { m_displayHistogram = display; @@ -333,12 +367,23 @@ void GLSpectrum::updateHistogram(const std::vector& spectrum) m_histogramHoldoffCount = m_histogramHoldoffBase; } + if(m_current.size() < (uint)m_fftSize) + m_current.resize(m_fftSize); + #define NO_AVX #ifdef NO_AVX for(int i = 0; i < m_fftSize; i++) { int v = (int)((spectrum[i] - m_referenceLevel) * 100.0 / m_powerRange + 100.0); - if((v >= 0) && (v <= 99)) { + if (v < 0) { + m_current[i] = m_referenceLevel - m_powerRange; + } + else if (v > 99) { + m_current[i] = m_referenceLevel; + } + else { + //m_current[i] = m_referenceLevel - m_powerRange + (v * m_powerRange) / 99.0; + m_current[i] = spectrum[i]; b = m_histogram + i * 100 + v; if(*b < 220) *b += m_histogramStroke; // was 4 @@ -517,7 +562,7 @@ void GLSpectrum::paintGL() } // paint histogram - if(m_displayHistogram || m_displayMaxHold) { + if(m_displayHistogram || m_displayMaxHold || m_displayCurrent) { glPushMatrix(); glTranslatef(m_glHistogramRect.x(), m_glHistogramRect.y(), 0); glScalef(m_glHistogramRect.width(), m_glHistogramRect.height(), 1); @@ -613,7 +658,7 @@ void GLSpectrum::paintGL() } // paint left scales (time and power) - if(m_displayWaterfall || m_displayMaxHold || m_displayHistogram ) { + if(m_displayWaterfall || m_displayMaxHold || m_displayCurrent || m_displayHistogram ) { glBindTexture(GL_TEXTURE_2D, m_leftMarginTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -640,7 +685,7 @@ void GLSpectrum::paintGL() } // paint frequency scale - if(m_displayWaterfall || m_displayMaxHold || m_displayHistogram ) { + if(m_displayWaterfall || m_displayMaxHold || m_displayCurrent || m_displayHistogram ) { glBindTexture(GL_TEXTURE_2D, m_frequencyTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -753,6 +798,31 @@ void GLSpectrum::paintGL() glPopMatrix(); } + // paint current spectrum line on top of histogram + if(m_displayCurrent) { + glPushMatrix(); + glTranslatef(m_glHistogramRect.x(), m_glHistogramRect.y(), 0); + glScalef(m_glHistogramRect.width() / (float)(m_fftSize - 1), -m_glHistogramRect.height() / m_powerRange, 1); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_LINE_SMOOTH); + glLineWidth(1.0f); + glColor3f(1.0f, 1.0f, 0.25f); // intense yellow + Real bottom = -m_powerRange; + glBegin(GL_LINE_STRIP); + for(int i = 0; i < m_fftSize; i++) { + Real v = m_current[i] - m_referenceLevel; + if(v > 0) + v = 0; + else if(v < bottom) + v = bottom; + glVertex2f(i, v); + } + glEnd(); + glDisable(GL_LINE_SMOOTH); + glPopMatrix(); + } + // paint waterfall grid if(m_displayWaterfall && m_displayGrid) { glEnable(GL_BLEND); @@ -800,7 +870,7 @@ void GLSpectrum::paintGL() } // paint histogram grid - if((m_displayHistogram || m_displayMaxHold) && (m_displayGrid)) { + if((m_displayHistogram || m_displayMaxHold || m_displayCurrent) && (m_displayGrid)) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glLineWidth(1.0f); @@ -881,7 +951,7 @@ void GLSpectrum::applyChanges() int leftMargin; int rightMargin = fm.width("000"); - if(m_displayWaterfall && (m_displayHistogram | m_displayMaxHold)) + if(m_displayWaterfall && (m_displayHistogram | m_displayMaxHold | m_displayCurrent)) { waterfallHeight = height() * m_waterfallShare - 1; @@ -1041,7 +1111,7 @@ void GLSpectrum::applyChanges() (float)1 ); } - else if(m_displayHistogram || m_displayMaxHold) + else if(m_displayHistogram || m_displayMaxHold || m_displayCurrent) { bottomMargin = frequencyScaleHeight; frequencyScaleTop = height() - bottomMargin; @@ -1133,7 +1203,7 @@ void GLSpectrum::applyChanges() 1); */ - if(m_displayHistogram || m_displayMaxHold || m_displayWaterfall) { + if(m_displayHistogram || m_displayMaxHold || m_displayCurrent || m_displayWaterfall) { dv->m_rect.setRect(m_frequencyScale.getPosFromValue(xc) + leftMargin - 1, topMargin, 5, @@ -1170,7 +1240,7 @@ void GLSpectrum::applyChanges() } } } - if(m_displayHistogram || m_displayMaxHold) { + if(m_displayHistogram || m_displayMaxHold || m_displayCurrent) { tickList = &m_powerScale.getTickList(); for(int i = 0; i < tickList->count(); i++) { tick = &(*tickList)[i]; @@ -1191,7 +1261,7 @@ void GLSpectrum::applyChanges() m_leftMarginTextureAllocated = true; } // prepare frequency scale - if(m_displayWaterfall || m_displayHistogram || m_displayMaxHold){ + if(m_displayWaterfall || m_displayHistogram || m_displayMaxHold || m_displayCurrent){ m_frequencyPixmap = QPixmap(width(), frequencyScaleHeight); m_frequencyPixmap.fill(Qt::transparent); { @@ -1320,7 +1390,7 @@ void GLSpectrum::applyChanges() void GLSpectrum::mouseMoveEvent(QMouseEvent* event) { - if(m_displayWaterfall && (m_displayWaterfall || m_displayHistogram || m_displayMaxHold)) { + if(m_displayWaterfall && (m_displayWaterfall || m_displayHistogram || m_displayMaxHold || m_displayCurrent)) { if(m_frequencyScaleRect.contains(event->pos())) { if(m_cursorState == CSNormal) { setCursor(Qt::SizeVerCursor); @@ -1355,7 +1425,7 @@ void GLSpectrum::mouseMoveEvent(QMouseEvent* event) m_channelMarkerStates[m_cursorChannel]->m_channelMarker->setCenterFrequency(freq); } - if(m_displayWaterfall || m_displayHistogram || m_displayMaxHold) { + if(m_displayWaterfall || m_displayHistogram || m_displayMaxHold || m_displayCurrent) { for(int i = 0; i < m_channelMarkerStates.size(); ++i) { if(m_channelMarkerStates[i]->m_rect.contains(event->pos())) { if(m_cursorState == CSNormal) { diff --git a/sdrbase/gui/glspectrumgui.cpp b/sdrbase/gui/glspectrumgui.cpp index b821e6816..2f4984950 100644 --- a/sdrbase/gui/glspectrumgui.cpp +++ b/sdrbase/gui/glspectrumgui.cpp @@ -23,6 +23,7 @@ GLSpectrumGUI::GLSpectrumGUI(QWidget* parent) : m_displayWaterfall(true), m_invertedWaterfall(false), m_displayMaxHold(false), + m_displayCurrent(false), m_displayHistogram(false), m_displayGrid(false), m_invert(true) @@ -85,6 +86,7 @@ QByteArray GLSpectrumGUI::serialize() const s.writeS32(13, m_displayGridIntensity); s.writeS32(14, m_histogramLateHoldoff); s.writeS32(15, m_histogramStroke); + s.writeBool(16, m_displayCurrent); return s.final(); } @@ -113,6 +115,7 @@ bool GLSpectrumGUI::deserialize(const QByteArray& data) d.readS32(13, &m_displayGridIntensity, 0); d.readS32(14, &m_histogramLateHoldoff, 1); d.readS32(15, &m_histogramStroke, 40); + d.readBool(16, &m_displayCurrent, false); applySettings(); return true; } else { @@ -137,6 +140,7 @@ void GLSpectrumGUI::applySettings() ui->stroke->setSliderPosition(m_histogramStroke); ui->waterfall->setChecked(m_displayWaterfall); ui->maxHold->setChecked(m_displayMaxHold); + ui->current->setChecked(m_displayCurrent); ui->histogram->setChecked(m_displayHistogram); ui->invert->setChecked(m_invert); ui->grid->setChecked(m_displayGrid); @@ -150,8 +154,11 @@ void GLSpectrumGUI::applySettings() m_glSpectrum->setDisplayWaterfall(m_displayWaterfall); m_glSpectrum->setInvertedWaterfall(m_invertedWaterfall); m_glSpectrum->setDisplayMaxHold(m_displayMaxHold); + m_glSpectrum->setDisplayCurrent(m_displayCurrent); m_glSpectrum->setDisplayHistogram(m_displayHistogram); m_glSpectrum->setDecay(m_decay); + m_glSpectrum->setHistoLateHoldoff(m_histogramLateHoldoff); + m_glSpectrum->setHistoStroke(m_histogramStroke); m_glSpectrum->setInvertedWaterfall(m_invert); m_glSpectrum->setDisplayGrid(m_displayGrid); m_glSpectrum->setDisplayGridIntensity(m_displayGridIntensity); @@ -198,13 +205,14 @@ void GLSpectrumGUI::on_decay_valueChanged(int index) void GLSpectrumGUI::on_holdoff_valueChanged(int index) { - if (index < 1) { + if (index < 0) { return; } m_histogramLateHoldoff = index; - ui->holdoff->setToolTip(QString("Holdoff: %1").arg(m_histogramLateHoldoff)); - if(m_glSpectrum != NULL) - m_glSpectrum->setDecay(m_decay); + //ui->holdoff->setToolTip(QString("Holdoff: %1").arg(m_histogramLateHoldoff)); + if(m_glSpectrum != NULL) { + applySettings(); + } } void GLSpectrumGUI::on_stroke_valueChanged(int index) @@ -213,9 +221,10 @@ void GLSpectrumGUI::on_stroke_valueChanged(int index) return; } m_histogramStroke = index; - ui->stroke->setToolTip(QString("Stroke: %1").arg(m_histogramStroke)); - if(m_glSpectrum != NULL) - m_glSpectrum->setDecay(m_decay); + //ui->stroke->setToolTip(QString("Stroke: %1").arg(m_histogramStroke)); + if(m_glSpectrum != NULL) { + applySettings(); + } } void GLSpectrumGUI::on_waterfall_toggled(bool checked) @@ -239,6 +248,13 @@ void GLSpectrumGUI::on_maxHold_toggled(bool checked) m_glSpectrum->setDisplayMaxHold(m_displayMaxHold); } +void GLSpectrumGUI::on_current_toggled(bool checked) +{ + m_displayCurrent = checked; + if(m_glSpectrum != NULL) + m_glSpectrum->setDisplayCurrent(m_displayCurrent); +} + void GLSpectrumGUI::on_invert_toggled(bool checked) { m_invert = checked; diff --git a/sdrbase/gui/glspectrumgui.ui b/sdrbase/gui/glspectrumgui.ui index 02be5b570..0cdff7145 100644 --- a/sdrbase/gui/glspectrumgui.ui +++ b/sdrbase/gui/glspectrumgui.ui @@ -6,7 +6,7 @@ 0 0 - 234 + 273 94 @@ -234,7 +234,7 @@ Decay: - 10 + 240 1 @@ -253,10 +253,10 @@ Holdoff: - 1 + 0 - 100 + 20 1 @@ -278,7 +278,7 @@ 4 - 100 + 240 1 @@ -370,7 +370,7 @@ - Display live spectrum + Display max hold Max Hold @@ -390,6 +390,41 @@ + + + + + 0 + 0 + + + + + 24 + 24 + + + + Display live spectrum + + + Max Hold + + + + :/current.png:/current.png + + + + 16 + 16 + + + + true + + + diff --git a/sdrbase/resources/current.png b/sdrbase/resources/current.png new file mode 100644 index 000000000..4497a4253 Binary files /dev/null and b/sdrbase/resources/current.png differ diff --git a/sdrbase/resources/res.qrc b/sdrbase/resources/res.qrc index d38c33f87..21207a6b6 100644 --- a/sdrbase/resources/res.qrc +++ b/sdrbase/resources/res.qrc @@ -22,5 +22,6 @@ display2_w.png horizontal_w.png vertical_w.png + current.png