mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-11-04 05:30:32 -05:00 
			
		
		
		
	Spectrum: Use widget for measurements
This commit is contained in:
		
							parent
							
								
									8b1da4bfef
								
							
						
					
					
						commit
						2d43a5515e
					
				@ -23,6 +23,7 @@
 | 
				
			|||||||
#include "dsp/dspengine.h"
 | 
					#include "dsp/dspengine.h"
 | 
				
			||||||
#include "dsp/dspcommands.h"
 | 
					#include "dsp/dspcommands.h"
 | 
				
			||||||
#include "gui/glspectrum.h"
 | 
					#include "gui/glspectrum.h"
 | 
				
			||||||
 | 
					#include "gui/glspectrumtop.h"
 | 
				
			||||||
#include "gui/glscope.h"
 | 
					#include "gui/glscope.h"
 | 
				
			||||||
#include "gui/basicchannelsettingsdialog.h"
 | 
					#include "gui/basicchannelsettingsdialog.h"
 | 
				
			||||||
#include "plugin/pluginapi.h"
 | 
					#include "plugin/pluginapi.h"
 | 
				
			||||||
@ -192,17 +193,17 @@ void ChannelAnalyzerGUI::setSpectrumDisplay()
 | 
				
			|||||||
    qDebug("ChannelAnalyzerGUI::setSpectrumDisplay: m_sinkSampleRate: %d", sinkSampleRate);
 | 
					    qDebug("ChannelAnalyzerGUI::setSpectrumDisplay: m_sinkSampleRate: %d", sinkSampleRate);
 | 
				
			||||||
    if (m_settings.m_ssb)
 | 
					    if (m_settings.m_ssb)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ui->glSpectrum->setCenterFrequency(sinkSampleRate/4);
 | 
					        ui->glSpectrumTop->getSpectrum()->setCenterFrequency(sinkSampleRate/4);
 | 
				
			||||||
        ui->glSpectrum->setSampleRate(sinkSampleRate/2);
 | 
					        ui->glSpectrumTop->getSpectrum()->setSampleRate(sinkSampleRate/2);
 | 
				
			||||||
        ui->glSpectrum->setSsbSpectrum(true);
 | 
					        ui->glSpectrumTop->getSpectrum()->setSsbSpectrum(true);
 | 
				
			||||||
        ui->glSpectrum->setLsbDisplay(ui->BW->value() < 0);
 | 
					        ui->glSpectrumTop->getSpectrum()->setLsbDisplay(ui->BW->value() < 0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ui->glSpectrum->setCenterFrequency(0);
 | 
					        ui->glSpectrumTop->getSpectrum()->setCenterFrequency(0);
 | 
				
			||||||
        ui->glSpectrum->setSampleRate(sinkSampleRate);
 | 
					        ui->glSpectrumTop->getSpectrum()->setSampleRate(sinkSampleRate);
 | 
				
			||||||
        ui->glSpectrum->setSsbSpectrum(false);
 | 
					        ui->glSpectrumTop->getSpectrum()->setSsbSpectrum(false);
 | 
				
			||||||
        ui->glSpectrum->setLsbDisplay(false);
 | 
					        ui->glSpectrumTop->getSpectrum()->setLsbDisplay(false);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -542,7 +543,7 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceUISet *device
 | 
				
			|||||||
    m_basebandSampleRate = m_channelAnalyzer->getChannelSampleRate();
 | 
					    m_basebandSampleRate = m_channelAnalyzer->getChannelSampleRate();
 | 
				
			||||||
    qDebug("ChannelAnalyzerGUI::ChannelAnalyzerGUI: m_basebandSampleRate: %d", m_basebandSampleRate);
 | 
					    qDebug("ChannelAnalyzerGUI::ChannelAnalyzerGUI: m_basebandSampleRate: %d", m_basebandSampleRate);
 | 
				
			||||||
    m_spectrumVis = m_channelAnalyzer->getSpectrumVis();
 | 
					    m_spectrumVis = m_channelAnalyzer->getSpectrumVis();
 | 
				
			||||||
	m_spectrumVis->setGLSpectrum(ui->glSpectrum);
 | 
						m_spectrumVis->setGLSpectrum(ui->glSpectrumTop->getSpectrum());
 | 
				
			||||||
    m_scopeVis = m_channelAnalyzer->getScopeVis();
 | 
					    m_scopeVis = m_channelAnalyzer->getScopeVis();
 | 
				
			||||||
    m_scopeVis->setGLScope(ui->glScope);
 | 
					    m_scopeVis->setGLScope(ui->glScope);
 | 
				
			||||||
    m_basebandSampleRate = m_channelAnalyzer->getChannelSampleRate();
 | 
					    m_basebandSampleRate = m_channelAnalyzer->getChannelSampleRate();
 | 
				
			||||||
@ -556,12 +557,12 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceUISet *device
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ui->rationalDownSamplerRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow));
 | 
						ui->rationalDownSamplerRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ui->glSpectrum->setCenterFrequency(m_basebandSampleRate/2);
 | 
						ui->glSpectrumTop->getSpectrum()->setCenterFrequency(m_basebandSampleRate/2);
 | 
				
			||||||
	ui->glSpectrum->setSampleRate(m_basebandSampleRate);
 | 
						ui->glSpectrumTop->getSpectrum()->setSampleRate(m_basebandSampleRate);
 | 
				
			||||||
	ui->glSpectrum->setDisplayWaterfall(true);
 | 
						ui->glSpectrumTop->getSpectrum()->setDisplayWaterfall(true);
 | 
				
			||||||
	ui->glSpectrum->setDisplayMaxHold(true);
 | 
						ui->glSpectrumTop->getSpectrum()->setDisplayMaxHold(true);
 | 
				
			||||||
	ui->glSpectrum->setSsbSpectrum(false);
 | 
						ui->glSpectrumTop->getSpectrum()->setSsbSpectrum(false);
 | 
				
			||||||
    ui->glSpectrum->setLsbDisplay(false);
 | 
					    ui->glSpectrumTop->getSpectrum()->setLsbDisplay(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ui->glScope->connectTimer(MainCore::instance()->getMasterTimer());
 | 
						ui->glScope->connectTimer(MainCore::instance()->getMasterTimer());
 | 
				
			||||||
	connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
 | 
						connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
 | 
				
			||||||
@ -578,7 +579,7 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceUISet *device
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	m_deviceUISet->addChannelMarker(&m_channelMarker);
 | 
						m_deviceUISet->addChannelMarker(&m_channelMarker);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ui->spectrumGUI->setBuddies(m_spectrumVis, ui->glSpectrum);
 | 
						ui->spectrumGUI->setBuddies(m_spectrumVis, ui->glSpectrumTop->getSpectrum(), ui->glSpectrumTop);
 | 
				
			||||||
	ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope);
 | 
						ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m_settings.setChannelMarker(&m_channelMarker);
 | 
						m_settings.setChannelMarker(&m_channelMarker);
 | 
				
			||||||
@ -694,7 +695,7 @@ void ChannelAnalyzerGUI::setFiltersUIBoundaries()
 | 
				
			|||||||
void ChannelAnalyzerGUI::blockApplySettings(bool block)
 | 
					void ChannelAnalyzerGUI::blockApplySettings(bool block)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ui->glScope->blockSignals(block);
 | 
					    ui->glScope->blockSignals(block);
 | 
				
			||||||
    ui->glSpectrum->blockSignals(block);
 | 
					    ui->glSpectrumTop->getSpectrum()->blockSignals(block);
 | 
				
			||||||
    m_doApplySettings = !block;
 | 
					    m_doApplySettings = !block;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -899,7 +899,7 @@
 | 
				
			|||||||
     <number>2</number>
 | 
					     <number>2</number>
 | 
				
			||||||
    </property>
 | 
					    </property>
 | 
				
			||||||
    <item>
 | 
					    <item>
 | 
				
			||||||
     <widget class="GLSpectrum" name="glSpectrum" native="true">
 | 
					     <widget class="GLSpectrumTop" name="glSpectrumTop" native="true">
 | 
				
			||||||
      <property name="sizePolicy">
 | 
					      <property name="sizePolicy">
 | 
				
			||||||
       <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
 | 
					       <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
 | 
				
			||||||
        <horstretch>0</horstretch>
 | 
					        <horstretch>0</horstretch>
 | 
				
			||||||
@ -1018,9 +1018,9 @@
 | 
				
			|||||||
   <container>1</container>
 | 
					   <container>1</container>
 | 
				
			||||||
  </customwidget>
 | 
					  </customwidget>
 | 
				
			||||||
  <customwidget>
 | 
					  <customwidget>
 | 
				
			||||||
   <class>GLSpectrum</class>
 | 
					   <class>GLSpectrumTop</class>
 | 
				
			||||||
   <extends>QWidget</extends>
 | 
					   <extends>QWidget</extends>
 | 
				
			||||||
   <header>gui/glspectrum.h</header>
 | 
					   <header>gui/glspectrumtop.h</header>
 | 
				
			||||||
   <container>1</container>
 | 
					   <container>1</container>
 | 
				
			||||||
  </customwidget>
 | 
					  </customwidget>
 | 
				
			||||||
  <customwidget>
 | 
					  <customwidget>
 | 
				
			||||||
 | 
				
			|||||||
@ -68,12 +68,14 @@ void SpectrumSettings::resetToDefaults()
 | 
				
			|||||||
    m_3DSpectrogramStyle = Outline;
 | 
					    m_3DSpectrogramStyle = Outline;
 | 
				
			||||||
    m_colorMap = "Angel";
 | 
					    m_colorMap = "Angel";
 | 
				
			||||||
    m_spectrumStyle = Line;
 | 
					    m_spectrumStyle = Line;
 | 
				
			||||||
    m_measurement = MeasurementNone;
 | 
					    m_measure = false;
 | 
				
			||||||
 | 
					    m_measurement = MeasurementPeaks;
 | 
				
			||||||
    m_measurementBandwidth = 10000;
 | 
					    m_measurementBandwidth = 10000;
 | 
				
			||||||
    m_measurementChSpacing = 10000;
 | 
					    m_measurementChSpacing = 10000;
 | 
				
			||||||
    m_measurementAdjChBandwidth = 10000;
 | 
					    m_measurementAdjChBandwidth = 10000;
 | 
				
			||||||
    m_measurementHarmonics = 5;
 | 
					    m_measurementHarmonics = 5;
 | 
				
			||||||
    m_measurementHighlight = true;
 | 
					    m_measurementHighlight = true;
 | 
				
			||||||
 | 
					    m_measurementPeaks = 5;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QByteArray SpectrumSettings::serialize() const
 | 
					QByteArray SpectrumSettings::serialize() const
 | 
				
			||||||
