Proof-of-concept TDR measurements
This commit is contained in:
parent
d313988bfd
commit
e68a9abffe
@ -19,10 +19,9 @@ HEADERS += \
|
||||
SpectrumAnalyzer/spectrumanalyzer.h \
|
||||
Tools/eseries.h \
|
||||
Tools/impedancematchdialog.h \
|
||||
Traces/bodeplotaxisdialog.h \
|
||||
Traces/fftcomplex.h \
|
||||
Traces/markerwidget.h \
|
||||
Traces/trace.h \
|
||||
Traces/tracebodeplot.h \
|
||||
Traces/traceeditdialog.h \
|
||||
Traces/traceexportdialog.h \
|
||||
Traces/traceimportdialog.h \
|
||||
@ -32,6 +31,8 @@ HEADERS += \
|
||||
Traces/traceplot.h \
|
||||
Traces/tracesmithchart.h \
|
||||
Traces/tracewidget.h \
|
||||
Traces/tracexyplot.h \
|
||||
Traces/xyplotaxisdialog.h \
|
||||
VNA/vna.h \
|
||||
appwindow.h \
|
||||
averaging.h \
|
||||
@ -63,10 +64,9 @@ SOURCES += \
|
||||
SpectrumAnalyzer/spectrumanalyzer.cpp \
|
||||
Tools/eseries.cpp \
|
||||
Tools/impedancematchdialog.cpp \
|
||||
Traces/bodeplotaxisdialog.cpp \
|
||||
Traces/fftcomplex.cpp \
|
||||
Traces/markerwidget.cpp \
|
||||
Traces/trace.cpp \
|
||||
Traces/tracebodeplot.cpp \
|
||||
Traces/traceeditdialog.cpp \
|
||||
Traces/traceexportdialog.cpp \
|
||||
Traces/traceimportdialog.cpp \
|
||||
@ -76,6 +76,8 @@ SOURCES += \
|
||||
Traces/traceplot.cpp \
|
||||
Traces/tracesmithchart.cpp \
|
||||
Traces/tracewidget.cpp \
|
||||
Traces/tracexyplot.cpp \
|
||||
Traces/xyplotaxisdialog.cpp \
|
||||
VNA/vna.cpp \
|
||||
appwindow.cpp \
|
||||
averaging.cpp \
|
||||
@ -103,12 +105,12 @@ FORMS += \
|
||||
Device/manualcontroldialog.ui \
|
||||
Generator/signalgenwidget.ui \
|
||||
Tools/impedancematchdialog.ui \
|
||||
Traces/bodeplotaxisdialog.ui \
|
||||
Traces/markerwidget.ui \
|
||||
Traces/traceeditdialog.ui \
|
||||
Traces/traceexportdialog.ui \
|
||||
Traces/traceimportdialog.ui \
|
||||
Traces/tracewidget.ui \
|
||||
Traces/xyplotaxisdialog.ui \
|
||||
main.ui \
|
||||
preferencesdialog.ui
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "tilewidget.h"
|
||||
#include "ui_tilewidget.h"
|
||||
#include <QDebug>
|
||||
#include "Traces/tracebodeplot.h"
|
||||
#include "Traces/tracexyplot.h"
|
||||
#include "Traces/tracesmithchart.h"
|
||||
|
||||
TileWidget::TileWidget(TraceModel &model, QWidget *parent) :
|
||||
@ -130,7 +130,7 @@ void TileWidget::on_bSmithchart_clicked()
|
||||
|
||||
void TileWidget::on_bBodeplot_clicked()
|
||||
{
|
||||
setContent(new TraceBodePlot(model));
|
||||
setContent(new TraceXYPlot(model));
|
||||
}
|
||||
|
||||
void TileWidget::traceDeleted(TracePlot *)
|
||||
|
@ -81,7 +81,7 @@
|
||||
<item>
|
||||
<widget class="QPushButton" name="bBodeplot">
|
||||
<property name="text">
|
||||
<string>Bodeplot</string>
|
||||
<string>XY-plot</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "Traces/tracemodel.h"
|
||||
#include "Traces/tracewidget.h"
|
||||
#include "Traces/tracesmithchart.h"
|
||||
#include "Traces/tracebodeplot.h"
|
||||
#include "Traces/tracexyplot.h"
|
||||
#include "Traces/traceimportdialog.h"
|
||||
#include "CustomWidgets/tilewidget.h"
|
||||
#include "CustomWidgets/siunitedit.h"
|
||||
@ -55,11 +55,11 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window)
|
||||
tPort2->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::Port2);
|
||||
traceModel.addTrace(tPort2);
|
||||
|
||||
auto tracebode = new TraceBodePlot(traceModel);
|
||||
auto tracebode = new TraceXYPlot(traceModel);
|
||||
tracebode->enableTrace(tPort1, true);
|
||||
tracebode->enableTrace(tPort2, true);
|
||||
tracebode->setYAxis(0, TraceBodePlot::YAxisType::Magnitude, false, false, -120,0,10);
|
||||
tracebode->setYAxis(1, TraceBodePlot::YAxisType::Disabled, false, true, 0,0,1);
|
||||
tracebode->setYAxis(0, TraceXYPlot::YAxisType::Magnitude, false, false, -120,0,10);
|
||||
tracebode->setYAxis(1, TraceXYPlot::YAxisType::Disabled, false, true, 0,0,1);
|
||||
|
||||
central->setPlot(tracebode);
|
||||
|
||||
|
@ -1,118 +0,0 @@
|
||||
#include "bodeplotaxisdialog.h"
|
||||
#include "ui_bodeplotaxisdialog.h"
|
||||
|
||||
BodeplotAxisDialog::BodeplotAxisDialog(TraceBodePlot *plot) :
|
||||
QDialog(nullptr),
|
||||
ui(new Ui::BodeplotAxisDialog),
|
||||
plot(plot)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// Setup GUI connections
|
||||
connect(ui->Y1type, qOverload<int>(&QComboBox::currentIndexChanged), [this](int index) {
|
||||
ui->Y1log->setEnabled(index != 0);
|
||||
ui->Y1linear->setEnabled(index != 0);
|
||||
ui->Y1auto->setEnabled(index != 0);
|
||||
bool autoRange = ui->Y1auto->isChecked();
|
||||
ui->Y1min->setEnabled(index != 0 && !autoRange);
|
||||
ui->Y1max->setEnabled(index != 0 && !autoRange);
|
||||
ui->Y1divs->setEnabled(index != 0 && !autoRange);
|
||||
auto type = (TraceBodePlot::YAxisType) index;
|
||||
QString unit;
|
||||
switch(type) {
|
||||
case TraceBodePlot::YAxisType::Magnitude: unit = "db"; break;
|
||||
case TraceBodePlot::YAxisType::Phase: unit = "°"; break;
|
||||
case TraceBodePlot::YAxisType::VSWR: unit = ""; break;
|
||||
default: unit = ""; break;
|
||||
}
|
||||
ui->Y1min->setUnit(unit);
|
||||
ui->Y1max->setUnit(unit);
|
||||
ui->Y1divs->setUnit(unit);
|
||||
});
|
||||
connect(ui->Y1auto, &QCheckBox::toggled, [this](bool checked) {
|
||||
ui->Y1min->setEnabled(!checked);
|
||||
ui->Y1max->setEnabled(!checked);
|
||||
ui->Y1divs->setEnabled(!checked);
|
||||
});
|
||||
|
||||
connect(ui->Y2type, qOverload<int>(&QComboBox::currentIndexChanged), [this](int index) {
|
||||
ui->Y2log->setEnabled(index != 0);
|
||||
ui->Y2linear->setEnabled(index != 0);
|
||||
ui->Y2auto->setEnabled(index != 0);
|
||||
bool autoRange = ui->Y2auto->isChecked();
|
||||
ui->Y2min->setEnabled(index != 0 && !autoRange);
|
||||
ui->Y2max->setEnabled(index != 0 && !autoRange);
|
||||
ui->Y2divs->setEnabled(index != 0 && !autoRange);
|
||||
auto type = (TraceBodePlot::YAxisType) index;
|
||||
QString unit;
|
||||
switch(type) {
|
||||
case TraceBodePlot::YAxisType::Magnitude: unit = "db"; break;
|
||||
case TraceBodePlot::YAxisType::Phase: unit = "°"; break;
|
||||
case TraceBodePlot::YAxisType::VSWR: unit = ""; break;
|
||||
default: unit = ""; break;
|
||||
}
|
||||
ui->Y2min->setUnit(unit);
|
||||
ui->Y2max->setUnit(unit);
|
||||
ui->Y2divs->setUnit(unit);
|
||||
});
|
||||
connect(ui->Y2auto, &QCheckBox::toggled, [this](bool checked) {
|
||||
ui->Y2min->setEnabled(!checked);
|
||||
ui->Y2max->setEnabled(!checked);
|
||||
ui->Y2divs->setEnabled(!checked);
|
||||
});
|
||||
|
||||
connect(ui->Xauto, &QCheckBox::toggled, [this](bool checked) {
|
||||
ui->Xmin->setEnabled(!checked);
|
||||
ui->Xmax->setEnabled(!checked);
|
||||
ui->Xdivs->setEnabled(!checked);
|
||||
});
|
||||
|
||||
ui->Xmin->setUnit("Hz");
|
||||
ui->Xmax->setUnit("Hz");
|
||||
ui->Xdivs->setUnit("Hz");
|
||||
ui->Xmin->setPrefixes(" kMG");
|
||||
ui->Xmax->setPrefixes(" kMG");
|
||||
ui->Xdivs->setPrefixes(" kMG");
|
||||
|
||||
// Fill initial values
|
||||
// assume same order in YAxisType enum as in ComboBox items
|
||||
ui->Y1type->setCurrentIndex((int) plot->YAxis[0].type);
|
||||
if(plot->YAxis[0].log) {
|
||||
ui->Y1log->setChecked(true);
|
||||
} else {
|
||||
ui->Y1linear->setChecked(true);
|
||||
}
|
||||
ui->Y1auto->setChecked(plot->YAxis[0].autorange);
|
||||
ui->Y1min->setValueQuiet(plot->YAxis[0].rangeMin);
|
||||
ui->Y1max->setValueQuiet(plot->YAxis[0].rangeMax);
|
||||
ui->Y1divs->setValueQuiet(plot->YAxis[0].rangeDiv);
|
||||
|
||||
ui->Y2type->setCurrentIndex((int) plot->YAxis[1].type);
|
||||
if(plot->YAxis[1].log) {
|
||||
ui->Y2log->setChecked(true);
|
||||
} else {
|
||||
ui->Y2linear->setChecked(true);
|
||||
}
|
||||
ui->Y2auto->setChecked(plot->YAxis[1].autorange);
|
||||
ui->Y2min->setValueQuiet(plot->YAxis[1].rangeMin);
|
||||
ui->Y2max->setValueQuiet(plot->YAxis[1].rangeMax);
|
||||
ui->Y2divs->setValueQuiet(plot->YAxis[1].rangeDiv);
|
||||
|
||||
ui->Xauto->setChecked(plot->XAxis.autorange);
|
||||
ui->Xmin->setValueQuiet(plot->XAxis.rangeMin);
|
||||
ui->Xmax->setValueQuiet(plot->XAxis.rangeMax);
|
||||
ui->Xdivs->setValueQuiet(plot->XAxis.rangeDiv);
|
||||
}
|
||||
|
||||
BodeplotAxisDialog::~BodeplotAxisDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void BodeplotAxisDialog::on_buttonBox_accepted()
|
||||
{
|
||||
// set plot values to the ones selected in the dialog
|
||||
plot->setYAxis(0, (TraceBodePlot::YAxisType) ui->Y1type->currentIndex(), ui->Y1log->isChecked(), ui->Y1auto->isChecked(), ui->Y1min->value(), ui->Y1max->value(), ui->Y1divs->value());
|
||||
plot->setYAxis(1, (TraceBodePlot::YAxisType) ui->Y2type->currentIndex(), ui->Y2log->isChecked(), ui->Y2auto->isChecked(), ui->Y2min->value(), ui->Y2max->value(), ui->Y2divs->value());
|
||||
plot->setXAxis(ui->Xauto->isChecked(), ui->Xmin->value(), ui->Xmax->value(), ui->Xdivs->value());
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
#ifndef BODEPLOTAXISDIALOG_H
|
||||
#define BODEPLOTAXISDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "tracebodeplot.h"
|
||||
|
||||
namespace Ui {
|
||||
class BodeplotAxisDialog;
|
||||
}
|
||||
|
||||
class BodeplotAxisDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BodeplotAxisDialog(TraceBodePlot *plot);
|
||||
~BodeplotAxisDialog();
|
||||
|
||||
private slots:
|
||||
void on_buttonBox_accepted();
|
||||
|
||||
private:
|
||||
Ui::BodeplotAxisDialog *ui;
|
||||
TraceBodePlot *plot;
|
||||
};
|
||||
|
||||
#endif // BODEPLOTAXISDIALOG_H
|
@ -1,462 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BodeplotAxisDialog</class>
|
||||
<widget class="QDialog" name="BodeplotAxisDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>715</width>
|
||||
<height>282</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Axis Setup</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>15</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Primary Y axis</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="Y1type">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disabled</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Magnitude</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Phase</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>VSWR</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="Y1linear">
|
||||
<property name="text">
|
||||
<string>Linear</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">Y1group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="Y1log">
|
||||
<property name="text">
|
||||
<string>Log</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">Y1group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Range:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="Y1auto">
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Maximum:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="SIUnitEdit" name="Y1max"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Minimum:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="SIUnitEdit" name="Y1min"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Divisions:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="SIUnitEdit" name="Y1divs"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>15</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Secondary Y axis</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="Y2type">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disabled</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Magnitude</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Phase</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>VSWR</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="Y2linear">
|
||||
<property name="text">
|
||||
<string>Linear</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">Y2group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="Y2log">
|
||||
<property name="text">
|
||||
<string>Log</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">Y2group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Range:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="Y2auto">
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Maximum:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="SIUnitEdit" name="Y2max"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Minimum:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="SIUnitEdit" name="Y2min"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Divisions:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="SIUnitEdit" name="Y2divs"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>15</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>X axis</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_6">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Range:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="Xauto">
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>Maximum:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="SIUnitEdit" name="Xmax"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>Minimum:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="SIUnitEdit" name="Xmin"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>Divisions:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="SIUnitEdit" name="Xdivs"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>SIUnitEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>CustomWidgets/siunitedit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>BodeplotAxisDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>BodeplotAxisDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="Y1group"/>
|
||||
<buttongroup name="Y2group"/>
|
||||
</buttongroups>
|
||||
</ui>
|
152
Software/PC_Application/Traces/fftcomplex.cpp
Normal file
152
Software/PC_Application/Traces/fftcomplex.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Free FFT and convolution (C++)
|
||||
*
|
||||
* Copyright (c) 2020 Project Nayuki. (MIT License)
|
||||
* https://www.nayuki.io/page/free-small-fft-in-multiple-languages
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
* - The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
* - The Software is provided "as is", without warranty of any kind, express or
|
||||
* implied, including but not limited to the warranties of merchantability,
|
||||
* fitness for a particular purpose and noninfringement. In no event shall the
|
||||
* authors or copyright holders be liable for any claim, damages or other
|
||||
* liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
* out of or in connection with the Software or the use or other dealings in the
|
||||
* Software.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include "fftcomplex.h"
|
||||
|
||||
using std::complex;
|
||||
using std::size_t;
|
||||
using std::uintmax_t;
|
||||
using std::vector;
|
||||
|
||||
|
||||
// Private function prototypes
|
||||
static size_t reverseBits(size_t val, int width);
|
||||
|
||||
|
||||
void Fft::transform(vector<complex<double> > &vec, bool inverse) {
|
||||
size_t n = vec.size();
|
||||
if (n == 0)
|
||||
return;
|
||||
else if ((n & (n - 1)) == 0) // Is power of 2
|
||||
transformRadix2(vec, inverse);
|
||||
else // More complicated algorithm for arbitrary sizes
|
||||
transformBluestein(vec, inverse);
|
||||
}
|
||||
|
||||
|
||||
void Fft::transformRadix2(vector<complex<double> > &vec, bool inverse) {
|
||||
// Length variables
|
||||
size_t n = vec.size();
|
||||
int levels = 0; // Compute levels = floor(log2(n))
|
||||
for (size_t temp = n; temp > 1U; temp >>= 1)
|
||||
levels++;
|
||||
if (static_cast<size_t>(1U) << levels != n)
|
||||
throw std::domain_error("Length is not a power of 2");
|
||||
|
||||
// Trigonometric table
|
||||
vector<complex<double> > expTable(n / 2);
|
||||
for (size_t i = 0; i < n / 2; i++)
|
||||
expTable[i] = std::polar(1.0, (inverse ? 2 : -2) * M_PI * i / n);
|
||||
|
||||
// Bit-reversed addressing permutation
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
size_t j = reverseBits(i, levels);
|
||||
if (j > i)
|
||||
std::swap(vec[i], vec[j]);
|
||||
}
|
||||
|
||||
// Cooley-Tukey decimation-in-time radix-2 FFT
|
||||
for (size_t size = 2; size <= n; size *= 2) {
|
||||
size_t halfsize = size / 2;
|
||||
size_t tablestep = n / size;
|
||||
for (size_t i = 0; i < n; i += size) {
|
||||
for (size_t j = i, k = 0; j < i + halfsize; j++, k += tablestep) {
|
||||
complex<double> temp = vec[j + halfsize] * expTable[k];
|
||||
vec[j + halfsize] = vec[j] - temp;
|
||||
vec[j] += temp;
|
||||
}
|
||||
}
|
||||
if (size == n) // Prevent overflow in 'size *= 2'
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Fft::transformBluestein(vector<complex<double> > &vec, bool inverse) {
|
||||
// Find a power-of-2 convolution length m such that m >= n * 2 + 1
|
||||
size_t n = vec.size();
|
||||
size_t m = 1;
|
||||
while (m / 2 <= n) {
|
||||
if (m > SIZE_MAX / 2)
|
||||
throw std::length_error("Vector too large");
|
||||
m *= 2;
|
||||
}
|
||||
|
||||
// Trigonometric table
|
||||
vector<complex<double> > expTable(n);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
uintmax_t temp = static_cast<uintmax_t>(i) * i;
|
||||
temp %= static_cast<uintmax_t>(n) * 2;
|
||||
double angle = (inverse ? M_PI : -M_PI) * temp / n;
|
||||
expTable[i] = std::polar(1.0, angle);
|
||||
}
|
||||
|
||||
// Temporary vectors and preprocessing
|
||||
vector<complex<double> > avec(m);
|
||||
for (size_t i = 0; i < n; i++)
|
||||
avec[i] = vec[i] * expTable[i];
|
||||
vector<complex<double> > bvec(m);
|
||||
bvec[0] = expTable[0];
|
||||
for (size_t i = 1; i < n; i++)
|
||||
bvec[i] = bvec[m - i] = std::conj(expTable[i]);
|
||||
|
||||
// Convolution
|
||||
vector<complex<double> > cvec(m);
|
||||
convolve(avec, bvec, cvec);
|
||||
|
||||
// Postprocessing
|
||||
for (size_t i = 0; i < n; i++)
|
||||
vec[i] = cvec[i] * expTable[i];
|
||||
}
|
||||
|
||||
|
||||
void Fft::convolve(
|
||||
const vector<complex<double> > &xvec,
|
||||
const vector<complex<double> > &yvec,
|
||||
vector<complex<double> > &outvec) {
|
||||
|
||||
size_t n = xvec.size();
|
||||
if (n != yvec.size() || n != outvec.size())
|
||||
throw std::domain_error("Mismatched lengths");
|
||||
vector<complex<double> > xv = xvec;
|
||||
vector<complex<double> > yv = yvec;
|
||||
transform(xv, false);
|
||||
transform(yv, false);
|
||||
for (size_t i = 0; i < n; i++)
|
||||
xv[i] *= yv[i];
|
||||
transform(xv, true);
|
||||
for (size_t i = 0; i < n; i++) // Scaling (because this FFT implementation omits it)
|
||||
outvec[i] = xv[i] / static_cast<double>(n);
|
||||
}
|
||||
|
||||
|
||||
static size_t reverseBits(size_t val, int width) {
|
||||
size_t result = 0;
|
||||
for (int i = 0; i < width; i++, val >>= 1)
|
||||
result = (result << 1) | (val & 1U);
|
||||
return result;
|
||||
}
|
62
Software/PC_Application/Traces/fftcomplex.h
Normal file
62
Software/PC_Application/Traces/fftcomplex.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Free FFT and convolution (C++)
|
||||
*
|
||||
* Copyright (c) 2020 Project Nayuki. (MIT License)
|
||||
* https://www.nayuki.io/page/free-small-fft-in-multiple-languages
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
* - The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
* - The Software is provided "as is", without warranty of any kind, express or
|
||||
* implied, including but not limited to the warranties of merchantability,
|
||||
* fitness for a particular purpose and noninfringement. In no event shall the
|
||||
* authors or copyright holders be liable for any claim, damages or other
|
||||
* liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
* out of or in connection with the Software or the use or other dealings in the
|
||||
* Software.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <complex>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace Fft {
|
||||
|
||||
/*
|
||||
* Computes the discrete Fourier transform (DFT) of the given complex vector, storing the result back into the vector.
|
||||
* The vector can have any length. This is a wrapper function. The inverse transform does not perform scaling, so it is not a true inverse.
|
||||
*/
|
||||
void transform(std::vector<std::complex<double> > &vec, bool inverse);
|
||||
|
||||
|
||||
/*
|
||||
* Computes the discrete Fourier transform (DFT) of the given complex vector, storing the result back into the vector.
|
||||
* The vector's length must be a power of 2. Uses the Cooley-Tukey decimation-in-time radix-2 algorithm.
|
||||
*/
|
||||
void transformRadix2(std::vector<std::complex<double> > &vec, bool inverse);
|
||||
|
||||
|
||||
/*
|
||||
* Computes the discrete Fourier transform (DFT) of the given complex vector, storing the result back into the vector.
|
||||
* The vector can have any length. This requires the convolution function, which in turn requires the radix-2 FFT function.
|
||||
* Uses Bluestein's chirp z-transform algorithm.
|
||||
*/
|
||||
void transformBluestein(std::vector<std::complex<double> > &vec, bool inverse);
|
||||
|
||||
|
||||
/*
|
||||
* Computes the circular convolution of the given complex vectors. Each vector's length must be the same.
|
||||
*/
|
||||
void convolve(
|
||||
const std::vector<std::complex<double> > &xvec,
|
||||
const std::vector<std::complex<double> > &yvec,
|
||||
std::vector<std::complex<double> > &outvec);
|
||||
|
||||
}
|
@ -1,9 +1,12 @@
|
||||
#include "trace.h"
|
||||
#include <math.h>
|
||||
#include "fftcomplex.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
Trace::Trace(QString name, QColor color, LiveParameter live)
|
||||
: _name(name),
|
||||
: tdr_users(0),
|
||||
_name(name),
|
||||
_color(color),
|
||||
_liveType(LivedataType::Overwrite),
|
||||
_liveParam(live),
|
||||
@ -64,6 +67,12 @@ void Trace::addData(Trace::Data d) {
|
||||
}
|
||||
emit dataAdded(this, d);
|
||||
emit dataChanged();
|
||||
if(lower == _data.begin()) {
|
||||
// received the first point, which means the last sweep just finished
|
||||
if(tdr_users) {
|
||||
updateTimeDomainData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Trace::setName(QString name) {
|
||||
@ -137,12 +146,79 @@ void Trace::removeMarker(TraceMarker *m)
|
||||
markers.erase(m);
|
||||
emit markerRemoved(m);
|
||||
}
|
||||
//#include <iostream>
|
||||
//#include <chrono>
|
||||
|
||||
void Trace::updateTimeDomainData()
|
||||
{
|
||||
// using namespace std::chrono;
|
||||
// auto starttime = duration_cast< milliseconds >(
|
||||
// system_clock::now().time_since_epoch()
|
||||
// ).count();
|
||||
auto steps = size();
|
||||
if(minFreq() * size() != maxFreq()) {
|
||||
// data is not available with correct frequency spacing, calculate required steps
|
||||
steps = maxFreq() / minFreq();
|
||||
}
|
||||
const double PI = 3.141592653589793238463;
|
||||
// reserve vector for negative frequenies and DC as well
|
||||
vector<complex<double>> frequencyDomain(2*steps + 1);
|
||||
// copy frequencies, use the flipped conjugate for negative part
|
||||
for(unsigned int i = 1;i<=steps;i++) {
|
||||
auto S = getData(minFreq() * i);
|
||||
constexpr double alpha0 = 0.54;
|
||||
auto hamming = alpha0 - (1.0 - alpha0) * -cos(PI * i / steps);
|
||||
S *= hamming;
|
||||
frequencyDomain[2 * steps - i + 1] = conj(S);
|
||||
frequencyDomain[i] = S;
|
||||
}
|
||||
// use simple extrapolation from lowest two points to extract DC value
|
||||
auto abs_DC = 2.0 * abs(frequencyDomain[1]) - abs(frequencyDomain[2]);
|
||||
auto phase_DC = 2.0 * arg(frequencyDomain[1]) - arg(frequencyDomain[2]);
|
||||
frequencyDomain[0] = polar(abs_DC, phase_DC);
|
||||
|
||||
auto fft_bins = frequencyDomain.size();
|
||||
timeDomain.clear();
|
||||
timeDomain.resize(fft_bins);
|
||||
const double fs = 1.0 / (minFreq() * fft_bins);
|
||||
double last_step = 0.0;
|
||||
|
||||
Fft::transform(frequencyDomain, true);
|
||||
for(unsigned int i = 0;i<fft_bins;i++) {
|
||||
TimedomainData t;
|
||||
t.time = fs * i;
|
||||
t.impulseResponse = real(frequencyDomain[i]) / fft_bins;
|
||||
t.stepResponse = last_step;
|
||||
last_step += t.impulseResponse;
|
||||
timeDomain.push_back(t);
|
||||
}
|
||||
// auto duration = duration_cast< milliseconds >(
|
||||
// system_clock::now().time_since_epoch()
|
||||
// ).count() - starttime;
|
||||
// cout << "TDR: " << this << " (took " << duration << "ms)" <<endl;
|
||||
}
|
||||
|
||||
void Trace::setReflection(bool value)
|
||||
{
|
||||
reflection = value;
|
||||
}
|
||||
|
||||
void Trace::addTDRinterest()
|
||||
{
|
||||
if(tdr_users == 0) {
|
||||
// no recent time domain data available, calculate now
|
||||
updateTimeDomainData();
|
||||
}
|
||||
tdr_users++;
|
||||
}
|
||||
|
||||
void Trace::removeTDRinterest()
|
||||
{
|
||||
if(tdr_users > 0) {
|
||||
tdr_users--;
|
||||
}
|
||||
}
|
||||
|
||||
void Trace::setCalibration(bool value)
|
||||
{
|
||||
calibration = value;
|
||||
@ -288,7 +364,16 @@ std::complex<double> Trace::getData(double frequency)
|
||||
return std::numeric_limits<std::complex<double>>::quiet_NaN();
|
||||
}
|
||||
|
||||
return sample(index(frequency)).S;
|
||||
auto i = index(frequency);
|
||||
if(_data.at(i).frequency == frequency) {
|
||||
return _data[i].S;
|
||||
} else {
|
||||
// no exact frequency match, needs to interpolate
|
||||
auto high = _data[i];
|
||||
auto low = _data[i-1];
|
||||
double alpha = (frequency - low.frequency) / (high.frequency - low.frequency);
|
||||
return low.S * (1 - alpha) + high.S * alpha;
|
||||
}
|
||||
}
|
||||
|
||||
int Trace::index(double frequency)
|
||||
|
@ -21,6 +21,13 @@ public:
|
||||
std::complex<double> S;
|
||||
};
|
||||
|
||||
class TimedomainData {
|
||||
public:
|
||||
double time;
|
||||
double impulseResponse;
|
||||
double stepResponse;
|
||||
};
|
||||
|
||||
enum class LiveParameter {
|
||||
S11,
|
||||
S12,
|
||||
@ -76,6 +83,14 @@ public:
|
||||
void setCalibration(bool value);
|
||||
void setReflection(bool value);
|
||||
|
||||
// TDR calculation can be ressource intensive, only perform when some other module is interested.
|
||||
// Each interested module should call addTDRinterest(), read the data with getTDR() and finally
|
||||
// call removeTDRinterest() once TDR updates are no longer required.
|
||||
// The data is only updated at the end of a sweep and upon the first addTDRinterest() call.
|
||||
void addTDRinterest();
|
||||
void removeTDRinterest();
|
||||
const std::vector<TimedomainData>& getTDR() { return timeDomain;}
|
||||
|
||||
public slots:
|
||||
void setTouchstoneParameter(int value);
|
||||
void setTouchstoneFilename(const QString &value);
|
||||
@ -98,7 +113,11 @@ signals:
|
||||
void markerRemoved(TraceMarker *m);
|
||||
|
||||
private:
|
||||
void updateTimeDomainData();
|
||||
void printTimeDomain();
|
||||
std::vector<Data> _data;
|
||||
std::vector<TimedomainData> timeDomain;
|
||||
unsigned int tdr_users;
|
||||
QString _name;
|
||||
QColor _color;
|
||||
LivedataType _liveType;
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "tracebodeplot.h"
|
||||
#include "tracexyplot.h"
|
||||
#include <QGridLayout>
|
||||
#include "qwtplotpiecewisecurve.h"
|
||||
#include "qwt_series_data.h"
|
||||
@ -11,18 +11,26 @@
|
||||
#include "tracemarker.h"
|
||||
#include <qwt_symbol.h>
|
||||
#include <qwt_picker_machine.h>
|
||||
#include "bodeplotaxisdialog.h"
|
||||
#include "xyplotaxisdialog.h"
|
||||
#include <preferences.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
set<TraceBodePlot*> TraceBodePlot::allPlots;
|
||||
set<TraceXYPlot*> TraceXYPlot::allPlots;
|
||||
|
||||
static double AxisTransformation(TraceBodePlot::YAxisType type, complex<double> data) {
|
||||
const set<TraceXYPlot::YAxisType> TraceXYPlot::YAxisTypes = {TraceXYPlot::YAxisType::Disabled,
|
||||
TraceXYPlot::YAxisType::Magnitude,
|
||||
TraceXYPlot::YAxisType::Phase,
|
||||
TraceXYPlot::YAxisType::VSWR,
|
||||
TraceXYPlot::YAxisType::Impulse,
|
||||
TraceXYPlot::YAxisType::Step,
|
||||
TraceXYPlot::YAxisType::Impedance};
|
||||
|
||||
static double FrequencyAxisTransformation(TraceXYPlot::YAxisType type, complex<double> data) {
|
||||
switch(type) {
|
||||
case TraceBodePlot::YAxisType::Magnitude: return 20*log10(abs(data)); break;
|
||||
case TraceBodePlot::YAxisType::Phase: return arg(data) * 180.0 / M_PI; break;
|
||||
case TraceBodePlot::YAxisType::VSWR:
|
||||
case TraceXYPlot::YAxisType::Magnitude: return 20*log10(abs(data)); break;
|
||||
case TraceXYPlot::YAxisType::Phase: return arg(data) * 180.0 / M_PI; break;
|
||||
case TraceXYPlot::YAxisType::VSWR:
|
||||
if(abs(data) < 1.0) {
|
||||
return (1+abs(data)) / (1-abs(data));
|
||||
}
|
||||
@ -31,31 +39,79 @@ static double AxisTransformation(TraceBodePlot::YAxisType type, complex<double>
|
||||
}
|
||||
return numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
static double TimeAxisTransformation(TraceXYPlot::YAxisType type, Trace *t, int index) {
|
||||
auto timeData = t->getTDR()[index];
|
||||
switch(type) {
|
||||
case TraceXYPlot::YAxisType::Impulse: return timeData.impulseResponse; break;
|
||||
case TraceXYPlot::YAxisType::Step: return timeData.stepResponse; break;
|
||||
case TraceXYPlot::YAxisType::Impedance:
|
||||
if(abs(timeData.stepResponse) < 1.0) {
|
||||
return 50 * (1+timeData.stepResponse) / (1-timeData.stepResponse);
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
template<TraceBodePlot::YAxisType E> class QwtTraceSeries : public QwtSeriesData<QPointF> {
|
||||
class QwtTraceSeries : public QwtSeriesData<QPointF> {
|
||||
public:
|
||||
QwtTraceSeries(Trace &t)
|
||||
QwtTraceSeries(Trace &t, TraceXYPlot::YAxisType Ytype, TraceXYPlot::XAxisType Xtype)
|
||||
: QwtSeriesData<QPointF>(),
|
||||
t(t){};
|
||||
Ytype(Ytype),
|
||||
Xtype(Xtype),
|
||||
t(t){}
|
||||
size_t size() const override {
|
||||
return t.size();
|
||||
switch(Ytype) {
|
||||
case TraceXYPlot::YAxisType::Magnitude:
|
||||
case TraceXYPlot::YAxisType::Phase:
|
||||
case TraceXYPlot::YAxisType::VSWR:
|
||||
return t.size();
|
||||
case TraceXYPlot::YAxisType::Impulse:
|
||||
case TraceXYPlot::YAxisType::Step:
|
||||
case TraceXYPlot::YAxisType::Impedance:
|
||||
return t.getTDR().size();
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
QPointF sample(size_t i) const override {
|
||||
Trace::Data d = t.sample(i);
|
||||
QPointF p;
|
||||
p.setX(d.frequency);
|
||||
p.setY(AxisTransformation(E, d.S));
|
||||
return p;
|
||||
switch(Ytype) {
|
||||
case TraceXYPlot::YAxisType::Magnitude:
|
||||
case TraceXYPlot::YAxisType::Phase:
|
||||
case TraceXYPlot::YAxisType::VSWR: {
|
||||
Trace::Data d = t.sample(i);
|
||||
QPointF p;
|
||||
p.setX(d.frequency);
|
||||
p.setY(FrequencyAxisTransformation(Ytype, d.S));
|
||||
return p;
|
||||
}
|
||||
case TraceXYPlot::YAxisType::Impulse:
|
||||
case TraceXYPlot::YAxisType::Step:
|
||||
case TraceXYPlot::YAxisType::Impedance: {
|
||||
auto sample = t.getTDR()[i];
|
||||
QPointF p;
|
||||
// TODO set distance
|
||||
p.setX(sample.time);
|
||||
p.setY(TimeAxisTransformation(Ytype, &t, i));
|
||||
return p;
|
||||
}
|
||||
default:
|
||||
return QPointF();
|
||||
}
|
||||
|
||||
}
|
||||
QRectF boundingRect() const override {
|
||||
return qwtBoundingRect(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
TraceXYPlot::YAxisType Ytype;
|
||||
TraceXYPlot::XAxisType Xtype;
|
||||
Trace &t;
|
||||
};
|
||||
|
||||
TraceBodePlot::TraceBodePlot(TraceModel &model, QWidget *parent)
|
||||
TraceXYPlot::TraceXYPlot(TraceModel &model, QWidget *parent)
|
||||
: TracePlot(parent),
|
||||
selectedMarker(nullptr)
|
||||
{
|
||||
@ -69,10 +125,10 @@ TraceBodePlot::TraceBodePlot(TraceModel &model, QWidget *parent)
|
||||
grid->attach(plot);
|
||||
setColorFromPreferences();
|
||||
|
||||
auto selectPicker = new BodeplotPicker(plot->xBottom, plot->yLeft, QwtPicker::NoRubberBand, QwtPicker::ActiveOnly, plot->canvas());
|
||||
auto selectPicker = new XYplotPicker(plot->xBottom, plot->yLeft, QwtPicker::NoRubberBand, QwtPicker::ActiveOnly, plot->canvas());
|
||||
selectPicker->setStateMachine(new QwtPickerClickPointMachine);
|
||||
|
||||
drawPicker = new BodeplotPicker(plot->xBottom, plot->yLeft, QwtPicker::NoRubberBand, QwtPicker::ActiveOnly, plot->canvas());
|
||||
drawPicker = new XYplotPicker(plot->xBottom, plot->yLeft, QwtPicker::NoRubberBand, QwtPicker::ActiveOnly, plot->canvas());
|
||||
drawPicker->setStateMachine(new QwtPickerDragPointMachine);
|
||||
drawPicker->setTrackerPen(QPen(Qt::white));
|
||||
|
||||
@ -94,14 +150,14 @@ TraceBodePlot::TraceBodePlot(TraceModel &model, QWidget *parent)
|
||||
setYAxis(1, YAxisType::Phase, false, false, -180, 180, 30);
|
||||
// enable autoscaling and set for full span (no information about actual span available yet)
|
||||
setXAxis(0, 6000000000);
|
||||
setXAxis(true, 0, 6000000000, 600000000);
|
||||
setXAxis(XAxisType::Frequency, true, 0, 6000000000, 600000000);
|
||||
// get notified when the span changes
|
||||
connect(&model, &TraceModel::SpanChanged, this, qOverload<double, double>(&TraceBodePlot::setXAxis));
|
||||
connect(&model, &TraceModel::SpanChanged, this, qOverload<double, double>(&TraceXYPlot::setXAxis));
|
||||
|
||||
allPlots.insert(this);
|
||||
}
|
||||
|
||||
TraceBodePlot::~TraceBodePlot()
|
||||
TraceXYPlot::~TraceXYPlot()
|
||||
{
|
||||
for(int axis = 0;axis < 2;axis++) {
|
||||
for(auto pd : curves[axis]) {
|
||||
@ -112,17 +168,16 @@ TraceBodePlot::~TraceBodePlot()
|
||||
allPlots.erase(this);
|
||||
}
|
||||
|
||||
void TraceBodePlot::setXAxis(double min, double max)
|
||||
void TraceXYPlot::setXAxis(double min, double max)
|
||||
{
|
||||
sweep_fmin = min;
|
||||
sweep_fmax = max;
|
||||
updateXAxis();
|
||||
}
|
||||
|
||||
void TraceBodePlot::setYAxis(int axis, TraceBodePlot::YAxisType type, bool log, bool autorange, double min, double max, double div)
|
||||
void TraceXYPlot::setYAxis(int axis, TraceXYPlot::YAxisType type, bool log, bool autorange, double min, double max, double div)
|
||||
{
|
||||
if(YAxis[axis].type != type) {
|
||||
YAxis[axis].type = type;
|
||||
if(YAxis[axis].Ytype != type) {
|
||||
// remove traces that are active but not supported with the new axis type
|
||||
bool erased = false;
|
||||
do {
|
||||
@ -136,6 +191,13 @@ void TraceBodePlot::setYAxis(int axis, TraceBodePlot::YAxisType type, bool log,
|
||||
}
|
||||
} while(erased);
|
||||
|
||||
if(isTDRtype(YAxis[axis].Ytype)) {
|
||||
for(auto t : tracesAxis[axis]) {
|
||||
t->removeTDRinterest();
|
||||
}
|
||||
}
|
||||
YAxis[axis].Ytype = type;
|
||||
|
||||
for(auto t : tracesAxis[axis]) {
|
||||
// supported but needs an adjusted QwtSeriesData
|
||||
auto td = curves[axis][t];
|
||||
@ -149,6 +211,9 @@ void TraceBodePlot::setYAxis(int axis, TraceBodePlot::YAxisType type, bool log,
|
||||
markerDataChanged(m);
|
||||
}
|
||||
}
|
||||
if(isTDRtype(type)) {
|
||||
t->addTDRinterest();
|
||||
}
|
||||
}
|
||||
}
|
||||
YAxis[axis].log = log;
|
||||
@ -168,8 +233,9 @@ void TraceBodePlot::setYAxis(int axis, TraceBodePlot::YAxisType type, bool log,
|
||||
replot();
|
||||
}
|
||||
|
||||
void TraceBodePlot::setXAxis(bool autorange, double min, double max, double div)
|
||||
void TraceXYPlot::setXAxis(XAxisType type, bool autorange, double min, double max, double div)
|
||||
{
|
||||
XAxis.Xtype = type;
|
||||
XAxis.autorange = autorange;
|
||||
XAxis.rangeMin = min;
|
||||
XAxis.rangeMax = max;
|
||||
@ -177,33 +243,45 @@ void TraceBodePlot::setXAxis(bool autorange, double min, double max, double div)
|
||||
updateXAxis();
|
||||
}
|
||||
|
||||
void TraceBodePlot::enableTrace(Trace *t, bool enabled)
|
||||
void TraceXYPlot::enableTrace(Trace *t, bool enabled)
|
||||
{
|
||||
for(int axis = 0;axis < 2;axis++) {
|
||||
if(supported(t, YAxis[axis].type)) {
|
||||
if(supported(t, YAxis[axis].Ytype)) {
|
||||
enableTraceAxis(t, axis, enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TraceBodePlot::updateGraphColors()
|
||||
void TraceXYPlot::updateGraphColors()
|
||||
{
|
||||
for(auto p : allPlots) {
|
||||
p->setColorFromPreferences();
|
||||
}
|
||||
}
|
||||
|
||||
void TraceBodePlot::updateContextMenu()
|
||||
bool TraceXYPlot::isTDRtype(TraceXYPlot::YAxisType type)
|
||||
{
|
||||
switch(type) {
|
||||
case YAxisType::Impulse:
|
||||
case YAxisType::Step:
|
||||
case YAxisType::Impedance:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void TraceXYPlot::updateContextMenu()
|
||||
{
|
||||
contextmenu->clear();
|
||||
auto setup = new QAction("Axis setup...");
|
||||
connect(setup, &QAction::triggered, [this]() {
|
||||
auto setup = new BodeplotAxisDialog(this);
|
||||
auto setup = new XYplotAxisDialog(this);
|
||||
setup->show();
|
||||
});
|
||||
contextmenu->addAction(setup);
|
||||
for(int axis = 0;axis < 2;axis++) {
|
||||
if(YAxis[axis].type == YAxisType::Disabled) {
|
||||
if(YAxis[axis].Ytype == YAxisType::Disabled) {
|
||||
continue;
|
||||
}
|
||||
if(axis == 0) {
|
||||
@ -213,7 +291,7 @@ void TraceBodePlot::updateContextMenu()
|
||||
}
|
||||
for(auto t : traces) {
|
||||
// Skip traces that are not applicable for the selected axis type
|
||||
if(!supported(t.first, YAxis[axis].type)) {
|
||||
if(!supported(t.first, YAxis[axis].Ytype)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -236,18 +314,18 @@ void TraceBodePlot::updateContextMenu()
|
||||
});
|
||||
}
|
||||
|
||||
bool TraceBodePlot::supported(Trace *)
|
||||
bool TraceXYPlot::supported(Trace *)
|
||||
{
|
||||
// potentially possible to add every kind of trace (depends on axis)
|
||||
return true;
|
||||
}
|
||||
|
||||
void TraceBodePlot::replot()
|
||||
void TraceXYPlot::replot()
|
||||
{
|
||||
plot->replot();
|
||||
}
|
||||
|
||||
QString TraceBodePlot::AxisTypeToName(TraceBodePlot::YAxisType type)
|
||||
QString TraceXYPlot::AxisTypeToName(TraceXYPlot::YAxisType type)
|
||||
{
|
||||
switch(type) {
|
||||
case YAxisType::Disabled: return "Disabled"; break;
|
||||
@ -258,7 +336,7 @@ QString TraceBodePlot::AxisTypeToName(TraceBodePlot::YAxisType type)
|
||||
}
|
||||
}
|
||||
|
||||
void TraceBodePlot::enableTraceAxis(Trace *t, int axis, bool enabled)
|
||||
void TraceXYPlot::enableTraceAxis(Trace *t, int axis, bool enabled)
|
||||
{
|
||||
bool alreadyEnabled = tracesAxis[axis].find(t) != tracesAxis[axis].end();
|
||||
if(alreadyEnabled != enabled) {
|
||||
@ -272,20 +350,26 @@ void TraceBodePlot::enableTraceAxis(Trace *t, int axis, bool enabled)
|
||||
cd.curve->setSamples(cd.data);
|
||||
curves[axis][t] = cd;
|
||||
// connect signals
|
||||
connect(t, &Trace::dataChanged, this, &TraceBodePlot::triggerReplot);
|
||||
connect(t, &Trace::colorChanged, this, &TraceBodePlot::traceColorChanged);
|
||||
connect(t, &Trace::visibilityChanged, this, &TraceBodePlot::traceColorChanged);
|
||||
connect(t, &Trace::visibilityChanged, this, &TraceBodePlot::triggerReplot);
|
||||
connect(t, &Trace::dataChanged, this, &TraceXYPlot::triggerReplot);
|
||||
connect(t, &Trace::colorChanged, this, &TraceXYPlot::traceColorChanged);
|
||||
connect(t, &Trace::visibilityChanged, this, &TraceXYPlot::traceColorChanged);
|
||||
connect(t, &Trace::visibilityChanged, this, &TraceXYPlot::triggerReplot);
|
||||
if(axis == 0) {
|
||||
connect(t, &Trace::markerAdded, this, &TraceBodePlot::markerAdded);
|
||||
connect(t, &Trace::markerRemoved, this, &TraceBodePlot::markerRemoved);
|
||||
connect(t, &Trace::markerAdded, this, &TraceXYPlot::markerAdded);
|
||||
connect(t, &Trace::markerRemoved, this, &TraceXYPlot::markerRemoved);
|
||||
auto tracemarkers = t->getMarkers();
|
||||
for(auto m : tracemarkers) {
|
||||
markerAdded(m);
|
||||
}
|
||||
}
|
||||
if(isTDRtype(YAxis[axis].Ytype)) {
|
||||
t->addTDRinterest();
|
||||
}
|
||||
traceColorChanged(t);
|
||||
} else {
|
||||
if(isTDRtype(YAxis[axis].Ytype)) {
|
||||
t->removeTDRinterest();
|
||||
}
|
||||
tracesAxis[axis].erase(t);
|
||||
// clean up and delete
|
||||
if(curves[axis].find(t) != curves[axis].end()) {
|
||||
@ -295,14 +379,14 @@ void TraceBodePlot::enableTraceAxis(Trace *t, int axis, bool enabled)
|
||||
int otherAxis = axis == 0 ? 1 : 0;
|
||||
if(curves[otherAxis].find(t) == curves[otherAxis].end()) {
|
||||
// this trace is not used anymore, disconnect from notifications
|
||||
disconnect(t, &Trace::dataChanged, this, &TraceBodePlot::triggerReplot);
|
||||
disconnect(t, &Trace::colorChanged, this, &TraceBodePlot::traceColorChanged);
|
||||
disconnect(t, &Trace::visibilityChanged, this, &TraceBodePlot::traceColorChanged);
|
||||
disconnect(t, &Trace::visibilityChanged, this, &TraceBodePlot::triggerReplot);
|
||||
disconnect(t, &Trace::dataChanged, this, &TraceXYPlot::triggerReplot);
|
||||
disconnect(t, &Trace::colorChanged, this, &TraceXYPlot::traceColorChanged);
|
||||
disconnect(t, &Trace::visibilityChanged, this, &TraceXYPlot::traceColorChanged);
|
||||
disconnect(t, &Trace::visibilityChanged, this, &TraceXYPlot::triggerReplot);
|
||||
}
|
||||
if(axis == 0) {
|
||||
disconnect(t, &Trace::markerAdded, this, &TraceBodePlot::markerAdded);
|
||||
disconnect(t, &Trace::markerRemoved, this, &TraceBodePlot::markerRemoved);
|
||||
disconnect(t, &Trace::markerAdded, this, &TraceXYPlot::markerAdded);
|
||||
disconnect(t, &Trace::markerRemoved, this, &TraceXYPlot::markerRemoved);
|
||||
auto tracemarkers = t->getMarkers();
|
||||
for(auto m : tracemarkers) {
|
||||
markerRemoved(m);
|
||||
@ -315,7 +399,7 @@ void TraceBodePlot::enableTraceAxis(Trace *t, int axis, bool enabled)
|
||||
}
|
||||
}
|
||||
|
||||
bool TraceBodePlot::supported(Trace *t, TraceBodePlot::YAxisType type)
|
||||
bool TraceXYPlot::supported(Trace *t, TraceXYPlot::YAxisType type)
|
||||
{
|
||||
switch(type) {
|
||||
case YAxisType::Disabled:
|
||||
@ -331,7 +415,7 @@ bool TraceBodePlot::supported(Trace *t, TraceBodePlot::YAxisType type)
|
||||
return true;
|
||||
}
|
||||
|
||||
void TraceBodePlot::updateXAxis()
|
||||
void TraceXYPlot::updateXAxis()
|
||||
{
|
||||
if(XAxis.autorange && sweep_fmax-sweep_fmin > 0) {
|
||||
QList<double> tickList;
|
||||
@ -346,21 +430,12 @@ void TraceBodePlot::updateXAxis()
|
||||
triggerReplot();
|
||||
}
|
||||
|
||||
QwtSeriesData<QPointF> *TraceBodePlot::createQwtSeriesData(Trace &t, int axis)
|
||||
QwtSeriesData<QPointF> *TraceXYPlot::createQwtSeriesData(Trace &t, int axis)
|
||||
{
|
||||
switch(YAxis[axis].type) {
|
||||
case YAxisType::Magnitude:
|
||||
return new QwtTraceSeries<YAxisType::Magnitude>(t);
|
||||
case YAxisType::Phase:
|
||||
return new QwtTraceSeries<YAxisType::Phase>(t);
|
||||
case YAxisType::VSWR:
|
||||
return new QwtTraceSeries<YAxisType::VSWR>(t);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
return new QwtTraceSeries(t, YAxis[axis].Ytype, XAxis.Xtype);
|
||||
}
|
||||
|
||||
void TraceBodePlot::traceColorChanged(Trace *t)
|
||||
void TraceXYPlot::traceColorChanged(Trace *t)
|
||||
{
|
||||
for(int axis = 0;axis < 2;axis++) {
|
||||
if(curves[axis].find(t) != curves[axis].end()) {
|
||||
@ -388,7 +463,7 @@ void TraceBodePlot::traceColorChanged(Trace *t)
|
||||
}
|
||||
}
|
||||
|
||||
void TraceBodePlot::markerAdded(TraceMarker *m)
|
||||
void TraceXYPlot::markerAdded(TraceMarker *m)
|
||||
{
|
||||
if(markers.count(m)) {
|
||||
return;
|
||||
@ -396,17 +471,17 @@ void TraceBodePlot::markerAdded(TraceMarker *m)
|
||||
auto qwtMarker = new QwtPlotMarker;
|
||||
markers[m] = qwtMarker;
|
||||
markerSymbolChanged(m);
|
||||
connect(m, &TraceMarker::symbolChanged, this, &TraceBodePlot::markerSymbolChanged);
|
||||
connect(m, &TraceMarker::dataChanged, this, &TraceBodePlot::markerDataChanged);
|
||||
connect(m, &TraceMarker::symbolChanged, this, &TraceXYPlot::markerSymbolChanged);
|
||||
connect(m, &TraceMarker::dataChanged, this, &TraceXYPlot::markerDataChanged);
|
||||
markerDataChanged(m);
|
||||
qwtMarker->attach(plot);
|
||||
triggerReplot();
|
||||
}
|
||||
|
||||
void TraceBodePlot::markerRemoved(TraceMarker *m)
|
||||
void TraceXYPlot::markerRemoved(TraceMarker *m)
|
||||
{
|
||||
disconnect(m, &TraceMarker::symbolChanged, this, &TraceBodePlot::markerSymbolChanged);
|
||||
disconnect(m, &TraceMarker::dataChanged, this, &TraceBodePlot::markerDataChanged);
|
||||
disconnect(m, &TraceMarker::symbolChanged, this, &TraceXYPlot::markerSymbolChanged);
|
||||
disconnect(m, &TraceMarker::dataChanged, this, &TraceXYPlot::markerDataChanged);
|
||||
if(markers.count(m)) {
|
||||
markers[m]->detach();
|
||||
delete markers[m];
|
||||
@ -415,15 +490,15 @@ void TraceBodePlot::markerRemoved(TraceMarker *m)
|
||||
triggerReplot();
|
||||
}
|
||||
|
||||
void TraceBodePlot::markerDataChanged(TraceMarker *m)
|
||||
void TraceXYPlot::markerDataChanged(TraceMarker *m)
|
||||
{
|
||||
auto qwtMarker = markers[m];
|
||||
qwtMarker->setXValue(m->getFrequency());
|
||||
qwtMarker->setYValue(AxisTransformation(YAxis[0].type, m->getData()));
|
||||
qwtMarker->setYValue(FrequencyAxisTransformation(YAxis[0].Ytype, m->getData()));
|
||||
triggerReplot();
|
||||
}
|
||||
|
||||
void TraceBodePlot::markerSymbolChanged(TraceMarker *m)
|
||||
void TraceXYPlot::markerSymbolChanged(TraceMarker *m)
|
||||
{
|
||||
auto qwtMarker = markers[m];
|
||||
auto old_sym = qwtMarker->symbol();
|
||||
@ -437,7 +512,7 @@ void TraceBodePlot::markerSymbolChanged(TraceMarker *m)
|
||||
triggerReplot();
|
||||
}
|
||||
|
||||
void TraceBodePlot::clicked(const QPointF pos)
|
||||
void TraceXYPlot::clicked(const QPointF pos)
|
||||
{
|
||||
auto clickPoint = drawPicker->plotToPixel(pos);
|
||||
unsigned int closestDistance = numeric_limits<unsigned int>::max();
|
||||
@ -461,7 +536,7 @@ void TraceBodePlot::clicked(const QPointF pos)
|
||||
}
|
||||
}
|
||||
|
||||
void TraceBodePlot::moved(const QPointF pos)
|
||||
void TraceXYPlot::moved(const QPointF pos)
|
||||
{
|
||||
if(!selectedMarker || !selectedCurve) {
|
||||
return;
|
||||
@ -469,7 +544,7 @@ void TraceBodePlot::moved(const QPointF pos)
|
||||
selectedMarker->setFrequency(pos.x());
|
||||
}
|
||||
|
||||
void TraceBodePlot::setColorFromPreferences()
|
||||
void TraceXYPlot::setColorFromPreferences()
|
||||
{
|
||||
auto pref = Preferences::getInstance();
|
||||
plot->setCanvasBackground(pref.General.graphColors.background);
|
@ -1,5 +1,5 @@
|
||||
#ifndef TRACEBODEPLOT_H
|
||||
#define TRACEBODEPLOT_H
|
||||
#ifndef TRACEXYPLOT_H
|
||||
#define TRACEXYPLOT_H
|
||||
|
||||
#include "traceplot.h"
|
||||
#include <set>
|
||||
@ -11,10 +11,10 @@
|
||||
#include <qwt_plot_picker.h>
|
||||
|
||||
// Derived plotpicker, exposing transformation functions
|
||||
class BodeplotPicker : public QwtPlotPicker {
|
||||
class XYplotPicker : public QwtPlotPicker {
|
||||
Q_OBJECT
|
||||
public:
|
||||
BodeplotPicker(int xAxis, int yAxis, RubberBand rubberBand, DisplayMode trackerMode, QWidget *w)
|
||||
XYplotPicker(int xAxis, int yAxis, RubberBand rubberBand, DisplayMode trackerMode, QWidget *w)
|
||||
: QwtPlotPicker(xAxis, yAxis, rubberBand, trackerMode, w) {};
|
||||
QPoint plotToPixel(const QPointF &pos) {
|
||||
return transform(pos);
|
||||
@ -24,33 +24,46 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class TraceBodePlot : public TracePlot
|
||||
class TraceXYPlot : public TracePlot
|
||||
{
|
||||
friend class BodeplotAxisDialog;
|
||||
friend class XYplotAxisDialog;
|
||||
Q_OBJECT
|
||||
public:
|
||||
TraceBodePlot(TraceModel &model, QWidget *parent = nullptr);
|
||||
~TraceBodePlot();
|
||||
TraceXYPlot(TraceModel &model, QWidget *parent = nullptr);
|
||||
~TraceXYPlot();
|
||||
|
||||
enum class YAxisType {
|
||||
Disabled = 0,
|
||||
// S parameter options
|
||||
Magnitude = 1,
|
||||
Phase = 2,
|
||||
VSWR = 3,
|
||||
// TDR options
|
||||
Impulse = 4,
|
||||
Step = 5,
|
||||
Impedance = 6,
|
||||
Last,
|
||||
};
|
||||
static const std::set<YAxisType> YAxisTypes;
|
||||
enum class XAxisType {
|
||||
Frequency,
|
||||
Time,
|
||||
Distance,
|
||||
};
|
||||
|
||||
virtual void setXAxis(double min, double max) override;
|
||||
void setYAxis(int axis, YAxisType type, bool log, bool autorange, double min, double max, double div);
|
||||
void setXAxis(bool autorange, double min, double max, double div);
|
||||
void setXAxis(XAxisType type, bool autorange, double min, double max, double div);
|
||||
void enableTrace(Trace *t, bool enabled) override;
|
||||
|
||||
// Applies potentially changed colors to all bodeplots
|
||||
// Applies potentially changed colors to all XY-plots
|
||||
static void updateGraphColors();
|
||||
|
||||
bool isTDRtype(YAxisType type);
|
||||
|
||||
protected:
|
||||
virtual void updateContextMenu();
|
||||
virtual bool supported(Trace *t);
|
||||
virtual void updateContextMenu() override;
|
||||
virtual bool supported(Trace *t) override;
|
||||
void replot() override;
|
||||
|
||||
private slots:
|
||||
@ -74,7 +87,10 @@ private:
|
||||
|
||||
class Axis {
|
||||
public:
|
||||
YAxisType type;
|
||||
union {
|
||||
YAxisType Ytype;
|
||||
XAxisType Xtype;
|
||||
};
|
||||
bool log;
|
||||
bool autorange;
|
||||
double rangeMin;
|
||||
@ -97,10 +113,10 @@ private:
|
||||
TraceMarker *selectedMarker;
|
||||
QwtPlotCurve *selectedCurve;
|
||||
|
||||
BodeplotPicker *drawPicker;
|
||||
XYplotPicker *drawPicker;
|
||||
|
||||
// keep track of all created plots for changing colors
|
||||
static std::set<TraceBodePlot*> allPlots;
|
||||
static std::set<TraceXYPlot*> allPlots;
|
||||
};
|
||||
|
||||
#endif // TRACEBODEPLOT_H
|
||||
#endif // TRACEXYPLOT_H
|
177
Software/PC_Application/Traces/xyplotaxisdialog.cpp
Normal file
177
Software/PC_Application/Traces/xyplotaxisdialog.cpp
Normal file
@ -0,0 +1,177 @@
|
||||
#include "xyplotaxisdialog.h"
|
||||
#include "ui_bodeplotaxisdialog.h"
|
||||
#include <QStandardItemModel>
|
||||
|
||||
using namespace std;
|
||||
|
||||
XYplotAxisDialog::XYplotAxisDialog(TraceXYPlot *plot) :
|
||||
QDialog(nullptr),
|
||||
ui(new Ui::XYplotAxisDialog),
|
||||
plot(plot)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// Setup GUI connections
|
||||
connect(ui->Y1type, qOverload<int>(&QComboBox::currentIndexChanged), [this](int index) {
|
||||
//ui->Y1log->setEnabled(index != 0);
|
||||
ui->Y1linear->setEnabled(index != 0);
|
||||
ui->Y1auto->setEnabled(index != 0);
|
||||
bool autoRange = ui->Y1auto->isChecked();
|
||||
ui->Y1min->setEnabled(index != 0 && !autoRange);
|
||||
ui->Y1max->setEnabled(index != 0 && !autoRange);
|
||||
ui->Y1divs->setEnabled(index != 0 && !autoRange);
|
||||
auto type = (TraceXYPlot::YAxisType) index;
|
||||
QString unit = YAxisUnit(type);
|
||||
ui->Y1min->setUnit(unit);
|
||||
ui->Y1max->setUnit(unit);
|
||||
ui->Y1divs->setUnit(unit);
|
||||
});
|
||||
connect(ui->Y1auto, &QCheckBox::toggled, [this](bool checked) {
|
||||
ui->Y1min->setEnabled(!checked);
|
||||
ui->Y1max->setEnabled(!checked);
|
||||
ui->Y1divs->setEnabled(!checked);
|
||||
});
|
||||
|
||||
connect(ui->Y2type, qOverload<int>(&QComboBox::currentIndexChanged), [this](int index) {
|
||||
//ui->Y2log->setEnabled(index != 0);
|
||||
ui->Y2linear->setEnabled(index != 0);
|
||||
ui->Y2auto->setEnabled(index != 0);
|
||||
bool autoRange = ui->Y2auto->isChecked();
|
||||
ui->Y2min->setEnabled(index != 0 && !autoRange);
|
||||
ui->Y2max->setEnabled(index != 0 && !autoRange);
|
||||
ui->Y2divs->setEnabled(index != 0 && !autoRange);
|
||||
auto type = (TraceXYPlot::YAxisType) index;
|
||||
QString unit = YAxisUnit(type);
|
||||
ui->Y2min->setUnit(unit);
|
||||
ui->Y2max->setUnit(unit);
|
||||
ui->Y2divs->setUnit(unit);
|
||||
});
|
||||
|
||||
connect(ui->XType, qOverload<int>(&QComboBox::currentIndexChanged), this, &XYplotAxisDialog::XAxisTypeChanged);
|
||||
|
||||
connect(ui->Y2auto, &QCheckBox::toggled, [this](bool checked) {
|
||||
ui->Y2min->setEnabled(!checked);
|
||||
ui->Y2max->setEnabled(!checked);
|
||||
ui->Y2divs->setEnabled(!checked);
|
||||
});
|
||||
|
||||
connect(ui->Xauto, &QCheckBox::toggled, [this](bool checked) {
|
||||
ui->Xmin->setEnabled(!checked);
|
||||
ui->Xmax->setEnabled(!checked);
|
||||
ui->Xdivs->setEnabled(!checked);
|
||||
});
|
||||
|
||||
ui->XType->setCurrentIndex((int) plot->XAxis.Xtype);
|
||||
ui->Xmin->setPrefixes("pnum kMG");
|
||||
ui->Xmax->setPrefixes("pnum kMG");
|
||||
ui->Xdivs->setPrefixes("pnum kMG");
|
||||
|
||||
// Fill initial values
|
||||
// assume same order in YAxisType enum as in ComboBox items
|
||||
ui->Y1type->setCurrentIndex((int) plot->YAxis[0].Ytype);
|
||||
if(plot->YAxis[0].log) {
|
||||
ui->Y1log->setChecked(true);
|
||||
} else {
|
||||
ui->Y1linear->setChecked(true);
|
||||
}
|
||||
ui->Y1auto->setChecked(plot->YAxis[0].autorange);
|
||||
ui->Y1min->setValueQuiet(plot->YAxis[0].rangeMin);
|
||||
ui->Y1max->setValueQuiet(plot->YAxis[0].rangeMax);
|
||||
ui->Y1divs->setValueQuiet(plot->YAxis[0].rangeDiv);
|
||||
|
||||
ui->Y2type->setCurrentIndex((int) plot->YAxis[1].Ytype);
|
||||
if(plot->YAxis[1].log) {
|
||||
ui->Y2log->setChecked(true);
|
||||
} else {
|
||||
ui->Y2linear->setChecked(true);
|
||||
}
|
||||
ui->Y2auto->setChecked(plot->YAxis[1].autorange);
|
||||
ui->Y2min->setValueQuiet(plot->YAxis[1].rangeMin);
|
||||
ui->Y2max->setValueQuiet(plot->YAxis[1].rangeMax);
|
||||
ui->Y2divs->setValueQuiet(plot->YAxis[1].rangeDiv);
|
||||
|
||||
ui->Xauto->setChecked(plot->XAxis.autorange);
|
||||
ui->Xmin->setValueQuiet(plot->XAxis.rangeMin);
|
||||
ui->Xmax->setValueQuiet(plot->XAxis.rangeMax);
|
||||
ui->Xdivs->setValueQuiet(plot->XAxis.rangeDiv);
|
||||
}
|
||||
|
||||
XYplotAxisDialog::~XYplotAxisDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void XYplotAxisDialog::on_buttonBox_accepted()
|
||||
{
|
||||
// set plot values to the ones selected in the dialog
|
||||
plot->setYAxis(0, (TraceXYPlot::YAxisType) ui->Y1type->currentIndex(), ui->Y1log->isChecked(), ui->Y1auto->isChecked(), ui->Y1min->value(), ui->Y1max->value(), ui->Y1divs->value());
|
||||
plot->setYAxis(1, (TraceXYPlot::YAxisType) ui->Y2type->currentIndex(), ui->Y2log->isChecked(), ui->Y2auto->isChecked(), ui->Y2min->value(), ui->Y2max->value(), ui->Y2divs->value());
|
||||
plot->setXAxis((TraceXYPlot::XAxisType) ui->XType->currentIndex(), ui->Xauto->isChecked(), ui->Xmin->value(), ui->Xmax->value(), ui->Xdivs->value());
|
||||
}
|
||||
|
||||
void XYplotAxisDialog::XAxisTypeChanged(int XAxisIndex)
|
||||
{
|
||||
auto type = (TraceXYPlot::XAxisType) XAxisIndex;
|
||||
auto supported = supportedYAxis(type);
|
||||
for(auto t : TraceXYPlot::YAxisTypes) {
|
||||
auto enable = supported.count(t) > 0;
|
||||
auto index = (int) t;
|
||||
auto *model = qobject_cast<QStandardItemModel *>(ui->Y1type->model());
|
||||
auto item = model->item(index);
|
||||
item->setFlags(enable ? item->flags() | Qt::ItemIsEnabled
|
||||
: item->flags() & ~Qt::ItemIsEnabled);
|
||||
model = qobject_cast<QStandardItemModel *>(ui->Y2type->model());
|
||||
item = model->item(index);
|
||||
item->setFlags(enable ? item->flags() | Qt::ItemIsEnabled
|
||||
: item->flags() & ~Qt::ItemIsEnabled);
|
||||
}
|
||||
// Disable Yaxis if previously selected type is not supported
|
||||
if(!supported.count((TraceXYPlot::YAxisType)ui->Y1type->currentIndex())) {
|
||||
ui->Y1type->setCurrentIndex(0);
|
||||
}
|
||||
if(!supported.count((TraceXYPlot::YAxisType)ui->Y2type->currentIndex())) {
|
||||
ui->Y2type->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
QString unit;
|
||||
switch(type) {
|
||||
case TraceXYPlot::XAxisType::Frequency: unit = "Hz"; break;
|
||||
case TraceXYPlot::XAxisType::Time: unit = "s"; break;
|
||||
case TraceXYPlot::XAxisType::Distance: unit = "m"; break;
|
||||
}
|
||||
ui->Xmin->setUnit(unit);
|
||||
ui->Xmax->setUnit(unit);
|
||||
ui->Xdivs->setUnit(unit);
|
||||
}
|
||||
|
||||
QString XYplotAxisDialog::YAxisUnit(TraceXYPlot::YAxisType type)
|
||||
{
|
||||
switch(type) {
|
||||
case TraceXYPlot::YAxisType::Magnitude: return "db"; break;
|
||||
case TraceXYPlot::YAxisType::Phase: return "°"; break;
|
||||
case TraceXYPlot::YAxisType::VSWR: return ""; break;
|
||||
case TraceXYPlot::YAxisType::Impulse: return ""; break;
|
||||
case TraceXYPlot::YAxisType::Step: return ""; break;
|
||||
case TraceXYPlot::YAxisType::Impedance: return "Ohm"; break;
|
||||
default: return ""; break;
|
||||
}
|
||||
}
|
||||
|
||||
std::set<TraceXYPlot::YAxisType> XYplotAxisDialog::supportedYAxis(TraceXYPlot::XAxisType type)
|
||||
{
|
||||
set<TraceXYPlot::YAxisType> ret = {TraceXYPlot::YAxisType::Disabled};
|
||||
switch(type) {
|
||||
case TraceXYPlot::XAxisType::Frequency:
|
||||
ret.insert(TraceXYPlot::YAxisType::Magnitude);
|
||||
ret.insert(TraceXYPlot::YAxisType::Phase);
|
||||
ret.insert(TraceXYPlot::YAxisType::VSWR);
|
||||
break;
|
||||
case TraceXYPlot::XAxisType::Time:
|
||||
case TraceXYPlot::XAxisType::Distance:
|
||||
ret.insert(TraceXYPlot::YAxisType::Impulse);
|
||||
ret.insert(TraceXYPlot::YAxisType::Step);
|
||||
ret.insert(TraceXYPlot::YAxisType::Impedance);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
30
Software/PC_Application/Traces/xyplotaxisdialog.h
Normal file
30
Software/PC_Application/Traces/xyplotaxisdialog.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef XYPLOTAXISDIALOG_H
|
||||
#define XYPLOTAXISDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "tracexyplot.h"
|
||||
|
||||
namespace Ui {
|
||||
class XYplotAxisDialog;
|
||||
}
|
||||
|
||||
class XYplotAxisDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit XYplotAxisDialog(TraceXYPlot *plot);
|
||||
~XYplotAxisDialog();
|
||||
|
||||
private slots:
|
||||
void on_buttonBox_accepted();
|
||||
void XAxisTypeChanged(int XAxisIndex);
|
||||
|
||||
private:
|
||||
QString YAxisUnit(TraceXYPlot::YAxisType type);
|
||||
std::set<TraceXYPlot::YAxisType> supportedYAxis(TraceXYPlot::XAxisType type);
|
||||
Ui::XYplotAxisDialog *ui;
|
||||
TraceXYPlot *plot;
|
||||
};
|
||||
|
||||
#endif // XYPLOTAXISDIALOG_H
|
547
Software/PC_Application/Traces/xyplotaxisdialog.ui
Normal file
547
Software/PC_Application/Traces/xyplotaxisdialog.ui
Normal file
@ -0,0 +1,547 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BodeplotAxisDialog</class>
|
||||
<widget class="QDialog" name="BodeplotAxisDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>715</width>
|
||||
<height>282</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Axis Setup</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>9</x>
|
||||
<y>248</y>
|
||||
<width>166</width>
|
||||
<height>25</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWidget" name="">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>701</width>
|
||||
<height>233</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>15</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Primary Y axis</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="Y1type">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disabled</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Magnitude</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Phase</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>VSWR</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Impulse Response</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Step Response</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Impedance</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="Y1linear">
|
||||
<property name="text">
|
||||
<string>Linear</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">Y1group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="Y1log">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Log</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">Y1group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Range:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="Y1auto">
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Maximum:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="SIUnitEdit" name="Y1max"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Minimum:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="SIUnitEdit" name="Y1min"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Divisions:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="SIUnitEdit" name="Y1divs"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>15</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Secondary Y axis</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="Y2type">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disabled</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Magnitude</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Phase</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>VSWR</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Impulse Response</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Step Response</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Impedance</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="Y2linear">
|
||||
<property name="text">
|
||||
<string>Linear</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">Y2group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="Y2log">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Log</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">Y2group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Range:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="Y2auto">
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Maximum:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="SIUnitEdit" name="Y2max"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Minimum:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="SIUnitEdit" name="Y2min"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Divisions:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="SIUnitEdit" name="Y2divs"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>15</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>X axis</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="XType">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Frequency</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Time</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Distance</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_6">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Range:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="Xauto">
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>Maximum:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="SIUnitEdit" name="Xmax"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>Minimum:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="SIUnitEdit" name="Xmin"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>Divisions:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="SIUnitEdit" name="Xdivs"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>SIUnitEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>CustomWidgets/siunitedit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>BodeplotAxisDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>BodeplotAxisDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="Y1group"/>
|
||||
<buttongroup name="Y2group"/>
|
||||
</buttongroups>
|
||||
</ui>
|
@ -26,7 +26,7 @@
|
||||
#include "Traces/tracemodel.h"
|
||||
#include "Traces/tracewidget.h"
|
||||
#include "Traces/tracesmithchart.h"
|
||||
#include "Traces/tracebodeplot.h"
|
||||
#include "Traces/tracexyplot.h"
|
||||
#include "Traces/traceimportdialog.h"
|
||||
#include "CustomWidgets/tilewidget.h"
|
||||
#include "CustomWidgets/siunitedit.h"
|
||||
@ -70,9 +70,9 @@ VNA::VNA(AppWindow *window)
|
||||
auto tracesmith2 = new TraceSmithChart(traceModel);
|
||||
tracesmith2->enableTrace(tS22, true);
|
||||
|
||||
auto tracebode1 = new TraceBodePlot(traceModel);
|
||||
auto tracebode1 = new TraceXYPlot(traceModel);
|
||||
tracebode1->enableTrace(tS12, true);
|
||||
auto tracebode2 = new TraceBodePlot(traceModel);
|
||||
auto tracebode2 = new TraceXYPlot(traceModel);
|
||||
tracebode2->enableTrace(tS21, true);
|
||||
|
||||
connect(&traceModel, &TraceModel::requiredExcitation, this, &VNA::ExcitationRequired);
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "Traces/tracemodel.h"
|
||||
#include "Traces/tracewidget.h"
|
||||
#include "Traces/tracesmithchart.h"
|
||||
#include "Traces/tracebodeplot.h"
|
||||
#include "Traces/tracexyplot.h"
|
||||
#include "Traces/traceimportdialog.h"
|
||||
#include "CustomWidgets/tilewidget.h"
|
||||
#include "CustomWidgets/siunitedit.h"
|
||||
@ -110,7 +110,7 @@ AppWindow::AppWindow(QWidget *parent)
|
||||
connect(ui->actionPreferences, &QAction::triggered, [=](){
|
||||
Preferences::getInstance().edit();
|
||||
// settings might have changed, update necessary stuff
|
||||
TraceBodePlot::updateGraphColors();
|
||||
TraceXYPlot::updateGraphColors();
|
||||
});
|
||||
|
||||
setWindowTitle("VNA");
|
||||
|
Loading…
Reference in New Issue
Block a user