Contant lines/limits on XY-Plot

This commit is contained in:
Jan Käberich 2022-04-22 13:46:46 +02:00
parent cacea26e3f
commit 27490e1a33
14 changed files with 201 additions and 33 deletions

View File

@ -379,6 +379,9 @@ Example (assuming <averaging sweep> = 3):
\subsubsection{VNA:ACQuisition:FINished}
\query{Queries whether the average filter has reached a steady state (that is <acquired sweeps> = <averaging sweeps>)}{VNA:ACQuisition:FINished?}{None}{TRUE or FALSE}
\subsubsection{VNA:ACQuisition:LIMit}
\query{Queries the status of limits that maybe set up on any graph}{VNA:ACQuisition:LIMit?}{None}{PASS or FAIL}
\subsubsection{VNA:STIMulus:LVL}
\event{Sets the output power of the stimulus signal when sweep type is frequency}{VNA:STIMulus:LVL}{<power>, in dBm}
\query{Queries the currently selected output power}{VNA:STIMulus:LVL?}{None}{power in dBm}
@ -602,6 +605,9 @@ Example (assuming <averaging sweep> = 3):
\subsubsection{SA:ACQuisition:FINished}
\query{Queries whether the average filter has reached a steady state (that is <acquired sweeps> = <averaging sweeps>)}{SA:ACQuisition:FINished?}{None}{TRUE or FALSE}
\subsubsection{SA:ACQuisition:LIMit}
\query{Queries the status of limits that maybe set up on any graph}{SA:ACQuisition:LIMit?}{None}{PASS or FAIL}
\subsubsection{SA:ACQuisition:SIGid}
\event{Enables/disables signal identification}{SA:ACQuisition:SIGid}{<enabled>, option are TRUE, FALSE, 1 or 0}
\query{Queries whether signal identification is enabled}{SA:ACQuisition:SIGid?}{None}{TRUE or FALSE}

View File