@ -120,6 +122,8 @@ QByteArray SpectrumSettings::serialize() const
 | 
				
			|||||||
    s.writeS32(39, m_measurementHarmonics);
 | 
					    s.writeS32(39, m_measurementHarmonics);
 | 
				
			||||||
    // 41, 42 used below
 | 
					    // 41, 42 used below
 | 
				
			||||||
    s.writeBool(42, m_measurementHighlight);
 | 
					    s.writeBool(42, m_measurementHighlight);
 | 
				
			||||||
 | 
					    s.writeS32(43, m_measurementPeaks);
 | 
				
			||||||
 | 
					    s.writeBool(44, m_measure);
 | 
				
			||||||
    s.writeS32(100, m_histogramMarkers.size());
 | 
					    s.writeS32(100, m_histogramMarkers.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (int i = 0; i < m_histogramMarkers.size(); i++) {
 | 
						for (int i = 0; i < m_histogramMarkers.size(); i++) {
 | 
				
			||||||
@ -221,12 +225,14 @@ bool SpectrumSettings::deserialize(const QByteArray& data)
 | 
				
			|||||||
        d.readS32(32, (int*)&m_3DSpectrogramStyle, (int)Outline);
 | 
					        d.readS32(32, (int*)&m_3DSpectrogramStyle, (int)Outline);
 | 
				
			||||||
        d.readString(33, &m_colorMap, "Angel");
 | 
					        d.readString(33, &m_colorMap, "Angel");
 | 
				
			||||||
        d.readS32(34, (int*)&m_spectrumStyle, (int)Line);
 | 
					        d.readS32(34, (int*)&m_spectrumStyle, (int)Line);
 | 
				
			||||||
        d.readS32(35, (int*)&m_measurement, (int)MeasurementNone);
 | 
					        d.readS32(35, (int*)&m_measurement, (int)MeasurementPeaks);
 | 
				
			||||||
        d.readS32(36, &m_measurementBandwidth, 10000);
 | 
					        d.readS32(36, &m_measurementBandwidth, 10000);
 | 
				
			||||||
        d.readS32(37, &m_measurementChSpacing, 10000);
 | 
					        d.readS32(37, &m_measurementChSpacing, 10000);
 | 
				
			||||||
        d.readS32(38, &m_measurementAdjChBandwidth, 10000);
 | 
					        d.readS32(38, &m_measurementAdjChBandwidth, 10000);
 | 
				
			||||||
        d.readS32(39, &m_measurementHarmonics, 5);
 | 
					        d.readS32(39, &m_measurementHarmonics, 5);
 | 
				
			||||||
        d.readBool(42, &m_measurementHighlight, true);
 | 
					        d.readBool(42, &m_measurementHighlight, true);
 | 
				
			||||||
 | 
					        d.readS32(43, &m_measurementPeaks, 5);
 | 
				
			||||||
 | 
					        d.readBool(44, &m_measure, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		int histogramMarkersSize;
 | 
							int histogramMarkersSize;
 | 
				
			||||||
		d.readS32(100, &histogramMarkersSize, 0);
 | 
							d.readS32(100, &histogramMarkersSize, 0);
 | 
				
			||||||
 | 
				
			|||||||
@ -72,16 +72,10 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    enum Measurement
 | 
					    enum Measurement
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        MeasurementNone,
 | 
					        MeasurementPeaks,
 | 
				
			||||||
        MeasurementPeak,
 | 
					 | 
				
			||||||
        MeasurementChannelPower,
 | 
					        MeasurementChannelPower,
 | 
				
			||||||
        MeasurementAdjacentChannelPower,
 | 
					        MeasurementAdjacentChannelPower,
 | 
				
			||||||
        MeasurementSNR,
 | 
					        MeasurementSNR
 | 
				
			||||||
        MeasurementSNFR,
 | 
					 | 
				
			||||||
        MeasurementTHD,
 | 
					 | 
				
			||||||
        MeasurementTHDPN,
 | 
					 | 
				
			||||||
        MeasurementSINAD,
 | 
					 | 
				
			||||||
        MeasurementSFDR
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int m_fftSize;
 | 
						int m_fftSize;
 | 
				
			||||||
@ -122,11 +116,13 @@ public:
 | 
				
			|||||||
    SpectrogramStyle m_3DSpectrogramStyle;
 | 
					    SpectrogramStyle m_3DSpectrogramStyle;
 | 
				
			||||||
    QString m_colorMap;
 | 
					    QString m_colorMap;
 | 
				
			||||||
    SpectrumStyle m_spectrumStyle;
 | 
					    SpectrumStyle m_spectrumStyle;
 | 
				
			||||||
 | 
					    bool m_measure;
 | 
				
			||||||
    Measurement m_measurement;
 | 
					    Measurement m_measurement;
 | 
				
			||||||
    int m_measurementBandwidth;
 | 
					    int m_measurementBandwidth;
 | 
				
			||||||
    int m_measurementChSpacing;
 | 
					    int m_measurementChSpacing;
 | 
				
			||||||
    int m_measurementAdjChBandwidth;
 | 
					    int m_measurementAdjChBandwidth;
 | 
				
			||||||
    int m_measurementHarmonics;
 | 
					    int m_measurementHarmonics;
 | 
				
			||||||
 | 
					    int m_measurementPeaks;
 | 
				
			||||||
    bool m_measurementHighlight;
 | 
					    bool m_measurementHighlight;
 | 
				
			||||||
	static const int m_log2FFTSizeMin = 6;   // 64
 | 
						static const int m_log2FFTSizeMin = 6;   // 64
 | 
				
			||||||
	static const int m_log2FFTSizeMax = 15;  // 32k
 | 
						static const int m_log2FFTSizeMax = 15;  // 32k
 | 
				
			||||||
 | 
				
			|||||||
@ -51,6 +51,7 @@ set(sdrgui_SOURCES
 | 
				
			|||||||
    gui/glshadertvarray.cpp
 | 
					    gui/glshadertvarray.cpp
 | 
				
			||||||
    gui/glspectrum.cpp
 | 
					    gui/glspectrum.cpp
 | 
				
			||||||
    gui/glspectrumgui.cpp
 | 
					    gui/glspectrumgui.cpp
 | 
				
			||||||
 | 
					    gui/glspectrumtop.cpp
 | 
				
			||||||
    gui/graphicsdialog.cpp
 | 
					    gui/graphicsdialog.cpp
 | 
				
			||||||
    gui/graphicsviewzoom.cpp
 | 
					    gui/graphicsviewzoom.cpp
 | 
				
			||||||
    gui/httpdownloadmanagergui.cpp
 | 
					    gui/httpdownloadmanagergui.cpp
 | 
				
			||||||
@ -69,6 +70,7 @@ set(sdrgui_SOURCES
 | 
				
			|||||||
    gui/sdrangelsplash.cpp
 | 
					    gui/sdrangelsplash.cpp
 | 
				
			||||||
    gui/spectrumcalibrationpointsdialog.cpp
 | 
					    gui/spectrumcalibrationpointsdialog.cpp
 | 
				
			||||||
    gui/spectrummarkersdialog.cpp
 | 
					    gui/spectrummarkersdialog.cpp
 | 
				
			||||||
 | 
					    gui/spectrummeasurements.cpp
 | 
				
			||||||
    gui/tickedslider.cpp
 | 
					    gui/tickedslider.cpp
 | 
				
			||||||
    gui/timedelegate.cpp
 | 
					    gui/timedelegate.cpp
 | 
				
			||||||
    gui/transverterbutton.cpp
 | 
					    gui/transverterbutton.cpp
 | 
				
			||||||
@ -154,6 +156,7 @@ set(sdrgui_HEADERS
 | 
				
			|||||||
    gui/glshadertextured.h
 | 
					    gui/glshadertextured.h
 | 
				
			||||||
    gui/glspectrum.h
 | 
					    gui/glspectrum.h
 | 
				
			||||||
    gui/glspectrumgui.h
 | 
					    gui/glspectrumgui.h
 | 
				
			||||||
 | 
					    gui/glspectrumtop.h
 | 
				
			||||||
    gui/graphicsdialog.h
 | 
					    gui/graphicsdialog.h
 | 
				
			||||||
    gui/graphicsviewzoom.h
 | 
					    gui/graphicsviewzoom.h
 | 
				
			||||||
    gui/httpdownloadmanagergui.h
 | 
					    gui/httpdownloadmanagergui.h
 | 
				
			||||||
@ -173,6 +176,7 @@ set(sdrgui_HEADERS
 | 
				
			|||||||
    gui/sdrangelsplash.h
 | 
					    gui/sdrangelsplash.h
 | 
				
			||||||
    gui/spectrumcalibrationpointsdialog.h
 | 
					    gui/spectrumcalibrationpointsdialog.h
 | 
				
			||||||
    gui/spectrummarkersdialog.h
 | 
					    gui/spectrummarkersdialog.h
 | 
				
			||||||
 | 
					    gui/spectrummeasurements.h
 | 
				
			||||||
    gui/tickedslider.h
 | 
					    gui/tickedslider.h
 | 
				
			||||||
    gui/timedelegate.h
 | 
					    gui/timedelegate.h
 | 
				
			||||||
    gui/transverterbutton.h
 | 
					    gui/transverterbutton.h
 | 
				
			||||||
 | 
				
			|||||||
@ -23,6 +23,7 @@
 | 
				
			|||||||
#include "dsp/dspdevicesourceengine.h"
 | 
					#include "dsp/dspdevicesourceengine.h"
 | 
				
			||||||
#include "dsp/dspdevicesinkengine.h"
 | 
					#include "dsp/dspdevicesinkengine.h"
 | 
				
			||||||
#include "gui/glspectrum.h"
 | 
					#include "gui/glspectrum.h"
 | 
				
			||||||
 | 
					#include "gui/glspectrumtop.h"
 | 
				
			||||||
#include "gui/glspectrumgui.h"
 | 
					#include "gui/glspectrumgui.h"
 | 
				
			||||||
// #include "gui/channelwindow.h"
 | 
					// #include "gui/channelwindow.h"
 | 
				
			||||||
#include "gui/workspace.h"
 | 
					#include "gui/workspace.h"
 | 
				
			||||||
@ -42,13 +43,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
DeviceUISet::DeviceUISet(int deviceSetIndex, DeviceSet *deviceSet)
 | 
					DeviceUISet::DeviceUISet(int deviceSetIndex, DeviceSet *deviceSet)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    m_spectrum = new GLSpectrum;
 | 
					    m_spectrumTop = new GLSpectrumTop();
 | 
				
			||||||
 | 
					    m_spectrum = m_spectrumTop->getSpectrum();
 | 
				
			||||||
    m_spectrum->setIsDeviceSpectrum(true);
 | 
					    m_spectrum->setIsDeviceSpectrum(true);
 | 
				
			||||||
    m_spectrumVis = deviceSet->m_spectrumVis;
 | 
					    m_spectrumVis = deviceSet->m_spectrumVis;
 | 
				
			||||||
    m_spectrumVis->setGLSpectrum(m_spectrum);
 | 
					    m_spectrumVis->setGLSpectrum(m_spectrum);
 | 
				
			||||||
    m_spectrumGUI = new GLSpectrumGUI;
 | 
					    m_spectrumGUI = new GLSpectrumGUI;
 | 
				
			||||||
    m_spectrumGUI->setBuddies(m_spectrumVis, m_spectrum);
 | 
					    m_spectrumGUI->setBuddies(m_spectrumVis, m_spectrum, m_spectrumTop);
 | 
				
			||||||
    m_mainSpectrumGUI = new MainSpectrumGUI(m_spectrum, m_spectrumGUI);
 | 
					    m_mainSpectrumGUI = new MainSpectrumGUI(m_spectrumTop, m_spectrum, m_spectrumGUI);
 | 
				
			||||||
    // m_channelWindow = new ChannelWindow;
 | 
					    // m_channelWindow = new ChannelWindow;
 | 
				
			||||||
    m_deviceAPI = nullptr;
 | 
					    m_deviceAPI = nullptr;
 | 
				
			||||||
    m_deviceGUI = nullptr;
 | 
					    m_deviceGUI = nullptr;
 | 
				
			||||||
 | 
				
			|||||||
@ -26,6 +26,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class SpectrumVis;
 | 
					class SpectrumVis;
 | 
				
			||||||
class GLSpectrum;
 | 
					class GLSpectrum;
 | 
				
			||||||
 | 
					class GLSpectrumTop;
 | 
				
			||||||
class GLSpectrumGUI;
 | 
					class GLSpectrumGUI;
 | 
				
			||||||
class MainSpectrumGUI;
 | 
					class MainSpectrumGUI;
 | 
				
			||||||
// class ChannelWindow;
 | 
					// class ChannelWindow;
 | 
				
			||||||
@ -53,6 +54,7 @@ class SDRGUI_API DeviceUISet : public QObject
 | 
				
			|||||||
    Q_OBJECT
 | 
					    Q_OBJECT
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    SpectrumVis *m_spectrumVis;
 | 
					    SpectrumVis *m_spectrumVis;
 | 
				
			||||||
 | 
					    GLSpectrumTop *m_spectrumTop;
 | 
				
			||||||
    GLSpectrum *m_spectrum;
 | 
					    GLSpectrum *m_spectrum;
 | 
				
			||||||
    GLSpectrumGUI *m_spectrumGUI;
 | 
					    GLSpectrumGUI *m_spectrumGUI;
 | 
				
			||||||
    MainSpectrumGUI *m_mainSpectrumGUI;
 | 
					    MainSpectrumGUI *m_mainSpectrumGUI;
 | 
				
			||||||
 | 
				
			|||||||
@ -27,6 +27,7 @@
 | 
				
			|||||||
#include "maincore.h"
 | 
					#include "maincore.h"
 | 
				
			||||||
#include "dsp/spectrumvis.h"
 | 
					#include "dsp/spectrumvis.h"
 | 
				
			||||||
#include "gui/glspectrum.h"
 | 
					#include "gui/glspectrum.h"
 | 
				
			||||||
 | 
					#include "gui/spectrummeasurements.h"
 | 
				
			||||||
#include "settings/mainsettings.h"
 | 
					#include "settings/mainsettings.h"
 | 
				
			||||||
#include "util/messagequeue.h"
 | 
					#include "util/messagequeue.h"
 | 
				
			||||||
#include "util/db.h"
 | 
					#include "util/db.h"
 | 
				
			||||||
@ -109,11 +110,14 @@ GLSpectrum::GLSpectrum(QWidget* parent) :
 | 
				
			|||||||
    m_messageQueueToGUI(nullptr),
 | 
					    m_messageQueueToGUI(nullptr),
 | 
				
			||||||
    m_openGLLogger(nullptr),
 | 
					    m_openGLLogger(nullptr),
 | 
				
			||||||
    m_isDeviceSpectrum(false),
 | 
					    m_isDeviceSpectrum(false),
 | 
				
			||||||
    m_measurement(SpectrumSettings::MeasurementNone),
 | 
					    m_measurements(nullptr),
 | 
				
			||||||
 | 
					    m_measure(false),
 | 
				
			||||||
 | 
					    m_measurement(SpectrumSettings::MeasurementPeaks),
 | 
				
			||||||
    m_measurementBandwidth(10000),
 | 
					    m_measurementBandwidth(10000),
 | 
				
			||||||
    m_measurementChSpacing(10000),
 | 
					    m_measurementChSpacing(10000),
 | 
				
			||||||
    m_measurementAdjChBandwidth(10000),
 | 
					    m_measurementAdjChBandwidth(10000),
 | 
				
			||||||
    m_measurementHarmonics(5),
 | 
					    m_measurementHarmonics(5),
 | 
				
			||||||
 | 
					    m_measurementPeaks(5),
 | 
				
			||||||
    m_measurementHighlight(true)
 | 
					    m_measurementHighlight(true)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // Enable multisampling anti-aliasing (MSAA)
 | 
					    // Enable multisampling anti-aliasing (MSAA)
 | 
				
			||||||
@ -491,18 +495,23 @@ void GLSpectrum::setUseCalibration(bool useCalibration)
 | 
				
			|||||||
    update();
 | 
					    update();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GLSpectrum::setMeasurementParams(SpectrumSettings::Measurement measurement,
 | 
					void GLSpectrum::setMeasurementParams(bool measure, SpectrumSettings::Measurement measurement,
 | 
				
			||||||
                                      int bandwidth, int chSpacing, int adjChBandwidth,
 | 
					                                      int bandwidth, int chSpacing, int adjChBandwidth,
 | 
				
			||||||
                                      int harmonics, bool highlight)
 | 
					                                      int harmonics, int peaks, bool highlight)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    m_mutex.lock();
 | 
					    m_mutex.lock();
 | 
				
			||||||
 | 
					    m_measure = measure;
 | 
				
			||||||
    m_measurement = measurement;
 | 
					    m_measurement = measurement;
 | 
				
			||||||
    m_measurementBandwidth = bandwidth;
 | 
					    m_measurementBandwidth = bandwidth;
 | 
				
			||||||
    m_measurementChSpacing = chSpacing;
 | 
					    m_measurementChSpacing = chSpacing;
 | 
				
			||||||
    m_measurementAdjChBandwidth = adjChBandwidth;
 | 
					    m_measurementAdjChBandwidth = adjChBandwidth;
 | 
				
			||||||
    m_measurementHarmonics = harmonics;
 | 
					    m_measurementHarmonics = harmonics;
 | 
				
			||||||
 | 
					    m_measurementPeaks = peaks;
 | 
				
			||||||
    m_measurementHighlight = highlight;
 | 
					    m_measurementHighlight = highlight;
 | 
				
			||||||
    m_changesPending = true;
 | 
					    m_changesPending = true;
 | 
				
			||||||
 | 
					    if (m_measurements) {
 | 
				
			||||||
 | 
					        m_measurements->setMeasurementParams(measurement, peaks);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    m_mutex.unlock();
 | 
					    m_mutex.unlock();
 | 
				
			||||||
    update();
 | 
					    update();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1672,12 +1681,12 @@ void GLSpectrum::paintGL()
 | 
				
			|||||||
        m_glShaderInfo.drawSurface(m_glInfoBoxMatrix, tex1, vtx1, 4);
 | 
					        m_glShaderInfo.drawSurface(m_glInfoBoxMatrix, tex1, vtx1, 4);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (m_currentSpectrum)
 | 
					    if (m_currentSpectrum && m_measure)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        switch (m_measurement)
 | 
					        switch (m_measurement)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
        case SpectrumSettings::MeasurementPeak:
 | 
					        case SpectrumSettings::MeasurementPeaks:
 | 
				
			||||||
            measurePeak();
 | 
					            measurePeaks();
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SpectrumSettings::MeasurementChannelPower:
 | 
					        case SpectrumSettings::MeasurementChannelPower:
 | 
				
			||||||
            measureChannelPower();
 | 
					            measureChannelPower();
 | 
				
			||||||
@ -1686,13 +1695,7 @@ void GLSpectrum::paintGL()
 | 
				
			|||||||
            measureAdjacentChannelPower();
 | 
					            measureAdjacentChannelPower();
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SpectrumSettings::MeasurementSNR:
 | 
					        case SpectrumSettings::MeasurementSNR:
 | 
				
			||||||
        case SpectrumSettings::MeasurementSNFR:
 | 
					 | 
				
			||||||
        case SpectrumSettings::MeasurementTHD:
 | 
					 | 
				
			||||||
        case SpectrumSettings::MeasurementTHDPN:
 | 
					 | 
				
			||||||
        case SpectrumSettings::MeasurementSINAD:
 | 
					 | 
				
			||||||
            measureSNR();
 | 
					            measureSNR();
 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        case SpectrumSettings::MeasurementSFDR:
 | 
					 | 
				
			||||||
            measureSFDR();
 | 
					            measureSFDR();
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
@ -2069,6 +2072,60 @@ void GLSpectrum::measurePeak()
 | 
				
			|||||||
        {m_peakPowerMaxStr, m_peakFrequencyMaxStr},
 | 
					        {m_peakPowerMaxStr, m_peakFrequencyMaxStr},
 | 
				
			||||||
        {m_peakPowerUnits, "Hz"}
 | 
					        {m_peakPowerUnits, "Hz"}
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					    if (m_measurements) {
 | 
				
			||||||
 | 
					        m_measurements->setPeak(0, frequency, power);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Find and display peaks
 | 
				
			||||||
 | 
					void GLSpectrum::measurePeaks()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Copy current spectrum so we can modify it
 | 
				
			||||||
 | 
					    Real *spectrum = new Real[m_nbBins];
 | 
				
			||||||
 | 
					    std::copy(m_currentSpectrum, m_currentSpectrum + m_nbBins, spectrum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i = 0; i < m_measurementPeaks; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Find peak
 | 
				
			||||||
 | 
					        int peakBin = findPeakBin(spectrum);
 | 
				
			||||||
 | 
					        int left, right;
 | 
				
			||||||
 | 
					        peakWidth(spectrum, peakBin, left, right, 0, m_nbBins);
 | 
				
			||||||
 | 
					        left++;
 | 
				
			||||||
 | 
					        right--;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        float power = m_linear ?
 | 
				
			||||||
 | 
					                        spectrum[peakBin] * (m_useCalibration ? m_calibrationGain : 1.0f) :
 | 
				
			||||||
 | 
					                        spectrum[peakBin] + (m_useCalibration ? m_calibrationShiftdB : 0.0f);
 | 
				
			||||||
 | 
					        int64_t frequency = binToFrequency(peakBin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add to table
 | 
				
			||||||
 | 
					        if (m_measurements) {
 | 
				
			||||||
 | 
					            m_measurements->setPeak(i, frequency, power);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (m_measurementHighlight)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            float x = peakBin / (float)m_nbBins;
 | 
				
			||||||
 | 
					            float y = (m_powerScale.getRangeMax() - power) / m_powerScale.getRange();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            QString text = QString::number(i + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            drawTextOverlayCentered(
 | 
				
			||||||
 | 
					                text,
 | 
				
			||||||
 | 
					                QColor(255, 255, 255),
 | 
				
			||||||
 | 
					                m_textOverlayFont,
 | 
				
			||||||
 | 
					                x * m_histogramRect.width(),
 | 
				
			||||||
 | 
					                y * m_histogramRect.height(),
 | 
				
			||||||
 | 
					                m_histogramRect);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Remove peak from spectrum so not found on next pass
 | 
				
			||||||
 | 
					        for (int j = left; j <= right; j++) {
 | 
				
			||||||
 | 
					            spectrum[j] = -std::numeric_limits<float>::max();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    delete spectrum;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Calculate and display channel power
 | 
					// Calculate and display channel power
 | 
				
			||||||
@ -2077,7 +2134,9 @@ void GLSpectrum::measureChannelPower()
 | 
				
			|||||||
    float power;
 | 
					    float power;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    power = calcChannelPower(m_centerFrequency, m_measurementBandwidth);
 | 
					    power = calcChannelPower(m_centerFrequency, m_measurementBandwidth);
 | 
				
			||||||
    drawTextRight("Power: ", QString::number(power, 'f', 1), "-120.0", "dB");
 | 
					    if (m_measurements) {
 | 
				
			||||||
 | 
					        m_measurements->setChannelPower(power);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (m_measurementHighlight) {
 | 
					    if (m_measurementHighlight) {
 | 
				
			||||||
        drawBandwidthMarkers(m_centerFrequency, m_measurementBandwidth, m_measurementLightMarkerColor);
 | 
					        drawBandwidthMarkers(m_centerFrequency, m_measurementBandwidth, m_measurementLightMarkerColor);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -2095,17 +2154,9 @@ void GLSpectrum::measureAdjacentChannelPower()
 | 
				
			|||||||
    float leftDiff = powerLeft - power;
 | 
					    float leftDiff = powerLeft - power;
 | 
				
			||||||
    float rightDiff = powerRight - power;
 | 
					    float rightDiff = powerRight - power;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    drawTextsRight(
 | 
					    if (m_measurements) {
 | 
				
			||||||
        {"L: ", "", "   C: ", "   R: ", ""},
 | 
					        m_measurements->setAdjacentChannelPower(powerLeft, leftDiff, power, powerRight, rightDiff);
 | 
				
			||||||
        {   QString::number(powerLeft, 'f', 1),
 | 
					    }
 | 
				
			||||||
            QString::number(leftDiff, 'f', 1),
 | 
					 | 
				
			||||||
            QString::number(power, 'f', 1),
 | 
					 | 
				
			||||||
            QString::number(powerRight, 'f', 1),
 | 
					 | 
				
			||||||
            QString::number(rightDiff, 'f', 1)
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {"-120.0", "-120.0", "-120.0", "-120.0", "-120.0"},
 | 
					 | 
				
			||||||
        {"dB", "dBc", "dB", "dB", "dBc"}
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (m_measurementHighlight)
 | 
					    if (m_measurementHighlight)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -2115,38 +2166,38 @@ void GLSpectrum::measureAdjacentChannelPower()
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const QVector4D GLSpectrum::m_measurementLightMarkerColor = QVector4D(0.5f, 0.5f, 0.5f, 0.4f);
 | 
					const QVector4D GLSpectrum::m_measurementLightMarkerColor = QVector4D(0.6f, 0.6f, 0.6f, 0.2f);
 | 
				
			||||||
const QVector4D GLSpectrum::m_measurementDarkMarkerColor = QVector4D(0.5f, 0.5f, 0.5f, 0.3f);
 | 
					const QVector4D GLSpectrum::m_measurementDarkMarkerColor = QVector4D(0.6f, 0.6f, 0.6f, 0.15f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Find the width of a peak, by seaching in either direction until
 | 
					// Find the width of a peak, by seaching in either direction until
 | 
				
			||||||
// power is no longer falling
 | 
					// power is no longer falling
 | 
				
			||||||
void GLSpectrum::peakWidth(int center, int &left, int &right, int maxLeft, int maxRight) const
 | 
					void GLSpectrum::peakWidth(const Real *spectrum, int center, int &left, int &right, int maxLeft, int maxRight) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    float prevLeft = m_currentSpectrum[center];
 | 
					    float prevLeft = spectrum[center];
 | 
				
			||||||
    float prevRight = m_currentSpectrum[center];
 | 
					    float prevRight = spectrum[center];
 | 
				
			||||||
    left = center - 1;
 | 
					    left = center - 1;
 | 
				
			||||||
    right = center + 1;
 | 
					    right = center + 1;
 | 
				
			||||||
    while ((left > maxLeft) && (m_currentSpectrum[left] < prevLeft) && (right < maxRight) && (m_currentSpectrum[right] < prevRight))
 | 
					    while ((left > maxLeft) && (spectrum[left] < prevLeft) && (right < maxRight) && (spectrum[right] < prevRight))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        prevLeft = m_currentSpectrum[left];
 | 
					        prevLeft = spectrum[left];
 | 
				
			||||||
        left--;
 | 
					        left--;
 | 
				
			||||||
        prevRight = m_currentSpectrum[right];
 | 
					        prevRight = spectrum[right];
 | 
				
			||||||
        right++;
 | 
					        right++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int GLSpectrum::findPeakBin() const
 | 
					int GLSpectrum::findPeakBin(const Real *spectrum) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int bin;
 | 
					    int bin;
 | 
				
			||||||
    float power;
 | 
					    float power;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bin = 0;
 | 
					    bin = 0;
 | 
				
			||||||
    power = m_currentSpectrum[0];
 | 
					    power = spectrum[0];
 | 
				
			||||||
    for (int i = 1; i < m_nbBins; i++)
 | 
					    for (int i = 1; i < m_nbBins; i++)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (m_currentSpectrum[i] > power)
 | 
					        if (spectrum[i] > power)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            power = m_currentSpectrum[i];
 | 
					            power = spectrum[i];
 | 
				
			||||||
            bin = i;
 | 
					            bin = i;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -2178,9 +2229,9 @@ int64_t GLSpectrum::binToFrequency(int bin) const
 | 
				
			|||||||
void GLSpectrum::measureSNR()
 | 
					void GLSpectrum::measureSNR()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // Find bin with max peak - that will be our signal
 | 
					    // Find bin with max peak - that will be our signal
 | 
				
			||||||
    int sig = findPeakBin();
 | 
					    int sig = findPeakBin(m_currentSpectrum);
 | 
				
			||||||
    int sigLeft, sigRight;
 | 
					    int sigLeft, sigRight;
 | 
				
			||||||
    peakWidth(sig, sigLeft, sigRight, 0, m_nbBins);
 | 
					    peakWidth(m_currentSpectrum, sig, sigLeft, sigRight, 0, m_nbBins);
 | 
				
			||||||
    int sigBins = sigRight - sigLeft - 1;
 | 
					    int sigBins = sigRight - sigLeft - 1;
 | 
				
			||||||
    int binsLeft = sig - sigLeft;
 | 
					    int binsLeft = sig - sigLeft;
 | 
				
			||||||
    int binsRight = sigRight - sig;
 | 
					    int binsRight = sigRight - sig;
 | 
				
			||||||
@ -2209,7 +2260,7 @@ void GLSpectrum::measureSNR()
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            hFreq = binToFrequency(hBin);
 | 
					            hFreq = binToFrequency(hBin);
 | 
				
			||||||
            int hLeft, hRight;
 | 
					            int hLeft, hRight;
 | 
				
			||||||
            peakWidth(hBin, hLeft, hRight, hBin - binsLeft, hBin + binsRight);
 | 
					            peakWidth(m_currentSpectrum, hBin, hLeft, hRight, hBin - binsLeft, hBin + binsRight);
 | 
				
			||||||
            int hBins = hRight - hLeft - 1;
 | 
					            int hBins = hRight - hLeft - 1;
 | 
				
			||||||
            if (m_measurementHighlight) {
 | 
					            if (m_measurementHighlight) {
 | 
				
			||||||
                drawPeakMarkers(binToFrequency(hLeft+1), binToFrequency(hRight-1), m_measurementDarkMarkerColor);
 | 
					                drawPeakMarkers(binToFrequency(hLeft+1), binToFrequency(hRight-1), m_measurementDarkMarkerColor);
 | 
				
			||||||
@ -2279,55 +2330,34 @@ void GLSpectrum::measureSNR()
 | 
				
			|||||||
        harmonicPower -= hNoise;
 | 
					        harmonicPower -= hNoise;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (m_measurement)
 | 
					    if (m_measurements)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    case SpectrumSettings::MeasurementSNR:
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        // Calculate SNR in dB over full bandwidth
 | 
					        // Calculate SNR in dB over full bandwidth
 | 
				
			||||||
        float snr = CalcDb::dbPower(sigPower / noisePower);
 | 
					        float snr = CalcDb::dbPower(sigPower / noisePower);
 | 
				
			||||||
        drawTextRight("SNR: ", QString::number(snr, 'f', 1), "100.0", "dB");
 | 
					
 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    case SpectrumSettings::MeasurementSNFR:
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        // Calculate SNR, where noise is median of noise summed over signal b/w
 | 
					        // Calculate SNR, where noise is median of noise summed over signal b/w
 | 
				
			||||||
        float snfr = CalcDb::dbPower(sigPower / inBandNoise);
 | 
					        float snfr = CalcDb::dbPower(sigPower / inBandNoise);
 | 
				
			||||||
        drawTextRight("SNFR: ", QString::number(snfr, 'f', 1), "100.0", "dB");
 | 
					
 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    case SpectrumSettings::MeasurementTHD:
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        // Calculate THD - Total harmonic distortion
 | 
					        // Calculate THD - Total harmonic distortion
 | 
				
			||||||
        float thd = harmonicPower / sigPower;
 | 
					        float thd = harmonicPower / sigPower;
 | 
				
			||||||
        float thdDB = CalcDb::dbPower(thd);
 | 
					        float thdDB = CalcDb::dbPower(thd);
 | 
				
			||||||
        drawTextRight("THD: ", QString::number(thdDB, 'f', 1), "-120.0", "dB");
 | 
					
 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    case SpectrumSettings::MeasurementTHDPN:
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        // Calculate THD+N - Total harmonic distortion plus noise
 | 
					        // Calculate THD+N - Total harmonic distortion plus noise
 | 
				
			||||||
        float thdpn = CalcDb::dbPower((harmonicPower + noisePower) / sigPower);
 | 
					        float thdpn = CalcDb::dbPower((harmonicPower + noisePower) / sigPower);
 | 
				
			||||||
        drawTextRight("THD+N: ", QString::number(thdpn, 'f', 1), "-120.0", "dB");
 | 
					
 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    case SpectrumSettings::MeasurementSINAD:
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        // Calculate SINAD - Signal to noise and distotion ratio (Should be -THD+N)
 | 
					        // Calculate SINAD - Signal to noise and distotion ratio (Should be -THD+N)
 | 
				
			||||||
        float sinad = CalcDb::dbPower((sigPower + harmonicPower + noisePower) / (harmonicPower + noisePower));
 | 
					        float sinad = CalcDb::dbPower((sigPower + harmonicPower + noisePower) / (harmonicPower + noisePower));
 | 
				
			||||||
        drawTextRight("SINAD: ", QString::number(sinad, 'f', 1), "120.0", "dB");
 | 
					
 | 
				
			||||||
        break;
 | 
					        m_measurements->setSNR(snr, snfr, thdDB, thdpn, sinad);
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GLSpectrum::measureSFDR()
 | 
					void GLSpectrum::measureSFDR()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // Find first peak which is our signal
 | 
					    // Find first peak which is our signal
 | 
				
			||||||
    int peakBin = findPeakBin();
 | 
					    int peakBin = findPeakBin(m_currentSpectrum);
 | 
				
			||||||
    int peakLeft, peakRight;
 | 
					    int peakLeft, peakRight;
 | 
				
			||||||
    peakWidth(peakBin, peakLeft, peakRight, 0, m_nbBins);
 | 
					    peakWidth(m_currentSpectrum, peakBin, peakLeft, peakRight, 0, m_nbBins);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Find next largest peak, which is the spur
 | 
					    // Find next largest peak, which is the spur
 | 
				
			||||||
    int nextPeakBin = -1;
 | 
					    int nextPeakBin = -1;
 | 
				
			||||||
@ -2353,13 +2383,15 @@ void GLSpectrum::measureSFDR()
 | 
				
			|||||||
        float sfdr = peakPowerDB - nextPeakPowerDB;
 | 
					        float sfdr = peakPowerDB - nextPeakPowerDB;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Display
 | 
					        // Display
 | 
				
			||||||
        drawTextRight("SFDR: ", QString::number(sfdr, 'f', 1), "100.0", "dB");
 | 
					        if (m_measurements) {
 | 
				
			||||||
 | 
					            m_measurements->setSFDR(sfdr);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        if (m_measurementHighlight)
 | 
					        if (m_measurementHighlight)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (m_linear) {
 | 
					            if (m_linear) {
 | 
				
			||||||
                drawPowerBandMarkers(peakPower, nextPeakPower, m_measurementLightMarkerColor);
 | 
					                drawPowerBandMarkers(peakPower, nextPeakPower, m_measurementDarkMarkerColor);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                drawPowerBandMarkers(peakPowerDB, nextPeakPowerDB, m_measurementLightMarkerColor);
 | 
					                drawPowerBandMarkers(peakPowerDB, nextPeakPowerDB, m_measurementDarkMarkerColor);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -4381,6 +4413,7 @@ int GLSpectrum::getPrecision(int value)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Draw text right justified in top info bar - currently unused
 | 
				
			||||||
void GLSpectrum::drawTextRight(const QString &text, const QString &value, const QString &max, const QString &units)
 | 
					void GLSpectrum::drawTextRight(const QString &text, const QString &value, const QString &max, const QString &units)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    drawTextsRight({text}, {value}, {max}, {units});
 | 
					    drawTextsRight({text}, {value}, {max}, {units});
 | 
				
			||||||
@ -4437,6 +4470,60 @@ void GLSpectrum::drawTextsRight(const QStringList &text, const QStringList &valu
 | 
				
			|||||||
    m_glShaderTextOverlay.drawSurface(m_glInfoBoxMatrix, tex1, vtx1, 4);
 | 
					    m_glShaderTextOverlay.drawSurface(m_glInfoBoxMatrix, tex1, vtx1, 4);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GLSpectrum::drawTextOverlayCentered (
 | 
				
			||||||
 | 
					    const QString &text,
 | 
				
			||||||
 | 
					    const QColor &color,
 | 
				
			||||||
 | 
					    const QFont& font,
 | 
				
			||||||
 | 
					    float shiftX,
 | 
				
			||||||
 | 
					    float shiftY,
 | 
				
			||||||
 | 
					    const QRectF &glRect)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (text.isEmpty()) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QFontMetricsF metrics(font);
 | 
				
			||||||
 | 
					    QRectF textRect = metrics.boundingRect(text);
 | 
				
			||||||
 | 
					    QRectF overlayRect(0, 0, textRect.width() * 1.05f + 4.0f, textRect.height());
 | 
				
			||||||
 | 
					    QPixmap channelOverlayPixmap = QPixmap(overlayRect.width(), overlayRect.height());
 | 
				
			||||||
 | 
					    channelOverlayPixmap.fill(Qt::transparent);
 | 
				
			||||||
 | 
					    QPainter painter(&channelOverlayPixmap);
 | 
				
			||||||
 | 
					    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing, false);
 | 
				
			||||||
 | 
					    painter.fillRect(overlayRect, QColor(0, 0, 0, 0x80));
 | 
				
			||||||
 | 
					    QColor textColor(color);
 | 
				
			||||||
 | 
					    textColor.setAlpha(0xC0);
 | 
				
			||||||
 | 
					    painter.setPen(textColor);
 | 
				
			||||||
 | 
					    painter.setFont(font);
 | 
				
			||||||
 | 
					    painter.drawText(QPointF(2.0f, overlayRect.height() - 4.0f), text);
 | 
				
			||||||
 | 
					    painter.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    m_glShaderTextOverlay.initTexture(channelOverlayPixmap.toImage());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        GLfloat vtx1[] = {
 | 
				
			||||||
 | 
					            0, 1,
 | 
				
			||||||
 | 
					            1, 1,
 | 
				
			||||||
 | 
					            1, 0,
 | 
				
			||||||
 | 
					            0, 0};
 | 
				
			||||||
 | 
					        GLfloat tex1[] = {
 | 
				
			||||||
 | 
					            0, 1,
 | 
				
			||||||
 | 
					            1, 1,
 | 
				
			||||||
 | 
					            1, 0,
 | 
				
			||||||
 | 
					            0, 0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        float rectX = glRect.x() + shiftX - ((overlayRect.width()/2)/width());
 | 
				
			||||||
 | 
					        float rectY = glRect.y() + shiftY + (4.0f / height()) - ((overlayRect.height()+5)/height());
 | 
				
			||||||
 | 
					        float rectW = overlayRect.width() / (float) width();
 | 
				
			||||||
 | 
					        float rectH = overlayRect.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_glShaderTextOverlay.drawSurface(mat, tex1, vtx1, 4);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GLSpectrum::drawTextOverlay(
 | 
					void GLSpectrum::drawTextOverlay(
 | 
				
			||||||
    const QString &text,
 | 
					    const QString &text,
 | 
				
			||||||
    const QColor &color,
 | 
					    const QColor &color,
 | 
				
			||||||
@ -4516,9 +4603,6 @@ void GLSpectrum::formatTextInfo(QString& info)
 | 
				
			|||||||
        getFrequencyZoom(centerFrequency, frequencySpan);
 | 
					        getFrequencyZoom(centerFrequency, frequencySpan);
 | 
				
			||||||
        info.append(tr("CF:%1 ").arg(displayScaled(centerFrequency, 'f', getPrecision(centerFrequency/frequencySpan), true)));
 | 
					        info.append(tr("CF:%1 ").arg(displayScaled(centerFrequency, 'f', getPrecision(centerFrequency/frequencySpan), true)));
 | 
				
			||||||
        info.append(tr("SP:%1 ").arg(displayScaled(frequencySpan, 'f', 3, true)));
 | 
					        info.append(tr("SP:%1 ").arg(displayScaled(frequencySpan, 'f', 3, true)));
 | 
				
			||||||
        if (m_measurement != SpectrumSettings::MeasurementNone) {
 | 
					 | 
				
			||||||
            info.append(tr("RBW:%1 ").arg(displayScaled(m_sampleRate / (float)m_fftSize, 'f', 3, true)));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -48,6 +48,7 @@ class QOpenGLShaderProgram;
 | 
				
			|||||||
class MessageQueue;
 | 
					class MessageQueue;
 | 
				
			||||||
class SpectrumVis;
 | 
					class SpectrumVis;
 | 
				
			||||||
class QOpenGLDebugLogger;
 | 
					class QOpenGLDebugLogger;
 | 
				
			||||||
 | 
					class SpectrumMeasurements;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SDRGUI_API GLSpectrum : public QOpenGLWidget, public GLSpectrumInterface {
 | 
					class SDRGUI_API GLSpectrum : public QOpenGLWidget, public GLSpectrumInterface {
 | 
				
			||||||
    Q_OBJECT
 | 
					    Q_OBJECT
 | 
				
			||||||
@ -161,9 +162,10 @@ public:
 | 
				
			|||||||
    void setDisplayTraceIntensity(int intensity);
 | 
					    void setDisplayTraceIntensity(int intensity);
 | 
				
			||||||
    void setLinear(bool linear);
 | 
					    void setLinear(bool linear);
 | 
				
			||||||
    void setUseCalibration(bool useCalibration);
 | 
					    void setUseCalibration(bool useCalibration);
 | 
				
			||||||
    void setMeasurementParams(SpectrumSettings::Measurement measurement, int bandwidth,
 | 
					    void setMeasurements(SpectrumMeasurements *measurements) { m_measurements = measurements; }
 | 
				
			||||||
                              int chSpacing, int adjChBandwidth,
 | 
					    void setMeasurementParams(bool measure, SpectrumSettings::Measurement measurement,
 | 
				
			||||||
                              int harmonics, bool highlight);
 | 
					                              int bandwidth, int chSpacing, int adjChBandwidth,
 | 
				
			||||||
 | 
					                              int harmonics, int peaks, bool highlight);
 | 
				
			||||||
    qint32 getSampleRate() const { return m_sampleRate; }
 | 
					    qint32 getSampleRate() const { return m_sampleRate; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void addChannelMarker(ChannelMarker* channelMarker);
 | 
					    void addChannelMarker(ChannelMarker* channelMarker);
 | 
				
			||||||
@ -375,11 +377,14 @@ private:
 | 
				
			|||||||
    QOpenGLDebugLogger *m_openGLLogger;
 | 
					    QOpenGLDebugLogger *m_openGLLogger;
 | 
				
			||||||
    bool m_isDeviceSpectrum;
 | 
					    bool m_isDeviceSpectrum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SpectrumMeasurements *m_measurements;
 | 
				
			||||||
 | 
					    bool m_measure;
 | 
				
			||||||
    SpectrumSettings::Measurement m_measurement;
 | 
					    SpectrumSettings::Measurement m_measurement;
 | 
				
			||||||
    int m_measurementBandwidth;
 | 
					    int m_measurementBandwidth;
 | 
				
			||||||
    int m_measurementChSpacing;
 | 
					    int m_measurementChSpacing;
 | 
				
			||||||
    int m_measurementAdjChBandwidth;
 | 
					    int m_measurementAdjChBandwidth;
 | 
				
			||||||
    int m_measurementHarmonics;
 | 
					    int m_measurementHarmonics;
 | 
				
			||||||
 | 
					    int m_measurementPeaks;
 | 
				
			||||||
    bool m_measurementHighlight;
 | 
					    bool m_measurementHighlight;
 | 
				
			||||||
    static const QVector4D m_measurementLightMarkerColor;
 | 
					    static const QVector4D m_measurementLightMarkerColor;
 | 
				
			||||||
    static const QVector4D m_measurementDarkMarkerColor;
 | 
					    static const QVector4D m_measurementDarkMarkerColor;
 | 
				
			||||||
@ -398,15 +403,16 @@ private:
 | 
				
			|||||||
    void drawAnnotationMarkers();
 | 
					    void drawAnnotationMarkers();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void measurePeak();
 | 
					    void measurePeak();
 | 
				
			||||||
 | 
					    void measurePeaks();
 | 
				
			||||||
    void measureChannelPower();
 | 
					    void measureChannelPower();
 | 
				
			||||||
    void measureAdjacentChannelPower();
 | 
					    void measureAdjacentChannelPower();
 | 
				
			||||||
    void measureSNR();
 | 
					    void measureSNR();
 | 
				
			||||||
    void measureSFDR();
 | 
					    void measureSFDR();
 | 
				
			||||||
    float calcChannelPower(int64_t centerFrequency, int channelBandwidth) const;
 | 
					    float calcChannelPower(int64_t centerFrequency, int channelBandwidth) const;
 | 
				
			||||||
    float calPower(float power) const;
 | 
					    float calPower(float power) const;
 | 
				
			||||||
    int findPeakBin() const;
 | 
					    int findPeakBin(const Real *spectrum) const;
 | 
				
			||||||
    void findPeak(float &power, float &frequency) const;
 | 
					    void findPeak(float &power, float &frequency) const;
 | 
				
			||||||
    void peakWidth(int center, int &left, int &right, int maxLeft, int maxRight) const;
 | 
					    void peakWidth(const Real *spectrum, int center, int &left, int &right, int maxLeft, int maxRight) const;
 | 
				
			||||||
    int frequencyToBin(int64_t frequency) const;
 | 
					    int frequencyToBin(int64_t frequency) const;
 | 
				
			||||||
    int64_t binToFrequency(int bin) const;
 | 
					    int64_t binToFrequency(int bin) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -441,6 +447,13 @@ private:
 | 
				
			|||||||
    int getPrecision(int value);
 | 
					    int getPrecision(int value);
 | 
				
			||||||
    void drawTextRight(const QString &text, const QString &value, const QString &max, const QString &units);
 | 
					    void drawTextRight(const QString &text, const QString &value, const QString &max, const QString &units);
 | 
				
			||||||
    void drawTextsRight(const QStringList &text, const QStringList &value, const QStringList &max, const QStringList &units);
 | 
					    void drawTextsRight(const QStringList &text, const QStringList &value, const QStringList &max, const QStringList &units);
 | 
				
			||||||
 | 
					    void drawTextOverlayCentered(
 | 
				
			||||||
 | 
					            const QString& text,
 | 
				
			||||||
 | 
					            const QColor& color,
 | 
				
			||||||
 | 
					            const QFont& font,
 | 
				
			||||||
 | 
					            float shiftX,
 | 
				
			||||||
 | 
					            float shiftY,
 | 
				
			||||||
 | 
					            const QRectF& glRect);
 | 
				
			||||||
    void drawTextOverlay(      //!< Draws a text overlay
 | 
					    void drawTextOverlay(      //!< Draws a text overlay
 | 
				
			||||||
            const QString& text,
 | 
					            const QString& text,
 | 
				
			||||||
            const QColor& color,
 | 
					            const QColor& color,
 | 
				
			||||||
 | 
				
			|||||||
@ -28,10 +28,12 @@
 | 
				
			|||||||
#include "dsp/fftwindow.h"
 | 
					#include "dsp/fftwindow.h"
 | 
				
			||||||
#include "dsp/spectrumvis.h"
 | 
					#include "dsp/spectrumvis.h"
 | 
				
			||||||
#include "gui/glspectrum.h"
 | 
					#include "gui/glspectrum.h"
 | 
				
			||||||
 | 
					#include "gui/glspectrumtop.h"
 | 
				
			||||||
#include "gui/crightclickenabler.h"
 | 
					#include "gui/crightclickenabler.h"
 | 
				
			||||||
#include "gui/wsspectrumsettingsdialog.h"
 | 
					#include "gui/wsspectrumsettingsdialog.h"
 | 
				
			||||||
#include "gui/spectrummarkersdialog.h"
 | 
					#include "gui/spectrummarkersdialog.h"
 | 
				
			||||||
#include "gui/spectrumcalibrationpointsdialog.h"
 | 
					#include "gui/spectrumcalibrationpointsdialog.h"
 | 
				
			||||||
 | 
					#include "gui/spectrummeasurements.h"
 | 
				
			||||||
#include "gui/flowlayout.h"
 | 
					#include "gui/flowlayout.h"
 | 
				
			||||||
#include "util/colormap.h"
 | 
					#include "util/colormap.h"
 | 
				
			||||||
#include "util/simpleserializer.h"
 | 
					#include "util/simpleserializer.h"
 | 
				
			||||||
@ -45,6 +47,7 @@ GLSpectrumGUI::GLSpectrumGUI(QWidget* parent) :
 | 
				
			|||||||
    ui(new Ui::GLSpectrumGUI),
 | 
					    ui(new Ui::GLSpectrumGUI),
 | 
				
			||||||
    m_spectrumVis(nullptr),
 | 
					    m_spectrumVis(nullptr),
 | 
				
			||||||
    m_glSpectrum(nullptr),
 | 
					    m_glSpectrum(nullptr),
 | 
				
			||||||
 | 
					    m_glSpectrumTop(nullptr),
 | 
				
			||||||
    m_doApplySettings(true),
 | 
					    m_doApplySettings(true),
 | 
				
			||||||
    m_calibrationShiftdB(0.0)
 | 
					    m_calibrationShiftdB(0.0)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -69,7 +72,7 @@ GLSpectrumGUI::GLSpectrumGUI(QWidget* parent) :
 | 
				
			|||||||
    ui->verticalLayout->addItem(flowLayout);
 | 
					    ui->verticalLayout->addItem(flowLayout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    on_linscale_toggled(false);
 | 
					    on_linscale_toggled(false);
 | 
				
			||||||
    on_measurement_currentIndexChanged(0);
 | 
					    displayMeasurementGUI();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QString levelStyle = QString(
 | 
					    QString levelStyle = QString(
 | 
				
			||||||
        "QSpinBox {background-color: rgb(79, 79, 79);}"
 | 
					        "QSpinBox {background-color: rgb(79, 79, 79);}"
 | 
				
			||||||
@ -101,13 +104,14 @@ GLSpectrumGUI::~GLSpectrumGUI()
 | 
				
			|||||||
    delete ui;
 | 
					    delete ui;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GLSpectrumGUI::setBuddies(SpectrumVis* spectrumVis, GLSpectrum* glSpectrum)
 | 
					void GLSpectrumGUI::setBuddies(SpectrumVis* spectrumVis, GLSpectrum* glSpectrum, GLSpectrumTop *glSpectrumTop)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    m_spectrumVis = spectrumVis;
 | 
					    m_spectrumVis = spectrumVis;
 | 
				
			||||||
    m_glSpectrum = glSpectrum;
 | 
					    m_glSpectrum = glSpectrum;
 | 
				
			||||||
    m_glSpectrum->setSpectrumVis(spectrumVis);
 | 
					    m_glSpectrum->setSpectrumVis(spectrumVis);
 | 
				
			||||||
    m_glSpectrum->setMessageQueueToGUI(&m_messageQueue);
 | 
					    m_glSpectrum->setMessageQueueToGUI(&m_messageQueue);
 | 
				
			||||||
    m_spectrumVis->setMessageQueueToGUI(&m_messageQueue);
 | 
					    m_spectrumVis->setMessageQueueToGUI(&m_messageQueue);
 | 
				
			||||||
 | 
					    m_glSpectrumTop = glSpectrumTop;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GLSpectrumGUI::resetToDefaults()
 | 
					void GLSpectrumGUI::resetToDefaults()
 | 
				
			||||||
@ -229,12 +233,15 @@ void GLSpectrumGUI::displaySettings()
 | 
				
			|||||||
    ui->calibration->setChecked(m_settings.m_useCalibration);
 | 
					    ui->calibration->setChecked(m_settings.m_useCalibration);
 | 
				
			||||||
    displayGotoMarkers();
 | 
					    displayGotoMarkers();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ui->measure->setChecked(m_settings.m_measure);
 | 
				
			||||||
    ui->measurement->setCurrentIndex((int) m_settings.m_measurement);
 | 
					    ui->measurement->setCurrentIndex((int) m_settings.m_measurement);
 | 
				
			||||||
    ui->highlight->setChecked(m_settings.m_measurementHighlight);
 | 
					    ui->highlight->setChecked(m_settings.m_measurementHighlight);
 | 
				
			||||||
    ui->bandwidth->setValue(m_settings.m_measurementBandwidth);
 | 
					    ui->bandwidth->setValue(m_settings.m_measurementBandwidth);
 | 
				
			||||||
    ui->chSpacing->setValue(m_settings.m_measurementChSpacing);
 | 
					    ui->chSpacing->setValue(m_settings.m_measurementChSpacing);
 | 
				
			||||||
    ui->adjChBandwidth->setValue(m_settings.m_measurementAdjChBandwidth);
 | 
					    ui->adjChBandwidth->setValue(m_settings.m_measurementAdjChBandwidth);
 | 
				
			||||||
    ui->harmonics->setValue(m_settings.m_measurementHarmonics);
 | 
					    ui->harmonics->setValue(m_settings.m_measurementHarmonics);
 | 
				
			||||||
 | 
					    ui->peaks->setValue(m_settings.m_measurementPeaks);
 | 
				
			||||||
 | 
					    displayMeasurementGUI();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ui->fftWindow->blockSignals(false);
 | 
					    ui->fftWindow->blockSignals(false);
 | 
				
			||||||
    ui->averaging->blockSignals(false);
 | 
					    ui->averaging->blockSignals(false);
 | 
				
			||||||
@ -344,11 +351,13 @@ void GLSpectrumGUI::applySpectrumSettings()
 | 
				
			|||||||
    m_glSpectrum->setCalibrationInterpMode(m_settings.m_calibrationInterpMode);
 | 
					    m_glSpectrum->setCalibrationInterpMode(m_settings.m_calibrationInterpMode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    m_glSpectrum->setMeasurementParams(
 | 
					    m_glSpectrum->setMeasurementParams(
 | 
				
			||||||
 | 
					        m_settings.m_measure,
 | 
				
			||||||
        m_settings.m_measurement,
 | 
					        m_settings.m_measurement,
 | 
				
			||||||
        m_settings.m_measurementBandwidth,
 | 
					        m_settings.m_measurementBandwidth,
 | 
				
			||||||
        m_settings.m_measurementChSpacing,
 | 
					        m_settings.m_measurementChSpacing,
 | 
				
			||||||
        m_settings.m_measurementAdjChBandwidth,
 | 
					        m_settings.m_measurementAdjChBandwidth,
 | 
				
			||||||
        m_settings.m_measurementHarmonics,
 | 
					        m_settings.m_measurementHarmonics,
 | 
				
			||||||
 | 
					        m_settings.m_measurementPeaks,
 | 
				
			||||||
        m_settings.m_measurementHighlight
 | 
					        m_settings.m_measurementHighlight
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1027,29 +1036,51 @@ void GLSpectrumGUI::updateCalibrationPoints()
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GLSpectrumGUI::on_measurement_currentIndexChanged(int index)
 | 
					void GLSpectrumGUI::displayMeasurementGUI()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    m_settings.m_measurement = (SpectrumSettings::Measurement)index;
 | 
					    bool show = m_settings.m_measure;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool highlight = (m_settings.m_measurement >= SpectrumSettings::MeasurementChannelPower);
 | 
					    if (m_glSpectrumTop) {
 | 
				
			||||||
    ui->highlight->setVisible(highlight);
 | 
					        m_glSpectrumTop->setMeasurementsVisible(show);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ui->measurement->setVisible(show);
 | 
				
			||||||
 | 
					    ui->highlight->setVisible(show);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool reset = (m_settings.m_measurement >= SpectrumSettings::MeasurementChannelPower);
 | 
				
			||||||
 | 
					    ui->resetMeasurements->setVisible(reset && show);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool bw = (m_settings.m_measurement == SpectrumSettings::MeasurementChannelPower)
 | 
					    bool bw = (m_settings.m_measurement == SpectrumSettings::MeasurementChannelPower)
 | 
				
			||||||
               || (m_settings.m_measurement == SpectrumSettings::MeasurementAdjacentChannelPower);
 | 
					               || (m_settings.m_measurement == SpectrumSettings::MeasurementAdjacentChannelPower);
 | 
				
			||||||
    ui->bandwidthLabel->setVisible(bw);
 | 
					    ui->bandwidthLabel->setVisible(bw && show);
 | 
				
			||||||
    ui->bandwidth->setVisible(bw);
 | 
					    ui->bandwidth->setVisible(bw && show);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool adj = m_settings.m_measurement == SpectrumSettings::MeasurementAdjacentChannelPower;
 | 
					    bool adj = m_settings.m_measurement == SpectrumSettings::MeasurementAdjacentChannelPower;
 | 
				
			||||||
    ui->chSpacingLabel->setVisible(adj);
 | 
					    ui->chSpacingLabel->setVisible(adj && show);
 | 
				
			||||||
    ui->chSpacing->setVisible(adj);
 | 
					    ui->chSpacing->setVisible(adj && show);
 | 
				
			||||||
    ui->adjChBandwidthLabel->setVisible(adj);
 | 
					    ui->adjChBandwidthLabel->setVisible(adj && show);
 | 
				
			||||||
    ui->adjChBandwidth->setVisible(adj);
 | 
					    ui->adjChBandwidth->setVisible(adj && show);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool harmonics = (m_settings.m_measurement >= SpectrumSettings::MeasurementSNR)
 | 
					    bool harmonics = (m_settings.m_measurement == SpectrumSettings::MeasurementSNR);
 | 
				
			||||||
                    && (m_settings.m_measurement <= SpectrumSettings::MeasurementSINAD);
 | 
					    ui->harmonicsLabel->setVisible(harmonics && show);
 | 
				
			||||||
    ui->harmonicsLabel->setVisible(harmonics);
 | 
					    ui->harmonics->setVisible(harmonics && show);
 | 
				
			||||||
    ui->harmonics->setVisible(harmonics);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool peaks = (m_settings.m_measurement == SpectrumSettings::MeasurementPeaks);
 | 
				
			||||||
 | 
					    ui->peaksLabel->setVisible(peaks && show);
 | 
				
			||||||
 | 
					    ui->peaks->setVisible(peaks && show);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GLSpectrumGUI::on_measure_clicked(bool checked)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    m_settings.m_measure = checked;
 | 
				
			||||||
 | 
					    displayMeasurementGUI();
 | 
				
			||||||
 | 
					    applySettings();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GLSpectrumGUI::on_measurement_currentIndexChanged(int index)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    m_settings.m_measurement = (SpectrumSettings::Measurement)index;
 | 
				
			||||||
 | 
					    displayMeasurementGUI();
 | 
				
			||||||
    applySettings();
 | 
					    applySettings();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1059,6 +1090,15 @@ void GLSpectrumGUI::on_highlight_toggled(bool checked)
 | 
				
			|||||||
    applySettings();
 | 
					    applySettings();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GLSpectrumGUI::on_resetMeasurements_clicked(bool checked)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void) checked;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (m_glSpectrumTop) {
 | 
				
			||||||
 | 
					        m_glSpectrumTop->getMeasurements()->reset();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GLSpectrumGUI::on_bandwidth_valueChanged(int value)
 | 
					void GLSpectrumGUI::on_bandwidth_valueChanged(int value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    m_settings.m_measurementBandwidth = value;
 | 
					    m_settings.m_measurementBandwidth = value;
 | 
				
			||||||
@ -1082,3 +1122,9 @@ void GLSpectrumGUI::on_harmonics_valueChanged(int value)
 | 
				
			|||||||
    m_settings.m_measurementHarmonics = value;
 | 
					    m_settings.m_measurementHarmonics = value;
 | 
				
			||||||
    applySettings();
 | 
					    applySettings();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GLSpectrumGUI::on_peaks_valueChanged(int value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    m_settings.m_measurementPeaks = value;
 | 
				
			||||||
 | 
					    applySettings();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -36,6 +36,7 @@ namespace Ui {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class SpectrumVis;
 | 
					class SpectrumVis;
 | 
				
			||||||
class GLSpectrum;
 | 
					class GLSpectrum;
 | 
				
			||||||
 | 
					class GLSpectrumTop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SDRGUI_API GLSpectrumGUI : public QWidget, public Serializable {
 | 
					class SDRGUI_API GLSpectrumGUI : public QWidget, public Serializable {
 | 
				
			||||||
	Q_OBJECT
 | 
						Q_OBJECT
 | 
				
			||||||
@ -52,7 +53,7 @@ public:
 | 
				
			|||||||
	explicit GLSpectrumGUI(QWidget* parent = NULL);
 | 
						explicit GLSpectrumGUI(QWidget* parent = NULL);
 | 
				
			||||||
	~GLSpectrumGUI();
 | 
						~GLSpectrumGUI();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void setBuddies(SpectrumVis* spectrumVis, GLSpectrum* glSpectrum);
 | 
						void setBuddies(SpectrumVis* spectrumVis, GLSpectrum* glSpectrum, GLSpectrumTop *glSpectrumTop = nullptr);
 | 
				
			||||||
    void setFFTSize(int log2FFTSize);
 | 
					    void setFFTSize(int log2FFTSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void resetToDefaults();
 | 
						void resetToDefaults();
 | 
				
			||||||
@ -67,6 +68,7 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	SpectrumVis* m_spectrumVis;
 | 
						SpectrumVis* m_spectrumVis;
 | 
				
			||||||
	GLSpectrum* m_glSpectrum;
 | 
						GLSpectrum* m_glSpectrum;
 | 
				
			||||||
 | 
					    GLSpectrumTop* m_glSpectrumTop;
 | 
				
			||||||
	MessageQueue m_messageQueue;
 | 
						MessageQueue m_messageQueue;
 | 
				
			||||||
    SpectrumSettings m_settings;
 | 
					    SpectrumSettings m_settings;
 | 
				
			||||||
    bool m_doApplySettings;
 | 
					    bool m_doApplySettings;
 | 
				
			||||||
@ -86,6 +88,7 @@ private:
 | 
				
			|||||||
	bool handleMessage(const Message& message);
 | 
						bool handleMessage(const Message& message);
 | 
				
			||||||
    void displayGotoMarkers();
 | 
					    void displayGotoMarkers();
 | 
				
			||||||
    QString displayScaled(int64_t value, char type, int precision, bool showMult);
 | 
					    QString displayScaled(int64_t value, char type, int precision, bool showMult);
 | 
				
			||||||
 | 
					    void displayMeasurementGUI();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private slots:
 | 
					private slots:
 | 
				
			||||||
	void on_fftWindow_currentIndexChanged(int index);
 | 
						void on_fftWindow_currentIndexChanged(int index);
 | 
				
			||||||
@ -123,12 +126,15 @@ private slots:
 | 
				
			|||||||
	void on_calibration_toggled(bool checked);
 | 
						void on_calibration_toggled(bool checked);
 | 
				
			||||||
    void on_gotoMarker_currentIndexChanged(int index);
 | 
					    void on_gotoMarker_currentIndexChanged(int index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void on_measure_clicked(bool checked);
 | 
				
			||||||
    void on_measurement_currentIndexChanged(int index);
 | 
					    void on_measurement_currentIndexChanged(int index);
 | 
				
			||||||
    void on_highlight_toggled(bool checked);
 | 
					    void on_highlight_toggled(bool checked);
 | 
				
			||||||
 | 
					    void on_resetMeasurements_clicked(bool checked);
 | 
				
			||||||
    void on_bandwidth_valueChanged(int value);
 | 
					    void on_bandwidth_valueChanged(int value);
 | 
				
			||||||
    void on_chSpacing_valueChanged(int value);
 | 
					    void on_chSpacing_valueChanged(int value);
 | 
				
			||||||
    void on_adjChBandwidth_valueChanged(int value);
 | 
					    void on_adjChBandwidth_valueChanged(int value);
 | 
				
			||||||
    void on_harmonics_valueChanged(int value);
 | 
					    void on_harmonics_valueChanged(int value);
 | 
				
			||||||
 | 
					    void on_peaks_valueChanged(int value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void handleInputMessages();
 | 
						void handleInputMessages();
 | 
				
			||||||
    void openWebsocketSpectrumSettingsDialog(const QPoint& p);
 | 
					    void openWebsocketSpectrumSettingsDialog(const QPoint& p);
 | 
				
			||||||
 | 
				
			|||||||
@ -1073,6 +1073,20 @@
 | 
				
			|||||||
       </property>
 | 
					       </property>
 | 
				
			||||||
      </widget>
 | 
					      </widget>
 | 
				
			||||||
     </item>
 | 
					     </item>
 | 
				
			||||||
 | 
					     <item>
 | 
				
			||||||
 | 
					      <widget class="ButtonSwitch" name="measure">
 | 
				
			||||||
 | 
					       <property name="toolTip">
 | 
				
			||||||
 | 
					        <string>Display measurements</string>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
 | 
					       <property name="icon">
 | 
				
			||||||
 | 
					        <iconset resource="../resources/res.qrc">
 | 
				
			||||||
 | 
					         <normaloff>:/ruler.png</normaloff>:/ruler.png</iconset>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
 | 
					       <property name="checkable">
 | 
				
			||||||
 | 
					        <bool>true</bool>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
 | 
					      </widget>
 | 
				
			||||||
 | 
					     </item>
 | 
				
			||||||
     <item>
 | 
					     <item>
 | 
				
			||||||
      <widget class="ButtonSwitch" name="calibration">
 | 
					      <widget class="ButtonSwitch" name="calibration">
 | 
				
			||||||
       <property name="toolTip">
 | 
					       <property name="toolTip">
 | 
				
			||||||
@ -1139,14 +1153,12 @@
 | 
				
			|||||||
       <property name="toolTip">
 | 
					       <property name="toolTip">
 | 
				
			||||||
        <string>Measurement</string>
 | 
					        <string>Measurement</string>
 | 
				
			||||||
       </property>
 | 
					       </property>
 | 
				
			||||||
 | 
					       <property name="currentIndex">
 | 
				
			||||||
 | 
					        <number>-1</number>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
       <item>
 | 
					       <item>
 | 
				
			||||||
        <property name="text">
 | 
					        <property name="text">
 | 
				
			||||||
         <string>None</string>
 | 
					         <string>Peaks</string>
 | 
				
			||||||
        </property>
 | 
					 | 
				
			||||||
       </item>
 | 
					 | 
				
			||||||
       <item>
 | 
					 | 
				
			||||||
        <property name="text">
 | 
					 | 
				
			||||||
         <string>Peak</string>
 | 
					 | 
				
			||||||
        </property>
 | 
					        </property>
 | 
				
			||||||
       </item>
 | 
					       </item>
 | 
				
			||||||
       <item>
 | 
					       <item>
 | 
				
			||||||
@ -1164,31 +1176,6 @@
 | 
				
			|||||||
         <string>SNR</string>
 | 
					         <string>SNR</string>
 | 
				
			||||||
        </property>
 | 
					        </property>
 | 
				
			||||||
       </item>
 | 
					       </item>
 | 
				
			||||||
       <item>
 | 
					 | 
				
			||||||
        <property name="text">
 | 
					 | 
				
			||||||
         <string>SNFR</string>
 | 
					 | 
				
			||||||
        </property>
 | 
					 | 
				
			||||||
       </item>
 | 
					 | 
				
			||||||
       <item>
 | 
					 | 
				
			||||||
        <property name="text">
 | 
					 | 
				
			||||||
         <string>THD</string>
 | 
					 | 
				
			||||||
        </property>
 | 
					 | 
				
			||||||
       </item>
 | 
					 | 
				
			||||||
       <item>
 | 
					 | 
				
			||||||
        <property name="text">
 | 
					 | 
				
			||||||
         <string>THD+N</string>
 | 
					 | 
				
			||||||
        </property>
 | 
					 | 
				
			||||||
       </item>
 | 
					 | 
				
			||||||
       <item>
 | 
					 | 
				
			||||||
        <property name="text">
 | 
					 | 
				
			||||||
         <string>SINAD</string>
 | 
					 | 
				
			||||||
        </property>
 | 
					 | 
				
			||||||
       </item>
 | 
					 | 
				
			||||||
       <item>
 | 
					 | 
				
			||||||
        <property name="text">
 | 
					 | 
				
			||||||
         <string>SFDR</string>
 | 
					 | 
				
			||||||
        </property>
 | 
					 | 
				
			||||||
       </item>
 | 
					 | 
				
			||||||
      </widget>
 | 
					      </widget>
 | 
				
			||||||
     </item>
 | 
					     </item>
 | 
				
			||||||
     <item>
 | 
					     <item>
 | 
				
			||||||
@ -1214,6 +1201,20 @@
 | 
				
			|||||||
       </property>
 | 
					       </property>
 | 
				
			||||||
      </widget>
 | 
					      </widget>
 | 
				
			||||||
     </item>
 | 
					     </item>
 | 
				
			||||||
 | 
					     <item>
 | 
				
			||||||
 | 
					      <widget class="QToolButton" name="resetMeasurements">
 | 
				
			||||||
 | 
					       <property name="toolTip">
 | 
				
			||||||
 | 
					        <string>Reset measurements</string>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
 | 
					       <property name="text">
 | 
				
			||||||
 | 
					        <string/>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
 | 
					       <property name="icon">
 | 
				
			||||||
 | 
					        <iconset resource="../resources/res.qrc">
 | 
				
			||||||
 | 
					         <normaloff>:/bin.png</normaloff>:/bin.png</iconset>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
 | 
					      </widget>
 | 
				
			||||||
 | 
					     </item>
 | 
				
			||||||
     <item>
 | 
					     <item>
 | 
				
			||||||
      <widget class="QLabel" name="bandwidthLabel">
 | 
					      <widget class="QLabel" name="bandwidthLabel">
 | 
				
			||||||
       <property name="text">
 | 
					       <property name="text">
 | 
				
			||||||
@ -1309,6 +1310,26 @@
 | 
				
			|||||||
       </property>
 | 
					       </property>
 | 
				
			||||||
      </widget>
 | 
					      </widget>
 | 
				
			||||||
     </item>
 | 
					     </item>
 | 
				
			||||||
 | 
					     <item>
 | 
				
			||||||
 | 
					      <widget class="QLabel" name="peaksLabel">
 | 
				
			||||||
 | 
					       <property name="text">
 | 
				
			||||||
 | 
					        <string>Peaks</string>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
 | 
					      </widget>
 | 
				
			||||||
 | 
					     </item>
 | 
				
			||||||
 | 
					     <item>
 | 
				
			||||||
 | 
					      <widget class="QSpinBox" name="peaks">
 | 
				
			||||||
 | 
					       <property name="toolTip">
 | 
				
			||||||
 | 
					        <string>Number of peaks to display</string>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
 | 
					       <property name="minimum">
 | 
				
			||||||
 | 
					        <number>1</number>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
 | 
					       <property name="maximum">
 | 
				
			||||||
 | 
					        <number>20</number>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
 | 
					      </widget>
 | 
				
			||||||
 | 
					     </item>
 | 
				
			||||||
    </layout>
 | 
					    </layout>
 | 
				
			||||||
   </item>
 | 
					   </item>
 | 
				
			||||||
  </layout>
 | 
					  </layout>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										51
									
								
								sdrgui/gui/glspectrumtop.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								sdrgui/gui/glspectrumtop.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					///////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					// Copyright (C) 2022 Jon Beniston, M7RCE                                        //
 | 
				
			||||||
 | 
					//                                                                               //
 | 
				
			||||||
 | 
					// This program is free software; you can redistribute it and/or modify          //
 | 
				
			||||||
 | 
					// it under the terms of the GNU General Public License as published by          //
 | 
				
			||||||
 | 
					// the Free Software Foundation as version 3 of the License, or                  //
 | 
				
			||||||
 | 
					// (at your option) any later version.                                           //
 | 
				
			||||||
 | 
					//                                                                               //
 | 
				
			||||||
 | 
					// This program is distributed in the hope that it will be useful,               //
 | 
				
			||||||
 | 
					// but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | 
				
			||||||
 | 
					// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | 
				
			||||||
 | 
					// GNU General Public License V3 for more details.                               //
 | 
				
			||||||
 | 
					//                                                                               //
 | 
				
			||||||
 | 
					// You should have received a copy of the GNU General Public License             //
 | 
				
			||||||
 | 
					// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
				
			||||||
 | 
					///////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QMainWindow>
 | 
				
			||||||
 | 
					#include <QDockWidget>
 | 
				
			||||||
 | 
					#include <QSplitter>
 | 
				
			||||||
 | 
					#include <QVBoxLayout>
 | 
				
			||||||
 | 
					#include <QLabel>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "gui/glspectrum.h"
 | 
				
			||||||
 | 
					#include "gui/glspectrumtop.h"
 | 
				
			||||||
 | 
					#include "gui/spectrummeasurements.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GLSpectrumTop::GLSpectrumTop(QWidget *parent) :
 | 
				
			||||||
 | 
					    QWidget(parent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    m_mainWindow = new QMainWindow();
 | 
				
			||||||
 | 
					    m_dock = new QDockWidget();
 | 
				
			||||||
 | 
					    m_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
 | 
				
			||||||
 | 
					    //m_dock->setTitleBarWidget(new QLabel("Measurements")); // Could add device or channel R:0 label and dock button?
 | 
				
			||||||
 | 
					    m_dock->setVisible(false);
 | 
				
			||||||
 | 
					    m_spectrum = new GLSpectrum();
 | 
				
			||||||
 | 
					    m_measurements = new SpectrumMeasurements();
 | 
				
			||||||
 | 
					    m_spectrum->setMeasurements(m_measurements);
 | 
				
			||||||
 | 
					    m_dock->setWidget(m_measurements);
 | 
				
			||||||
 | 
					    m_mainWindow->setCentralWidget(m_spectrum);
 | 
				
			||||||
 | 
					    m_mainWindow->addDockWidget(Qt::BottomDockWidgetArea, m_dock);
 | 
				
			||||||
 | 
					    QVBoxLayout *layout = new QVBoxLayout(this);
 | 
				
			||||||
 | 
					    layout->setContentsMargins(0, 0, 0, 0);
 | 
				
			||||||
 | 
					    layout->addWidget(m_mainWindow);
 | 
				
			||||||
 | 
					    setLayout(layout);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GLSpectrumTop::setMeasurementsVisible(bool visible)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    m_dock->setVisible(visible);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										48
									
								
								sdrgui/gui/glspectrumtop.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								sdrgui/gui/glspectrumtop.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					///////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					// Copyright (C) 2022 Jon Beniston, M7RCE                                        //
 | 
				
			||||||
 | 
					//                                                                               //
 | 
				
			||||||
 | 
					// This program is free software; you can redistribute it and/or modify          //
 | 
				
			||||||
 | 
					// it under the terms of the GNU General Public License as published by          //
 | 
				
			||||||
 | 
					// the Free Software Foundation as version 3 of the License, or                  //
 | 
				
			||||||
 | 
					// (at your option) any later version.                                           //
 | 
				
			||||||
 | 
					//                                                                               //
 | 
				
			||||||
 | 
					// This program is distributed in the hope that it will be useful,               //
 | 
				
			||||||
 | 
					// but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | 
				
			||||||
 | 
					// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | 
				
			||||||
 | 
					// GNU General Public License V3 for more details.                               //
 | 
				
			||||||
 | 
					//                                                                               //
 | 
				
			||||||
 | 
					// You should have received a copy of the GNU General Public License             //
 | 
				
			||||||
 | 
					// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
				
			||||||
 | 
					///////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef SDRGUI_GLSPECTRUMTOP_H_
 | 
				
			||||||
 | 
					#define SDRGUI_GLSPECTRUMTOP_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QWidget>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "export.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QMainWindow;
 | 
				
			||||||
 | 
					class QDockWidget;
 | 
				
			||||||
 | 
					class GLSpectrum;
 | 
				
			||||||
 | 
					class SpectrumMeasurements;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Combines GLSpectrum in a QMainWindow with SpectrumMeasurements in a QDockWidget
 | 
				
			||||||
 | 
					class SDRGUI_API GLSpectrumTop : public QWidget {
 | 
				
			||||||
 | 
					    Q_OBJECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    GLSpectrumTop(QWidget *parent = nullptr);
 | 
				
			||||||
 | 
					    GLSpectrum *getSpectrum() const { return m_spectrum; }
 | 
				
			||||||
 | 
					    SpectrumMeasurements *getMeasurements() const { return m_measurements; }
 | 
				
			||||||
 | 
					    void setMeasurementsVisible(bool visible);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    QMainWindow *m_mainWindow;
 | 
				
			||||||
 | 
					    QDockWidget *m_dock;
 | 
				
			||||||
 | 
					    GLSpectrum *m_spectrum;
 | 
				
			||||||
 | 
					    SpectrumMeasurements *m_measurements;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // SDRGUI_GLSPECTRUMTOP_H_
 | 
				
			||||||
							
								
								
									
										610
									
								
								sdrgui/gui/spectrummeasurements.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										610
									
								
								sdrgui/gui/spectrummeasurements.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,610 @@
 | 
				
			|||||||
 | 
					///////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					// Copyright (C) 2022 Jon Beniston, M7RCE                                        //
 | 
				
			||||||
 | 
					//                                                                               //
 | 
				
			||||||
 | 
					// This program is free software; you can redistribute it and/or modify          //
 | 
				
			||||||
 | 
					// it under the terms of the GNU General Public License as published by          //
 | 
				
			||||||
 | 
					// the Free Software Foundation as version 3 of the License, or                  //
 | 
				
			||||||
 | 
					// (at your option) any later version.                                           //
 | 
				
			||||||
 | 
					//                                                                               //
 | 
				
			||||||
 | 
					// This program is distributed in the hope that it will be useful,               //
 | 
				
			||||||
 | 
					// but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | 
				
			||||||
 | 
					// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | 
				
			||||||
 | 
					// GNU General Public License V3 for more details.                               //
 | 
				
			||||||
 | 
					//                                                                               //
 | 
				
			||||||
 | 
					// You should have received a copy of the GNU General Public License             //
 | 
				
			||||||
 | 
					// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
				
			||||||
 | 
					///////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QTableWidgetItem>
 | 
				
			||||||
 | 
					#include <QHeaderView>
 | 
				
			||||||
 | 
					#include <QVBoxLayout>
 | 
				
			||||||
 | 
					#include <QMenu>
 | 
				
			||||||
 | 
					#include <QAction>
 | 
				
			||||||
 | 
					#include <QClipboard>
 | 
				
			||||||
 | 
					#include <QGuiApplication>
 | 
				
			||||||
 | 
					#include <QDebug>
 | 
				
			||||||
 | 
					#include <QPainter>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "gui/spectrummeasurements.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QStyledItemDelegate>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SDRGUI_API UnitsDelegate : public QStyledItemDelegate {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    UnitsDelegate(QObject *parent = nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        QString s = text(index);
 | 
				
			||||||
 | 
					        return QSize(width(s, option.fontMetrics) + 2, option.fontMetrics.height());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int width(const QString &s, const QFontMetrics &fm) const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int left = s.size() > 0 ? fm.leftBearing(s[0]) : 0;
 | 
				
			||||||
 | 
					        int right = s.size() > 0 ? fm.rightBearing(s[s.size()-1]) : 0;
 | 
				
			||||||
 | 
					        return fm.horizontalAdvance(s) + left + right;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QString text(const QModelIndex &index) const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        QString units = index.data(UNITS_ROLE).toString();
 | 
				
			||||||
 | 
					        QString s;
 | 
				
			||||||
 | 
					        if (units == "Hz")
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            s = formatEngineering(index.data().toLongLong());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            int precision = index.data(PRECISION_ROLE).toInt();
 | 
				
			||||||
 | 
					            double d = index.data().toDouble();
 | 
				
			||||||
 | 
					            s = QString::number(d, 'f', precision);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return s + units;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    enum Roles {
 | 
				
			||||||
 | 
					        UNITS_ROLE = Qt::UserRole,
 | 
				
			||||||
 | 
					        PRECISION_ROLE,
 | 
				
			||||||
 | 
					        SPEC_ROLE
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
					    QString formatEngineering(int64_t value) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UnitsDelegate::UnitsDelegate(QObject *parent) :
 | 
				
			||||||
 | 
					    QStyledItemDelegate(parent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QString UnitsDelegate::formatEngineering(int64_t value) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (value == 0) {
 | 
				
			||||||
 | 
					        return "0";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    int64_t absValue = std::abs(value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QString digits = QString::number(absValue);
 | 
				
			||||||
 | 
					    int cnt = digits.size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QString point = QLocale::system().decimalPoint();
 | 
				
			||||||
 | 
					    QString group = QLocale::system().groupSeparator();
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    for (i = cnt - 3; i >= 4; i -= 3)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        digits = digits.insert(i, group);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (absValue >= 1000) {
 | 
				
			||||||
 | 
					        digits = digits.insert(i, point);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (cnt > 9) {
 | 
				
			||||||
 | 
					        digits = digits.append("G");
 | 
				
			||||||
 | 
					    } else if (cnt > 6) {
 | 
				
			||||||
 | 
					        digits = digits.append("M");
 | 
				
			||||||
 | 
					    } else if (cnt > 3) {
 | 
				
			||||||
 | 
					        digits = digits.append("k");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (value < 0) {
 | 
				
			||||||
 | 
					        digits = digits.insert(0, "-");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return digits;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UnitsDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QFontMetrics fm = painter->fontMetrics();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QString s = text(index);
 | 
				
			||||||
 | 
					    int sWidth = width(s, fm);
 | 
				
			||||||
 | 
					    while ((sWidth > option.rect.width()) && !s.isEmpty())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        s = s.mid(1);
 | 
				
			||||||
 | 
					        sWidth = width(s, fm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int y = option.rect.y() + (option.rect.height()) - ((option.rect.height() - fm.ascent()) / 2); // Align center vertically
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QStyleOptionViewItem opt = option;
 | 
				
			||||||
 | 
					    initStyleOption(&opt, index);
 | 
				
			||||||
 | 
					    QPalette::ColorGroup cg = opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
 | 
				
			||||||
 | 
					    painter->setPen(opt.palette.color(cg, QPalette::Text));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    painter->drawText(option.rect.x() + option.rect.width() - 1 - sWidth, y, s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const QStringList SpectrumMeasurements::m_measurementColumns = {
 | 
				
			||||||
 | 
					    "Current",
 | 
				
			||||||
 | 
					    "Mean",
 | 
				
			||||||
 | 
					    "Min",
 | 
				
			||||||
 | 
					    "Max",
 | 
				
			||||||
 | 
					    "Range",
 | 
				
			||||||
 | 
					    "Std Dev",
 | 
				
			||||||
 | 
					    "Count",
 | 
				
			||||||
 | 
					    "Spec",
 | 
				
			||||||
 | 
					    "Fails",
 | 
				
			||||||
 | 
					    ""
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const QStringList SpectrumMeasurements::m_tooltips = {
 | 
				
			||||||
 | 
					    "Current value",
 | 
				
			||||||
 | 
					    "Mean average of values",
 | 
				
			||||||
 | 
					    "Minimum value",
 | 
				
			||||||
 | 
					    "Maximum value",
 | 
				
			||||||
 | 
					    "Range of values (Max-Min)",
 | 
				
			||||||
 | 
					    "Standard deviation",
 | 
				
			||||||
 | 
					    "Count of values",
 | 
				
			||||||
 | 
					    "Specification for value.\n\nE.g. <-100.5, >34.5 or =10.2",
 | 
				
			||||||
 | 
					    "Count of values that failed to meet specification",
 | 
				
			||||||
 | 
					    ""
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SpectrumMeasurements::SpectrumMeasurements(QWidget *parent) :
 | 
				
			||||||
 | 
					    QWidget(parent),
 | 
				
			||||||
 | 
					    m_table(nullptr),
 | 
				
			||||||
 | 
					    m_peakTable(nullptr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    m_textBrush.setColor(Qt::white);  // Should get this from the style sheet?
 | 
				
			||||||
 | 
					    m_redBrush.setColor(Qt::red);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QVBoxLayout *layout = new QVBoxLayout();
 | 
				
			||||||
 | 
					    layout->setContentsMargins(0, 0, 0, 0);
 | 
				
			||||||
 | 
					    setLayout(layout);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::createMeasurementsTable(const QStringList &rows, const QStringList &units)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    m_table = new QTableWidget();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    m_table->horizontalHeader()->setSectionsMovable(true);
 | 
				
			||||||
 | 
					    m_table->verticalHeader()->setSectionsMovable(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    m_table->setColumnCount(m_measurementColumns.size());
 | 
				
			||||||
 | 
					    for (int i = 0; i < m_measurementColumns.size(); i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        QTableWidgetItem *item = new QTableWidgetItem(m_measurementColumns[i]);
 | 
				
			||||||
 | 
					        item->setToolTip(m_tooltips[i]);
 | 
				
			||||||
 | 
					        m_table->setHorizontalHeaderItem(i, item);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Cell context menu
 | 
				
			||||||
 | 
					    m_table->setContextMenuPolicy(Qt::CustomContextMenu);
 | 
				
			||||||
 | 
					    connect(m_table, &QTableWidget::customContextMenuRequested, this, &SpectrumMeasurements::tableContextMenu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    m_table->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
 | 
				
			||||||
 | 
					    m_table->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Fill up space at end of rows
 | 
				
			||||||
 | 
					    m_table->horizontalHeader()->setSectionResizeMode(COL_EMPTY, QHeaderView::Stretch);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    m_table->setRowCount(rows.size());
 | 
				
			||||||
 | 
					    for (int i = 0; i < rows.size(); i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        m_table->setVerticalHeaderItem(i, new QTableWidgetItem(rows[i]));
 | 
				
			||||||
 | 
					        for (int j = 0; j < m_measurementColumns.size(); j++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            QTableWidgetItem *item = new QTableWidgetItem();
 | 
				
			||||||
 | 
					            item->setFlags(Qt::ItemIsEnabled);
 | 
				
			||||||
 | 
					            item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
 | 
				
			||||||
 | 
					            if (j < COL_COUNT)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                item->setData(UnitsDelegate::UNITS_ROLE, units[i]);
 | 
				
			||||||
 | 
					                item->setData(UnitsDelegate::PRECISION_ROLE, 1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (j == COL_SPEC)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            m_table->setItem(i, j, item);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Measurement m;
 | 
				
			||||||
 | 
					        m.m_units = units[i];
 | 
				
			||||||
 | 
					        m_measurements.append(m);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    resizeMeasurementsTable();
 | 
				
			||||||
 | 
					    for (int i = 0; i < COL_COUNT; i++) {
 | 
				
			||||||
 | 
					        m_table->setItemDelegateForColumn(i, new UnitsDelegate());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    createTableMenus();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::createPeakTable(int peaks)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    m_peakTable = new QTableWidget();
 | 
				
			||||||
 | 
					    m_peakTable->horizontalHeader()->setSectionsMovable(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QStringList columns = QStringList{"Frequency", "Power", ""};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    m_peakTable->setColumnCount(columns.size());
 | 
				
			||||||
 | 
					    m_peakTable->setRowCount(peaks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i = 0; i < columns.size(); i++) {
 | 
				
			||||||
 | 
					        m_peakTable->setHorizontalHeaderItem(i, new QTableWidgetItem(columns[i]));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (int i = 0; i < peaks; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        for (int j = 0; j < 3; j++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            QTableWidgetItem *item = new QTableWidgetItem();
 | 
				
			||||||
 | 
					            item->setFlags(Qt::ItemIsEnabled);
 | 
				
			||||||
 | 
					            if (j == COL_FREQUENCY) {
 | 
				
			||||||
 | 
					                item->setData(UnitsDelegate::UNITS_ROLE, "Hz");
 | 
				
			||||||
 | 
					            } else if (j == COL_POWER) {
 | 
				
			||||||
 | 
					                item->setData(UnitsDelegate::UNITS_ROLE, " dB");
 | 
				
			||||||
 | 
					                item->setData(UnitsDelegate::PRECISION_ROLE, 1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            m_peakTable->setItem(i, j, item);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    resizePeakTable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    m_peakTable->setItemDelegateForColumn(COL_FREQUENCY, new UnitsDelegate());
 | 
				
			||||||
 | 
					    m_peakTable->setItemDelegateForColumn(COL_POWER, new UnitsDelegate());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Fill up space at end of rows
 | 
				
			||||||
 | 
					    m_peakTable->horizontalHeader()->setSectionResizeMode(COL_PEAK_EMPTY, QHeaderView::Stretch);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    m_peakTable->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
 | 
				
			||||||
 | 
					    m_peakTable->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Cell context menu
 | 
				
			||||||
 | 
					    m_peakTable->setContextMenuPolicy(Qt::CustomContextMenu);
 | 
				
			||||||
 | 
					    connect(m_peakTable, &QTableWidget::customContextMenuRequested, this, &SpectrumMeasurements::peakTableContextMenu);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::createTableMenus()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Add context menu to allow hiding/showing of columns
 | 
				
			||||||
 | 
					    m_rowMenu = new QMenu(m_table);
 | 
				
			||||||
 | 
					    for (int i = 0; i < m_table->verticalHeader()->count(); i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        QString text = m_table->verticalHeaderItem(i)->text();
 | 
				
			||||||
 | 
					        m_rowMenu->addAction(createCheckableItem(text, i, true, true));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    m_table->verticalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
 | 
				
			||||||
 | 
					    connect(m_table->verticalHeader(), &QTableWidget::customContextMenuRequested, this, &SpectrumMeasurements::rowSelectMenu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add context menu to allow hiding/showing of rows
 | 
				
			||||||
 | 
					    m_columnMenu = new QMenu(m_table);
 | 
				
			||||||
 | 
					    for (int i = 0; i < m_table->horizontalHeader()->count(); i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        QString text = m_table->horizontalHeaderItem(i)->text();
 | 
				
			||||||
 | 
					        m_columnMenu->addAction(createCheckableItem(text, i, true, false));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    m_table->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
 | 
				
			||||||
 | 
					    connect(m_table->horizontalHeader(), &QTableWidget::customContextMenuRequested, this, &SpectrumMeasurements::columnSelectMenu);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::createChannelPowerTable()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QStringList rows = {"Channel power"};
 | 
				
			||||||
 | 
					    QStringList units = {" dB"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    createMeasurementsTable(rows, units);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::createAdjacentChannelPowerTable()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QStringList rows = {"Left power", "Left ACPR", "Center power", "Right power", "Right ACPR"};
 | 
				
			||||||
 | 
					    QStringList units = {" dB", " dBc", " dB", " dB", " dBc"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    createMeasurementsTable(rows, units);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::createSNRTable()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QStringList rows = {"SNR", "SNFR", "THD", "THD+N", "SINAD", "SFDR",};
 | 
				
			||||||
 | 
					    QStringList units = {" dB", " dB", " dB", " dB", " dB", " dBc"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    createMeasurementsTable(rows, units);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Create column select menu item
 | 
				
			||||||
 | 
					QAction *SpectrumMeasurements::createCheckableItem(QString &text, int idx, bool checked, bool row)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QAction *action = new QAction(text, this);
 | 
				
			||||||
 | 
					    action->setCheckable(true);
 | 
				
			||||||
 | 
					    action->setChecked(checked);
 | 
				
			||||||
 | 
					    action->setData(QVariant(idx));
 | 
				
			||||||
 | 
					    if (row) {
 | 
				
			||||||
 | 
					        connect(action, &QAction::triggered, this, &SpectrumMeasurements::rowSelectMenuChecked);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        connect(action, &QAction::triggered, this, &SpectrumMeasurements::columnSelectMenuChecked);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return action;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Right click in table header - show row select menu
 | 
				
			||||||
 | 
					void SpectrumMeasurements::rowSelectMenu(QPoint pos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    m_rowMenu->popup(m_table->verticalHeader()->viewport()->mapToGlobal(pos));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Hide/show row when menu selected
 | 
				
			||||||
 | 
					void SpectrumMeasurements::rowSelectMenuChecked(bool checked)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void) checked;
 | 
				
			||||||
 | 
					    QAction* action = qobject_cast<QAction*>(sender());
 | 
				
			||||||
 | 
					    if (action != nullptr)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int idx = action->data().toInt(nullptr);
 | 
				
			||||||
 | 
					        m_table->setRowHidden(idx, !action->isChecked());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Right click in table header - show column select menu
 | 
				
			||||||
 | 
					void SpectrumMeasurements::columnSelectMenu(QPoint pos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    m_columnMenu->popup(m_table->horizontalHeader()->viewport()->mapToGlobal(pos));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Hide/show column when menu selected
 | 
				
			||||||
 | 
					void SpectrumMeasurements::columnSelectMenuChecked(bool checked)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void) checked;
 | 
				
			||||||
 | 
					    QAction* action = qobject_cast<QAction*>(sender());
 | 
				
			||||||
 | 
					    if (action != nullptr)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int idx = action->data().toInt(nullptr);
 | 
				
			||||||
 | 
					        m_table->setColumnHidden(idx, !action->isChecked());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::tableContextMenu(QPoint pos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QTableWidgetItem *item = m_table->itemAt(pos);
 | 
				
			||||||
 | 
					    if (item)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int row = item->row();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        QMenu* tableContextMenu = new QMenu(m_table);
 | 
				
			||||||
 | 
					        connect(tableContextMenu, &QMenu::aboutToHide, tableContextMenu, &QMenu::deleteLater);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Copy current cell
 | 
				
			||||||
 | 
					        QAction* copyAction = new QAction("Copy", tableContextMenu);
 | 
				
			||||||
 | 
					        const QString text = item->text();
 | 
				
			||||||
 | 
					        connect(copyAction, &QAction::triggered, this, [text]()->void {
 | 
				
			||||||
 | 
					            QClipboard *clipboard = QGuiApplication::clipboard();
 | 
				
			||||||
 | 
					            clipboard->setText(text);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        tableContextMenu->addAction(copyAction);
 | 
				
			||||||
 | 
					        tableContextMenu->addSeparator();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tableContextMenu->popup(m_table->viewport()->mapToGlobal(pos));
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::peakTableContextMenu(QPoint pos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QTableWidgetItem *item = m_peakTable->itemAt(pos);
 | 
				
			||||||
 | 
					    if (item)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int row = item->row();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        QMenu* tableContextMenu = new QMenu(m_peakTable);
 | 
				
			||||||
 | 
					        connect(tableContextMenu, &QMenu::aboutToHide, tableContextMenu, &QMenu::deleteLater);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Copy current cell
 | 
				
			||||||
 | 
					        QAction* copyAction = new QAction("Copy", tableContextMenu);
 | 
				
			||||||
 | 
					        const QString text = item->text();
 | 
				
			||||||
 | 
					        connect(copyAction, &QAction::triggered, this, [text]()->void {
 | 
				
			||||||
 | 
					            QClipboard *clipboard = QGuiApplication::clipboard();
 | 
				
			||||||
 | 
					            clipboard->setText(text);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        tableContextMenu->addAction(copyAction);
 | 
				
			||||||
 | 
					        tableContextMenu->addSeparator();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tableContextMenu->popup(m_peakTable->viewport()->mapToGlobal(pos));
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::resizeMeasurementsTable()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Fill table with a row of dummy data that will size the columns nicely
 | 
				
			||||||
 | 
					    int row = m_table->rowCount();
 | 
				
			||||||
 | 
					    m_table->setRowCount(row + 1);
 | 
				
			||||||
 | 
					    m_table->setItem(row, COL_CURRENT, new QTableWidgetItem("-120.0 dBc"));
 | 
				
			||||||
 | 
					    m_table->setItem(row, COL_MEAN, new QTableWidgetItem("-120.0 dBc"));
 | 
				
			||||||
 | 
					    m_table->setItem(row, COL_MIN, new QTableWidgetItem("-120.0 dBc"));
 | 
				
			||||||
 | 
					    m_table->setItem(row, COL_MAX, new QTableWidgetItem("-120.0 dBc"));
 | 
				
			||||||
 | 
					    m_table->setItem(row, COL_RANGE, new QTableWidgetItem("-120.0 dBc"));
 | 
				
			||||||
 | 
					    m_table->setItem(row, COL_STD_DEV, new QTableWidgetItem("-120.0 dBc"));
 | 
				
			||||||
 | 
					    m_table->setItem(row, COL_COUNT, new QTableWidgetItem("100000"));
 | 
				
			||||||
 | 
					    m_table->setItem(row, COL_SPEC, new QTableWidgetItem(">= -120.0"));
 | 
				
			||||||
 | 
					    m_table->setItem(row, COL_FAILS, new QTableWidgetItem("100000"));
 | 
				
			||||||
 | 
					    m_table->resizeColumnsToContents();
 | 
				
			||||||
 | 
					    m_table->removeRow(row);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::resizePeakTable()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Fill table with a row of dummy data that will size the columns nicely
 | 
				
			||||||
 | 
					    int row = m_peakTable->rowCount();
 | 
				
			||||||
 | 
					    m_peakTable->setRowCount(row + 1);
 | 
				
			||||||
 | 
					    m_peakTable->setItem(row, COL_FREQUENCY, new QTableWidgetItem("6.000,000,000GHz"));
 | 
				
			||||||
 | 
					    m_peakTable->setItem(row, COL_POWER, new QTableWidgetItem("-120.0 dB"));
 | 
				
			||||||
 | 
					    m_peakTable->resizeColumnsToContents();
 | 
				
			||||||
 | 
					    m_peakTable->removeRow(row);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::setMeasurementParams(SpectrumSettings::Measurement measurement, int peaks)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Tried using setVisible(), but that would hang, so delete and recreate
 | 
				
			||||||
 | 
					    delete m_peakTable;
 | 
				
			||||||
 | 
					    m_peakTable = nullptr;
 | 
				
			||||||
 | 
					    delete m_table;
 | 
				
			||||||
 | 
					    m_table = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (measurement)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    case SpectrumSettings::MeasurementPeaks:
 | 
				
			||||||
 | 
					        createPeakTable(peaks);
 | 
				
			||||||
 | 
					        layout()->addWidget(m_peakTable);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case SpectrumSettings::MeasurementChannelPower:
 | 
				
			||||||
 | 
					        reset();
 | 
				
			||||||
 | 
					        createChannelPowerTable();
 | 
				
			||||||
 | 
					        layout()->addWidget(m_table);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case SpectrumSettings::MeasurementAdjacentChannelPower:
 | 
				
			||||||
 | 
					        reset();
 | 
				
			||||||
 | 
					        createAdjacentChannelPowerTable();
 | 
				
			||||||
 | 
					        layout()->addWidget(m_table);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case SpectrumSettings::MeasurementSNR:
 | 
				
			||||||
 | 
					        reset();
 | 
				
			||||||
 | 
					        createSNRTable();
 | 
				
			||||||
 | 
					        layout()->addWidget(m_table);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::reset()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (int i = 0; i < m_measurements.size(); i++) {
 | 
				
			||||||
 | 
					        m_measurements[i].reset();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (m_table)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        for (int i = 0; i < m_table->rowCount(); i++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            for (int j = 0; j < m_table->columnCount(); j++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (j != COL_SPEC) {
 | 
				
			||||||
 | 
					                    m_table->item(i, j)->setText("");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Check the value meets the user-defined specification
 | 
				
			||||||
 | 
					bool SpectrumMeasurements::checkSpec(const QString &spec, double value) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (spec.isEmpty()) {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (spec.startsWith("<="))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        double limit = spec.mid(2).toDouble();
 | 
				
			||||||
 | 
					        return value <= limit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (spec[0] == '<')
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        double limit = spec.mid(1).toDouble();
 | 
				
			||||||
 | 
					        return value < limit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (spec.startsWith(">="))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        double limit = spec.mid(2).toDouble();
 | 
				
			||||||
 | 
					        return value >= limit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (spec[0] == '>')
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        double limit = spec.mid(1).toDouble();
 | 
				
			||||||
 | 
					        return value > limit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (spec[0] == '=')
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        double limit = spec.mid(1).toDouble();
 | 
				
			||||||
 | 
					        return value == limit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::updateMeasurement(int row, float value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    m_measurements[row].add(value);
 | 
				
			||||||
 | 
					    double mean = m_measurements[row].mean();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    m_table->item(row, COL_CURRENT)->setData(Qt::DisplayRole, value);
 | 
				
			||||||
 | 
					    m_table->item(row, COL_MEAN)->setData(Qt::DisplayRole, mean);
 | 
				
			||||||
 | 
					    m_table->item(row, COL_MIN)->setData(Qt::DisplayRole, m_measurements[row].m_min);
 | 
				
			||||||
 | 
					    m_table->item(row, COL_MAX)->setData(Qt::DisplayRole, m_measurements[row].m_max);
 | 
				
			||||||
 | 
					    m_table->item(row, COL_RANGE)->setData(Qt::DisplayRole, m_measurements[row].m_max - m_measurements[row].m_min);
 | 
				
			||||||
 | 
					    m_table->item(row, COL_STD_DEV)->setData(Qt::DisplayRole, m_measurements[row].stdDev());
 | 
				
			||||||
 | 
					    m_table->item(row, COL_COUNT)->setData(Qt::DisplayRole, m_measurements[row].m_values.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QString spec = m_table->item(row, COL_SPEC)->text();
 | 
				
			||||||
 | 
					    bool valueOK = checkSpec(spec, value);
 | 
				
			||||||
 | 
					    bool meanOK = checkSpec(spec, mean);
 | 
				
			||||||
 | 
					    bool minOK = checkSpec(spec, m_measurements[row].m_min);
 | 
				
			||||||
 | 
					    bool mmaxOK = checkSpec(spec, m_measurements[row].m_max);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!valueOK)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        m_measurements[row].m_fails++;
 | 
				
			||||||
 | 
					        m_table->item(row, 8)->setData(Qt::DisplayRole, m_measurements[row].m_fails);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // item->setForeground doesn't work, perhaps as we have style sheet applied?
 | 
				
			||||||
 | 
					    m_table->item(row, COL_CURRENT)->setData(Qt::ForegroundRole, valueOK ? m_textBrush : m_redBrush);
 | 
				
			||||||
 | 
					    m_table->item(row, COL_MEAN)->setData(Qt::ForegroundRole, meanOK ? m_textBrush : m_redBrush);
 | 
				
			||||||
 | 
					    m_table->item(row, COL_MIN)->setData(Qt::ForegroundRole, minOK ? m_textBrush : m_redBrush);
 | 
				
			||||||
 | 
					    m_table->item(row, COL_MAX)->setData(Qt::ForegroundRole, mmaxOK ? m_textBrush : m_redBrush);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::setSNR(float snr, float snfr, float thd, float thdpn, float sinad)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    updateMeasurement(0, snr);
 | 
				
			||||||
 | 
					    updateMeasurement(1, snfr);
 | 
				
			||||||
 | 
					    updateMeasurement(2, thd);
 | 
				
			||||||
 | 
					    updateMeasurement(3, thdpn);
 | 
				
			||||||
 | 
					    updateMeasurement(4, sinad);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::setSFDR(float sfdr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    updateMeasurement(5, sfdr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::setChannelPower(float power)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    updateMeasurement(0, power);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::setAdjacentChannelPower(float left, float leftACPR, float center, float right, float rightACPR)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    updateMeasurement(0, left);
 | 
				
			||||||
 | 
					    updateMeasurement(1, leftACPR);
 | 
				
			||||||
 | 
					    updateMeasurement(2, center);
 | 
				
			||||||
 | 
					    updateMeasurement(3, right);
 | 
				
			||||||
 | 
					    updateMeasurement(4, rightACPR);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpectrumMeasurements::setPeak(int peak, int64_t frequency, float power)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    m_peakTable->item(peak, COL_FREQUENCY)->setData(Qt::DisplayRole, frequency);
 | 
				
			||||||
 | 
					    m_peakTable->item(peak, COL_POWER)->setData(Qt::DisplayRole, power);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										146
									
								
								sdrgui/gui/spectrummeasurements.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								sdrgui/gui/spectrummeasurements.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,146 @@
 | 
				
			|||||||
 | 
					///////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					// Copyright (C) 2022 Jon Beniston, M7RCE                                        //
 | 
				
			||||||
 | 
					//                                                                               //
 | 
				
			||||||
 | 
					// This program is free software; you can redistribute it and/or modify          //
 | 
				
			||||||
 | 
					// it under the terms of the GNU General Public License as published by          //
 | 
				
			||||||
 | 
					// the Free Software Foundation as version 3 of the License, or                  //
 | 
				
			||||||
 | 
					// (at your option) any later version.                                           //
 | 
				
			||||||
 | 
					//                                                                               //
 | 
				
			||||||
 | 
					// This program is distributed in the hope that it will be useful,               //
 | 
				
			||||||
 | 
					// but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | 
				
			||||||
 | 
					// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | 
				
			||||||
 | 
					// GNU General Public License V3 for more details.                               //
 | 
				
			||||||
 | 
					//                                                                               //
 | 
				
			||||||
 | 
					// You should have received a copy of the GNU General Public License             //
 | 
				
			||||||
 | 
					// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
				
			||||||
 | 
					///////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef SDRGUI_SPECTRUMMEASUREMENTS_H_
 | 
				
			||||||
 | 
					#define SDRGUI_SPECTRUMMEASUREMENTS_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QWidget>
 | 
				
			||||||
 | 
					#include <QMenu>
 | 
				
			||||||
 | 
					#include <QTableWidget>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "dsp/spectrumsettings.h"
 | 
				
			||||||
 | 
					#include "export.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Displays spectrum measurements in a table
 | 
				
			||||||
 | 
					class SDRGUI_API SpectrumMeasurements : public QWidget {
 | 
				
			||||||
 | 
					    Q_OBJECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct Measurement {
 | 
				
			||||||
 | 
					        QList<float> m_values;
 | 
				
			||||||
 | 
					        float m_min;
 | 
				
			||||||
 | 
					        float m_max;
 | 
				
			||||||
 | 
					        double m_sum;
 | 
				
			||||||
 | 
					        int m_fails;
 | 
				
			||||||
 | 
					        QString m_units;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Measurement()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            reset();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void reset()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            m_values.clear();
 | 
				
			||||||
 | 
					            m_min = std::numeric_limits<float>::max();
 | 
				
			||||||
 | 
					            m_max = -std::numeric_limits<float>::max();
 | 
				
			||||||
 | 
					            m_sum = 0.0;
 | 
				
			||||||
 | 
					            m_fails = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void add(float value)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            m_min = std::min(value, m_min);
 | 
				
			||||||
 | 
					            m_max = std::max(value, m_max);
 | 
				
			||||||
 | 
					            m_sum += value;
 | 
				
			||||||
 | 
					            m_values.append(value);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        double mean() const
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return m_sum / m_values.size();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        double stdDev() const
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            double u = mean();
 | 
				
			||||||
 | 
					            double sum = 0.0;
 | 
				
			||||||
 | 
					            for (int i = 0; i < m_values.size(); i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                double d = m_values[i] - u;
 | 
				
			||||||
 | 
					                sum += d * d;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (m_values.size() < 2) {
 | 
				
			||||||
 | 
					                return 0.0;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                return sqrt(sum / (m_values.size() - 1));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    SpectrumMeasurements(QWidget *parent = nullptr);
 | 
				
			||||||
 | 
					    void setMeasurementParams(SpectrumSettings::Measurement measurement, int peaks);
 | 
				
			||||||
 | 
					    void setSNR(float snr, float snfr, float thd, float thdpn, float sinad);
 | 
				
			||||||
 | 
					    void setSFDR(float sfdr);
 | 
				
			||||||
 | 
					    void setChannelPower(float power);
 | 
				
			||||||
 | 
					    void setAdjacentChannelPower(float left, float leftACPR, float center, float right, float rightACPR);
 | 
				
			||||||
 | 
					    void setPeak(int peak, int64_t frequency, float power);
 | 
				
			||||||
 | 
					    void reset();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    void createMeasurementsTable(const QStringList &rows, const QStringList &units);
 | 
				
			||||||
 | 
					    void createPeakTable(int peaks);
 | 
				
			||||||
 | 
					    void createTableMenus();
 | 
				
			||||||
 | 
					    void createChannelPowerTable();
 | 
				
			||||||
 | 
					    void createAdjacentChannelPowerTable();
 | 
				
			||||||
 | 
					    void createSNRTable();
 | 
				
			||||||
 | 
					    void tableContextMenu(QPoint pos);
 | 
				
			||||||
 | 
					    void peakTableContextMenu(QPoint pos);
 | 
				
			||||||
 | 
					    void rowSelectMenu(QPoint pos);
 | 
				
			||||||
 | 
					    void rowSelectMenuChecked(bool checked);
 | 
				
			||||||
 | 
					    void columnSelectMenu(QPoint pos);
 | 
				
			||||||
 | 
					    void columnSelectMenuChecked(bool checked);
 | 
				
			||||||
 | 
					    QAction *createCheckableItem(QString &text, int idx, bool checked, bool row);
 | 
				
			||||||
 | 
					    void resizeMeasurementsTable();
 | 
				
			||||||
 | 
					    void resizePeakTable();
 | 
				
			||||||
 | 
					    void updateMeasurement(int row, float value);
 | 
				
			||||||
 | 
					    bool checkSpec(const QString &spec, double value) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QTableWidget *m_table;
 | 
				
			||||||
 | 
					    QMenu *m_rowMenu;
 | 
				
			||||||
 | 
					    QMenu *m_columnMenu;
 | 
				
			||||||
 | 
					    QList<Measurement> m_measurements;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QTableWidget *m_peakTable;
 | 
				
			||||||
 | 
					    QBrush m_textBrush;
 | 
				
			||||||
 | 
					    QBrush m_redBrush;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    enum MeasurementsCol {
 | 
				
			||||||
 | 
					        COL_CURRENT,
 | 
				
			||||||
 | 
					        COL_MEAN,
 | 
				
			||||||
 | 
					        COL_MIN,
 | 
				
			||||||
 | 
					        COL_MAX,
 | 
				
			||||||
 | 
					        COL_RANGE,
 | 
				
			||||||
 | 
					        COL_STD_DEV,
 | 
				
			||||||
 | 
					        COL_COUNT,
 | 
				
			||||||
 | 
					        COL_SPEC,
 | 
				
			||||||
 | 
					        COL_FAILS,
 | 
				
			||||||
 | 
					        COL_EMPTY
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    enum PeakTableCol {
 | 
				
			||||||
 | 
					        COL_FREQUENCY,
 | 
				
			||||||
 | 
					        COL_POWER,
 | 
				
			||||||
 | 
					        COL_PEAK_EMPTY
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static const QStringList m_measurementColumns;
 | 
				
			||||||
 | 
					    static const QStringList m_tooltips;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // SDRGUI_SPECTRUMMEASUREMENTS_H_
 | 
				
			||||||
@ -26,13 +26,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "mainwindow.h"
 | 
					#include "mainwindow.h"
 | 
				
			||||||
#include "gui/glspectrum.h"
 | 
					#include "gui/glspectrum.h"
 | 
				
			||||||
 | 
					#include "gui/glspectrumtop.h"
 | 
				
			||||||
#include "gui/glspectrumgui.h"
 | 
					#include "gui/glspectrumgui.h"
 | 
				
			||||||
#include "gui/workspaceselectiondialog.h"
 | 
					#include "gui/workspaceselectiondialog.h"
 | 
				
			||||||
#include "dsp/spectrumvis.h"
 | 
					#include "dsp/spectrumvis.h"
 | 
				
			||||||
#include "mainspectrumgui.h"
 | 
					#include "mainspectrumgui.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MainSpectrumGUI::MainSpectrumGUI(GLSpectrum *spectrum, GLSpectrumGUI *spectrumGUI, QWidget *parent) :
 | 
					MainSpectrumGUI::MainSpectrumGUI(GLSpectrumTop *spectrumTop, GLSpectrum *spectrum, GLSpectrumGUI *spectrumGUI, QWidget *parent) :
 | 
				
			||||||
    QMdiSubWindow(parent),
 | 
					    QMdiSubWindow(parent),
 | 
				
			||||||
 | 
					    m_spectrumTop(spectrumTop),
 | 
				
			||||||
    m_spectrum(spectrum),
 | 
					    m_spectrum(spectrum),
 | 
				
			||||||
    m_spectrumGUI(spectrumGUI),
 | 
					    m_spectrumGUI(spectrumGUI),
 | 
				
			||||||
    m_deviceType(DeviceRx),
 | 
					    m_deviceType(DeviceRx),
 | 
				
			||||||
@ -113,7 +115,7 @@ MainSpectrumGUI::MainSpectrumGUI(GLSpectrum *spectrum, GLSpectrumGUI *spectrumGU
 | 
				
			|||||||
    m_topLayout->addWidget(m_hideButton);
 | 
					    m_topLayout->addWidget(m_hideButton);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    m_spectrumLayout = new QHBoxLayout();
 | 
					    m_spectrumLayout = new QHBoxLayout();
 | 
				
			||||||
    m_spectrumLayout->addWidget(spectrum);
 | 
					    m_spectrumLayout->addWidget(spectrumTop);
 | 
				
			||||||
    spectrum->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
 | 
					    spectrum->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
 | 
				
			||||||
    m_spectrumGUILayout = new QHBoxLayout();
 | 
					    m_spectrumGUILayout = new QHBoxLayout();
 | 
				
			||||||
    m_spectrumGUILayout->addWidget(spectrumGUI);
 | 
					    m_spectrumGUILayout->addWidget(spectrumGUI);
 | 
				
			||||||
@ -151,7 +153,7 @@ MainSpectrumGUI::MainSpectrumGUI(GLSpectrum *spectrum, GLSpectrumGUI *spectrumGU
 | 
				
			|||||||
MainSpectrumGUI::~MainSpectrumGUI()
 | 
					MainSpectrumGUI::~MainSpectrumGUI()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    qDebug("MainSpectrumGUI::~MainSpectrumGUI");
 | 
					    qDebug("MainSpectrumGUI::~MainSpectrumGUI");
 | 
				
			||||||
    m_spectrumLayout->removeWidget(m_spectrum);
 | 
					    m_spectrumLayout->removeWidget(m_spectrumTop);
 | 
				
			||||||
    m_spectrumGUILayout->removeWidget(m_spectrumGUI);
 | 
					    m_spectrumGUILayout->removeWidget(m_spectrumGUI);
 | 
				
			||||||
    delete m_sizeGripBottomRight;
 | 
					    delete m_sizeGripBottomRight;
 | 
				
			||||||
    delete m_bottomLayout;
 | 
					    delete m_bottomLayout;
 | 
				
			||||||
 | 
				
			|||||||
@ -26,6 +26,7 @@
 | 
				
			|||||||
#include "export.h"
 | 
					#include "export.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class GLSpectrum;
 | 
					class GLSpectrum;
 | 
				
			||||||
 | 
					class GLSpectrumTop;
 | 
				
			||||||
class GLSpectrumGUI;
 | 
					class GLSpectrumGUI;
 | 
				
			||||||
class QLabel;
 | 
					class QLabel;
 | 
				
			||||||
class QPushButton;
 | 
					class QPushButton;
 | 
				
			||||||
@ -44,7 +45,7 @@ public:
 | 
				
			|||||||
        DeviceMIMO
 | 
					        DeviceMIMO
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	MainSpectrumGUI(GLSpectrum *spectrum, GLSpectrumGUI *spectrumGUI, QWidget *parent = nullptr);
 | 
						MainSpectrumGUI(GLSpectrumTop *spectrumTop, GLSpectrum *spectrum, GLSpectrumGUI *spectrumGUI, QWidget *parent = nullptr);
 | 
				
			||||||
	virtual ~MainSpectrumGUI();
 | 
						virtual ~MainSpectrumGUI();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void setDeviceType(DeviceType type);
 | 
					    void setDeviceType(DeviceType type);
 | 
				
			||||||
@ -60,6 +61,7 @@ public:
 | 
				
			|||||||
    const QByteArray& getGeometryBytes() const { return m_geometryBytes; }
 | 
					    const QByteArray& getGeometryBytes() const { return m_geometryBytes; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
					    GLSpectrumTop *m_spectrumTop;
 | 
				
			||||||
    GLSpectrum *m_spectrum;
 | 
					    GLSpectrum *m_spectrum;
 | 
				
			||||||
    GLSpectrumGUI *m_spectrumGUI;
 | 
					    GLSpectrumGUI *m_spectrumGUI;
 | 
				
			||||||
    int m_workspaceIndex;
 | 
					    int m_workspaceIndex;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user