2022-10-01 23:10:44 +08:00
# include " vna.h "
# include "unit.h"
# include "CustomWidgets/toggleswitch.h"
# include "Traces/tracemodel.h"
# include "tracewidgetvna.h"
# include "Traces/tracesmithchart.h"
# include "Traces/tracexyplot.h"
# include "Traces/traceimportdialog.h"
# include "CustomWidgets/tilewidget.h"
# include "CustomWidgets/siunitedit.h"
# include "Traces/Marker/markerwidget.h"
# include "Tools/impedancematchdialog.h"
2022-11-09 19:33:14 +08:00
# include "Tools/mixedmodeconversion.h"
2022-10-01 23:10:44 +08:00
# include "ui_main.h"
# include "preferences.h"
# include "Generator/signalgenwidget.h"
# include "CustomWidgets/informationbox.h"
# include "Deembedding/manualdeembeddingdialog.h"
# include "Calibration/manualcalibrationdialog.h"
# include "Calibration/LibreCAL/librecaldialog.h"
# include "Util/util.h"
# include "Tools/parameters.h"
# include <QGridLayout>
# include <QVBoxLayout>
# include <QHBoxLayout>
# include <QPushButton>
# include <math.h>
# include <QToolBar>
# include <QMenu>
# include <QToolButton>
# include <QActionGroup>
# include <QSpinBox>
# include <QCheckBox>
# include <QComboBox>
# include <QSettings>
# include <algorithm>
# include <QMessageBox>
# include <QFileDialog>
# include <QFile>
# include <iostream>
# include <fstream>
# include <QDateTime>
# include <QDockWidget>
# include <queue>
# include <QApplication>
# include <QActionGroup>
# include <QErrorMessage>
# include <QDebug>
2022-10-30 06:20:57 +08:00
# include <QStyle>
2022-12-13 05:59:10 +08:00
# include <QScrollArea>
2023-02-13 05:58:45 +08:00
# include <QStandardItemModel>
2023-03-18 01:50:46 +08:00
# include <QDateTime>
2022-10-01 23:10:44 +08:00
VNA : : VNA ( AppWindow * window , QString name )
: Mode ( window , name , " VNA " ) ,
deembedding ( traceModel ) ,
deembedding_active ( false ) ,
2022-12-15 07:00:15 +08:00
tiles ( new TileWidget ( traceModel ) ) ,
central ( new QScrollArea )
2022-10-01 23:10:44 +08:00
{
2022-12-13 05:59:10 +08:00
central - > setWidget ( tiles ) ;
central - > setWidgetResizable ( true ) ;
2022-10-01 23:10:44 +08:00
averages = 1 ;
singleSweep = false ;
calMeasuring = false ;
calWaitFirst = false ;
2023-07-30 19:09:47 +08:00
calDialog = nullptr ;
2022-10-01 23:10:44 +08:00
changingSettings = false ;
settings . sweepType = SweepType : : Frequency ;
settings . zerospan = false ;
traceModel . setSource ( TraceModel : : DataSource : : VNA ) ;
2022-10-30 19:07:59 +08:00
configurationTimer . setSingleShot ( true ) ;
connect ( & configurationTimer , & QTimer : : timeout , this , [ = ] ( ) {
ConfigureDevice ( ) ;
} ) ;
2022-10-01 23:10:44 +08:00
// Create default traces
createDefaultTracesAndGraphs ( 2 ) ;
connect ( & traceModel , & TraceModel : : requiredExcitation , this , & VNA : : ExcitationRequired ) ;
// Create menu entries and connections
auto calMenu = new QMenu ( " Calibration " , window ) ;
window - > menuBar ( ) - > insertMenu ( window - > getUi ( ) - > menuWindow - > menuAction ( ) , calMenu ) ;
actions . insert ( calMenu - > menuAction ( ) ) ;
auto calLoad = calMenu - > addAction ( " Load " ) ;
saveCal = calMenu - > addAction ( " Save " ) ;
calMenu - > addSeparator ( ) ;
connect ( calLoad , & QAction : : triggered , [ = ] ( ) {
2022-11-10 06:29:37 +08:00
LoadCalibration ( ) ;
2023-01-16 07:25:29 +08:00
if ( window - > getDevice ( ) & & ! cal . validForDevice ( window - > getDevice ( ) - > getSerial ( ) ) ) {
2022-12-16 05:43:41 +08:00
InformationBox : : ShowMessage ( " Invalid calibration " , " The selected calibration was created for a different device. You can still load it but the resulting "
" data likely isn't useful. " ) ;
}
2022-10-01 23:10:44 +08:00
} ) ;
connect ( saveCal , & QAction : : triggered , [ = ] ( ) {
2022-11-10 06:29:37 +08:00
SaveCalibration ( ) ;
2022-10-01 23:10:44 +08:00
} ) ;
connect ( & cal , & Calibration : : startMeasurements , this , & VNA : : StartCalibrationMeasurements ) ;
auto calData = calMenu - > addAction ( " Calibration Measurements " ) ;
connect ( calData , & QAction : : triggered , [ = ] ( ) {
cal . edit ( ) ;
} ) ;
auto calEditKit = calMenu - > addAction ( " Edit Calibration Kit " ) ;
connect ( calEditKit , & QAction : : triggered , [ = ] ( ) {
2022-10-06 04:17:53 +08:00
cal . getKit ( ) . edit ( [ = ] ( ) {
if ( cal . getCaltype ( ) . type ! = Calibration : : Type : : None ) {
cal . compute ( cal . getCaltype ( ) ) ;
}
} ) ;
2022-10-01 23:10:44 +08:00
} ) ;
auto calElectronic = calMenu - > addAction ( " Electronic Calibration " ) ;
connect ( calElectronic , & QAction : : triggered , [ = ] ( ) {
auto d = new LibreCALDialog ( & cal ) ;
d - > show ( ) ;
} ) ;
calMenu - > addSeparator ( ) ;
auto calImportTerms = calMenu - > addAction ( " Import error terms as traces " ) ;
calImportTerms - > setEnabled ( false ) ;
connect ( calImportTerms , & QAction : : triggered , [ = ] ( ) {
auto import = new TraceImportDialog ( traceModel , cal . getErrorTermTraces ( ) ) ;
if ( AppWindow : : showGUI ( ) ) {
import - > show ( ) ;
}
} ) ;
auto calImportMeas = calMenu - > addAction ( " Import measurements as traces " ) ;
calImportMeas - > setEnabled ( false ) ;
connect ( calImportMeas , & QAction : : triggered , [ = ] ( ) {
auto import = new TraceImportDialog ( traceModel , cal . getMeasurementTraces ( ) ) ;
if ( AppWindow : : showGUI ( ) ) {
import - > show ( ) ;
}
} ) ;
calMenu - > addSeparator ( ) ;
auto calApplyToTraces = calMenu - > addAction ( " Apply to traces... " ) ;
calApplyToTraces - > setEnabled ( false ) ;
connect ( calApplyToTraces , & QAction : : triggered , [ = ] ( ) {
auto manualCalibration = new ManualCalibrationDialog ( traceModel , & cal ) ;
if ( AppWindow : : showGUI ( ) ) {
manualCalibration - > show ( ) ;
}
} ) ;
2023-07-30 00:11:57 +08:00
cal . getKit ( ) . setIdealDefault ( ) ;
2022-10-01 23:10:44 +08:00
// portExtension.setCalkit(&cal.getCalibrationKit());
// De-embedding menu
auto menuDeembed = new QMenu ( " De-embedding " , window ) ;
window - > menuBar ( ) - > insertMenu ( window - > getUi ( ) - > menuWindow - > menuAction ( ) , menuDeembed ) ;
actions . insert ( menuDeembed - > menuAction ( ) ) ;
auto confDeembed = menuDeembed - > addAction ( " Setup... " ) ;
connect ( confDeembed , & QAction : : triggered , & deembedding , & Deembedding : : configure ) ;
enableDeembeddingAction = menuDeembed - > addAction ( " De-embed VNA samples " ) ;
enableDeembeddingAction - > setCheckable ( true ) ;
enableDeembeddingAction - > setEnabled ( false ) ;
connect ( enableDeembeddingAction , & QAction : : toggled , this , & VNA : : EnableDeembedding ) ;
auto manualDeembed = menuDeembed - > addAction ( " De-embed traces... " ) ;
manualDeembed - > setEnabled ( false ) ;
connect ( manualDeembed , & QAction : : triggered , [ = ] ( ) {
auto manualDeembedding = new ManualDeembeddingDialog ( traceModel , & deembedding ) ;
if ( AppWindow : : showGUI ( ) ) {
manualDeembedding - > show ( ) ;
}
} ) ;
connect ( & deembedding , & Deembedding : : optionAdded , [ = ] ( ) {
EnableDeembedding ( true ) ;
enableDeembeddingAction - > setEnabled ( true ) ;
manualDeembed - > setEnabled ( true ) ;
} ) ;
connect ( & deembedding , & Deembedding : : allOptionsCleared , [ = ] ( ) {
EnableDeembedding ( false ) ;
enableDeembeddingAction - > setEnabled ( false ) ;
manualDeembed - > setEnabled ( false ) ;
} ) ;
// Tools menu
auto toolsMenu = new QMenu ( " Tools " , window ) ;
window - > menuBar ( ) - > insertMenu ( window - > getUi ( ) - > menuWindow - > menuAction ( ) , toolsMenu ) ;
actions . insert ( toolsMenu - > menuAction ( ) ) ;
auto impedanceMatching = toolsMenu - > addAction ( " Impedance Matching " ) ;
connect ( impedanceMatching , & QAction : : triggered , this , & VNA : : StartImpedanceMatching ) ;
2022-11-09 19:33:14 +08:00
auto mixedMode = toolsMenu - > addAction ( " Mixed Mode Conversion " ) ;
connect ( mixedMode , & QAction : : triggered , this , & VNA : : StartMixedModeConversion ) ;
2022-10-01 23:10:44 +08:00
defaultCalMenu = new QMenu ( " Default Calibration " , window ) ;
assignDefaultCal = defaultCalMenu - > addAction ( " Assign... " ) ;
removeDefaultCal = defaultCalMenu - > addAction ( " Remove " ) ;
removeDefaultCal - > setEnabled ( false ) ;
defaultCalMenu - > setEnabled ( false ) ;
actions . insert ( window - > getUi ( ) - > menuDevice - > addSeparator ( ) ) ;
window - > getUi ( ) - > menuDevice - > addMenu ( defaultCalMenu ) ;
actions . insert ( defaultCalMenu - > menuAction ( ) ) ;
connect ( assignDefaultCal , & QAction : : triggered , [ = ] ( ) {
if ( window - > getDevice ( ) ) {
2023-01-16 07:25:29 +08:00
auto key = " DefaultCalibration " + window - > getDevice ( ) - > getSerial ( ) ;
2022-10-01 23:10:44 +08:00
QSettings settings ;
auto filename = QFileDialog : : getOpenFileName ( nullptr , " Load calibration data " , settings . value ( key ) . toString ( ) , " Calibration files (*.cal) " , nullptr , QFileDialog : : DontUseNativeDialog ) ;
if ( ! filename . isEmpty ( ) ) {
settings . setValue ( key , filename ) ;
removeDefaultCal - > setEnabled ( true ) ;
2022-12-16 05:43:41 +08:00
LoadCalibration ( filename ) ;
2022-10-01 23:10:44 +08:00
}
}
} ) ;
connect ( removeDefaultCal , & QAction : : triggered , [ = ] ( ) {
QSettings settings ;
2023-01-16 07:25:29 +08:00
settings . remove ( " DefaultCalibration " + window - > getDevice ( ) - > getSerial ( ) ) ;
2022-10-01 23:10:44 +08:00
removeDefaultCal - > setEnabled ( false ) ;
} ) ;
// Sweep toolbar
auto tb_sweep = new QToolBar ( " Sweep " ) ;
std : : vector < QAction * > frequencySweepActions ;
std : : vector < QAction * > powerSweepActions ;
2022-10-30 06:20:57 +08:00
auto bRun = new QPushButton ( " Run/Stop " ) ;
bRun - > setToolTip ( " Pause/continue sweep " ) ;
bRun - > setCheckable ( true ) ;
running = true ;
connect ( bRun , & QPushButton : : toggled , [ = ] ( ) {
if ( bRun - > isChecked ( ) ) {
Run ( ) ;
} else {
Stop ( ) ;
}
} ) ;
connect ( this , & VNA : : sweepStopped , [ = ] ( ) {
bRun - > blockSignals ( true ) ;
bRun - > setChecked ( false ) ;
bRun - > setIcon ( bRun - > style ( ) - > standardIcon ( QStyle : : SP_MediaPause ) ) ;
bRun - > blockSignals ( false ) ;
} ) ;
connect ( this , & VNA : : sweepStarted , [ = ] ( ) {
bRun - > blockSignals ( true ) ;
bRun - > setChecked ( true ) ;
bRun - > setIcon ( bRun - > style ( ) - > standardIcon ( QStyle : : SP_MediaPlay ) ) ;
bRun - > blockSignals ( false ) ;
} ) ;
tb_sweep - > addWidget ( bRun ) ;
2022-10-01 23:10:44 +08:00
auto bSingle = new QPushButton ( " Single " ) ;
bSingle - > setToolTip ( " Single sweep " ) ;
bSingle - > setCheckable ( true ) ;
connect ( bSingle , & QPushButton : : toggled , this , & VNA : : SetSingleSweep ) ;
connect ( this , & VNA : : singleSweepChanged , bSingle , & QPushButton : : setChecked ) ;
tb_sweep - > addWidget ( bSingle ) ;
2022-10-30 06:20:57 +08:00
tb_sweep - > addWidget ( new QLabel ( " Sweep type: " ) ) ;
2023-02-13 05:58:45 +08:00
cbSweepType = new QComboBox ( ) ;
2022-10-30 06:20:57 +08:00
cbSweepType - > addItem ( " Frequency " ) ;
cbSweepType - > addItem ( " Power " ) ;
tb_sweep - > addWidget ( cbSweepType ) ;
2022-10-01 23:10:44 +08:00
auto eStart = new SIUnitEdit ( " Hz " , " kMG " , 6 ) ;
// calculate width required with expected string length
2023-03-25 03:59:34 +08:00
auto width = QFontMetrics ( eStart - > font ( ) ) . horizontalAdvance ( " 3.00000GHz " ) + 15 ;
2022-10-01 23:10:44 +08:00
eStart - > setFixedWidth ( width ) ;
eStart - > setToolTip ( " Start frequency " ) ;
connect ( eStart , & SIUnitEdit : : valueChanged , this , & VNA : : SetStartFreq ) ;
connect ( this , & VNA : : startFreqChanged , eStart , & SIUnitEdit : : setValueQuiet ) ;
frequencySweepActions . push_back ( tb_sweep - > addWidget ( new QLabel ( " Start: " ) ) ) ;
frequencySweepActions . push_back ( tb_sweep - > addWidget ( eStart ) ) ;
auto eCenter = new SIUnitEdit ( " Hz " , " kMG " , 6 ) ;
eCenter - > setFixedWidth ( width ) ;
eCenter - > setToolTip ( " Center frequency " ) ;
connect ( eCenter , & SIUnitEdit : : valueChanged , this , & VNA : : SetCenterFreq ) ;
connect ( this , & VNA : : centerFreqChanged , eCenter , & SIUnitEdit : : setValueQuiet ) ;
frequencySweepActions . push_back ( tb_sweep - > addWidget ( new QLabel ( " Center: " ) ) ) ;
frequencySweepActions . push_back ( tb_sweep - > addWidget ( eCenter ) ) ;
auto eStop = new SIUnitEdit ( " Hz " , " kMG " , 6 ) ;
eStop - > setFixedWidth ( width ) ;
eStop - > setToolTip ( " Stop frequency " ) ;
connect ( eStop , & SIUnitEdit : : valueChanged , this , & VNA : : SetStopFreq ) ;
connect ( this , & VNA : : stopFreqChanged , eStop , & SIUnitEdit : : setValueQuiet ) ;
frequencySweepActions . push_back ( tb_sweep - > addWidget ( new QLabel ( " Stop: " ) ) ) ;
frequencySweepActions . push_back ( tb_sweep - > addWidget ( eStop ) ) ;
auto eSpan = new SIUnitEdit ( " Hz " , " kMG " , 6 ) ;
eSpan - > setFixedWidth ( width ) ;
eSpan - > setToolTip ( " Span " ) ;
connect ( eSpan , & SIUnitEdit : : valueChanged , this , & VNA : : SetSpan ) ;
connect ( this , & VNA : : spanChanged , eSpan , & SIUnitEdit : : setValueQuiet ) ;
frequencySweepActions . push_back ( tb_sweep - > addWidget ( new QLabel ( " Span: " ) ) ) ;
frequencySweepActions . push_back ( tb_sweep - > addWidget ( eSpan ) ) ;
auto bFull = new QPushButton ( QIcon : : fromTheme ( " zoom-fit-best " , QIcon ( " :/icons/zoom-fit.png " ) ) , " " ) ;
bFull - > setToolTip ( " Full span " ) ;
connect ( bFull , & QPushButton : : clicked , this , & VNA : : SetFullSpan ) ;
frequencySweepActions . push_back ( tb_sweep - > addWidget ( bFull ) ) ;
auto bZoomIn = new QPushButton ( QIcon : : fromTheme ( " zoom-in " , QIcon ( " :/icons/zoom-in.png " ) ) , " " ) ;
bZoomIn - > setToolTip ( " Zoom in " ) ;
connect ( bZoomIn , & QPushButton : : clicked , this , & VNA : : SpanZoomIn ) ;
frequencySweepActions . push_back ( tb_sweep - > addWidget ( bZoomIn ) ) ;
auto bZoomOut = new QPushButton ( QIcon : : fromTheme ( " zoom-out " , QIcon ( " :/icons/zoom-out.png " ) ) , " " ) ;
bZoomOut - > setToolTip ( " Zoom out " ) ;
connect ( bZoomOut , & QPushButton : : clicked , this , & VNA : : SpanZoomOut ) ;
frequencySweepActions . push_back ( tb_sweep - > addWidget ( bZoomOut ) ) ;
2023-02-13 05:58:45 +08:00
bZero = new QPushButton ( " 0 " ) ;
2022-10-01 23:10:44 +08:00
bZero - > setToolTip ( " Zero span " ) ;
bZero - > setMaximumWidth ( 28 ) ;
bZero - > setMaximumHeight ( 24 ) ;
connect ( bZero , & QPushButton : : clicked , this , & VNA : : SetZeroSpan ) ;
frequencySweepActions . push_back ( tb_sweep - > addWidget ( bZero ) ) ;
2023-02-13 05:58:45 +08:00
cbLogSweep = new QCheckBox ( " Log " ) ;
2022-10-01 23:10:44 +08:00
cbLogSweep - > setToolTip ( " Logarithmic sweep " ) ;
connect ( cbLogSweep , & QCheckBox : : toggled , this , & VNA : : SetLogSweep ) ;
connect ( this , & VNA : : logSweepChanged , cbLogSweep , & QCheckBox : : setChecked ) ;
frequencySweepActions . push_back ( tb_sweep - > addWidget ( cbLogSweep ) ) ;
// power sweep widgets
auto sbPowerLow = new QDoubleSpinBox ( ) ;
2023-03-25 03:59:34 +08:00
width = QFontMetrics ( sbPowerLow - > font ( ) ) . horizontalAdvance ( " -30.00dBm " ) + 20 ;
2022-10-01 23:10:44 +08:00
sbPowerLow - > setFixedWidth ( width ) ;
sbPowerLow - > setRange ( - 100.0 , 100.0 ) ;
sbPowerLow - > setSingleStep ( 0.25 ) ;
sbPowerLow - > setSuffix ( " dbm " ) ;
sbPowerLow - > setToolTip ( " Stimulus level " ) ;
sbPowerLow - > setKeyboardTracking ( false ) ;
connect ( sbPowerLow , qOverload < double > ( & QDoubleSpinBox : : valueChanged ) , this , & VNA : : SetStartPower ) ;
connect ( this , & VNA : : startPowerChanged , sbPowerLow , & QDoubleSpinBox : : setValue ) ;
powerSweepActions . push_back ( tb_sweep - > addWidget ( new QLabel ( " From: " ) ) ) ;
powerSweepActions . push_back ( tb_sweep - > addWidget ( sbPowerLow ) ) ;
auto sbPowerHigh = new QDoubleSpinBox ( ) ;
2023-03-25 03:59:34 +08:00
width = QFontMetrics ( sbPowerHigh - > font ( ) ) . horizontalAdvance ( " -30.00dBm " ) + 20 ;
2022-10-01 23:10:44 +08:00
sbPowerHigh - > setFixedWidth ( width ) ;
sbPowerHigh - > setRange ( - 100.0 , 100.0 ) ;
sbPowerHigh - > setSingleStep ( 0.25 ) ;
sbPowerHigh - > setSuffix ( " dbm " ) ;
sbPowerHigh - > setToolTip ( " Stimulus level " ) ;
sbPowerHigh - > setKeyboardTracking ( false ) ;
connect ( sbPowerHigh , qOverload < double > ( & QDoubleSpinBox : : valueChanged ) , this , & VNA : : SetStopPower ) ;
connect ( this , & VNA : : stopPowerChanged , sbPowerHigh , & QDoubleSpinBox : : setValue ) ;
powerSweepActions . push_back ( tb_sweep - > addWidget ( new QLabel ( " To: " ) ) ) ;
powerSweepActions . push_back ( tb_sweep - > addWidget ( sbPowerHigh ) ) ;
auto ePowerFreq = new SIUnitEdit ( " Hz " , " kMG " , 6 ) ;
2023-03-25 03:59:34 +08:00
width = QFontMetrics ( ePowerFreq - > font ( ) ) . horizontalAdvance ( " 3.00000GHz " ) + 15 ;
2022-10-01 23:10:44 +08:00
ePowerFreq - > setFixedWidth ( width ) ;
ePowerFreq - > setToolTip ( " Start frequency " ) ;
connect ( ePowerFreq , & SIUnitEdit : : valueChanged , this , & VNA : : SetPowerSweepFrequency ) ;
connect ( this , & VNA : : powerSweepFrequencyChanged , ePowerFreq , & SIUnitEdit : : setValueQuiet ) ;
powerSweepActions . push_back ( tb_sweep - > addWidget ( new QLabel ( " at: " ) ) ) ;
powerSweepActions . push_back ( tb_sweep - > addWidget ( ePowerFreq ) ) ;
window - > addToolBar ( tb_sweep ) ;
toolbars . insert ( tb_sweep ) ;
// Acquisition toolbar
auto tb_acq = new QToolBar ( " Acquisition " ) ;
auto dbm = new QDoubleSpinBox ( ) ;
2023-03-25 03:59:34 +08:00
width = QFontMetrics ( dbm - > font ( ) ) . horizontalAdvance ( " -30.00dBm " ) + 20 ;
2022-10-01 23:10:44 +08:00
dbm - > setFixedWidth ( width ) ;
dbm - > setRange ( - 100.0 , 100.0 ) ;
dbm - > setSingleStep ( 0.25 ) ;
dbm - > setSuffix ( " dbm " ) ;
dbm - > setToolTip ( " Stimulus level " ) ;
dbm - > setKeyboardTracking ( false ) ;
connect ( dbm , qOverload < double > ( & QDoubleSpinBox : : valueChanged ) , this , & VNA : : SetSourceLevel ) ;
connect ( this , & VNA : : sourceLevelChanged , dbm , & QDoubleSpinBox : : setValue ) ;
frequencySweepActions . push_back ( tb_acq - > addWidget ( new QLabel ( " Level: " ) ) ) ;
frequencySweepActions . push_back ( tb_acq - > addWidget ( dbm ) ) ;
auto points = new QSpinBox ( ) ;
points - > setFixedWidth ( 65 ) ;
points - > setRange ( 1 , UINT16_MAX ) ;
points - > setSingleStep ( 100 ) ;
points - > setToolTip ( " Points/sweep " ) ;
points - > setKeyboardTracking ( false ) ;
connect ( points , qOverload < int > ( & QSpinBox : : valueChanged ) , this , & VNA : : SetPoints ) ;
connect ( this , & VNA : : pointsChanged , [ = ] ( int p ) {
points - > blockSignals ( true ) ;
points - > setValue ( p ) ;
points - > blockSignals ( false ) ;
} ) ;
tb_acq - > addWidget ( new QLabel ( " Points: " ) ) ;
tb_acq - > addWidget ( points ) ;
2023-02-08 01:30:05 +08:00
auto eBandwidth = new SIUnitEdit ( " Hz " , " kM " , 3 ) ;
2022-10-01 23:10:44 +08:00
eBandwidth - > setFixedWidth ( 70 ) ;
eBandwidth - > setToolTip ( " IF bandwidth " ) ;
connect ( eBandwidth , & SIUnitEdit : : valueChanged , this , & VNA : : SetIFBandwidth ) ;
connect ( this , & VNA : : IFBandwidthChanged , eBandwidth , & SIUnitEdit : : setValueQuiet ) ;
tb_acq - > addWidget ( new QLabel ( " IF BW: " ) ) ;
tb_acq - > addWidget ( eBandwidth ) ;
tb_acq - > addWidget ( new QLabel ( " Averaging: " ) ) ;
lAverages = new QLabel ( " 0/ " ) ;
tb_acq - > addWidget ( lAverages ) ;
auto sbAverages = new QSpinBox ;
sbAverages - > setRange ( 1 , 99 ) ;
sbAverages - > setFixedWidth ( 40 ) ;
connect ( sbAverages , qOverload < int > ( & QSpinBox : : valueChanged ) , this , & VNA : : SetAveraging ) ;
connect ( this , & VNA : : averagingChanged , sbAverages , & QSpinBox : : setValue ) ;
tb_acq - > addWidget ( sbAverages ) ;
window - > addToolBar ( tb_acq ) ;
toolbars . insert ( tb_acq ) ;
// Calibration toolbar (and populate calibration menu)
auto tb_cal = new QToolBar ( " Calibration " ) ;
calLabel = new QLabel ( " Calibration: " ) ;
UpdateCalWidget ( ) ;
tb_cal - > addWidget ( calLabel ) ;
auto cbEnableCal = new QCheckBox ;
tb_cal - > addWidget ( cbEnableCal ) ;
auto cbType = new QComboBox ( ) ;
auto updateCalComboBox = [ = ] ( ) {
auto cals = cal . getAvailableCalibrations ( ) ;
cbType - > blockSignals ( true ) ;
cbType - > clear ( ) ;
for ( auto c : cals ) {
if ( c . type = = Calibration : : Type : : None ) {
continue ;
}
cbType - > addItem ( c . getShortString ( ) ) ;
}
cbType - > setCurrentText ( cal . getCaltype ( ) . getShortString ( ) ) ;
cbType - > blockSignals ( false ) ;
} ;
connect ( this , & VNA : : deviceInitialized , updateCalComboBox ) ;
updateCalComboBox ( ) ;
auto calToolbarLambda = [ = ] ( ) {
if ( cbEnableCal - > isChecked ( ) ) {
// Get requested calibration type from combobox
ApplyCalibration ( Calibration : : CalType : : fromShortString ( cbType - > currentText ( ) ) ) ;
} else {
DisableCalibration ( ) ;
}
} ;
// Calibration connections
connect ( & cal , & Calibration : : activated , this , & VNA : : UpdateStatusbar ) ;
connect ( & cal , & Calibration : : deactivated , this , & VNA : : UpdateStatusbar ) ;
connect ( cbEnableCal , & QCheckBox : : stateChanged , calToolbarLambda ) ;
connect ( cbType , qOverload < int > ( & QComboBox : : currentIndexChanged ) , calToolbarLambda ) ;
connect ( & cal , & Calibration : : deactivated , [ = ] ( ) {
cbType - > blockSignals ( true ) ;
cbEnableCal - > blockSignals ( true ) ;
cbEnableCal - > setCheckState ( Qt : : CheckState : : Unchecked ) ;
// visually indicate loss of calibration
// cal. file unknown at this moment
UpdateCalWidget ( ) ;
cbType - > blockSignals ( false ) ;
cbEnableCal - > blockSignals ( false ) ;
calImportTerms - > setEnabled ( false ) ;
calImportMeas - > setEnabled ( false ) ;
calApplyToTraces - > setEnabled ( false ) ;
2022-10-02 05:11:13 +08:00
// saveCal->setEnabled(false);
2022-10-01 23:10:44 +08:00
} ) ;
connect ( & cal , & Calibration : : activated , [ = ] ( Calibration : : CalType applied ) {
cbType - > blockSignals ( true ) ;
cbEnableCal - > blockSignals ( true ) ;
cbType - > setCurrentText ( applied . getShortString ( ) ) ;
cbEnableCal - > setCheckState ( Qt : : CheckState : : Checked ) ;
// restore default look of widget
// on hover, show name of active cal. file
UpdateCalWidget ( ) ;
cbType - > blockSignals ( false ) ;
cbEnableCal - > blockSignals ( false ) ;
calImportTerms - > setEnabled ( true ) ;
calImportMeas - > setEnabled ( true ) ;
calApplyToTraces - > setEnabled ( true ) ;
saveCal - > setEnabled ( true ) ;
} ) ;
tb_cal - > addWidget ( cbType ) ;
window - > addToolBar ( tb_cal ) ;
auto configureToolbarForFrequencySweep = [ = ] ( ) {
for ( auto a : frequencySweepActions ) {
a - > setVisible ( true ) ;
}
for ( auto a : powerSweepActions ) {
a - > setVisible ( false ) ;
}
// enable calibration menu entries
calData - > setEnabled ( true ) ;
} ;
auto configureToolbarForPowerSweep = [ = ] ( ) {
for ( auto a : frequencySweepActions ) {
a - > setVisible ( false ) ;
}
for ( auto a : powerSweepActions ) {
a - > setVisible ( true ) ;
}
// disable calibration menu entries
calData - > setEnabled ( false ) ;
} ;
connect ( cbSweepType , qOverload < int > ( & QComboBox : : currentIndexChanged ) , [ = ] ( int index ) {
SetSweepType ( ( SweepType ) index ) ;
} ) ;
connect ( this , & VNA : : sweepTypeChanged , [ = ] ( SweepType sw ) {
if ( sw = = SweepType : : Frequency ) {
configureToolbarForFrequencySweep ( ) ;
} else if ( sw = = SweepType : : Power ) {
configureToolbarForPowerSweep ( ) ;
}
cbSweepType - > setCurrentIndex ( ( int ) sw ) ;
} ) ;
configureToolbarForFrequencySweep ( ) ;
// initial setup is frequency sweep
configureToolbarForFrequencySweep ( ) ;
SetSweepType ( SweepType : : Frequency ) ;
toolbars . insert ( tb_cal ) ;
markerModel = new MarkerModel ( traceModel , this ) ;
auto tracesDock = new QDockWidget ( " Traces " ) ;
traceWidget = new TraceWidgetVNA ( traceModel , cal , deembedding ) ;
tracesDock - > setWidget ( traceWidget ) ;
window - > addDockWidget ( Qt : : LeftDockWidgetArea , tracesDock ) ;
docks . insert ( tracesDock ) ;
auto markerWidget = new MarkerWidget ( * markerModel ) ;
auto markerDock = new QDockWidget ( " Marker " ) ;
markerDock - > setWidget ( markerWidget ) ;
window - > addDockWidget ( Qt : : BottomDockWidgetArea , markerDock ) ;
docks . insert ( markerDock ) ;
SetupSCPI ( ) ;
// Set initial sweep settings
2022-10-06 04:17:53 +08:00
auto & pref = Preferences : : getInstance ( ) ;
2022-10-01 23:10:44 +08:00
if ( pref . Acquisition . useMedianAveraging ) {
average . setMode ( Averaging : : Mode : : Median ) ;
} else {
average . setMode ( Averaging : : Mode : : Mean ) ;
}
if ( pref . Startup . RememberSweepSettings ) {
LoadSweepSettings ( ) ;
} else {
settings . Freq . start = pref . Startup . DefaultSweep . f_start ;
settings . Freq . stop = pref . Startup . DefaultSweep . f_stop ;
SetLogSweep ( pref . Startup . DefaultSweep . logSweep ) ;
SetSourceLevel ( pref . Startup . DefaultSweep . f_excitation ) ;
ConstrainAndUpdateFrequencies ( ) ;
SetStartPower ( pref . Startup . DefaultSweep . dbm_start ) ;
SetStopPower ( pref . Startup . DefaultSweep . dbm_stop ) ;
SetPowerSweepFrequency ( pref . Startup . DefaultSweep . dbm_freq ) ;
SetIFBandwidth ( pref . Startup . DefaultSweep . bandwidth ) ;
SetAveraging ( pref . Startup . DefaultSweep . averaging ) ;
SetPoints ( pref . Startup . DefaultSweep . points ) ;
if ( pref . Startup . DefaultSweep . type = = " Power Sweep " ) {
SetSweepType ( SweepType : : Power ) ;
} else {
SetSweepType ( SweepType : : Frequency ) ;
}
}
// Set ObjectName for toolbars and docks
for ( auto d : findChildren < QDockWidget * > ( ) ) {
d - > setObjectName ( d - > windowTitle ( ) ) ;
}
for ( auto t : findChildren < QToolBar * > ( ) ) {
t - > setObjectName ( t - > windowTitle ( ) ) ;
}
finalize ( central ) ;
}
Calibration : : InterpolationType VNA : : getCalInterpolation ( )
{
double f_min , f_max ;
switch ( settings . sweepType ) {
case SweepType : : Last :
// should never get here, use frequency values just in case
case SweepType : : Frequency :
f_min = settings . Freq . start ;
f_max = settings . Freq . stop ;
break ;
case SweepType : : Power :
f_min = settings . Power . frequency ;
f_max = settings . Power . frequency ;
break ;
}
return cal . getInterpolation ( f_min , f_max , settings . npoints ) ;
}
QString VNA : : getCalStyle ( )
{
auto interpol = getCalInterpolation ( ) ;
QString style = " " ;
switch ( interpol )
{
case Calibration : : InterpolationType : : Unchanged :
case Calibration : : InterpolationType : : Exact :
case Calibration : : InterpolationType : : Interpolate :
style = " " ;
break ;
case Calibration : : InterpolationType : : Extrapolate :
style = " background-color: yellow " ;
break ;
case Calibration : : InterpolationType : : NoCalibration :
style = " background-color: red " ;
break ;
}
return style ;
}
QString VNA : : getCalToolTip ( )
{
auto interpol = getCalInterpolation ( ) ;
QString txt = " " ;
switch ( interpol )
{
case Calibration : : InterpolationType : : Unchanged :
case Calibration : : InterpolationType : : Exact :
case Calibration : : InterpolationType : : Interpolate :
case Calibration : : InterpolationType : : Extrapolate :
{
QString lo = Unit : : ToString ( cal . getMinFreq ( ) , " " , " kMG " , 5 ) ;
QString hi = Unit : : ToString ( cal . getMaxFreq ( ) , " " , " kMG " , 5 ) ;
if ( settings . Freq . start < cal . getMinFreq ( ) ) { lo = " <font color= \" red \" > " + lo + " </font> " ; }
if ( settings . Freq . stop > cal . getMaxFreq ( ) ) { hi = " <font color= \" red \" > " + hi + " </font> " ; }
txt =
" limits: " + lo + " - " + hi
+ " <br> "
+ " points: " + QString : : number ( cal . getNumPoints ( ) )
+ " <br> "
" file: " + cal . getCurrentCalibrationFile ( ) ;
break ;
}
case Calibration : : InterpolationType : : NoCalibration :
txt = " none " ;
break ;
}
return txt ;
}
void VNA : : deactivate ( )
{
StoreSweepSettings ( ) ;
Mode : : deactivate ( ) ;
}
2023-02-13 05:58:45 +08:00
static void SetComboBoxItemEnabled ( QComboBox * comboBox , int index , bool enabled )
{
auto * model = qobject_cast < QStandardItemModel * > ( comboBox - > model ( ) ) ;
assert ( model ) ;
if ( ! model ) return ;
auto * item = model - > item ( index ) ;
assert ( item ) ;
if ( ! item ) return ;
item - > setEnabled ( enabled ) ;
}
2022-10-01 23:10:44 +08:00
void VNA : : initializeDevice ( )
{
2023-02-08 01:30:05 +08:00
if ( ! window - > getDevice ( ) - > supports ( DeviceDriver : : Feature : : VNA ) ) {
InformationBox : : ShowError ( " Unsupported " , " The connected device does not support VNA mode " ) ;
return ;
}
2023-02-13 05:58:45 +08:00
cbLogSweep - > setEnabled ( window - > getDevice ( ) - > supports ( DeviceDriver : : Feature : : VNALogSweep ) ) ;
if ( ! window - > getDevice ( ) - > supports ( DeviceDriver : : Feature : : VNALogSweep ) ) {
SetLogSweep ( false ) ;
}
bZero - > setEnabled ( window - > getDevice ( ) - > supports ( DeviceDriver : : Feature : : VNAZeroSpan ) ) ;
SetComboBoxItemEnabled ( cbSweepType , 0 , window - > getDevice ( ) - > supports ( DeviceDriver : : Feature : : VNAFrequencySweep ) ) ;
SetComboBoxItemEnabled ( cbSweepType , 1 , window - > getDevice ( ) - > supports ( DeviceDriver : : Feature : : VNAPowerSweep ) ) ;
2022-10-01 23:10:44 +08:00
defaultCalMenu - > setEnabled ( true ) ;
2023-01-16 07:25:29 +08:00
connect ( window - > getDevice ( ) , & DeviceDriver : : VNAmeasurementReceived , this , & VNA : : NewDatapoint , Qt : : UniqueConnection ) ;
2022-10-01 23:10:44 +08:00
// Check if default calibration exists and attempt to load it
QSettings s ;
2023-01-16 07:25:29 +08:00
auto key = " DefaultCalibration " + window - > getDevice ( ) - > getSerial ( ) ;
2022-10-01 23:10:44 +08:00
if ( s . contains ( key ) ) {
auto filename = s . value ( key ) . toString ( ) ;
qDebug ( ) < < " Attempting to load default calibration file " < < filename ;
if ( QFile : : exists ( filename ) ) {
if ( cal . fromFile ( filename ) ) {
qDebug ( ) < < " Calibration successful from " < < filename ;
} else {
qDebug ( ) < < " Calibration not successfull from: " < < filename ;
}
} else {
qDebug ( ) < < " Calibration file not found: " < < filename ;
}
removeDefaultCal - > setEnabled ( true ) ;
} else {
qDebug ( ) < < " No default calibration file set for this device " ;
removeDefaultCal - > setEnabled ( false ) ;
}
// Configure initial state of device
2023-02-20 20:08:31 +08:00
ConstrainAndUpdateFrequencies ( ) ;
2022-10-01 23:10:44 +08:00
SettingsChanged ( ) ;
emit deviceInitialized ( ) ;
2023-01-16 07:25:29 +08:00
if ( window - > getDevice ( ) & & ! cal . validForDevice ( window - > getDevice ( ) - > getSerial ( ) ) ) {
2022-12-16 05:43:41 +08:00
InformationBox : : ShowMessage ( " Invalid calibration " , " The current calibration was created for a different device. You can still use it but the resulting "
" data likely isn't useful. " ) ;
}
2022-10-01 23:10:44 +08:00
}
void VNA : : deviceDisconnected ( )
{
defaultCalMenu - > setEnabled ( false ) ;
2022-10-30 06:20:57 +08:00
emit sweepStopped ( ) ;
2022-10-01 23:10:44 +08:00
}
void VNA : : shutdown ( )
{
if ( cal . hasUnsavedChanges ( ) & & cal . getCaltype ( ) . type ! = Calibration : : Type : : None ) {
auto save = InformationBox : : AskQuestion ( " Save calibration? " , " The calibration contains data that has not been saved yet. Do you want to save it before exiting? " , false ) ;
if ( save ) {
2022-11-10 06:29:37 +08:00
SaveCalibration ( ) ;
2022-10-01 23:10:44 +08:00
}
}
}
nlohmann : : json VNA : : toJSON ( )
{
nlohmann : : json j ;
// save current sweep/acquisition settings
nlohmann : : json sweep ;
sweep [ " type " ] = SweepTypeToString ( settings . sweepType ) . toStdString ( ) ;
nlohmann : : json freq ;
freq [ " start " ] = settings . Freq . start ;
freq [ " stop " ] = settings . Freq . stop ;
freq [ " power " ] = settings . Freq . excitation_power ;
freq [ " log " ] = settings . Freq . logSweep ;
sweep [ " frequency " ] = freq ;
sweep [ " single " ] = singleSweep ;
nlohmann : : json power ;
power [ " start " ] = settings . Power . start ;
power [ " stop " ] = settings . Power . stop ;
power [ " frequency " ] = settings . Power . frequency ;
sweep [ " power " ] = power ;
sweep [ " points " ] = settings . npoints ;
sweep [ " IFBW " ] = settings . bandwidth ;
j [ " sweep " ] = sweep ;
j [ " traces " ] = traceModel . toJSON ( ) ;
2022-12-13 05:59:10 +08:00
j [ " tiles " ] = tiles - > toJSON ( ) ;
2022-10-01 23:10:44 +08:00
j [ " markers " ] = markerModel - > toJSON ( ) ;
j [ " de-embedding " ] = deembedding . toJSON ( ) ;
j [ " de-embedding_enabled " ] = deembedding_active ;
return j ;
}
void VNA : : fromJSON ( nlohmann : : json j )
{
if ( j . is_null ( ) ) {
return ;
}
if ( j . contains ( " traces " ) ) {
traceModel . fromJSON ( j [ " traces " ] ) ;
}
if ( j . contains ( " tiles " ) ) {
2022-12-13 05:59:10 +08:00
tiles - > fromJSON ( j [ " tiles " ] ) ;
2022-10-01 23:10:44 +08:00
}
if ( j . contains ( " markers " ) ) {
markerModel - > fromJSON ( j [ " markers " ] ) ;
}
if ( j . contains ( " de-embedding " ) ) {
deembedding . fromJSON ( j [ " de-embedding " ] ) ;
EnableDeembedding ( j . value ( " de-embedding_enabled " , true ) ) ;
} else {
EnableDeembedding ( false ) ;
}
// sweep configuration has to go last so graphs can catch events from changed sweep
if ( j . contains ( " sweep " ) ) {
auto sweep = j [ " sweep " ] ;
// restore sweep settings, keep current value as default in case of missing entry
SetPoints ( sweep . value ( " points " , settings . npoints ) ) ;
SetIFBandwidth ( sweep . value ( " IFBW " , settings . bandwidth ) ) ;
if ( sweep . contains ( " frequency " ) ) {
auto freq = sweep [ " frequency " ] ;
SetStartFreq ( freq . value ( " start " , settings . Freq . start ) ) ;
SetStopFreq ( freq . value ( " stop " , settings . Freq . stop ) ) ;
SetSourceLevel ( freq . value ( " power " , settings . Freq . excitation_power ) ) ;
SetLogSweep ( freq . value ( " log " , settings . Freq . logSweep ) ) ;
}
if ( sweep . contains ( " power " ) ) {
auto power = sweep [ " power " ] ;
SetStartPower ( power . value ( " start " , settings . Power . start ) ) ;
SetStopPower ( power . value ( " stop " , settings . Power . stop ) ) ;
SetPowerSweepFrequency ( power . value ( " frequency " , settings . Power . frequency ) ) ;
}
auto type = SweepTypeFromString ( QString : : fromStdString ( sweep [ " type " ] ) ) ;
if ( type = = SweepType : : Last ) {
// default to frequency sweep
type = SweepType : : Frequency ;
}
SetSweepType ( type ) ;
SetSingleSweep ( sweep . value ( " single " , singleSweep ) ) ;
}
}
using namespace std ;
2023-01-16 07:25:29 +08:00
void VNA : : NewDatapoint ( DeviceDriver : : VNAMeasurement m )
2022-10-01 23:10:44 +08:00
{
if ( isActive ! = true ) {
// ignore
return ;
}
if ( changingSettings ) {
// already setting new sweep settings, ignore incoming points from old settings
return ;
}
2023-03-18 01:50:46 +08:00
// Calculate sweep time
if ( m . pointNum = = 0 ) {
// new sweep started
static auto lastStart = QDateTime : : currentDateTimeUtc ( ) ;
auto now = QDateTime : : currentDateTimeUtc ( ) ;
auto sweepTime = lastStart . msecsTo ( now ) ;
lastStart = now ;
qDebug ( ) < < " Sweep took " < < sweepTime < < " milliseconds " ;
}
2022-10-01 23:10:44 +08:00
if ( singleSweep & & average . getLevel ( ) = = averages ) {
2022-10-30 06:20:57 +08:00
Stop ( ) ;
2023-04-03 19:05:52 +08:00
return ;
2022-10-01 23:10:44 +08:00
}
auto m_avg = m ;
bool needsSegmentUpdate = false ;
if ( settings . segments > 1 ) {
// using multiple segments, adjust pointNum
auto pointsPerSegment = ceil ( ( double ) settings . npoints / settings . segments ) ;
if ( m_avg . pointNum = = pointsPerSegment - 1 ) {
needsSegmentUpdate = true ;
}
m_avg . pointNum + = pointsPerSegment * settings . activeSegment ;
if ( m_avg . pointNum = = settings . npoints - 1 ) {
needsSegmentUpdate = true ;
}
}
if ( m_avg . pointNum > = settings . npoints ) {
qWarning ( ) < < " Ignoring point with too large point number ( " < < m . pointNum < < " ) " ;
return ;
}
m_avg = average . process ( m_avg ) ;
if ( calMeasuring ) {
if ( average . currentSweep ( ) = = averages ) {
// this is the last averaging sweep, use values for calibration
if ( ! calWaitFirst | | m_avg . pointNum = = 0 ) {
calWaitFirst = false ;
cal . addMeasurements ( calMeasurements , m_avg ) ;
if ( m_avg . pointNum = = settings . npoints - 1 ) {
calMeasuring = false ;
cal . measurementsComplete ( ) ;
2023-07-30 19:09:47 +08:00
delete calDialog ;
2022-10-01 23:10:44 +08:00
}
}
}
int percentage = ( ( ( average . currentSweep ( ) - 1 ) * 100 ) + ( m_avg . pointNum + 1 ) * 100 / settings . npoints ) / averages ;
2022-11-14 07:08:45 +08:00
emit calibrationMeasurementPercentage ( percentage ) ;
2022-10-01 23:10:44 +08:00
}
cal . correctMeasurement ( m_avg ) ;
TraceMath : : DataType type ;
if ( settings . zerospan ) {
type = TraceMath : : DataType : : TimeZeroSpan ;
// keep track of first point time
if ( m_avg . pointNum = = 0 ) {
settings . firstPointTime = m_avg . us ;
m_avg . us = 0 ;
} else {
m_avg . us - = settings . firstPointTime ;
}
} else {
switch ( settings . sweepType ) {
case SweepType : : Last :
case SweepType : : Frequency :
type = TraceMath : : DataType : : Frequency ;
break ;
case SweepType : : Power :
type = TraceMath : : DataType : : Power ;
break ;
}
}
2022-12-12 03:37:29 +08:00
traceModel . addVNAData ( m_avg , type , false ) ;
if ( deembedding_active ) {
deembedding . Deembed ( m_avg ) ;
traceModel . addVNAData ( m_avg , type , true ) ;
}
2022-10-01 23:10:44 +08:00
emit dataChanged ( ) ;
if ( m_avg . pointNum = = settings . npoints - 1 ) {
UpdateAverageCount ( ) ;
markerModel - > updateMarkers ( ) ;
}
2022-11-14 07:08:45 +08:00
2022-10-01 23:10:44 +08:00
static unsigned int lastPoint = 0 ;
if ( m_avg . pointNum > 0 & & m_avg . pointNum ! = lastPoint + 1 ) {
qWarning ( ) < < " Got point " < < m_avg . pointNum < < " but last received point was " < < lastPoint < < " ( " < < ( m_avg . pointNum - lastPoint - 1 ) < < " missed points) " ;
}
lastPoint = m_avg . pointNum ;
if ( needsSegmentUpdate ) {
changingSettings = true ;
if ( settings . activeSegment < settings . segments - 1 ) {
settings . activeSegment + + ;
} else {
settings . activeSegment = 0 ;
}
2022-10-30 19:07:59 +08:00
SettingsChanged ( ) ;
2022-10-01 23:10:44 +08:00
}
}
void VNA : : UpdateAverageCount ( )
{
lAverages - > setText ( QString : : number ( average . getLevel ( ) ) + " / " ) ;
}
2022-10-30 19:07:59 +08:00
void VNA : : SettingsChanged ( )
2022-10-01 23:10:44 +08:00
{
2022-10-30 19:07:59 +08:00
configurationTimer . start ( 100 ) ;
2022-11-19 22:47:08 +08:00
changingSettings = true ;
ResetLiveTraces ( ) ;
2022-10-01 23:10:44 +08:00
}
void VNA : : StartImpedanceMatching ( )
{
auto dialog = new ImpedanceMatchDialog ( * markerModel ) ;
if ( AppWindow : : showGUI ( ) ) {
dialog - > show ( ) ;
}
}
2022-11-09 19:33:14 +08:00
void VNA : : StartMixedModeConversion ( )
{
auto dialog = new MixedModeConversion ( traceModel ) ;
connect ( dialog , & MixedModeConversion : : tracesCreated , [ = ] ( std : : vector < Trace * > traces ) {
auto d = new TraceImportDialog ( traceModel , traces ) ;
if ( AppWindow : : showGUI ( ) ) {
d - > show ( ) ;
}
} ) ;
if ( AppWindow : : showGUI ( ) ) {
dialog - > show ( ) ;
}
}
2022-10-01 23:10:44 +08:00
void VNA : : SetSweepType ( SweepType sw )
{
if ( settings . sweepType ! = sw ) {
settings . sweepType = sw ;
emit sweepTypeChanged ( sw ) ;
2022-11-19 22:47:08 +08:00
ConstrainAndUpdateFrequencies ( ) ;
2022-10-01 23:10:44 +08:00
SettingsChanged ( ) ;
}
}
void VNA : : SetStartFreq ( double freq )
{
settings . Freq . start = freq ;
if ( settings . Freq . stop < freq ) {
settings . Freq . stop = freq ;
}
ConstrainAndUpdateFrequencies ( ) ;
}
void VNA : : SetStopFreq ( double freq )
{
settings . Freq . stop = freq ;
if ( settings . Freq . start > freq ) {
settings . Freq . start = freq ;
}
ConstrainAndUpdateFrequencies ( ) ;
}
void VNA : : SetCenterFreq ( double freq )
{
auto old_span = settings . Freq . stop - settings . Freq . start ;
2023-01-16 07:25:29 +08:00
if ( freq - old_span / 2 < = DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . minFreq ) {
2022-10-01 23:10:44 +08:00
// would shift start frequency below minimum
settings . Freq . start = 0 ;
settings . Freq . stop = 2 * freq ;
2023-01-16 07:25:29 +08:00
} else if ( freq + old_span / 2 > = DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . maxFreq ) {
2022-10-01 23:10:44 +08:00
// would shift stop frequency above maximum
2023-01-16 07:25:29 +08:00
settings . Freq . start = 2 * freq - DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . maxFreq ;
settings . Freq . stop = DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . maxFreq ;
2022-10-01 23:10:44 +08:00
} else {
settings . Freq . start = freq - old_span / 2 ;
settings . Freq . stop = freq + old_span / 2 ;
}
ConstrainAndUpdateFrequencies ( ) ;
}
void VNA : : SetSpan ( double span )
{
2023-01-16 07:25:29 +08:00
auto maxFreq = DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . maxFreq ;
2022-10-01 23:10:44 +08:00
auto old_center = ( settings . Freq . start + settings . Freq . stop ) / 2 ;
2023-01-16 07:25:29 +08:00
if ( old_center < DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . minFreq + span / 2 ) {
2022-10-01 23:10:44 +08:00
// would shift start frequency below minimum
2023-01-16 07:25:29 +08:00
settings . Freq . start = DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . minFreq ;
settings . Freq . stop = DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . minFreq + span ;
2022-10-01 23:10:44 +08:00
} else if ( old_center > maxFreq - span / 2 ) {
// would shift stop frequency above maximum
settings . Freq . start = maxFreq - span ;
settings . Freq . stop = maxFreq ;
} else {
settings . Freq . start = old_center - span / 2 ;
settings . Freq . stop = settings . Freq . start + span ;
}
ConstrainAndUpdateFrequencies ( ) ;
}
void VNA : : SetFullSpan ( )
{
2022-10-30 01:32:16 +08:00
auto & pref = Preferences : : getInstance ( ) ;
if ( pref . Acquisition . fullSpanCalibratedRange & & cal . getNumPoints ( ) > 0 ) {
// calibration is active, use it as the full span range
settings . Freq . start = cal . getMinFreq ( ) ;
settings . Freq . stop = cal . getMaxFreq ( ) ;
} else {
if ( pref . Acquisition . fullSpanManual ) {
settings . Freq . start = pref . Acquisition . fullSpanStart ;
settings . Freq . stop = pref . Acquisition . fullSpanStop ;
} else {
2023-01-16 07:25:29 +08:00
settings . Freq . start = DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . minFreq ;
settings . Freq . stop = DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . maxFreq ;
2022-10-30 01:32:16 +08:00
}
}
2022-10-01 23:10:44 +08:00
ConstrainAndUpdateFrequencies ( ) ;
}
void VNA : : SetZeroSpan ( )
{
auto center = ( settings . Freq . start + settings . Freq . stop ) / 2 ;
SetStartFreq ( center ) ;
SetStopFreq ( center ) ;
}
void VNA : : SpanZoomIn ( )
{
auto center = ( settings . Freq . start + settings . Freq . stop ) / 2 ;
auto old_span = settings . Freq . stop - settings . Freq . start ;
settings . Freq . start = center - old_span / 4 ;
settings . Freq . stop = center + old_span / 4 ;
ConstrainAndUpdateFrequencies ( ) ;
}
void VNA : : SpanZoomOut ( )
{
auto center = ( settings . Freq . start + settings . Freq . stop ) / 2 ;
auto old_span = settings . Freq . stop - settings . Freq . start ;
if ( center > old_span ) {
settings . Freq . start = center - old_span ;
} else {
settings . Freq . start = 0 ;
}
settings . Freq . stop = center + old_span ;
ConstrainAndUpdateFrequencies ( ) ;
}
void VNA : : SetLogSweep ( bool log )
{
if ( settings . Freq . logSweep ! = log ) {
settings . Freq . logSweep = log ;
emit logSweepChanged ( log ) ;
SettingsChanged ( ) ;
}
}
void VNA : : SetSourceLevel ( double level )
{
2023-01-16 07:25:29 +08:00
if ( level > DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . maxdBm ) {
level = DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . maxdBm ;
} else if ( level < DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . mindBm ) {
level = DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . mindBm ;
2022-10-01 23:10:44 +08:00
}
emit sourceLevelChanged ( level ) ;
settings . Freq . excitation_power = level ;
SettingsChanged ( ) ;
}
void VNA : : SetStartPower ( double level )
{
settings . Power . start = level ;
emit startPowerChanged ( level ) ;
ConstrainAndUpdateFrequencies ( ) ;
}
void VNA : : SetStopPower ( double level )
{
settings . Power . stop = level ;
emit stopPowerChanged ( level ) ;
ConstrainAndUpdateFrequencies ( ) ;
}
void VNA : : SetPowerSweepFrequency ( double freq )
{
settings . Power . frequency = freq ;
emit powerSweepFrequencyChanged ( freq ) ;
2022-11-19 22:47:08 +08:00
ConstrainAndUpdateFrequencies ( ) ;
2022-10-01 23:10:44 +08:00
SettingsChanged ( ) ;
}
void VNA : : SetPoints ( unsigned int points )
{
2023-01-16 07:25:29 +08:00
unsigned int maxPoints = Preferences : : getInstance ( ) . Acquisition . allowSegmentedSweep ? UINT16_MAX : DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . maxPoints ;
2022-10-01 23:10:44 +08:00
if ( points > maxPoints ) {
points = maxPoints ;
} else if ( points < 2 ) {
points = 2 ;
}
2023-01-16 07:25:29 +08:00
if ( points > DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . maxPoints ) {
2022-10-01 23:10:44 +08:00
// needs segmented sweep
2023-01-16 07:25:29 +08:00
settings . segments = ceil ( ( double ) points / DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . maxPoints ) ;
2022-10-01 23:10:44 +08:00
settings . activeSegment = 0 ;
} else {
// can fit all points into one segment
settings . segments = 1 ;
settings . activeSegment = 0 ;
}
emit pointsChanged ( points ) ;
settings . npoints = points ;
SettingsChanged ( ) ;
}
void VNA : : SetIFBandwidth ( double bandwidth )
{
2023-01-16 07:25:29 +08:00
if ( bandwidth > DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . maxIFBW ) {
bandwidth = DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . maxIFBW ;
} else if ( bandwidth < DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . minIFBW ) {
bandwidth = DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . minIFBW ;
2022-10-01 23:10:44 +08:00
}
settings . bandwidth = bandwidth ;
emit IFBandwidthChanged ( settings . bandwidth ) ;
SettingsChanged ( ) ;
}
void VNA : : SetAveraging ( unsigned int averages )
{
this - > averages = averages ;
average . setAverages ( averages ) ;
emit averagingChanged ( averages ) ;
SettingsChanged ( ) ;
}
void VNA : : ExcitationRequired ( )
{
if ( ! Preferences : : getInstance ( ) . Acquisition . alwaysExciteAllPorts ) {
2023-01-16 07:25:29 +08:00
for ( unsigned int i = 1 ; i < DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . ports ; i + + ) {
2022-10-01 23:10:44 +08:00
auto required = traceModel . PortExcitationRequired ( i ) ;
auto set = find ( settings . excitedPorts . begin ( ) , settings . excitedPorts . end ( ) , i ) ! = settings . excitedPorts . end ( ) ;
if ( required ! = set ) {
// Required port excitation changed
SettingsChanged ( ) ;
break ;
}
}
}
}
void VNA : : DisableCalibration ( )
{
cal . deactivate ( ) ;
}
void VNA : : ApplyCalibration ( Calibration : : CalType type )
{
if ( cal . canCompute ( type ) ) {
try {
cal . compute ( type ) ;
} catch ( runtime_error & e ) {
InformationBox : : ShowError ( " Calibration failure " , e . what ( ) ) ;
DisableCalibration ( ) ;
}
} else {
if ( settings . sweepType = = SweepType : : Frequency ) {
// Not all required traces available
InformationBox : : ShowMessageBlocking ( " Missing calibration measurements " , " Not all calibration measurements for this type of calibration have been taken. The calibration can be enabled after the missing measurements have been acquired. " ) ;
DisableCalibration ( ) ;
cal . edit ( ) ;
} else {
// Not all required traces available
InformationBox : : ShowMessageBlocking ( " Missing calibration measurements " , " Not all calibration measurements for this type of calibration have been taken. Please switch to frequency sweep to take these measurements. " ) ;
DisableCalibration ( ) ;
}
}
}
void VNA : : StartCalibrationMeasurements ( std : : set < CalibrationMeasurement : : Base * > m )
{
if ( ! window - > getDevice ( ) ) {
return ;
}
// Stop sweep
2022-10-30 06:20:57 +08:00
running = false ;
2022-10-31 22:09:19 +08:00
ConfigureDevice ( ) ;
2022-10-01 23:10:44 +08:00
calMeasurements = m ;
// Delete any already captured data of this measurement
cal . clearMeasurements ( m ) ;
calWaitFirst = true ;
// show messagebox
QString text = " Measuring " ;
if ( m . size ( ) = = 1 ) {
text . append ( " \" " ) ;
text . append ( CalibrationMeasurement : : Base : : TypeToString ( ( * m . begin ( ) ) - > getType ( ) ) ) ;
text . append ( " \" parameters. " ) ;
} else {
text . append ( " multiple calibration standards. " ) ;
}
2023-07-30 19:09:47 +08:00
calDialog = new QProgressDialog ( ) ;
calDialog - > setLabelText ( text ) ;
calDialog - > setCancelButtonText ( " Abort " ) ;
calDialog - > setWindowTitle ( " Taking calibration measurement... " ) ;
calDialog - > setValue ( 0 ) ;
calDialog - > setWindowModality ( Qt : : ApplicationModal ) ;
2022-10-01 23:10:44 +08:00
// always show the dialog
2023-07-30 19:09:47 +08:00
calDialog - > setMinimumDuration ( 0 ) ;
// A modal QProgressDialog calls processEvents() in setValue(). Needs to use a queued connection to update the progress
// value from within the NewDatapoint slot to prevent possible re-entrancy.
connect ( this , & VNA : : calibrationMeasurementPercentage , calDialog , & QProgressDialog : : setValue , Qt : : QueuedConnection ) ;
connect ( calDialog , & QProgressDialog : : canceled , this , [ = ] ( ) {
2022-10-01 23:10:44 +08:00
// the user aborted the calibration measurement
calMeasuring = false ;
cal . clearMeasurements ( calMeasurements ) ;
2023-07-30 19:09:47 +08:00
delete calDialog ;
} , Qt : : UniqueConnection ) ;
2022-10-01 23:10:44 +08:00
// Trigger sweep to start from beginning
2022-10-31 22:09:19 +08:00
running = true ;
2022-10-30 19:07:59 +08:00
ConfigureDevice ( true , [ = ] ( bool ) {
2022-10-01 23:10:44 +08:00
// enable calibration measurement only in transmission callback (prevents accidental sampling of data which was still being processed)
calMeasuring = true ;
} ) ;
}
void VNA : : SetupSCPI ( )
{
SCPINode : : add ( new SCPICommand ( " SWEEP " , [ = ] ( QStringList params ) - > QString {
if ( params . size ( ) > = 1 ) {
if ( params [ 0 ] = = " FREQUENCY " ) {
SetSweepType ( SweepType : : Frequency ) ;
2022-11-19 22:47:08 +08:00
ResetLiveTraces ( ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
2022-10-01 23:10:44 +08:00
} else if ( params [ 0 ] = = " POWER " ) {
SetSweepType ( SweepType : : Power ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
}
// either no parameter or invalid
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} , [ = ] ( QStringList ) - > QString {
return settings . sweepType = = SweepType : : Frequency ? " FREQUENCY " : " POWER " ;
} ) ) ;
auto scpi_freq = new SCPINode ( " FREQuency " ) ;
SCPINode : : add ( scpi_freq ) ;
scpi_freq - > add ( new SCPICommand ( " SPAN " , [ = ] ( QStringList params ) - > QString {
unsigned long long newval ;
if ( ! SCPI : : paramToULongLong ( params , 0 , newval ) ) {
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
SetSpan ( newval ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
} , [ = ] ( QStringList ) - > QString {
return QString : : number ( settings . Freq . stop - settings . Freq . start , ' f ' , 0 ) ;
} ) ) ;
scpi_freq - > add ( new SCPICommand ( " START " , [ = ] ( QStringList params ) - > QString {
unsigned long long newval ;
if ( ! SCPI : : paramToULongLong ( params , 0 , newval ) ) {
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
SetStartFreq ( newval ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
} , [ = ] ( QStringList ) - > QString {
return QString : : number ( settings . Freq . start , ' f ' , 0 ) ;
} ) ) ;
scpi_freq - > add ( new SCPICommand ( " CENTer " , [ = ] ( QStringList params ) - > QString {
unsigned long long newval ;
if ( ! SCPI : : paramToULongLong ( params , 0 , newval ) ) {
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
SetCenterFreq ( newval ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
} , [ = ] ( QStringList ) - > QString {
return QString : : number ( ( settings . Freq . start + settings . Freq . stop ) / 2 , ' f ' , 0 ) ;
} ) ) ;
scpi_freq - > add ( new SCPICommand ( " STOP " , [ = ] ( QStringList params ) - > QString {
unsigned long long newval ;
if ( ! SCPI : : paramToULongLong ( params , 0 , newval ) ) {
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
SetStopFreq ( newval ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
} , [ = ] ( QStringList ) - > QString {
return QString : : number ( settings . Freq . stop , ' f ' , 0 ) ;
} ) ) ;
scpi_freq - > add ( new SCPICommand ( " FULL " , [ = ] ( QStringList params ) - > QString {
Q_UNUSED ( params )
SetFullSpan ( ) ;
2022-11-19 22:47:08 +08:00
ResetLiveTraces ( ) ;
2022-10-01 23:10:44 +08:00
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
} , nullptr ) ) ;
scpi_freq - > add ( new SCPICommand ( " ZERO " , [ = ] ( QStringList params ) - > QString {
Q_UNUSED ( params )
SetZeroSpan ( ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
} , nullptr ) ) ;
auto scpi_power = new SCPINode ( " POWer " ) ;
SCPINode : : add ( scpi_power ) ;
scpi_power - > add ( new SCPICommand ( " START " , [ = ] ( QStringList params ) - > QString {
double newval ;
if ( ! SCPI : : paramToDouble ( params , 0 , newval ) ) {
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
SetStartPower ( newval ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
} , [ = ] ( QStringList ) - > QString {
return QString : : number ( settings . Power . start ) ;
} ) ) ;
scpi_power - > add ( new SCPICommand ( " STOP " , [ = ] ( QStringList params ) - > QString {
double newval ;
if ( ! SCPI : : paramToDouble ( params , 0 , newval ) ) {
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
SetStopPower ( newval ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
} , [ = ] ( QStringList ) - > QString {
return QString : : number ( settings . Power . stop ) ;
} ) ) ;
auto scpi_acq = new SCPINode ( " ACQuisition " ) ;
SCPINode : : add ( scpi_acq ) ;
scpi_acq - > add ( new SCPICommand ( " IFBW " , [ = ] ( QStringList params ) - > QString {
unsigned long long newval ;
if ( ! SCPI : : paramToULongLong ( params , 0 , newval ) ) {
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
SetIFBandwidth ( newval ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
} , [ = ] ( QStringList ) - > QString {
return QString : : number ( settings . bandwidth ) ;
} ) ) ;
scpi_acq - > add ( new SCPICommand ( " POINTS " , [ = ] ( QStringList params ) - > QString {
unsigned long long newval ;
if ( ! SCPI : : paramToULongLong ( params , 0 , newval ) ) {
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
SetPoints ( newval ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
} , [ = ] ( QStringList ) - > QString {
return QString : : number ( settings . npoints ) ;
} ) ) ;
scpi_acq - > add ( new SCPICommand ( " AVG " , [ = ] ( QStringList params ) - > QString {
unsigned long long newval ;
if ( ! SCPI : : paramToULongLong ( params , 0 , newval ) ) {
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
SetAveraging ( newval ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
} , [ = ] ( QStringList ) - > QString {
return QString : : number ( averages ) ;
} ) ) ;
scpi_acq - > add ( new SCPICommand ( " AVGLEVel " , nullptr , [ = ] ( QStringList ) - > QString {
return QString : : number ( average . getLevel ( ) ) ;
} ) ) ;
scpi_acq - > add ( new SCPICommand ( " FINished " , nullptr , [ = ] ( QStringList ) - > QString {
return average . getLevel ( ) = = averages ? SCPI : : getResultName ( SCPI : : Result : : True ) : SCPI : : getResultName ( SCPI : : Result : : False ) ;
} ) ) ;
scpi_acq - > add ( new SCPICommand ( " LIMit " , nullptr , [ = ] ( QStringList ) - > QString {
2022-12-13 05:59:10 +08:00
return tiles - > allLimitsPassing ( ) ? " PASS " : " FAIL " ;
2022-10-01 23:10:44 +08:00
} ) ) ;
scpi_acq - > add ( new SCPICommand ( " SINGLE " , [ = ] ( QStringList params ) - > QString {
bool single ;
if ( ! SCPI : : paramToBool ( params , 0 , single ) ) {
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
SetSingleSweep ( single ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
} , [ = ] ( QStringList ) - > QString {
return singleSweep ? SCPI : : getResultName ( SCPI : : Result : : True ) : SCPI : : getResultName ( SCPI : : Result : : False ) ;
} ) ) ;
2022-10-30 06:20:57 +08:00
scpi_acq - > add ( new SCPICommand ( " RUN " , [ = ] ( QStringList ) - > QString {
Run ( ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
} , [ = ] ( QStringList ) - > QString {
return running ? SCPI : : getResultName ( SCPI : : Result : : True ) : SCPI : : getResultName ( SCPI : : Result : : False ) ;
} ) ) ;
scpi_acq - > add ( new SCPICommand ( " STOP " , [ = ] ( QStringList ) - > QString {
Stop ( ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
} , nullptr ) ) ;
2022-10-01 23:10:44 +08:00
auto scpi_stim = new SCPINode ( " STIMulus " ) ;
SCPINode : : add ( scpi_stim ) ;
scpi_stim - > add ( new SCPICommand ( " LVL " , [ = ] ( QStringList params ) - > QString {
double newval ;
if ( ! SCPI : : paramToDouble ( params , 0 , newval ) ) {
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
SetSourceLevel ( newval ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
} , [ = ] ( QStringList ) - > QString {
return QString : : number ( settings . Freq . excitation_power ) ;
} ) ) ;
scpi_stim - > add ( new SCPICommand ( " FREQuency " , [ = ] ( QStringList params ) - > QString {
unsigned long long newval ;
if ( ! SCPI : : paramToULongLong ( params , 0 , newval ) ) {
return SCPI : : getResultName ( SCPI : : Result : : Error ) ;
} else {
SetPowerSweepFrequency ( newval ) ;
return SCPI : : getResultName ( SCPI : : Result : : Empty ) ;
}
} , [ = ] ( QStringList ) - > QString {
return QString : : number ( settings . Power . frequency , ' f ' , 0 ) ;
} ) ) ;
SCPINode : : add ( traceWidget ) ;
SCPINode : : add ( & cal ) ;
cal . add ( new SCPICommand ( " BUSy " , nullptr , [ = ] ( QStringList ) - > QString {
return CalibrationMeasurementActive ( ) ? SCPI : : getResultName ( SCPI : : Result : : True ) : SCPI : : getResultName ( SCPI : : Result : : False ) ;
} ) ) ;
2022-12-13 00:39:17 +08:00
SCPINode : : add ( & deembedding ) ;
2022-10-01 23:10:44 +08:00
}
void VNA : : ConstrainAndUpdateFrequencies ( )
{
2023-01-17 07:25:58 +08:00
if ( settings . Freq . stop > DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . maxFreq ) {
settings . Freq . stop = DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . maxFreq ;
2022-10-01 23:10:44 +08:00
}
if ( settings . Freq . start > settings . Freq . stop ) {
settings . Freq . start = settings . Freq . stop ;
}
2023-01-16 07:25:29 +08:00
if ( settings . Freq . start < DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . minFreq ) {
settings . Freq . start = DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . minFreq ;
2022-10-01 23:10:44 +08:00
}
settings . zerospan = ( settings . sweepType = = SweepType : : Frequency & & settings . Freq . start = = settings . Freq . stop )
| | ( settings . sweepType = = SweepType : : Power & & settings . Power . start = = settings . Power . stop ) ;
emit startFreqChanged ( settings . Freq . start ) ;
emit stopFreqChanged ( settings . Freq . stop ) ;
emit spanChanged ( settings . Freq . stop - settings . Freq . start ) ;
emit centerFreqChanged ( ( settings . Freq . stop + settings . Freq . start ) / 2 ) ;
SettingsChanged ( ) ;
}
void VNA : : LoadSweepSettings ( )
{
2022-10-06 04:17:53 +08:00
auto & pref = Preferences : : getInstance ( ) ;
2022-10-01 23:10:44 +08:00
QSettings s ;
// frequency sweep settings
settings . Freq . start = s . value ( " SweepFreqStart " , pref . Startup . DefaultSweep . f_start ) . toULongLong ( ) ;
settings . Freq . stop = s . value ( " SweepFreqStop " , pref . Startup . DefaultSweep . f_stop ) . toULongLong ( ) ;
SetSourceLevel ( s . value ( " SweepFreqLevel " , pref . Startup . DefaultSweep . f_excitation ) . toDouble ( ) ) ;
SetLogSweep ( s . value ( " SweepFreqLog " , pref . Startup . DefaultSweep . logSweep ) . toBool ( ) ) ;
// power sweep settings
SetStartPower ( s . value ( " SweepPowerStart " , pref . Startup . DefaultSweep . dbm_start ) . toDouble ( ) ) ;
SetStopPower ( s . value ( " SweepPowerStop " , pref . Startup . DefaultSweep . dbm_stop ) . toDouble ( ) ) ;
SetPowerSweepFrequency ( s . value ( " SweepPowerFreq " , pref . Startup . DefaultSweep . dbm_freq ) . toULongLong ( ) ) ;
SetPoints ( s . value ( " SweepPoints " , pref . Startup . DefaultSweep . points ) . toInt ( ) ) ;
SetIFBandwidth ( s . value ( " SweepBandwidth " , pref . Startup . DefaultSweep . bandwidth ) . toUInt ( ) ) ;
SetAveraging ( s . value ( " SweepAveraging " , pref . Startup . DefaultSweep . averaging ) . toInt ( ) ) ;
ConstrainAndUpdateFrequencies ( ) ;
auto typeString = s . value ( " SweepType " , pref . Startup . DefaultSweep . type ) . toString ( ) ;
if ( typeString = = " Power " ) {
SetSweepType ( SweepType : : Power ) ;
} else {
SetSweepType ( SweepType : : Frequency ) ;
}
}
void VNA : : StoreSweepSettings ( )
{
QSettings s ;
s . setValue ( " SweepType " , settings . sweepType = = SweepType : : Frequency ? " Frequency " : " Power " ) ;
s . setValue ( " SweepFreqStart " , static_cast < unsigned long long > ( settings . Freq . start ) ) ;
s . setValue ( " SweepFreqStop " , static_cast < unsigned long long > ( settings . Freq . stop ) ) ;
s . setValue ( " SweepFreqLevel " , settings . Freq . excitation_power ) ;
s . setValue ( " SweepFreqLog " , settings . Freq . logSweep ) ;
s . setValue ( " SweepPowerStart " , settings . Power . start ) ;
s . setValue ( " SweepPowerStop " , settings . Power . stop ) ;
s . setValue ( " SweepPowerFreq " , static_cast < unsigned long long > ( settings . Power . frequency ) ) ;
s . setValue ( " SweepBandwidth " , settings . bandwidth ) ;
s . setValue ( " SweepPoints " , settings . npoints ) ;
s . setValue ( " SweepAveraging " , averages ) ;
}
void VNA : : UpdateCalWidget ( )
{
calLabel - > setStyleSheet ( getCalStyle ( ) ) ;
calLabel - > setToolTip ( getCalToolTip ( ) ) ;
}
void VNA : : createDefaultTracesAndGraphs ( int ports )
{
auto getDefaultColor = [ ] ( int ports , int i , int j ) - > QColor {
// Default colors for up to four ports, ensures that e.g. S21 always has the same color
const array < vector < QColor > , 4 > defaultColors = { {
{ Qt : : yellow } ,
{ Qt : : yellow , Qt : : blue , Qt : : green , Qt : : red } ,
{ Qt : : yellow , Qt : : blue , Qt : : cyan , Qt : : green , Qt : : red , Qt : : darkGreen , Qt : : darkBlue , Qt : : darkYellow , Qt : : magenta } ,
{ Qt : : yellow , Qt : : blue , Qt : : cyan , Qt : : darkCyan , Qt : : green , Qt : : red , Qt : : darkGreen , Qt : : gray , Qt : : darkBlue , Qt : : darkYellow , Qt : : magenta , Qt : : darkMagenta , Qt : : cyan , Qt : : darkGray , Qt : : lightGray , Qt : : darkRed } ,
} } ;
if ( ports > = 1 & & ports < = 4 ) {
return defaultColors [ ports - 1 ] [ i * ports + j ] ;
} else {
// not enough predefined colors available for all ports, just cycle through list
const array < QColor , 16 > list = { {
Qt : : yellow , Qt : : blue , Qt : : green , Qt : : red , Qt : : cyan , Qt : : magenta , Qt : : yellow , Qt : : darkRed , Qt : : darkGreen , Qt : : darkBlue , Qt : : gray , Qt : : darkCyan , Qt : : darkMagenta , Qt : : darkYellow , Qt : : darkGray , Qt : : lightGray
} } ;
auto index = ( i * ports + j ) % list . size ( ) ;
return list [ index ] ;
}
} ;
2023-02-18 00:30:54 +08:00
if ( ports > 1 ) {
vector < vector < TracePlot * > > plots ;
for ( int i = 0 ; i < ports ; i + + ) {
plots . push_back ( vector < TracePlot * > ( ) ) ;
for ( int j = 0 ; j < ports ; j + + ) {
QString param = " S " + QString : : number ( i + 1 ) + QString : : number ( j + 1 ) ;
auto trace = new Trace ( param , getDefaultColor ( ports , i , j ) , param ) ;
traceModel . addTrace ( trace ) ;
TracePlot * plot ;
if ( i = = j ) {
plot = new TraceSmithChart ( traceModel ) ;
} else {
plot = new TraceXYPlot ( traceModel ) ;
}
plot - > updateSpan ( settings . Freq . start , settings . Freq . stop ) ;
plot - > enableTrace ( trace , true ) ;
plots [ i ] . push_back ( plot ) ;
2022-10-01 23:10:44 +08:00
}
}
2023-02-18 00:30:54 +08:00
// Add created graphs to tiles
tiles - > clear ( ) ;
TileWidget * tile = tiles ;
2022-10-01 23:10:44 +08:00
for ( int i = 0 ; i < ports ; i + + ) {
2023-02-18 00:30:54 +08:00
TileWidget * row ;
if ( i ! = ports - 1 ) {
// this is not the last row, split tile
tile - > splitVertically ( ) ;
row = tile - > Child1 ( ) ;
tile = tile - > Child2 ( ) ;
2022-10-01 23:10:44 +08:00
} else {
2023-02-18 00:30:54 +08:00
row = tile ;
}
for ( int j = 0 ; j < ports ; j + + ) {
TileWidget * graphTile ;
if ( j ! = ports - 1 ) {
row - > splitHorizontally ( ) ;
graphTile = row - > Child1 ( ) ;
row = row - > Child2 ( ) ;
} else {
graphTile = row ;
}
graphTile - > setPlot ( plots [ i ] [ j ] ) ;
2022-10-01 23:10:44 +08:00
}
2023-02-18 00:30:54 +08:00
}
if ( ports > = 3 ) {
// default split at the middle does not result in all plots being the same size, adjust
tile = tiles ;
for ( int i = 0 ; i < ports ; i + + ) {
TileWidget * rowTile ;
if ( i < ports - 1 ) {
tile - > setSplitPercentage ( 100 / ( ports - i ) ) ;
rowTile = tile - > Child1 ( ) ;
} else {
rowTile = tile ;
}
for ( int j = 0 ; j < ports - 1 ; j + + ) {
rowTile - > setSplitPercentage ( 100 / ( ports - j ) ) ;
rowTile = rowTile - > Child2 ( ) ;
}
tile = tile - > Child2 ( ) ;
2022-10-01 23:10:44 +08:00
}
}
2023-02-18 00:30:54 +08:00
} else if ( ports = = 1 ) {
tiles - > clear ( ) ;
tiles - > splitHorizontally ( ) ;
auto trace = new Trace ( " S11 " , getDefaultColor ( ports , 0 , 0 ) , " S11 " ) ;
traceModel . addTrace ( trace ) ;
auto smithchart = new TraceSmithChart ( traceModel ) ;
auto xyplot = new TraceXYPlot ( traceModel ) ;
smithchart - > updateSpan ( settings . Freq . start , settings . Freq . stop ) ;
smithchart - > enableTrace ( trace , true ) ;
xyplot - > updateSpan ( settings . Freq . start , settings . Freq . stop ) ;
xyplot - > enableTrace ( trace , true ) ;
tiles - > Child1 ( ) - > setPlot ( smithchart ) ;
tiles - > Child2 ( ) - > setPlot ( xyplot ) ;
2022-10-01 23:10:44 +08:00
}
}
void VNA : : EnableDeembedding ( bool enable )
{
deembedding_active = enable ;
enableDeembeddingAction - > blockSignals ( true ) ;
enableDeembeddingAction - > setChecked ( enable ) ;
enableDeembeddingAction - > blockSignals ( false ) ;
2022-12-12 03:37:29 +08:00
for ( auto t : traceModel . getLiveTraces ( ) ) {
if ( enable ) {
t - > setDeembeddingActive ( true ) ;
} else {
t - > clearDeembedding ( ) ;
}
}
2022-10-01 23:10:44 +08:00
}
void VNA : : setAveragingMode ( Averaging : : Mode mode )
{
average . setMode ( mode ) ;
}
void VNA : : preset ( )
{
for ( auto t : traceModel . getTraces ( ) ) {
if ( Trace : : isVNAParameter ( t - > name ( ) ) ) {
traceModel . removeTrace ( t ) ;
}
}
// Create default traces
2023-01-16 07:25:29 +08:00
createDefaultTracesAndGraphs ( DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . ports ) ;
2022-10-01 23:10:44 +08:00
}
QString VNA : : SweepTypeToString ( VNA : : SweepType sw )
{
switch ( sw ) {
case SweepType : : Frequency : return " Frequency " ;
case SweepType : : Power : return " Power " ;
default : return " Unknown " ;
}
}
VNA : : SweepType VNA : : SweepTypeFromString ( QString s )
{
for ( int i = 0 ; i < ( int ) SweepType : : Last ; i + + ) {
if ( SweepTypeToString ( ( SweepType ) i ) = = s ) {
return ( SweepType ) i ;
}
}
// not found
return SweepType : : Last ;
}
void VNA : : UpdateStatusbar ( )
{
if ( cal . getCaltype ( ) . type ! = Calibration : : Type : : None ) {
QFileInfo fi ( cal . getCurrentCalibrationFile ( ) ) ;
auto filename = fi . fileName ( ) ;
if ( filename . isEmpty ( ) ) {
filename = " Unsaved " ;
}
setStatusbarMessage ( " Calibration: " + filename ) ;
} else {
setStatusbarMessage ( " Calibration: - " ) ;
}
}
void VNA : : SetSingleSweep ( bool single )
{
if ( singleSweep ! = single ) {
singleSweep = single ;
emit singleSweepChanged ( single ) ;
}
2022-10-30 06:20:57 +08:00
if ( single ) {
2022-10-30 19:07:59 +08:00
Run ( ) ;
2022-10-30 06:20:57 +08:00
}
}
void VNA : : Run ( )
{
running = true ;
2022-10-30 19:07:59 +08:00
ConfigureDevice ( ) ;
2022-10-30 06:20:57 +08:00
}
void VNA : : Stop ( )
{
running = false ;
2022-10-30 19:07:59 +08:00
ConfigureDevice ( false ) ;
}
void VNA : : ConfigureDevice ( bool resetTraces , std : : function < void ( bool ) > cb )
{
if ( running ) {
if ( resetTraces ) {
2022-11-19 22:47:08 +08:00
ResetLiveTraces ( ) ;
2022-10-30 19:07:59 +08:00
}
changingSettings = true ;
// assemble VNA protocol settings
2023-01-16 07:25:29 +08:00
DeviceDriver : : VNASettings s = { } ;
2022-10-30 19:07:59 +08:00
s . IFBW = settings . bandwidth ;
if ( Preferences : : getInstance ( ) . Acquisition . alwaysExciteAllPorts ) {
2023-02-08 01:30:05 +08:00
for ( unsigned int i = 1 ; i < = DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . ports ; i + + ) {
2022-10-30 19:07:59 +08:00
s . excitedPorts . push_back ( i ) ;
}
} else {
2023-02-08 01:30:05 +08:00
for ( unsigned int i = 1 ; i < = DeviceDriver : : getInfo ( window - > getDevice ( ) ) . Limits . VNA . ports ; i + + ) {
2022-10-30 19:07:59 +08:00
if ( traceModel . PortExcitationRequired ( i ) )
s . excitedPorts . push_back ( i ) ;
}
}
settings . excitedPorts = s . excitedPorts ;
double start = settings . sweepType = = SweepType : : Frequency ? settings . Freq . start : settings . Power . start ;
double stop = settings . sweepType = = SweepType : : Frequency ? settings . Freq . stop : settings . Power . stop ;
int npoints = settings . npoints ;
emit traceModel . SpanChanged ( start , stop ) ;
if ( settings . segments > 1 ) {
// more than one segment, adjust start/stop
npoints = ceil ( ( double ) settings . npoints / settings . segments ) ;
unsigned int segmentStartPoint = npoints * settings . activeSegment ;
unsigned int segmentStopPoint = segmentStartPoint + npoints - 1 ;
if ( segmentStopPoint > = settings . npoints ) {
segmentStopPoint = settings . npoints - 1 ;
npoints = settings . npoints - segmentStartPoint ;
}
auto seg_start = Util : : Scale < double > ( segmentStartPoint , 0 , settings . npoints - 1 , start , stop ) ;
auto seg_stop = Util : : Scale < double > ( segmentStopPoint , 0 , settings . npoints - 1 , start , stop ) ;
start = seg_start ;
stop = seg_stop ;
}
if ( settings . sweepType = = SweepType : : Frequency ) {
s . freqStart = start ;
s . freqStop = stop ;
s . points = npoints ;
s . dBmStart = settings . Freq . excitation_power ;
s . dBmStop = settings . Freq . excitation_power ;
s . logSweep = settings . Freq . logSweep ;
} else if ( settings . sweepType = = SweepType : : Power ) {
s . freqStart = settings . Power . frequency ;
s . freqStop = settings . Power . frequency ;
s . points = npoints ;
s . dBmStart = start ;
s . dBmStop = stop ;
s . logSweep = false ;
}
if ( window - > getDevice ( ) & & isActive ) {
window - > getDevice ( ) - > setVNA ( s , [ = ] ( bool res ) {
// device received command, reset traces now
if ( resetTraces ) {
2022-11-19 22:47:08 +08:00
ResetLiveTraces ( ) ;
2022-10-30 19:07:59 +08:00
}
if ( cb ) {
cb ( res ) ;
}
changingSettings = false ;
} ) ;
emit sweepStarted ( ) ;
} else {
// no device, unable to start sweep
emit sweepStopped ( ) ;
changingSettings = false ;
}
} else {
if ( window - > getDevice ( ) ) {
changingSettings = true ;
window - > getDevice ( ) - > setIdle ( [ = ] ( bool ) {
changingSettings = false ;
} ) ;
} else {
emit sweepStopped ( ) ;
changingSettings = false ;
}
2022-10-31 22:09:19 +08:00
emit sweepStopped ( ) ;
2022-10-30 19:07:59 +08:00
}
2022-10-01 23:10:44 +08:00
}
2022-11-19 22:47:08 +08:00
void VNA : : ResetLiveTraces ( )
{
settings . activeSegment = 0 ;
average . reset ( settings . npoints ) ;
traceModel . clearLiveData ( ) ;
UpdateAverageCount ( ) ;
UpdateCalWidget ( ) ;
}
2022-10-01 23:10:44 +08:00
bool VNA : : LoadCalibration ( QString filename )
{
2022-10-14 06:27:22 +08:00
return cal . fromFile ( filename ) ;
2022-10-01 23:10:44 +08:00
}
2022-11-10 06:29:37 +08:00
bool VNA : : SaveCalibration ( QString filename )
{
return cal . toFile ( filename ) ;
}