@ -110,6 +110,18 @@ void TileWidget::fromJSON(nlohmann::json j)
}
}
bool TileWidget::allLimitsPassing()
{
if(isSplit) {
return child1->allLimitsPassing() && child2->allLimitsPassing();
} else if(hasContent) {
return content->getLimitPassing();
} else {
// empty tile always passes
return true;
}
}
void TileWidget::splitVertically()
{
if(isSplit) {

View File

@ -28,6 +28,9 @@ public:
virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override;
// check potential trace limits on graphs, only returns true if all traces in all graphs are within limits
bool allLimitsPassing();
public slots:
void splitVertically();
void splitHorizontally();

View File

@ -905,6 +905,9 @@ void SpectrumAnalyzer::SetupSCPI()
scpi_acq->add(new SCPICommand("FINished", nullptr, [=](QStringList) -> QString {
return average.getLevel() == averages ? "TRUE" : "FALSE";
}));
scpi_acq->add(new SCPICommand("LIMit", nullptr, [=](QStringList) -> QString {
return central->allLimitsPassing() ? "PASS" : "FAIL";
}));
scpi_acq->add(new SCPICommand("SIGid", [=](QStringList params) -> QString {
if (params.size() != 1) {
return "ERROR";

View File

@ -97,10 +97,16 @@
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTableWidget" name="tableWidget">
<widget class="QTableWidget" name="pointTable">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
@ -186,21 +192,5 @@
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>XYPlotConstantLineEditDialog</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>
</ui>

View File

@ -22,7 +22,8 @@ TracePlot::TracePlot(TraceModel &model, QWidget *parent)
traceRemovalPending(false),
dropPending(false),
dropTrace(nullptr),
marginTop(20)
marginTop(20),
limitPassing(true)
{
contextmenu = new QMenu();
markedForDeletion = false;
@ -492,6 +493,11 @@ void TracePlot::markerRemoved(Marker *m)
triggerReplot();
}
bool TracePlot::getLimitPassing() const
{
return limitPassing;
}
TraceModel &TracePlot::getModel() const
{
return model;

View File

@ -32,6 +32,8 @@ public:
TraceModel &getModel() const;
bool getLimitPassing() const;
public slots:
void updateGraphColors();
@ -106,6 +108,8 @@ protected:
QLabel *cursorLabel;
unsigned int marginTop;
bool limitPassing;
};
#endif // TRACEPLOT_H

View File

@ -350,7 +350,7 @@ void TraceXYPlot::draw(QPainter &p)
{
auto pref = Preferences::getInstance();
bool limitPassing = true;
limitPassing = true;
auto w = p.window();
auto pen = QPen(pref.Graphs.Color.axis, 0);
@ -647,7 +647,42 @@ void TraceXYPlot::draw(QPainter &p)
}
}
// TODO check limitPassing
// only show limit indication if there are limit lines configured
if(constantLines.size() > 0) {
switch(pref.Graphs.limitIndication) {
case GraphLimitIndication::PassFailText: {
QString text;
if(limitPassing) {
p.setPen(Qt::green);
text = "PASS";
} else {
p.setPen(Qt::red);
text = "FAIL";
}
auto font = p.font();
font.setPixelSize(20);
p.setFont(font);
p.drawText(plotRect.x() + 2, plotRect.y() + 22, text);
}
break;
case GraphLimitIndication::Overlay:
if(!limitPassing) {
p.setOpacity(0.5);
p.setBrush(Qt::red);
p.setPen(Qt::red);
p.drawRect(plotRect);
auto font = p.font();
font.setPixelSize(20);
p.setFont(font);
p.setOpacity(1.0);
p.setPen(Qt::red);
p.drawText(plotRect, Qt::AlignCenter, "LIMIT FAIL");
}
break;
default:
break;
}
}
if(dropPending) {
p.setOpacity(0.5);
@ -1200,18 +1235,72 @@ void XYPlotConstantLine::editDialog(QString xUnit, QString yUnitPrimary, QString
connect(ui->color, &ColorPickerButton::colorChanged, [=](){
color = ui->color->getColor();
});
auto updatePointTable = [=](){
sort(points.begin(), points.end(), [](QPointF &a, QPointF &b) -> bool{
return a.x() < b.x();
});
ui->pointTable->blockSignals(true);
ui->pointTable->clear();
ui->pointTable->setHorizontalHeaderLabels({"#", "X", "Y"});
ui->pointTable->setColumnCount(3);
ui->pointTable->setRowCount(points.size());
QString yUnit = axis == Axis::Primary ? yUnitPrimary : yUnitSecondary;
for(unsigned int i=0;i<points.size();i++) {
auto numItem = new QTableWidgetItem(QString::number(i+1));
numItem->setFlags(numItem->flags() &= ~(Qt::ItemIsEditable | Qt::ItemIsSelectable));
auto xItem = new QTableWidgetItem(Unit::ToString(points[i].x(), xUnit, "pnum kMG", 6));
auto yItem = new QTableWidgetItem(Unit::ToString(points[i].y(), yUnit, "pnum kMG", 6));
ui->pointTable->setItem(i, 0, numItem);
ui->pointTable->setItem(i, 1, xItem);
ui->pointTable->setItem(i, 2, yItem);
}
ui->pointTable->blockSignals(false);
};
connect(ui->axis, qOverload<int>(&QComboBox::currentIndexChanged), [=](){
axis = (Axis) ui->axis->currentIndex();
// TODO apply unit change
updatePointTable();
});
connect(ui->passFail, qOverload<int>(&QComboBox::currentIndexChanged), [=](){
passFail = (PassFail) ui->passFail->currentIndex();
});
// TODO handle adding/removing of points
// handle adding/removing of points
connect(ui->pointTable, &QTableWidget::itemChanged, [=](QTableWidgetItem *item){
auto row = ui->pointTable->row(item);
auto column = ui->pointTable->column(item);
auto& point = points[row];
if(column == 1) {
// changed X coordinate
point.setX(Unit::FromString(item->text(), xUnit, "pnum kMG"));
// potentially reordered the points, update whole table
updatePointTable();
} else {
// change Y coordinate
QString yUnit = axis == Axis::Primary ? yUnitPrimary : yUnitSecondary;
point.setY(Unit::FromString(item->text(), yUnit, "pnum kMG"));
// point order only depends on X coordinate, no table update necessary, only update text of the changed item
ui->pointTable->blockSignals(true);
item->setText(Unit::ToString(point.y(), yUnit, "pnum kMG", 6));
ui->pointTable->blockSignals(false);
}
});
connect(ui->addPoint, &QPushButton::clicked, [=](){
points.push_back(QPointF());
updatePointTable();
});
connect(ui->removePoint, &QPushButton::clicked, [=](){
auto row = ui->pointTable->currentRow();
if(row >= 0 && row < (int) points.size()) {
points.erase(points.begin() + row);
updatePointTable();
}
});
connect(d, &QDialog::finished, this, &XYPlotConstantLine::editingFinished);
updatePointTable();
if(AppWindow::showGUI()) {
d->show();
}
@ -1221,7 +1310,8 @@ QString XYPlotConstantLine::getDescription()
{
QString ret;
ret += name;
ret += ", " + QString::number(points.size()) + " points, limit: "+PassFailToString(passFail);
ret += ", " + AxisToString(axis) + " axis, ";
ret += QString::number(points.size()) + " points, limit: "+PassFailToString(passFail);
return ret;
}

View File

@ -165,7 +165,11 @@ XYplotAxisDialog::XYplotAxisDialog(TraceXYPlot *plot) :
};
for(auto l : plot->constantLines) {
ui->lineList->addItem(l->getDescription());
auto item = new QListWidgetItem(l->getDescription());
ui->lineList->addItem(item);
connect(l, &XYPlotConstantLine::editingFinished, [=](){
item->setText(l->getDescription());
});
}
if(plot->constantLines.size() > 0) {
ui->removeLine->setEnabled(true);

View File

@ -1374,6 +1374,9 @@ void VNA::SetupSCPI()
scpi_acq->add(new SCPICommand("FINished", nullptr, [=](QStringList) -> QString {
return average.getLevel() == averages ? "TRUE" : "FALSE";
}));
scpi_acq->add(new SCPICommand("LIMit", nullptr, [=](QStringList) -> QString {
return central->allLimitsPassing() ? "PASS" : "FAIL";
}));
auto scpi_stim = new SCPINode("STIMulus");
SCPINode::add(scpi_stim);
scpi_stim->add(new SCPICommand("LVL", [=](QStringList params) -> QString {

View File

@ -248,6 +248,7 @@ void PreferencesDialog::setInitialGUIState()
ui->GraphsColorTicksBackgroundEnabled->setChecked(p->Graphs.Color.Ticks.Background.enabled);
ui->GraphsColorTicksBackground->setColor(p->Graphs.Color.Ticks.Background.background);
ui->GraphsDomainChangeBehavior->setCurrentIndex((int) p->Graphs.domainChangeBehavior);
ui->GraphsLimitIndication->setCurrentIndex((int) p->Graphs.limitIndication);
ui->GraphsLineWidth->setValue(p->Graphs.lineWidth);
ui->GraphsFontSizeAxis->setValue(p->Graphs.fontSizeAxis);
ui->GraphsFontSizeCursorOverlay->setValue(p->Graphs.fontSizeCursorOverlay);
@ -312,6 +313,7 @@ void PreferencesDialog::updateFromGUI()
p->Graphs.Color.Ticks.Background.background = ui->GraphsColorTicksBackground->getColor();
p->Graphs.Color.Ticks.divisions = ui->GraphsColorTicksDivisions->getColor();
p->Graphs.domainChangeBehavior = (GraphDomainChangeBehavior) ui->GraphsDomainChangeBehavior->currentIndex();
p->Graphs.limitIndication = (GraphLimitIndication) ui->GraphsLimitIndication->currentIndex();
p->Graphs.lineWidth = ui->GraphsLineWidth->value();
p->Graphs.fontSizeAxis = ui->GraphsFontSizeAxis->value();
p->Graphs.fontSizeCursorOverlay = ui->GraphsFontSizeCursorOverlay->value();

View File

@ -16,6 +16,14 @@ enum GraphDomainChangeBehavior {
Q_DECLARE_METATYPE(GraphDomainChangeBehavior);
enum GraphLimitIndication {
DontShowAnything = 0,
PassFailText = 1,
Overlay = 2,
};
Q_DECLARE_METATYPE(GraphLimitIndication);
class Preferences : public Savable {
public:
@ -93,6 +101,7 @@ public:
} Ticks;
} Color;
GraphDomainChangeBehavior domainChangeBehavior;
GraphLimitIndication limitIndication;
double lineWidth;
int fontSizeAxis;
@ -166,6 +175,7 @@ private:
{&Graphs.Color.Ticks.Background.background, "Graphs.Color.Ticks.Background.background", QColor(20, 20, 20)},
{&Graphs.Color.Ticks.divisions, "Graphs.Color.Ticks.divisions", QColor(Qt::gray)},
{&Graphs.domainChangeBehavior, "Graphs.domainChangeBehavior", GraphDomainChangeBehavior::AdjustGraphs},
{&Graphs.limitIndication, "Graphs.limitIndication", GraphLimitIndication::PassFailText},
{&Graphs.lineWidth, "Graphs.lineWidth", 1.0},
{&Graphs.fontSizeAxis, "Graphs.fontSizeAxis", 10},
{&Graphs.fontSizeCursorOverlay, "Graphs.fontSizeCursorOverlay", 12},

View File

@ -77,9 +77,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>654</width>
<height>884</height>
<y>-319</y>
<width>651</width>
<height>854</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_12">
@ -98,7 +98,7 @@
</size>
</property>
<property name="currentIndex">
<number>3</number>
<number>2</number>
</property>
<widget class="QWidget" name="Startup">
<layout class="QHBoxLayout" name="horizontalLayout_4">
@ -1150,6 +1150,41 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_17">
<property name="title">
<string>Limit checking</string>
</property>
<layout class="QFormLayout" name="formLayout_12">
<item row="0" column="0">
<widget class="QLabel" name="label_43">
<property name="text">
<string>Behavior:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="GraphsLimitIndication">
<item>
<property name="text">
<string>Don't show any indication</string>
</property>
</item>
<item>
<property name="text">
<string>PASS/FAIL text in graph corner</string>
</property>
</item>
<item>
<property name="text">
<string>Overlay over whole graph on FAIL</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
@ -1360,16 +1395,16 @@
</layout>
</widget>
<customwidgets>
<customwidget>
<class>SIUnitEdit</class>
<extends>QLineEdit</extends>
<header>CustomWidgets/siunitedit.h</header>
</customwidget>
<customwidget>
<class>ColorPickerButton</class>
<extends>QPushButton</extends>
<header>CustomWidgets/colorpickerbutton.h</header>
</customwidget>
<customwidget>
<class>SIUnitEdit</class>
<extends>QLineEdit</extends>
<header>CustomWidgets/siunitedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>