Merge branch 'master' into compoundDevice

This commit is contained in:
Jan Käberich 2022-09-04 19:15:53 +02:00
commit 00ef868671
15 changed files with 579 additions and 633 deletions

View File

@ -684,18 +684,51 @@ void Marker::traceDataChanged()
void Marker::updateSymbol()
{
if(isDisplayedMarker()) {
constexpr int width = 15, height = 15;
symbol = QPixmap(width, height);
symbol.fill(Qt::transparent);
QPainter p(&symbol);
p.setRenderHint(QPainter::Antialiasing);
QPointF points[] = {QPointF(0,0),QPointF(width,0),QPointF(width/2,height)};
auto traceColor = parentTrace->color();
p.setPen(traceColor);
p.setBrush(traceColor);
p.drawConvexPolygon(points, 3);
p.setPen(Util::getFontColorFromBackground(traceColor));
p.drawText(QRectF(0,0,width, height*2.0/3.0), Qt::AlignCenter, QString::number(number) + suffix);
auto style = Preferences::getInstance().Marker.symbolStyle;
switch(style) {
case MarkerSymbolStyle::FilledNumberInside: {
constexpr int width = 15, height = 15;
symbol = QPixmap(width, height);
symbol.fill(Qt::transparent);
QPainter p(&symbol);
p.setRenderHint(QPainter::Antialiasing);
QPointF points[] = {QPointF(0,0),QPointF(width,0),QPointF(width/2,height)};
auto traceColor = parentTrace->color();
p.setPen(traceColor);
p.setBrush(traceColor);
p.drawConvexPolygon(points, 3);
p.setPen(Util::getFontColorFromBackground(traceColor));
p.drawText(QRectF(0,0,width, height * 2.0 / 3.0), Qt::AlignCenter, QString::number(number) + suffix);
}
break;
case MarkerSymbolStyle::FilledNumberAbove: {
constexpr int width = 15, height = 30;
symbol = QPixmap(width, height);
symbol.fill(Qt::transparent);
QPainter p(&symbol);
p.setRenderHint(QPainter::Antialiasing);
QPointF points[] = {QPointF(0,height/2),QPointF(width,height/2),QPointF(width/2,height)};
auto traceColor = parentTrace->color();
p.setPen(traceColor);
p.setBrush(traceColor);
p.drawConvexPolygon(points, 3);
p.drawText(QRectF(0,0,width, height * 0.45), Qt::AlignCenter, QString::number(number) + suffix);
}
break;
case MarkerSymbolStyle::EmptyNumberAbove: {
constexpr int width = 15, height = 30;
symbol = QPixmap(width, height);
symbol.fill(Qt::transparent);
QPainter p(&symbol);
p.setRenderHint(QPainter::Antialiasing);
QPointF points[] = {QPointF(0,height/2),QPointF(width,height/2),QPointF(width/2,height)};
auto traceColor = parentTrace->color();
p.setPen(traceColor);
p.drawConvexPolygon(points, 3);
p.drawText(QRectF(0,0,width, height * 0.45), Qt::AlignCenter, QString::number(number) + suffix);
}
break;
}
} else {
symbol = QPixmap(1,1);
}

View File

@ -17,8 +17,34 @@ ImpedanceRenormalization::ImpedanceRenormalization()
void ImpedanceRenormalization::transformDatapoint(VirtualDevice::VNAMeasurement &p)
{
//p.S = Sparam(ABCDparam(p.S, p.Z0), impedance);
// TODO
std::map<QString, std::complex<double>> transformed;
int ports = 0;
QString name = "S11";
while(p.measurements.count(name) > 0) {
ports++;
name = "S"+QString::number(ports+1)+QString::number(ports+1);
}
for(auto i=1;i<=ports;i++) {
auto S11name = "S"+QString::number(i)+QString::number(i);
auto S11 = p.measurements[S11name];
transformed[S11name] = Sparam(ABCDparam(Sparam(S11, 0.0, 0.0, 1.0), p.Z0), impedance).m11;
for(auto j=i+1;j<=ports;j++) {
auto S12name = "S"+QString::number(i)+QString::number(j);
auto S21name = "S"+QString::number(j)+QString::number(i);
auto S22name = "S"+QString::number(j)+QString::number(j);
if(!p.measurements.count(S12name) || !p.measurements.count(S21name) || !p.measurements.count(S22name)) {
// not all measurements available, skip this
continue;
}
auto S12 = p.measurements[S12name];
auto S21 = p.measurements[S21name];
auto S22 = p.measurements[S22name];
auto S_t = Sparam(ABCDparam(Sparam(S11, S12, S21, S22), p.Z0), impedance);
transformed[S12name] = S_t.m12;
transformed[S21name] = S_t.m21;
}
}
p.measurements = transformed;
p.Z0 = impedance;
}

View File

@ -24,6 +24,7 @@ MatchingNetwork::MatchingNetwork()
dragComponent = nullptr;
dropComponent = nullptr;
addNetwork = true;
port = 1;
}
void MatchingNetwork::transformDatapoint(VirtualDevice::VNAMeasurement &p)
@ -34,26 +35,40 @@ void MatchingNetwork::transformDatapoint(VirtualDevice::VNAMeasurement &p)
// this point is not calculated yet
MatchingPoint m;
// start with identiy matrix
m.p1 = ABCDparam(1.0,0.0,0.0,1.0);
for(auto c : p1Network) {
m.p1 = m.p1 * c->parameters(p.frequency);
}
// same for network at port 2
m.p2 = ABCDparam(1.0,0.0,0.0,1.0);
for(auto c : p2Network) {
m.p2 = m.p2 * c->parameters(p.frequency);
m.p = ABCDparam(1.0,0.0,0.0,1.0);
for(auto c : network) {
m.p = m.p * c->parameters(p.frequency);
}
if(!addNetwork) {
// need to remove the effect of the networks, invert matrices
m.p1 = m.p1.inverse();
m.p2 = m.p2.inverse();
// need to remove the effect of the network, invert matrix
m.p = m.p.inverse();
}
matching[p.frequency] = m;
}
// at this point the map contains the matching network effect
auto m = matching[p.frequency];
auto corrected = m.p1 * measurement * m.p2;
p.fromSparam(Sparam(corrected, p.Z0), 1, 2);
VirtualDevice::VNAMeasurement uncorrected = p;
// correct reflection measurement (in case no two-port measurement is complete
QString name = "S"+QString::number(port)+QString::number(port);
if(uncorrected.measurements.count(name) > 0) {
auto S = Sparam(uncorrected.measurements[name], 0.0, 0.0, 1.0);
auto corrected = Sparam(m.p * ABCDparam(S, p.Z0), p.Z0);
p.measurements[name] = corrected.m11;
}
// handle the rest of the measurements
for(int i=0;i<VirtualDevice::getInfo(VirtualDevice::getConnected()).ports;i++) {
for(int j=i+1;j<VirtualDevice::getInfo(VirtualDevice::getConnected()).ports;j++) {
if(i == port) {
auto S = uncorrected.toSparam(i, j);
auto corrected = Sparam(m.p * ABCDparam(S, p.Z0), p.Z0);
p.fromSparam(corrected, i, j);
} else if(j == port) {
auto S = uncorrected.toSparam(i, j);
auto corrected = Sparam(ABCDparam(S, p.Z0) * m.p, p.Z0);
p.fromSparam(corrected, i, j);
}
}
}
}
void MatchingNetwork::edit()
@ -80,6 +95,10 @@ void MatchingNetwork::edit()
ui->lParallelL->installEventFilter(this);
ui->lParallelR->installEventFilter(this);
ui->lDefinedThrough->installEventFilter(this);
ui->port->setValue(port);
ui->port->setMaximum(VirtualDevice::getInfo(VirtualDevice::getConnected()).ports);
layout->setContentsMargins(0,0,0,0);
layout->setSpacing(0);
layout->addStretch(1);
@ -93,26 +112,15 @@ void MatchingNetwork::edit()
DUT->setMaximumSize(DUTWidth, 151);
DUT->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
DUT->setStyleSheet("image: url(:/icons/DUT.png);");
auto p2 = new QWidget();
p2->setMinimumSize(portWidth, 151);
p2->setMaximumSize(portWidth, 151);
p2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
p2->setStyleSheet("image: url(:/icons/port2.png);");
layout->addWidget(p1);
for(auto w : p1Network) {
for(auto w : network) {
layout->addWidget(w);
connect(w, &MatchingComponent::MatchingComponent::valueChanged, [=](){
matching.clear();
});
}
layout->addWidget(DUT);
for(auto w : p2Network) {
layout->addWidget(w);
connect(w, &MatchingComponent::MatchingComponent::valueChanged, [=](){
matching.clear();
});
}
layout->addWidget(p2);
layout->addStretch(1);
@ -129,37 +137,34 @@ void MatchingNetwork::edit()
// network changed, need to recalculate matching
matching.clear();
});
connect(ui->port, qOverload<int>(&QSpinBox::valueChanged), [=](){
port = ui->port->value();
});
connect(ui->buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
}
nlohmann::json MatchingNetwork::toJSON()
{
nlohmann::json j;
nlohmann::json jn1, jn2;
for(auto c : p1Network) {
nlohmann::json jn;
for(auto c : network) {
nlohmann::json jc;
jc["component"] = c->getName().toStdString();
jc["params"] = c->toJSON();
jn1.push_back(jc);
jn.push_back(jc);
}
for(auto c : p2Network) {
nlohmann::json jc;
jc["component"] = c->getName().toStdString();
jc["params"] = c->toJSON();
jn2.push_back(jc);
}
j["port1"] = jn1;
j["port2"] = jn2;
j["port"] = port;
j["network"] = jn;
j["addNetwork"] = addNetwork;
return j;
}
void MatchingNetwork::fromJSON(nlohmann::json j)
{
p1Network.clear();
p2Network.clear();
if(j.contains("port1")) {
for(auto jc : j["port1"]) {
network.clear();
port = j.value("port", 1);
if(j.contains("network")) {
for(auto jc : j["network"]) {
if(!jc.contains("component")) {
continue;
}
@ -168,20 +173,7 @@ void MatchingNetwork::fromJSON(nlohmann::json j)
continue;
}
c->fromJSON(jc["params"]);
p1Network.push_back(c);
}
}
if(j.contains("port2")) {
for(auto jc : j["port2"]) {
if(!jc.contains("component")) {
continue;
}
auto c = MatchingComponent::createFromName(QString::fromStdString(jc["component"]));
if(!c) {
continue;
}
c->fromJSON(jc["params"]);
p2Network.push_back(c);
network.push_back(c);
}
}
addNetwork = j.value("addNetwork", true);
@ -192,15 +184,9 @@ MatchingComponent *MatchingNetwork::componentAtPosition(int pos)
{
pos -= graph->layout()->itemAt(0)->geometry().width();
pos -= portWidth;
if(pos > 0 && pos <= (int) p1Network.size() * componentWidth) {
if(pos > 0 && pos <= (int) network.size() * componentWidth) {
// position is in port 1 network
return p1Network[pos / componentWidth];
} else if(pos > (int) p1Network.size() * componentWidth + DUTWidth) {
pos -= (int) p1Network.size() * componentWidth + DUTWidth;
if(pos <= (int) p2Network.size() * componentWidth) {
// position is in port 2 network
return p2Network[pos / componentWidth];
}
return network[pos / componentWidth];
}
return nullptr;
}
@ -209,28 +195,15 @@ unsigned int MatchingNetwork::findInsertPosition(int xcoord)
{
xcoord -= graph->layout()->itemAt(0)->geometry().width();
xcoord -= portWidth;
if(xcoord <= (int) p1Network.size() * componentWidth + DUTWidth/2) {
// added in port 1 network
int index = (xcoord + componentWidth / 2) / componentWidth;
if(index < 0) {
index = 0;
} else if(index > (int) p1Network.size()) {
index = p1Network.size();
}
// add 2 (first two widgets are always the stretch and port 1 widget)
return index + 2;
} else {
// added in port 2 network
xcoord -= (int) p1Network.size() * componentWidth + DUTWidth;
int index = (xcoord + componentWidth / 2) / componentWidth;
if(index < 0) {
index = 0;
} else if(index > (int) p2Network.size()) {
index = p2Network.size();
}
// add 3 (same two widgets as in port 1 + DUT) and the size of the port 1 network
return index + 3 + p1Network.size();
// added in port 1 network
int index = (xcoord + componentWidth / 2) / componentWidth;
if(index < 0) {
index = 0;
} else if(index > (int) network.size()) {
index = network.size();
}
// add 2 (first two widgets are always the stretch and port 1 widget)
return index + 2;
}
void MatchingNetwork::addComponentAtPosition(int pos, MatchingComponent *c)
@ -242,12 +215,7 @@ void MatchingNetwork::addComponentAtPosition(int pos, MatchingComponent *c)
// add component to correct matching network
index -= 2; // first two widgets are fixed
if(index <= p1Network.size()) {
addComponent(true, index, c);
} else {
index -= 1 + p1Network.size();
addComponent(false, index, c);
}
addComponent(index, c);
// network changed, need to recalculate matching
matching.clear();
@ -256,22 +224,13 @@ void MatchingNetwork::addComponentAtPosition(int pos, MatchingComponent *c)
});
}
void MatchingNetwork::addComponent(bool port1, int index, MatchingComponent *c)
void MatchingNetwork::addComponent(int index, MatchingComponent *c)
{
if(port1) {
p1Network.insert(p1Network.begin() + index, c);
// remove from list when the component deletes itself
connect(c, &MatchingComponent::deleted, [=](){
p1Network.erase(remove(p1Network.begin(), p1Network.end(), c), p1Network.end());
});
} else {
// same procedure for port 2 network
p2Network.insert(p2Network.begin() + index, c);
// remove from list when the component deletes itself
connect(c, &MatchingComponent::deleted, [=](){
p2Network.erase(remove(p2Network.begin(), p2Network.end(), c), p2Network.end());
});
}
network.insert(network.begin() + index, c);
// remove from list when the component deletes itself
connect(c, &MatchingComponent::deleted, [=](){
network.erase(remove(network.begin(), network.end(), c), network.end());
});
}
void MatchingNetwork::createDragComponent(MatchingComponent *c)
@ -326,8 +285,7 @@ bool MatchingNetwork::eventFilter(QObject *object, QEvent *event)
// remove and hide component while it is being dragged
graph->layout()->removeWidget(dragComponent);
dragComponent->hide();
p1Network.erase(remove(p1Network.begin(), p1Network.end(), dragComponent), p1Network.end());
p2Network.erase(remove(p2Network.begin(), p2Network.end(), dragComponent), p2Network.end());
network.erase(remove(network.begin(), network.end(), dragComponent), network.end());
graph->update();
// network changed, need to recalculate matching

View File

@ -77,11 +77,13 @@ private:
MatchingComponent *componentAtPosition(int pos);
unsigned int findInsertPosition(int xcoord);
void addComponentAtPosition(int pos, MatchingComponent *c);
void addComponent(bool port1, int index, MatchingComponent *c);
void addComponent(int index, MatchingComponent *c);
void createDragComponent(MatchingComponent *c);
void updateInsertIndicator(int xcoord);
bool eventFilter(QObject *object, QEvent *event) override;
std::vector<MatchingComponent*> p1Network, p2Network;
std::vector<MatchingComponent*> network;
int port;
QWidget *graph, *insertIndicator;
QPoint dragStartPosition;
@ -91,7 +93,7 @@ private:
class MatchingPoint {
public:
ABCDparam p1, p2;
ABCDparam p;
};
std::map<double, MatchingPoint> matching;

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>772</width>
<height>443</height>
<width>913</width>
<height>633</height>
</rect>
</property>
<property name="windowTitle">
@ -21,6 +21,37 @@
</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Port:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="port">
<property name="minimum">
<number>1</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
@ -48,7 +79,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>750</width>
<width>891</width>
<height>168</height>
</rect>
</property>

View File

@ -13,50 +13,35 @@ using namespace std;
PortExtension::PortExtension()
: DeembeddingOption()
{
port1.enabled = false;
port1.frequency = 0;
port1.loss = 0;
port1.DCloss = 0;
port1.delay = 0;
port1.velocityFactor = 0.66;
port2.enabled = false;
port2.frequency = 0;
port2.loss = 0;
port2.DCloss = 0;
port2.delay = 0;
port2.velocityFactor = 0.66;
ext.frequency = 0;
ext.loss = 0;
ext.DCloss = 0;
ext.delay = 0;
ext.velocityFactor = 0.66;
port = 1;
kit = nullptr;
}
void PortExtension::transformDatapoint(VirtualDevice::VNAMeasurement &d)
{
if(port1.enabled || port2.enabled) {
if(port1.enabled) {
auto phase = -2 * M_PI * port1.delay * d.frequency;
auto db_attennuation = port1.DCloss;
if(port1.frequency != 0) {
db_attennuation += port1.loss * sqrt(d.frequency / port1.frequency);
}
// convert from db to factor
auto att = pow(10.0, -db_attennuation / 20.0);
auto correction = polar<double>(att, phase);
d.measurements["S11"] /= correction * correction;
d.measurements["S21"] /= correction;
d.measurements["S12"] /= correction;
auto phase = -2 * M_PI * ext.delay * d.frequency;
auto db_attennuation = ext.DCloss;
if(ext.frequency != 0) {
db_attennuation += ext.loss * sqrt(d.frequency / ext.frequency);
}
// convert from db to factor
auto att = pow(10.0, -db_attennuation / 20.0);
auto correction = polar<double>(att, phase);
for(auto &m : d.measurements) {
if(m.first.mid(1, 1).toInt() == port) {
// selected port is the destination of this S parameter
m.second /= correction;
}
if(port2.enabled) {
auto phase = -2 * M_PI * port2.delay * d.frequency;
auto db_attennuation = port2.DCloss;
if(port2.frequency != 0) {
db_attennuation += port2.loss * sqrt(d.frequency / port2.frequency);
}
// convert from db to factor
auto att = pow(10.0, -db_attennuation / 20.0);
auto correction = polar<double>(att, phase);
d.measurements["S22"] /= correction * correction;
d.measurements["S21"] /= correction;
d.measurements["S12"] /= correction;
if(m.first.mid(2, 1).toInt() == port) {
// selected port is the source of this S parameter
m.second /= correction;
}
}
}
@ -73,117 +58,56 @@ void PortExtension::edit()
});
// set initial values
ui->P1Enabled->setChecked(port1.enabled);
ui->P1Time->setUnit("s");
ui->P1Time->setPrefixes("pnum ");
ui->P1Distance->setUnit("m");
ui->P1Distance->setPrefixes("m ");
ui->P1DCloss->setUnit("db");
ui->P1Loss->setUnit("db");
ui->P1Frequency->setUnit("Hz");
ui->P1Frequency->setPrefixes(" kMG");
ui->P1Time->setValue(port1.delay);
ui->P1Velocity->setValue(port1.velocityFactor);
ui->P1Distance->setValue(port1.delay * port1.velocityFactor * c);
ui->P1DCloss->setValue(port1.DCloss);
ui->P1Loss->setValue(port1.loss);
ui->P1Frequency->setValue(port1.frequency);
ui->Time->setUnit("s");
ui->Time->setPrefixes("pnum ");
ui->Distance->setUnit("m");
ui->Distance->setPrefixes("m ");
ui->DCloss->setUnit("db");
ui->Loss->setUnit("db");
ui->Frequency->setUnit("Hz");
ui->Frequency->setPrefixes(" kMG");
ui->Time->setValue(ext.delay);
ui->Velocity->setValue(ext.velocityFactor);
ui->Distance->setValue(ext.delay * ext.velocityFactor * c);
ui->DCloss->setValue(ext.DCloss);
ui->Loss->setValue(ext.loss);
ui->Frequency->setValue(ext.frequency);
if(!kit) {
ui->P1calkit->setEnabled(false);
}
ui->P2Enabled->setChecked(port2.enabled);
ui->P2Time->setUnit("s");
ui->P2Time->setPrefixes("pnum ");
ui->P2Distance->setUnit("m");
ui->P2Distance->setPrefixes("m ");
ui->P2DCloss->setUnit("db");
ui->P2Loss->setUnit("db");
ui->P2Frequency->setUnit("Hz");
ui->P2Frequency->setPrefixes(" kMG");
ui->P2Time->setValue(port2.delay);
ui->P2Velocity->setValue(port2.velocityFactor);
ui->P2Distance->setValue(port2.delay * port2.velocityFactor * c);
ui->P2DCloss->setValue(port2.DCloss);
ui->P2Loss->setValue(port2.loss);
ui->P2Frequency->setValue(port2.frequency);
if(!kit) {
ui->P2calkit->setEnabled(false);
ui->calkit->setEnabled(false);
}
auto updateValuesFromUI = [=](){
port1.delay = ui->P1Time->value();
port1.velocityFactor = ui->P1Velocity->value();
port1.DCloss = ui->P1DCloss->value();
port1.loss = ui->P1Loss->value();
port1.frequency = ui->P1Frequency->value();
port2.delay = ui->P2Time->value();
port2.velocityFactor = ui->P2Velocity->value();
port2.DCloss = ui->P2DCloss->value();
port2.loss = ui->P2Loss->value();
port2.frequency = ui->P2Frequency->value();
ext.delay = ui->Time->value();
ext.velocityFactor = ui->Velocity->value();
ext.DCloss = ui->DCloss->value();
ext.loss = ui->Loss->value();
ext.frequency = ui->Frequency->value();
};
connect(ui->P1Enabled, &QCheckBox::toggled, [=](bool enabled) {
port1.enabled = enabled;
});
// connections to link delay and distance
connect(ui->P1Time, &SIUnitEdit::valueChanged, [=](double newval) {
ui->P1Distance->setValueQuiet(newval * ui->P1Velocity->value() * c);
connect(ui->Time, &SIUnitEdit::valueChanged, [=](double newval) {
ui->Distance->setValueQuiet(newval * ui->Velocity->value() * c);
updateValuesFromUI();
});
connect(ui->P1Distance, &SIUnitEdit::valueChanged, [=](double newval) {
ui->P1Time->setValueQuiet(newval / (ui->P1Velocity->value() * c));
connect(ui->Distance, &SIUnitEdit::valueChanged, [=](double newval) {
ui->Time->setValueQuiet(newval / (ui->Velocity->value() * c));
updateValuesFromUI();
});
connect(ui->P1Velocity, &SIUnitEdit::valueChanged, [=](double newval) {
ui->P1Time->setValueQuiet(ui->P1Distance->value() / (newval * c));
connect(ui->Velocity, &SIUnitEdit::valueChanged, [=](double newval) {
ui->Time->setValueQuiet(ui->Distance->value() / (newval * c));
updateValuesFromUI();
});
connect(ui->P1DCloss, &SIUnitEdit::valueChanged, updateValuesFromUI);
connect(ui->P1Loss, &SIUnitEdit::valueChanged, updateValuesFromUI);
connect(ui->P1Frequency, &SIUnitEdit::valueChanged, updateValuesFromUI);
connect(ui->P1short, &QPushButton::pressed, [=](){
connect(ui->DCloss, &SIUnitEdit::valueChanged, updateValuesFromUI);
connect(ui->Loss, &SIUnitEdit::valueChanged, updateValuesFromUI);
connect(ui->Frequency, &SIUnitEdit::valueChanged, updateValuesFromUI);
connect(ui->_short, &QPushButton::pressed, [=](){
isOpen = false;
isPort1 = true;
isIdeal = ui->P1ideal->isChecked();
isIdeal = ui->ideal->isChecked();
startMeasurement();
});
connect(ui->P1open, &QPushButton::pressed, [=](){
connect(ui->open, &QPushButton::pressed, [=](){
isOpen = true;
isPort1 = true;
isIdeal = ui->P1ideal->isChecked();
startMeasurement();
});
connect(ui->P2Enabled, &QCheckBox::toggled, [=](bool enabled) {
port2.enabled = enabled;
});
connect(ui->P2Time, &SIUnitEdit::valueChanged, [=](double newval) {
ui->P2Distance->setValueQuiet(newval * ui->P2Velocity->value() * c);
updateValuesFromUI();
});
connect(ui->P2Distance, &SIUnitEdit::valueChanged, [=](double newval) {
ui->P2Time->setValueQuiet(newval / (ui->P2Velocity->value() * c));
updateValuesFromUI();
});
connect(ui->P2Velocity, &SIUnitEdit::valueChanged, [=](double newval) {
ui->P2Time->setValueQuiet(ui->P2Distance->value() / (newval * c));
updateValuesFromUI();
});
connect(ui->P2DCloss, &SIUnitEdit::valueChanged, updateValuesFromUI);
connect(ui->P2Loss, &SIUnitEdit::valueChanged, updateValuesFromUI);
connect(ui->P2Frequency, &SIUnitEdit::valueChanged, updateValuesFromUI);
connect(ui->P2short, &QPushButton::pressed, [=](){
isOpen = false;
isPort1 = false;
isIdeal = ui->P2ideal->isChecked();
startMeasurement();
});
connect(ui->P2open, &QPushButton::pressed, [=](){
isOpen = true;
isPort1 = false;
isIdeal = ui->P2ideal->isChecked();
isIdeal = ui->ideal->isChecked();
startMeasurement();
});
@ -203,22 +127,17 @@ void PortExtension::measurementCompleted(std::vector<VirtualDevice::VNAMeasureme
double avg_x = 0.0, avg_y = 0.0;
for(auto p : m) {
// grab correct measurement
complex<double> reflection;
if(isPort1) {
reflection = p.measurements["S11"];
} else {
reflection = p.measurements["S22"];
}
QString name = "S"+QString::number(port)+QString::number(port);
auto reflection = p.measurements[name];
// remove calkit if specified
if(!isIdeal) {
complex<double> calStandard = 1.0;
// TODO
// auto standards = kit->toSOLT(p.frequency);
// if(isOpen) {
// calStandard = standards.Open;
// } else {
// calStandard = standards.Short;
// }
auto comp = isOpen ? CalStandard::Virtual::Type::Open : CalStandard::Virtual::Type::Short;
for(auto s : kit->getStandards()) {
if(s->getType() == comp) {
calStandard = static_cast<CalStandard::OnePort*>(s)->toS11(p.frequency);
}
}
// remove effect of calibration standard
reflection /= calStandard;
}
@ -266,23 +185,16 @@ void PortExtension::measurementCompleted(std::vector<VirtualDevice::VNAMeasureme
double DCloss = -alpha / 2;
double loss = -beta / 2;
double freq = m.back().frequency;
if(isPort1) {
ui->P1Time->setValue(delay);
ui->P1DCloss->setValue(DCloss);
ui->P1Loss->setValue(loss);
ui->P1Frequency->setValue(freq);
} else {
ui->P2Time->setValue(delay);
ui->P2DCloss->setValue(DCloss);
ui->P2Loss->setValue(loss);
ui->P2Frequency->setValue(freq);
}
ui->Time->setValue(delay);
ui->DCloss->setValue(DCloss);
ui->Loss->setValue(loss);
ui->Frequency->setValue(freq);
}
}
void PortExtension::startMeasurement()
{
emit triggerMeasurement(isPort1, false, false, !isPort1);
emit triggerMeasurement();
}
void PortExtension::setCalkit(Calkit *kit)
@ -293,35 +205,28 @@ void PortExtension::setCalkit(Calkit *kit)
nlohmann::json PortExtension::toJSON()
{
nlohmann::json j;
for(int i=0;i<2;i++) {
auto ext = i == 0 ? port1 : port2;
nlohmann::json je;
je["enabled"] = ext.enabled;
je["delay"] = ext.delay;
je["velocityFactor"] = ext.velocityFactor;
je["DCloss"] = ext.DCloss;
je["loss"] = ext.loss;
je["frequency"] = ext.frequency;
j.push_back(je);
}
j["port"] = port;
j["delay"] = ext.delay;
j["velocityFactor"] = ext.velocityFactor;
j["DCloss"] = ext.DCloss;
j["loss"] = ext.loss;
j["frequency"] = ext.frequency;
return j;
}
void PortExtension::fromJSON(nlohmann::json j)
{
for(int i=0;i<2;i++) {
Extension ext;
nlohmann::json je = j[i];
ext.enabled = je.value("enabled", false);
ext.delay = je.value("delay", 0.0);
ext.velocityFactor = je.value("velocityFactor", 0.66);
ext.DCloss = je.value("DCloss", 0.0);
ext.loss = je.value("loss", 0.0);
ext.frequency = je.value("frequency", 6000000000);
if(i==0) {
port1 = ext;
} else {
port2 = ext;
}
nlohmann::json jfrom;
if(j.contains("port")) {
// new format
jfrom = j;
} else {
jfrom = j[0];
port = 1;
}
ext.delay = jfrom.value("delay", 0.0);
ext.velocityFactor = jfrom.value("velocityFactor", 0.66);
ext.DCloss = jfrom.value("DCloss", 0.0);
ext.loss = jfrom.value("loss", 0.0);
ext.frequency = jfrom.value("frequency", 6000000000);
}

View File

@ -31,18 +31,17 @@ private:
void startMeasurement();
class Extension {
public:
bool enabled;
double delay;
double velocityFactor;
double DCloss;
double loss;
double frequency;
};
Extension port1, port2;
Extension ext;
// status variables for automatic measurements
Calkit *kit;
bool isPort1;
int port;
bool isOpen;
bool isIdeal;

View File

@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>318</width>
<height>505</height>
<width>312</width>
<height>459</height>
</rect>
</property>
<property name="windowTitle">
@ -21,310 +21,157 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Port:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="port">
<property name="minimum">
<number>1</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Delay</string>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Port 1</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QCheckBox" name="P1Enabled">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Delay</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Distance:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="SIUnitEdit" name="P1Distance"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Time:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="SIUnitEdit" name="P1Time"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Velocity Factor:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="SIUnitEdit" name="P1Velocity"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Loss</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>At DC:</string>
</property>
</widget>
</item>
<item>
<widget class="SIUnitEdit" name="P1DCloss"/>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="SIUnitEdit" name="P1Loss"/>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>at</string>
</property>
</widget>
</item>
<item>
<widget class="SIUnitEdit" name="P1Frequency"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Determine automatically</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QRadioButton" name="P1ideal">
<property name="text">
<string>Assume ideal open/short</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="P1calkit">
<property name="text">
<string>Use definition from calibration kit</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="P1short">
<property name="text">
<string>Measure short</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="P1open">
<property name="text">
<string>Measure open</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Port 2</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QCheckBox" name="P2Enabled">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_6">
<property name="title">
<string>Delay</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Distance:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="SIUnitEdit" name="P2Distance"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Time:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="SIUnitEdit" name="P2Time"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Velocity Factor:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="SIUnitEdit" name="P2Velocity"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_5">
<property name="title">
<string>Loss</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>At DC:</string>
</property>
</widget>
</item>
<item>
<widget class="SIUnitEdit" name="P2DCloss"/>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="SIUnitEdit" name="P2Loss"/>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>at</string>
</property>
</widget>
</item>
<item>
<widget class="SIUnitEdit" name="P2Frequency"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Determine automatically</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QRadioButton" name="P2ideal">
<property name="text">
<string>Assume ideal open/short</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="P2calkit">
<property name="text">
<string>Use definition from calibration kit</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="P2short">
<property name="text">
<string>Measure short</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="P2open">
<property name="text">
<string>Measure open</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Distance:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="SIUnitEdit" name="Distance"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Time:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="SIUnitEdit" name="Time"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Velocity Factor:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="SIUnitEdit" name="Velocity"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Loss</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>At DC:</string>
</property>
</widget>
</item>
<item>
<widget class="SIUnitEdit" name="DCloss"/>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="SIUnitEdit" name="Loss"/>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>at</string>
</property>
</widget>
</item>
<item>
<widget class="SIUnitEdit" name="Frequency"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Determine automatically</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QRadioButton" name="ideal">
<property name="text">
<string>Assume ideal open/short</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="calkit">
<property name="text">
<string>Use definition from calibration kit</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="_short">
<property name="text">
<string>Measure short</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="open">
<property name="text">
<string>Measure open</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>

View File

@ -13,13 +13,15 @@ using namespace std;
TwoThru::TwoThru()
{
Z0 = 50.0;
port1 = 1;
port2 = 2;
}
void TwoThru::transformDatapoint(VirtualDevice::VNAMeasurement &p)
{
// correct measurement
if(points.size() > 0) {
Tparam meas(p.toSparam(1,2));
Tparam meas(p.toSparam(port1,port2));
Tparam inv1, inv2;
if(p.frequency < points.front().freq) {
@ -49,7 +51,7 @@ void TwoThru::transformDatapoint(VirtualDevice::VNAMeasurement &p)
// perform correction
Tparam corrected = inv1*meas*inv2;
// transform back into S parameters
p.fromSparam(Sparam(corrected), 1, 2);
p.fromSparam(Sparam(corrected), port1, port2);
}
}
@ -125,6 +127,27 @@ void TwoThru::edit()
ui->Z0->setVisible(false);
ui->lZ0->setVisible(false);
ui->port1->setValue(port1);
ui->port1->setMaximum(VirtualDevice::getInfo(VirtualDevice::getConnected()).ports);
ui->port2->setValue(port2);
ui->port2->setMaximum(VirtualDevice::getInfo(VirtualDevice::getConnected()).ports);
auto portChanged = [=](){
port1 = ui->port1->value();
port2 = ui->port2->value();
// clear all points
points.clear();
measurements2xthru.clear();
measurementsDUT.clear();
// enable taking of new measurements only if ports are different
ui->bMeasure->setEnabled(port1 != port2);
ui->bMeasureDUT->setEnabled(port1 != port2);
updateGUI();
};
connect(ui->port1, qOverload<int>(&QSpinBox::valueChanged), portChanged);
connect(ui->port2, qOverload<int>(&QSpinBox::valueChanged), portChanged);
connect(ui->bMeasure, &QPushButton::clicked, [=](){
measuringDUT = false;
measuring2xthru = true;
@ -168,6 +191,8 @@ void TwoThru::edit()
nlohmann::json TwoThru::toJSON()
{
nlohmann::json j;
j["port1"] = port1;
j["port2"] = port2;
for(auto p : points) {
nlohmann::json jp;
jp["frequency"] = p.freq;
@ -194,6 +219,8 @@ nlohmann::json TwoThru::toJSON()
void TwoThru::fromJSON(nlohmann::json j)
{
port1 = j.value("port1", 1);
port2 = j.value("port2", 2);
points.clear();
for(auto jp : j) {
Point p;
@ -229,10 +256,11 @@ std::vector<TwoThru::Point> TwoThru::calculateErrorBoxes(std::vector<VirtualDevi
// ignore possible DC point
continue;
}
S11.push_back(m.measurements["S11"]);
S12.push_back(m.measurements["S12"]);
S21.push_back(m.measurements["S21"]);
S22.push_back(m.measurements["S22"]);
auto S = m.toSparam(port1, port2);
S11.push_back(S.m11);
S12.push_back(S.m12);
S21.push_back(S.m21);
S22.push_back(S.m22);
f.push_back(m.frequency);
}
auto n = f.size();

View File

@ -33,12 +33,13 @@ private:
};
static std::vector<VirtualDevice::VNAMeasurement> interpolateEvenFrequencySteps(std::vector<VirtualDevice::VNAMeasurement> input);
static std::vector<Point> calculateErrorBoxes(std::vector<VirtualDevice::VNAMeasurement> data_2xthru);
static std::vector<Point> calculateErrorBoxes(std::vector<VirtualDevice::VNAMeasurement> data_2xthru, std::vector<VirtualDevice::VNAMeasurement> data_fix_dut_fix, double z0);
std::vector<Point> calculateErrorBoxes(std::vector<VirtualDevice::VNAMeasurement> data_2xthru);
std::vector<Point> calculateErrorBoxes(std::vector<VirtualDevice::VNAMeasurement> data_2xthru, std::vector<VirtualDevice::VNAMeasurement> data_fix_dut_fix, double z0);
std::vector<VirtualDevice::VNAMeasurement> measurements2xthru;
std::vector<VirtualDevice::VNAMeasurement> measurementsDUT;
double Z0;
int port1, port2;
std::vector<Point> points;
bool measuring2xthru;
bool measuringDUT;

View File

@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>701</width>
<height>465</height>
<width>732</width>
<height>520</height>
</rect>
</property>
<property name="windowTitle">
@ -19,7 +19,7 @@
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,0,0">
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,0,0,0">
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
@ -51,6 +51,56 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Configuration</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>2xthru is between ports</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="port1">
<property name="minimum">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>and</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="port2">
<property name="minimum">
<number>1</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">

View File

@ -1,11 +1,14 @@
#include "appwindow.h"
#include <QtWidgets/QApplication>
#include "Device/device.h"
#include "Device/virtualdevice.h"
#ifdef Q_OS_UNIX
#include <signal.h>
#endif
#include "Tools/parameters.h"
#include <complex>
using namespace std;
static QApplication *app;
static AppWindow *window;
@ -21,9 +24,6 @@ int main(int argc, char *argv[]) {
qSetMessagePattern("%{time process}: [%{type}] %{message}");
Device::RegisterTypes();
VirtualDevice::RegisterTypes();
app = new QApplication(argc, argv);
QCoreApplication::setOrganizationName("LibreVNA");
QCoreApplication::setApplicationName("LibreVNA-GUI");
@ -31,6 +31,34 @@ int main(int argc, char *argv[]) {
QCoreApplication::setApplicationVersion(window->getAppVersion() + "-" +
window->getAppGitHash().left(9));
Device::RegisterTypes();
auto S11 = complex<double>(-0.5, 0.25);
auto S22 = complex<double>(0.5, 0.15);
auto S33 = complex<double>(0.8, -0.25);
auto S12 = complex<double>(0.1, 0);
auto S21 = complex<double>(0.2, 0.3);
auto S13 = complex<double>(0.3, -0.2);
auto S31 = complex<double>(0.4, 0.4);
auto S23 = complex<double>(0.5, 0.2);
auto S32 = complex<double>(0.6, -0.2);
auto p12 = Sparam(S11, S12, S21, S22);
auto p12_only = Sparam(0.0, S12, 1.0, 0.0);
auto p13 = Sparam(S11, S13, S31, S33);
auto p23 = Sparam(S22, S23, S32, S33);
// convert to 75 ohm
auto p12_75 = Sparam(ABCDparam(p12, 50.0), 75.0);
auto p12_only_75 = Sparam(ABCDparam(p12_only, 50.0), 75.0);
auto p13_75 = Sparam(ABCDparam(p12, 50.0), 75.0);
auto Zp23_75 = Sparam(ABCDparam(p12, 50.0), 75.0);
auto p1 = Sparam(S11, 0.0, 0.0, 1.0);
auto p1_75 = Sparam(ABCDparam(p12, 50.0), 75.0);
#ifdef Q_OS_UNIX
signal(SIGINT, tryExitGracefully);

View File

@ -310,6 +310,7 @@ void PreferencesDialog::setInitialGUIState()
ui->MarkerShowAllMarkerData->setChecked(p->Marker.defaultBehavior.showAllData);
ui->MarkerInterpolate->setCurrentIndex(p->Marker.interpolatePoints ? 1 : 0);
ui->MarkerSortOrder->setCurrentIndex((int) p->Marker.sortOrder);
ui->MarkerSymbolStyle->setCurrentIndex((int) p->Marker.symbolStyle);
ui->SCPIServerEnabled->setChecked(p->SCPIServer.enabled);
ui->SCPIServerPort->setValue(p->SCPIServer.port);
@ -380,6 +381,7 @@ void PreferencesDialog::updateFromGUI()
p->Marker.defaultBehavior.showAllData = ui->MarkerShowAllMarkerData->isChecked();
p->Marker.interpolatePoints = ui->MarkerInterpolate->currentIndex() == 1;
p->Marker.sortOrder = (MarkerSortOrder) ui->MarkerSortOrder->currentIndex();
p->Marker.symbolStyle = (MarkerSymbolStyle) ui->MarkerSymbolStyle->currentIndex();
p->SCPIServer.enabled = ui->SCPIServerEnabled->isChecked();
p->SCPIServer.port = ui->SCPIServerPort->value();

View File

@ -34,6 +34,14 @@ enum MarkerSortOrder {
Q_DECLARE_METATYPE(MarkerSortOrder)
enum MarkerSymbolStyle {
FilledNumberInside = 0,
FilledNumberAbove = 1,
EmptyNumberAbove = 2,
};
Q_DECLARE_METATYPE(MarkerSymbolStyle);
class Preferences : public Savable {
public:
@ -126,6 +134,7 @@ public:
} defaultBehavior;
bool interpolatePoints;
MarkerSortOrder sortOrder;
MarkerSymbolStyle symbolStyle;
} Marker;
struct {
bool enabled;
@ -204,6 +213,7 @@ private:
{&Marker.defaultBehavior.showAllData, "Marker.defaultBehavior.ShowAllData", false},
{&Marker.interpolatePoints, "Marker.interpolatePoints", false},
{&Marker.sortOrder, "Marker.sortOrder", MarkerSortOrder::PrefMarkerSortXCoord},
{&Marker.symbolStyle, "Marker.symbolStyle", MarkerSymbolStyle::EmptyNumberAbove},
{&SCPIServer.enabled, "SCPIServer.enabled", true},
{&SCPIServer.port, "SCPIServer.port", 19542},
{&compoundDeviceJSON, "compoundDeviceJSON", "[]"},

View File

@ -84,7 +84,7 @@
<x>0</x>
<y>0</y>
<width>687</width>
<height>938</height>
<height>884</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_12">
@ -103,7 +103,7 @@
</size>
</property>
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="Startup">
<layout class="QHBoxLayout" name="horizontalLayout_4">
@ -1286,6 +1286,32 @@
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_45">
<property name="text">
<string>Symbol Style:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="MarkerSymbolStyle">
<item>
<property name="text">
<string>Filled triangle - Marker number inside</string>
</property>
</item>
<item>
<property name="text">
<string>Filled triangle - Marker number above</string>
</property>
</item>
<item>
<property name="text">
<string>Empty triangle - Marker number above</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>