Prepare GUI for power sweep

This commit is contained in:
Jan Käberich 2021-07-09 18:42:22 +02:00
parent fc5947c9a8
commit 6490d6fd14
11 changed files with 159 additions and 74 deletions

View File

@ -41,6 +41,7 @@ void Math::Expression::edit()
exp = ui->expEdit->text(); exp = ui->expEdit->text();
expressionChanged(); expressionChanged();
}); });
// TODO add power domain
if(dataType == DataType::Time) { if(dataType == DataType::Time) {
// select the label explaining the time domain variables (frequency label is the default) // select the label explaining the time domain variables (frequency label is the default)
ui->stackedWidget->setCurrentIndex(1); ui->stackedWidget->setCurrentIndex(1);

View File

@ -60,6 +60,7 @@ public:
enum class DataType { enum class DataType {
Frequency, Frequency,
Time, Time,
Power,
Invalid, Invalid,
}; };

View File

@ -21,7 +21,7 @@ Trace::Trace(QString name, QColor color, LiveParameter live)
paused(false), paused(false),
createdFromFile(false), createdFromFile(false),
calibration(false), calibration(false),
timeDomain(false), domain(DataType::Frequency),
lastMath(nullptr) lastMath(nullptr)
{ {
MathInfo self = {.math = this, .enabled = true}; MathInfo self = {.math = this, .enabled = true};
@ -31,7 +31,7 @@ Trace::Trace(QString name, QColor color, LiveParameter live)
self.enabled = false; self.enabled = false;
dataType = DataType::Frequency; dataType = DataType::Frequency;
connect(this, &Trace::typeChanged, [=](){ connect(this, &Trace::typeChanged, [=](){
dataType = timeDomain ? DataType::Time : DataType::Frequency; dataType = domain;
emit outputTypeChanged(dataType); emit outputTypeChanged(dataType);
}); });
} }
@ -120,7 +120,7 @@ void Trace::fillFromTouchstone(Touchstone &t, unsigned int parameter)
throw runtime_error("Parameter for touchstone out of range"); throw runtime_error("Parameter for touchstone out of range");
} }
clear(); clear();
timeDomain = false; domain = DataType::Frequency;
fileParemeter = parameter; fileParemeter = parameter;
filename = t.getFilename(); filename = t.getFilename();
for(unsigned int i=0;i<t.points();i++) { for(unsigned int i=0;i<t.points();i++) {
@ -206,7 +206,13 @@ QString Trace::fillFromCSV(CSV &csv, unsigned int parameter)
fileParemeter = parameter; fileParemeter = parameter;
filename = csv.getFilename(); filename = csv.getFilename();
auto xColumn = csv.getColumn(0); auto xColumn = csv.getColumn(0);
timeDomain = csv.getHeader(0).compare("time", Qt::CaseInsensitive) == 0; if(csv.getHeader(0).compare("time", Qt::CaseInsensitive) == 0) {
domain = DataType::Time;
} else if(csv.getHeader(0).compare("power", Qt::CaseInsensitive) == 0) {
domain = DataType::Power;
} else {
domain = DataType::Frequency;
}
for(unsigned int i=0;i<xColumn.size();i++) { for(unsigned int i=0;i<xColumn.size();i++) {
Data d; Data d;
d.x = xColumn[i]; d.x = xColumn[i];
@ -242,7 +248,8 @@ void Trace::fillFromDatapoints(Trace &S11, Trace &S12, Trace &S21, Trace &S22, c
void Trace::fromLivedata(Trace::LivedataType type, LiveParameter param) void Trace::fromLivedata(Trace::LivedataType type, LiveParameter param)
{ {
timeDomain = false; // TODO set domain depending on incoming data
domain = DataType::Frequency;
createdFromFile = false; createdFromFile = false;
_liveType = type; _liveType = type;
_liveParam = param; _liveParam = param;
@ -635,11 +642,7 @@ void Trace::setReflection(bool value)
TraceMath::DataType Trace::outputType(TraceMath::DataType inputType) TraceMath::DataType Trace::outputType(TraceMath::DataType inputType)
{ {
Q_UNUSED(inputType); Q_UNUSED(inputType);
if(timeDomain) { return domain;
return DataType::Time;
} else {
return DataType::Frequency;
}
} }
QString Trace::description() QString Trace::description()

View File

@ -173,7 +173,7 @@ private:
bool paused; bool paused;
bool createdFromFile; bool createdFromFile;
bool calibration; bool calibration;
bool timeDomain; DataType domain;
QString filename; QString filename;
unsigned int fileParemeter; unsigned int fileParemeter;
std::set<Marker*> markers; std::set<Marker*> markers;

View File

@ -294,6 +294,8 @@ QVariant MathModel::data(const QModelIndex &index, int role) const
return "Time"; return "Time";
case TraceMath::DataType::Frequency: case TraceMath::DataType::Frequency:
return "Frequency"; return "Frequency";
case TraceMath::DataType::Power:
return "Power";
case TraceMath::DataType::Invalid: case TraceMath::DataType::Invalid:
return "Invalid"; return "Invalid";
} }

View File

@ -337,9 +337,14 @@ bool TraceSmithChart::supported(Trace *t)
bool TraceSmithChart::dropSupported(Trace *t) bool TraceSmithChart::dropSupported(Trace *t)
{ {
if(t->outputType() == Trace::DataType::Frequency && t->isReflection()) { if(!t->isReflection()) {
return false;
}
switch(t->outputType()) {
case Trace::DataType::Frequency:
case Trace::DataType::Power:
return true; return true;
} else { default:
return false; return false;
} }
} }

View File

@ -711,9 +711,10 @@ void TraceXYPlot::updateAxisTicks()
QString TraceXYPlot::AxisTypeToName(TraceXYPlot::XAxisType type) QString TraceXYPlot::AxisTypeToName(TraceXYPlot::XAxisType type)
{ {
switch(type) { switch(type) {
case XAxisType::Frequency: return "Frequency"; break; case XAxisType::Frequency: return "Frequency";
case XAxisType::Time: return "Time"; break; case XAxisType::Time: return "Time";
case XAxisType::Distance: return "Distance"; break; case XAxisType::Distance: return "Distance";
case XAxisType::Power: return "Power";
default: return "Unknown"; default: return "Unknown";
} }
} }
@ -824,6 +825,11 @@ bool TraceXYPlot::supported(Trace *t, TraceXYPlot::YAxisType type)
return false; return false;
} }
break; break;
case XAxisType::Power:
if(t->outputType() != Trace::DataType::Power) {
return false;
}
break;
default: default:
break; break;
} }
@ -981,29 +987,34 @@ bool TraceXYPlot::xCoordinateVisible(double x)
void TraceXYPlot::traceDropped(Trace *t, QPoint position) void TraceXYPlot::traceDropped(Trace *t, QPoint position)
{ {
if(t->outputType() == Trace::DataType::Frequency && XAxis.type != XAxisType::Frequency) { if(!supported(t)) {
// needs to switch to frequency domain graph // needs to switch to a different domain for the graph
if(!InformationBox::AskQuestion("X Axis Domain Change", "You dropped a frequency domain trace but the graph is still set up for the time domain." if(!InformationBox::AskQuestion("X Axis Domain Change", "You dropped a trace that is not supported with the currently selected X axis domain."
" Do you want to remove all traces and change the graph to frequency domain?", true, "DomainChangeRequest")) { " Do you want to remove all traces and change the graph to the correct domain?", true, "DomainChangeRequest")) {
// user declined to change domain, to not add trace // user declined to change domain, to not add trace
return; return;
} }
setXAxis(XAxisType::Frequency, XAxisMode::FitTraces, 0, 1, 0.1); switch(t->outputType()) {
setYAxis(0, YAxisType::Magnitude, false, true, 0, 1, 1.0); case Trace::DataType::Frequency:
setYAxis(1, YAxisType::Phase, false, true, 0, 1, 1.0); setXAxis(XAxisType::Frequency, XAxisMode::FitTraces, 0, 1, 0.1);
} setYAxis(0, YAxisType::Magnitude, false, true, 0, 1, 1.0);
if(t->outputType() != Trace::DataType::Frequency && XAxis.type == XAxisType::Frequency) { setYAxis(1, YAxisType::Phase, false, true, 0, 1, 1.0);
// needs to switch to time domain graph break;
if(!InformationBox::AskQuestion("X Axis Domain Change", "You dropped a time domain trace but the graph is still set up for the frequency domain." case Trace::DataType::Time:
" Do you want to remove all traces and change the graph to time domain?", true, "DomainChangeRequest")) { setXAxis(XAxisType::Time, XAxisMode::FitTraces, 0, 1, 0.1);
// user declined to change domain, to not add trace setYAxis(0, YAxisType::ImpulseMag, false, true, 0, 1, 1.0);
setYAxis(1, YAxisType::Disabled, false, true, 0, 1, 1.0);
break;
case Trace::DataType::Power:
setXAxis(XAxisType::Power, XAxisMode::FitTraces, 0, 1, 0.1);
setYAxis(0, YAxisType::Magnitude, false, true, 0, 1, 1.0);
setYAxis(1, YAxisType::Phase, false, true, 0, 1, 1.0);
break;
case Trace::DataType::Invalid:
// unable to add
return; return;
} }
setXAxis(XAxisType::Time, XAxisMode::FitTraces, 0, 1, 0.1);
setYAxis(0, YAxisType::ImpulseMag, false, true, 0, 1, 1.0);
setYAxis(1, YAxisType::Disabled, false, true, 0, 1, 1.0);
} }
if(YAxis[0].type == YAxisType::Disabled && YAxis[1].type == YAxisType::Disabled) { if(YAxis[0].type == YAxisType::Disabled && YAxis[1].type == YAxisType::Disabled) {
// no Y axis enabled, unable to drop // no Y axis enabled, unable to drop
return; return;
@ -1053,23 +1064,24 @@ QString TraceXYPlot::mouseText(QPoint pos)
QString TraceXYPlot::AxisUnit(TraceXYPlot::YAxisType type) QString TraceXYPlot::AxisUnit(TraceXYPlot::YAxisType type)
{ {
switch(type) { switch(type) {
case TraceXYPlot::YAxisType::Magnitude: return "db"; break; case TraceXYPlot::YAxisType::Magnitude: return "db";
case TraceXYPlot::YAxisType::Phase: return "°"; break; case TraceXYPlot::YAxisType::Phase: return "°";
case TraceXYPlot::YAxisType::VSWR: return ""; break; case TraceXYPlot::YAxisType::VSWR: return "";
case TraceXYPlot::YAxisType::ImpulseReal: return ""; break; case TraceXYPlot::YAxisType::ImpulseReal: return "";
case TraceXYPlot::YAxisType::ImpulseMag: return "db"; break; case TraceXYPlot::YAxisType::ImpulseMag: return "db";
case TraceXYPlot::YAxisType::Step: return ""; break; case TraceXYPlot::YAxisType::Step: return "";
case TraceXYPlot::YAxisType::Impedance: return "Ohm"; break; case TraceXYPlot::YAxisType::Impedance: return "Ohm";
default: return ""; break; default: return "";
} }
} }
QString TraceXYPlot::AxisUnit(TraceXYPlot::XAxisType type) QString TraceXYPlot::AxisUnit(TraceXYPlot::XAxisType type)
{ {
switch(type) { switch(type) {
case XAxisType::Frequency: return "Hz"; break; case XAxisType::Frequency: return "Hz";
case XAxisType::Time: return "s"; break; case XAxisType::Time: return "s";
case XAxisType::Distance: return "m"; break; case XAxisType::Distance: return "m";
case XAxisType::Power: return "dBm";
default: return ""; break; default: return ""; break;
} }
} }

View File

@ -34,6 +34,7 @@ public:
Frequency, Frequency,
Time, Time,
Distance, Distance,
Power,
Last, Last,
}; };
enum class XAxisMode { enum class XAxisMode {

View File

@ -18,6 +18,10 @@ XYplotAxisDialog::XYplotAxisDialog(TraceXYPlot *plot) :
ui->Y2type->addItem(TraceXYPlot::AxisTypeToName((TraceXYPlot::YAxisType) i)); ui->Y2type->addItem(TraceXYPlot::AxisTypeToName((TraceXYPlot::YAxisType) i));
} }
for(int i=0;i<(int) TraceXYPlot::XAxisType::Last;i++) {
ui->XType->addItem(TraceXYPlot::AxisTypeToName((TraceXYPlot::XAxisType) i));
}
// Setup GUI connections // Setup GUI connections
connect(ui->Y1type, qOverload<int>(&QComboBox::currentIndexChanged), [this](int index) { connect(ui->Y1type, qOverload<int>(&QComboBox::currentIndexChanged), [this](int index) {
//ui->Y1log->setEnabled(index != 0); //ui->Y1log->setEnabled(index != 0);
@ -178,6 +182,7 @@ std::set<TraceXYPlot::YAxisType> XYplotAxisDialog::supportedYAxis(TraceXYPlot::X
set<TraceXYPlot::YAxisType> ret = {TraceXYPlot::YAxisType::Disabled}; set<TraceXYPlot::YAxisType> ret = {TraceXYPlot::YAxisType::Disabled};
switch(type) { switch(type) {
case TraceXYPlot::XAxisType::Frequency: case TraceXYPlot::XAxisType::Frequency:
case TraceXYPlot::XAxisType::Power:
ret.insert(TraceXYPlot::YAxisType::Magnitude); ret.insert(TraceXYPlot::YAxisType::Magnitude);
ret.insert(TraceXYPlot::YAxisType::Phase); ret.insert(TraceXYPlot::YAxisType::Phase);
ret.insert(TraceXYPlot::YAxisType::VSWR); ret.insert(TraceXYPlot::YAxisType::VSWR);

View File

@ -313,23 +313,7 @@
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QComboBox" name="XType"> <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> </item>
</layout> </layout>
</item> </item>

View File

@ -235,6 +235,16 @@ VNA::VNA(AppWindow *window)
// Sweep toolbar // Sweep toolbar
auto tb_sweep = new QToolBar("Sweep"); auto tb_sweep = new QToolBar("Sweep");
std::vector<QAction*> frequencySweepActions;
std::vector<QAction*> powerSweepActions;
tb_sweep->addWidget(new QLabel("Sweep type:"));
auto cbSweepType = new QComboBox();
cbSweepType->addItem("Frequency");
cbSweepType->addItem("Power");
tb_sweep->addWidget(cbSweepType);
auto eStart = new SIUnitEdit("Hz", " kMG", 6); auto eStart = new SIUnitEdit("Hz", " kMG", 6);
// calculate width required with expected string length // calculate width required with expected string length
auto width = QFontMetrics(eStart->font()).width("3.00000GHz") + 15; auto width = QFontMetrics(eStart->font()).width("3.00000GHz") + 15;
@ -242,47 +252,80 @@ VNA::VNA(AppWindow *window)
eStart->setToolTip("Start frequency"); eStart->setToolTip("Start frequency");
connect(eStart, &SIUnitEdit::valueChanged, this, &VNA::SetStartFreq); connect(eStart, &SIUnitEdit::valueChanged, this, &VNA::SetStartFreq);
connect(this, &VNA::startFreqChanged, eStart, &SIUnitEdit::setValueQuiet); connect(this, &VNA::startFreqChanged, eStart, &SIUnitEdit::setValueQuiet);
tb_sweep->addWidget(new QLabel("Start:")); frequencySweepActions.push_back(tb_sweep->addWidget(new QLabel("Start:")));
tb_sweep->addWidget(eStart); frequencySweepActions.push_back(tb_sweep->addWidget(eStart));
auto eCenter = new SIUnitEdit("Hz", " kMG", 6); auto eCenter = new SIUnitEdit("Hz", " kMG", 6);
eCenter->setFixedWidth(width); eCenter->setFixedWidth(width);
eCenter->setToolTip("Center frequency"); eCenter->setToolTip("Center frequency");
connect(eCenter, &SIUnitEdit::valueChanged, this, &VNA::SetCenterFreq); connect(eCenter, &SIUnitEdit::valueChanged, this, &VNA::SetCenterFreq);
connect(this, &VNA::centerFreqChanged, eCenter, &SIUnitEdit::setValueQuiet); connect(this, &VNA::centerFreqChanged, eCenter, &SIUnitEdit::setValueQuiet);
tb_sweep->addWidget(new QLabel("Center:")); frequencySweepActions.push_back(tb_sweep->addWidget(new QLabel("Center:")));
tb_sweep->addWidget(eCenter); frequencySweepActions.push_back(tb_sweep->addWidget(eCenter));
auto eStop = new SIUnitEdit("Hz", " kMG", 6); auto eStop = new SIUnitEdit("Hz", " kMG", 6);
eStop->setFixedWidth(width); eStop->setFixedWidth(width);
eStop->setToolTip("Stop frequency"); eStop->setToolTip("Stop frequency");
connect(eStop, &SIUnitEdit::valueChanged, this, &VNA::SetStopFreq); connect(eStop, &SIUnitEdit::valueChanged, this, &VNA::SetStopFreq);
connect(this, &VNA::stopFreqChanged, eStop, &SIUnitEdit::setValueQuiet); connect(this, &VNA::stopFreqChanged, eStop, &SIUnitEdit::setValueQuiet);
tb_sweep->addWidget(new QLabel("Stop:")); frequencySweepActions.push_back(tb_sweep->addWidget(new QLabel("Stop:")));
tb_sweep->addWidget(eStop); frequencySweepActions.push_back(tb_sweep->addWidget(eStop));
auto eSpan = new SIUnitEdit("Hz", " kMG", 6); auto eSpan = new SIUnitEdit("Hz", " kMG", 6);
eSpan->setFixedWidth(width); eSpan->setFixedWidth(width);
eSpan->setToolTip("Span"); eSpan->setToolTip("Span");
connect(eSpan, &SIUnitEdit::valueChanged, this, &VNA::SetSpan); connect(eSpan, &SIUnitEdit::valueChanged, this, &VNA::SetSpan);
connect(this, &VNA::spanChanged, eSpan, &SIUnitEdit::setValueQuiet); connect(this, &VNA::spanChanged, eSpan, &SIUnitEdit::setValueQuiet);
tb_sweep->addWidget(new QLabel("Span:")); frequencySweepActions.push_back(tb_sweep->addWidget(new QLabel("Span:")));
tb_sweep->addWidget(eSpan); frequencySweepActions.push_back(tb_sweep->addWidget(eSpan));
auto bFull = new QPushButton(QIcon::fromTheme("zoom-fit-best", QIcon(":/icons/zoom-fit.png")), ""); auto bFull = new QPushButton(QIcon::fromTheme("zoom-fit-best", QIcon(":/icons/zoom-fit.png")), "");
bFull->setToolTip("Full span"); bFull->setToolTip("Full span");
connect(bFull, &QPushButton::clicked, this, &VNA::SetFullSpan); connect(bFull, &QPushButton::clicked, this, &VNA::SetFullSpan);
tb_sweep->addWidget(bFull); frequencySweepActions.push_back(tb_sweep->addWidget(bFull));
auto bZoomIn = new QPushButton(QIcon::fromTheme("zoom-in", QIcon(":/icons/zoom-in.png")), ""); auto bZoomIn = new QPushButton(QIcon::fromTheme("zoom-in", QIcon(":/icons/zoom-in.png")), "");
bZoomIn->setToolTip("Zoom in"); bZoomIn->setToolTip("Zoom in");
connect(bZoomIn, &QPushButton::clicked, this, &VNA::SpanZoomIn); connect(bZoomIn, &QPushButton::clicked, this, &VNA::SpanZoomIn);
tb_sweep->addWidget(bZoomIn); frequencySweepActions.push_back(tb_sweep->addWidget(bZoomIn));
auto bZoomOut = new QPushButton(QIcon::fromTheme("zoom-out", QIcon(":/icons/zoom-out.png")), ""); auto bZoomOut = new QPushButton(QIcon::fromTheme("zoom-out", QIcon(":/icons/zoom-out.png")), "");
bZoomOut->setToolTip("Zoom out"); bZoomOut->setToolTip("Zoom out");
connect(bZoomOut, &QPushButton::clicked, this, &VNA::SpanZoomOut); connect(bZoomOut, &QPushButton::clicked, this, &VNA::SpanZoomOut);
tb_sweep->addWidget(bZoomOut); frequencySweepActions.push_back(tb_sweep->addWidget(bZoomOut));
// power sweep widgets
auto sbPowerLow = new QDoubleSpinBox();
width = QFontMetrics(sbPowerLow->font()).width("-30.00dBm") + 20;
sbPowerLow->setFixedWidth(width);
sbPowerLow->setRange(-100.0, 100.0);
sbPowerLow->setSingleStep(0.25);
sbPowerLow->setSuffix("dbm");
sbPowerLow->setToolTip("Stimulus level");
sbPowerLow->setKeyboardTracking(false);
// TODO connect
powerSweepActions.push_back(tb_sweep->addWidget(new QLabel("From:")));
powerSweepActions.push_back(tb_sweep->addWidget(sbPowerLow));
auto sbPowerHigh = new QDoubleSpinBox();
width = QFontMetrics(sbPowerHigh->font()).width("-30.00dBm") + 20;
sbPowerHigh->setFixedWidth(width);
sbPowerHigh->setRange(-100.0, 100.0);
sbPowerHigh->setSingleStep(0.25);
sbPowerHigh->setSuffix("dbm");
sbPowerHigh->setToolTip("Stimulus level");
sbPowerHigh->setKeyboardTracking(false);
// TODO connect
powerSweepActions.push_back(tb_sweep->addWidget(new QLabel("To:")));
powerSweepActions.push_back(tb_sweep->addWidget(sbPowerHigh));
auto ePowerFreq = new SIUnitEdit("Hz", " kMG", 6);
width = QFontMetrics(ePowerFreq->font()).width("3.00000GHz") + 15;
ePowerFreq->setFixedWidth(width);
ePowerFreq->setToolTip("Start frequency");
// TODO connect
powerSweepActions.push_back(tb_sweep->addWidget(new QLabel("at:")));
powerSweepActions.push_back(tb_sweep->addWidget(ePowerFreq));
window->addToolBar(tb_sweep); window->addToolBar(tb_sweep);
toolbars.insert(tb_sweep); toolbars.insert(tb_sweep);
@ -299,8 +342,36 @@ VNA::VNA(AppWindow *window)
dbm->setKeyboardTracking(false); dbm->setKeyboardTracking(false);
connect(dbm, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &VNA::SetSourceLevel); connect(dbm, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &VNA::SetSourceLevel);
connect(this, &VNA::sourceLevelChanged, dbm, &QDoubleSpinBox::setValue); connect(this, &VNA::sourceLevelChanged, dbm, &QDoubleSpinBox::setValue);
tb_acq->addWidget(new QLabel("Level:")); frequencySweepActions.push_back(tb_acq->addWidget(new QLabel("Level:")));
tb_acq->addWidget(dbm); frequencySweepActions.push_back(tb_acq->addWidget(dbm));
auto configureToolbarForFrequencySweep = [=](){
for(auto a : frequencySweepActions) {
a->setVisible(true);
}
for(auto a : powerSweepActions) {
a->setVisible(false);
}
};
auto configureToolbarForPowerSweep = [=](){
for(auto a : frequencySweepActions) {
a->setVisible(false);
}
for(auto a : powerSweepActions) {
a->setVisible(true);
}
};
connect(cbSweepType, &QComboBox::currentTextChanged, [=](QString text) {
if(text == "Frequency") {
configureToolbarForFrequencySweep();
} else if(text == "Power") {
configureToolbarForPowerSweep();
}
});
// initial setup is frequency sweep
configureToolbarForFrequencySweep();
auto points = new QSpinBox(); auto points = new QSpinBox();
points->setFixedWidth(55); points->setFixedWidth(55);